diff --git a/lib/python3.12/site-packages/packaging/__init__.py b/lib/python3.12/site-packages/packaging/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..d45c22cfd88e2b88976b46d4171a502b602658ec --- /dev/null +++ b/lib/python3.12/site-packages/packaging/__init__.py @@ -0,0 +1,15 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +__title__ = "packaging" +__summary__ = "Core utilities for Python packages" +__uri__ = "https://github.com/pypa/packaging" + +__version__ = "25.0" + +__author__ = "Donald Stufft and individual contributors" +__email__ = "donald@stufft.io" + +__license__ = "BSD-2-Clause or Apache-2.0" +__copyright__ = f"2014 {__author__}" diff --git a/lib/python3.12/site-packages/packaging/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..478c675d80ffe7c0f6a1d850ffb58977031cca13 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/__init__.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/_elffile.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/_elffile.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d800f1437c7c413e10764d90281faadf38abb56 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/_elffile.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/_manylinux.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/_manylinux.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..75c5639ba2f485a2cc79c27d87eeed0f8ba1a3fa Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/_manylinux.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/_musllinux.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/_musllinux.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ecce4bfdb6190184b704cf9f4b652b8a1ac24412 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/_musllinux.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/_parser.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/_parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9de16db0281e259b5365be03a447e39a85d8243 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/_parser.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/_structures.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/_structures.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7fc05f68fce4e20cb915fa91695d3b8911bdf6ce Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/_structures.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/_tokenizer.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/_tokenizer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66d53882aafcd3f0a6e1aa6597d4f94a4c3e39b9 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/_tokenizer.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/markers.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/markers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..262a4baabfcbfd2b79f5982aa7cdae31f04f5bb7 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/markers.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/metadata.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/metadata.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81cba6a699c45b9238df52ac13569c1a5160cc59 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/metadata.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/requirements.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/requirements.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..adb33e95c96ac12c2673998d90c5dbccdb21b501 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/requirements.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/specifiers.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/specifiers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e7d3e6b41a55b2179addd1fb4f7401a90a57ac0 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/specifiers.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/tags.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/tags.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a5412150ff8409c8bf35f515f39b75f421e4f88 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/tags.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..719b7889adc73f9271ed5134e2b19ed44868b412 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/utils.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/__pycache__/version.cpython-312.pyc b/lib/python3.12/site-packages/packaging/__pycache__/version.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7935f542893e7164ae0233b4ce123bab1589baa3 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/__pycache__/version.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/_elffile.py b/lib/python3.12/site-packages/packaging/_elffile.py new file mode 100644 index 0000000000000000000000000000000000000000..7a5afc33b0a2401cf509bb6a8d1143d5230324d9 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/_elffile.py @@ -0,0 +1,109 @@ +""" +ELF file parser. + +This provides a class ``ELFFile`` that parses an ELF executable in a similar +interface to ``ZipFile``. Only the read interface is implemented. + +Based on: https://gist.github.com/lyssdod/f51579ae8d93c8657a5564aefc2ffbca +ELF header: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html +""" + +from __future__ import annotations + +import enum +import os +import struct +from typing import IO + + +class ELFInvalid(ValueError): + pass + + +class EIClass(enum.IntEnum): + C32 = 1 + C64 = 2 + + +class EIData(enum.IntEnum): + Lsb = 1 + Msb = 2 + + +class EMachine(enum.IntEnum): + I386 = 3 + S390 = 22 + Arm = 40 + X8664 = 62 + AArc64 = 183 + + +class ELFFile: + """ + Representation of an ELF executable. + """ + + def __init__(self, f: IO[bytes]) -> None: + self._f = f + + try: + ident = self._read("16B") + except struct.error as e: + raise ELFInvalid("unable to parse identification") from e + magic = bytes(ident[:4]) + if magic != b"\x7fELF": + raise ELFInvalid(f"invalid magic: {magic!r}") + + self.capacity = ident[4] # Format for program header (bitness). + self.encoding = ident[5] # Data structure encoding (endianness). + + try: + # e_fmt: Format for program header. + # p_fmt: Format for section header. + # p_idx: Indexes to find p_type, p_offset, and p_filesz. + e_fmt, self._p_fmt, self._p_idx = { + (1, 1): ("HHIIIIIHHH", ">IIIIIIII", (0, 1, 4)), # 32-bit MSB. + (2, 1): ("HHIQQQIHHH", ">IIQQQQQQ", (0, 2, 5)), # 64-bit MSB. + }[(self.capacity, self.encoding)] + except KeyError as e: + raise ELFInvalid( + f"unrecognized capacity ({self.capacity}) or encoding ({self.encoding})" + ) from e + + try: + ( + _, + self.machine, # Architecture type. + _, + _, + self._e_phoff, # Offset of program header. + _, + self.flags, # Processor-specific flags. + _, + self._e_phentsize, # Size of section. + self._e_phnum, # Number of sections. + ) = self._read(e_fmt) + except struct.error as e: + raise ELFInvalid("unable to parse machine and section information") from e + + def _read(self, fmt: str) -> tuple[int, ...]: + return struct.unpack(fmt, self._f.read(struct.calcsize(fmt))) + + @property + def interpreter(self) -> str | None: + """ + The path recorded in the ``PT_INTERP`` section header. + """ + for index in range(self._e_phnum): + self._f.seek(self._e_phoff + self._e_phentsize * index) + try: + data = self._read(self._p_fmt) + except struct.error: + continue + if data[self._p_idx[0]] != 3: # Not PT_INTERP. + continue + self._f.seek(data[self._p_idx[1]]) + return os.fsdecode(self._f.read(data[self._p_idx[2]])).strip("\0") + return None diff --git a/lib/python3.12/site-packages/packaging/_manylinux.py b/lib/python3.12/site-packages/packaging/_manylinux.py new file mode 100644 index 0000000000000000000000000000000000000000..95f55762e86f08af76aaa95f5cd147d4517c6d66 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/_manylinux.py @@ -0,0 +1,262 @@ +from __future__ import annotations + +import collections +import contextlib +import functools +import os +import re +import sys +import warnings +from typing import Generator, Iterator, NamedTuple, Sequence + +from ._elffile import EIClass, EIData, ELFFile, EMachine + +EF_ARM_ABIMASK = 0xFF000000 +EF_ARM_ABI_VER5 = 0x05000000 +EF_ARM_ABI_FLOAT_HARD = 0x00000400 + + +# `os.PathLike` not a generic type until Python 3.9, so sticking with `str` +# as the type for `path` until then. +@contextlib.contextmanager +def _parse_elf(path: str) -> Generator[ELFFile | None, None, None]: + try: + with open(path, "rb") as f: + yield ELFFile(f) + except (OSError, TypeError, ValueError): + yield None + + +def _is_linux_armhf(executable: str) -> bool: + # hard-float ABI can be detected from the ELF header of the running + # process + # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf + with _parse_elf(executable) as f: + return ( + f is not None + and f.capacity == EIClass.C32 + and f.encoding == EIData.Lsb + and f.machine == EMachine.Arm + and f.flags & EF_ARM_ABIMASK == EF_ARM_ABI_VER5 + and f.flags & EF_ARM_ABI_FLOAT_HARD == EF_ARM_ABI_FLOAT_HARD + ) + + +def _is_linux_i686(executable: str) -> bool: + with _parse_elf(executable) as f: + return ( + f is not None + and f.capacity == EIClass.C32 + and f.encoding == EIData.Lsb + and f.machine == EMachine.I386 + ) + + +def _have_compatible_abi(executable: str, archs: Sequence[str]) -> bool: + if "armv7l" in archs: + return _is_linux_armhf(executable) + if "i686" in archs: + return _is_linux_i686(executable) + allowed_archs = { + "x86_64", + "aarch64", + "ppc64", + "ppc64le", + "s390x", + "loongarch64", + "riscv64", + } + return any(arch in allowed_archs for arch in archs) + + +# If glibc ever changes its major version, we need to know what the last +# minor version was, so we can build the complete list of all versions. +# For now, guess what the highest minor version might be, assume it will +# be 50 for testing. Once this actually happens, update the dictionary +# with the actual value. +_LAST_GLIBC_MINOR: dict[int, int] = collections.defaultdict(lambda: 50) + + +class _GLibCVersion(NamedTuple): + major: int + minor: int + + +def _glibc_version_string_confstr() -> str | None: + """ + Primary implementation of glibc_version_string using os.confstr. + """ + # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely + # to be broken or missing. This strategy is used in the standard library + # platform module. + # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183 + try: + # Should be a string like "glibc 2.17". + version_string: str | None = os.confstr("CS_GNU_LIBC_VERSION") + assert version_string is not None + _, version = version_string.rsplit() + except (AssertionError, AttributeError, OSError, ValueError): + # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... + return None + return version + + +def _glibc_version_string_ctypes() -> str | None: + """ + Fallback implementation of glibc_version_string using ctypes. + """ + try: + import ctypes + except ImportError: + return None + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + # + # We must also handle the special case where the executable is not a + # dynamically linked executable. This can occur when using musl libc, + # for example. In this situation, dlopen() will error, leading to an + # OSError. Interestingly, at least in the case of musl, there is no + # errno set on the OSError. The single string argument used to construct + # OSError comes from libc itself and is therefore not portable to + # hard code here. In any case, failure to call dlopen() means we + # can proceed, so we bail on our attempt. + try: + process_namespace = ctypes.CDLL(None) + except OSError: + return None + + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str: str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +def _glibc_version_string() -> str | None: + """Returns glibc version string, or None if not using glibc.""" + return _glibc_version_string_confstr() or _glibc_version_string_ctypes() + + +def _parse_glibc_version(version_str: str) -> tuple[int, int]: + """Parse glibc version. + + We use a regexp instead of str.split because we want to discard any + random junk that might come after the minor version -- this might happen + in patched/forked versions of glibc (e.g. Linaro's version of glibc + uses version strings like "2.20-2014.11"). See gh-3588. + """ + m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str) + if not m: + warnings.warn( + f"Expected glibc version with 2 components major.minor, got: {version_str}", + RuntimeWarning, + stacklevel=2, + ) + return -1, -1 + return int(m.group("major")), int(m.group("minor")) + + +@functools.lru_cache +def _get_glibc_version() -> tuple[int, int]: + version_str = _glibc_version_string() + if version_str is None: + return (-1, -1) + return _parse_glibc_version(version_str) + + +# From PEP 513, PEP 600 +def _is_compatible(arch: str, version: _GLibCVersion) -> bool: + sys_glibc = _get_glibc_version() + if sys_glibc < version: + return False + # Check for presence of _manylinux module. + try: + import _manylinux + except ImportError: + return True + if hasattr(_manylinux, "manylinux_compatible"): + result = _manylinux.manylinux_compatible(version[0], version[1], arch) + if result is not None: + return bool(result) + return True + if version == _GLibCVersion(2, 5): + if hasattr(_manylinux, "manylinux1_compatible"): + return bool(_manylinux.manylinux1_compatible) + if version == _GLibCVersion(2, 12): + if hasattr(_manylinux, "manylinux2010_compatible"): + return bool(_manylinux.manylinux2010_compatible) + if version == _GLibCVersion(2, 17): + if hasattr(_manylinux, "manylinux2014_compatible"): + return bool(_manylinux.manylinux2014_compatible) + return True + + +_LEGACY_MANYLINUX_MAP = { + # CentOS 7 w/ glibc 2.17 (PEP 599) + (2, 17): "manylinux2014", + # CentOS 6 w/ glibc 2.12 (PEP 571) + (2, 12): "manylinux2010", + # CentOS 5 w/ glibc 2.5 (PEP 513) + (2, 5): "manylinux1", +} + + +def platform_tags(archs: Sequence[str]) -> Iterator[str]: + """Generate manylinux tags compatible to the current platform. + + :param archs: Sequence of compatible architectures. + The first one shall be the closest to the actual architecture and be the part of + platform tag after the ``linux_`` prefix, e.g. ``x86_64``. + The ``linux_`` prefix is assumed as a prerequisite for the current platform to + be manylinux-compatible. + + :returns: An iterator of compatible manylinux tags. + """ + if not _have_compatible_abi(sys.executable, archs): + return + # Oldest glibc to be supported regardless of architecture is (2, 17). + too_old_glibc2 = _GLibCVersion(2, 16) + if set(archs) & {"x86_64", "i686"}: + # On x86/i686 also oldest glibc to be supported is (2, 5). + too_old_glibc2 = _GLibCVersion(2, 4) + current_glibc = _GLibCVersion(*_get_glibc_version()) + glibc_max_list = [current_glibc] + # We can assume compatibility across glibc major versions. + # https://sourceware.org/bugzilla/show_bug.cgi?id=24636 + # + # Build a list of maximum glibc versions so that we can + # output the canonical list of all glibc from current_glibc + # down to too_old_glibc2, including all intermediary versions. + for glibc_major in range(current_glibc.major - 1, 1, -1): + glibc_minor = _LAST_GLIBC_MINOR[glibc_major] + glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor)) + for arch in archs: + for glibc_max in glibc_max_list: + if glibc_max.major == too_old_glibc2.major: + min_minor = too_old_glibc2.minor + else: + # For other glibc major versions oldest supported is (x, 0). + min_minor = -1 + for glibc_minor in range(glibc_max.minor, min_minor, -1): + glibc_version = _GLibCVersion(glibc_max.major, glibc_minor) + tag = "manylinux_{}_{}".format(*glibc_version) + if _is_compatible(arch, glibc_version): + yield f"{tag}_{arch}" + # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags. + if glibc_version in _LEGACY_MANYLINUX_MAP: + legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version] + if _is_compatible(arch, glibc_version): + yield f"{legacy_tag}_{arch}" diff --git a/lib/python3.12/site-packages/packaging/_musllinux.py b/lib/python3.12/site-packages/packaging/_musllinux.py new file mode 100644 index 0000000000000000000000000000000000000000..d2bf30b56319ba862c5c9a1a39a87c6d1cb68718 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/_musllinux.py @@ -0,0 +1,85 @@ +"""PEP 656 support. + +This module implements logic to detect if the currently running Python is +linked against musl, and what musl version is used. +""" + +from __future__ import annotations + +import functools +import re +import subprocess +import sys +from typing import Iterator, NamedTuple, Sequence + +from ._elffile import ELFFile + + +class _MuslVersion(NamedTuple): + major: int + minor: int + + +def _parse_musl_version(output: str) -> _MuslVersion | None: + lines = [n for n in (n.strip() for n in output.splitlines()) if n] + if len(lines) < 2 or lines[0][:4] != "musl": + return None + m = re.match(r"Version (\d+)\.(\d+)", lines[1]) + if not m: + return None + return _MuslVersion(major=int(m.group(1)), minor=int(m.group(2))) + + +@functools.lru_cache +def _get_musl_version(executable: str) -> _MuslVersion | None: + """Detect currently-running musl runtime version. + + This is done by checking the specified executable's dynamic linking + information, and invoking the loader to parse its output for a version + string. If the loader is musl, the output would be something like:: + + musl libc (x86_64) + Version 1.2.2 + Dynamic Program Loader + """ + try: + with open(executable, "rb") as f: + ld = ELFFile(f).interpreter + except (OSError, TypeError, ValueError): + return None + if ld is None or "musl" not in ld: + return None + proc = subprocess.run([ld], stderr=subprocess.PIPE, text=True) + return _parse_musl_version(proc.stderr) + + +def platform_tags(archs: Sequence[str]) -> Iterator[str]: + """Generate musllinux tags compatible to the current platform. + + :param archs: Sequence of compatible architectures. + The first one shall be the closest to the actual architecture and be the part of + platform tag after the ``linux_`` prefix, e.g. ``x86_64``. + The ``linux_`` prefix is assumed as a prerequisite for the current platform to + be musllinux-compatible. + + :returns: An iterator of compatible musllinux tags. + """ + sys_musl = _get_musl_version(sys.executable) + if sys_musl is None: # Python not dynamically linked against musl. + return + for arch in archs: + for minor in range(sys_musl.minor, -1, -1): + yield f"musllinux_{sys_musl.major}_{minor}_{arch}" + + +if __name__ == "__main__": # pragma: no cover + import sysconfig + + plat = sysconfig.get_platform() + assert plat.startswith("linux-"), "not linux" + + print("plat:", plat) + print("musl:", _get_musl_version(sys.executable)) + print("tags:", end=" ") + for t in platform_tags(re.sub(r"[.-]", "_", plat.split("-", 1)[-1])): + print(t, end="\n ") diff --git a/lib/python3.12/site-packages/packaging/_parser.py b/lib/python3.12/site-packages/packaging/_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..0007c0aa64aeae24c7e0ca90790a25ba51dbf7d6 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/_parser.py @@ -0,0 +1,353 @@ +"""Handwritten parser of dependency specifiers. + +The docstring for each __parse_* function contains EBNF-inspired grammar representing +the implementation. +""" + +from __future__ import annotations + +import ast +from typing import NamedTuple, Sequence, Tuple, Union + +from ._tokenizer import DEFAULT_RULES, Tokenizer + + +class Node: + def __init__(self, value: str) -> None: + self.value = value + + def __str__(self) -> str: + return self.value + + def __repr__(self) -> str: + return f"<{self.__class__.__name__}('{self}')>" + + def serialize(self) -> str: + raise NotImplementedError + + +class Variable(Node): + def serialize(self) -> str: + return str(self) + + +class Value(Node): + def serialize(self) -> str: + return f'"{self}"' + + +class Op(Node): + def serialize(self) -> str: + return str(self) + + +MarkerVar = Union[Variable, Value] +MarkerItem = Tuple[MarkerVar, Op, MarkerVar] +MarkerAtom = Union[MarkerItem, Sequence["MarkerAtom"]] +MarkerList = Sequence[Union["MarkerList", MarkerAtom, str]] + + +class ParsedRequirement(NamedTuple): + name: str + url: str + extras: list[str] + specifier: str + marker: MarkerList | None + + +# -------------------------------------------------------------------------------------- +# Recursive descent parser for dependency specifier +# -------------------------------------------------------------------------------------- +def parse_requirement(source: str) -> ParsedRequirement: + return _parse_requirement(Tokenizer(source, rules=DEFAULT_RULES)) + + +def _parse_requirement(tokenizer: Tokenizer) -> ParsedRequirement: + """ + requirement = WS? IDENTIFIER WS? extras WS? requirement_details + """ + tokenizer.consume("WS") + + name_token = tokenizer.expect( + "IDENTIFIER", expected="package name at the start of dependency specifier" + ) + name = name_token.text + tokenizer.consume("WS") + + extras = _parse_extras(tokenizer) + tokenizer.consume("WS") + + url, specifier, marker = _parse_requirement_details(tokenizer) + tokenizer.expect("END", expected="end of dependency specifier") + + return ParsedRequirement(name, url, extras, specifier, marker) + + +def _parse_requirement_details( + tokenizer: Tokenizer, +) -> tuple[str, str, MarkerList | None]: + """ + requirement_details = AT URL (WS requirement_marker?)? + | specifier WS? (requirement_marker)? + """ + + specifier = "" + url = "" + marker = None + + if tokenizer.check("AT"): + tokenizer.read() + tokenizer.consume("WS") + + url_start = tokenizer.position + url = tokenizer.expect("URL", expected="URL after @").text + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + + tokenizer.expect("WS", expected="whitespace after URL") + + # The input might end after whitespace. + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + + marker = _parse_requirement_marker( + tokenizer, span_start=url_start, after="URL and whitespace" + ) + else: + specifier_start = tokenizer.position + specifier = _parse_specifier(tokenizer) + tokenizer.consume("WS") + + if tokenizer.check("END", peek=True): + return (url, specifier, marker) + + marker = _parse_requirement_marker( + tokenizer, + span_start=specifier_start, + after=( + "version specifier" + if specifier + else "name and no valid version specifier" + ), + ) + + return (url, specifier, marker) + + +def _parse_requirement_marker( + tokenizer: Tokenizer, *, span_start: int, after: str +) -> MarkerList: + """ + requirement_marker = SEMICOLON marker WS? + """ + + if not tokenizer.check("SEMICOLON"): + tokenizer.raise_syntax_error( + f"Expected end or semicolon (after {after})", + span_start=span_start, + ) + tokenizer.read() + + marker = _parse_marker(tokenizer) + tokenizer.consume("WS") + + return marker + + +def _parse_extras(tokenizer: Tokenizer) -> list[str]: + """ + extras = (LEFT_BRACKET wsp* extras_list? wsp* RIGHT_BRACKET)? + """ + if not tokenizer.check("LEFT_BRACKET", peek=True): + return [] + + with tokenizer.enclosing_tokens( + "LEFT_BRACKET", + "RIGHT_BRACKET", + around="extras", + ): + tokenizer.consume("WS") + extras = _parse_extras_list(tokenizer) + tokenizer.consume("WS") + + return extras + + +def _parse_extras_list(tokenizer: Tokenizer) -> list[str]: + """ + extras_list = identifier (wsp* ',' wsp* identifier)* + """ + extras: list[str] = [] + + if not tokenizer.check("IDENTIFIER"): + return extras + + extras.append(tokenizer.read().text) + + while True: + tokenizer.consume("WS") + if tokenizer.check("IDENTIFIER", peek=True): + tokenizer.raise_syntax_error("Expected comma between extra names") + elif not tokenizer.check("COMMA"): + break + + tokenizer.read() + tokenizer.consume("WS") + + extra_token = tokenizer.expect("IDENTIFIER", expected="extra name after comma") + extras.append(extra_token.text) + + return extras + + +def _parse_specifier(tokenizer: Tokenizer) -> str: + """ + specifier = LEFT_PARENTHESIS WS? version_many WS? RIGHT_PARENTHESIS + | WS? version_many WS? + """ + with tokenizer.enclosing_tokens( + "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", + around="version specifier", + ): + tokenizer.consume("WS") + parsed_specifiers = _parse_version_many(tokenizer) + tokenizer.consume("WS") + + return parsed_specifiers + + +def _parse_version_many(tokenizer: Tokenizer) -> str: + """ + version_many = (SPECIFIER (WS? COMMA WS? SPECIFIER)*)? + """ + parsed_specifiers = "" + while tokenizer.check("SPECIFIER"): + span_start = tokenizer.position + parsed_specifiers += tokenizer.read().text + if tokenizer.check("VERSION_PREFIX_TRAIL", peek=True): + tokenizer.raise_syntax_error( + ".* suffix can only be used with `==` or `!=` operators", + span_start=span_start, + span_end=tokenizer.position + 1, + ) + if tokenizer.check("VERSION_LOCAL_LABEL_TRAIL", peek=True): + tokenizer.raise_syntax_error( + "Local version label can only be used with `==` or `!=` operators", + span_start=span_start, + span_end=tokenizer.position, + ) + tokenizer.consume("WS") + if not tokenizer.check("COMMA"): + break + parsed_specifiers += tokenizer.read().text + tokenizer.consume("WS") + + return parsed_specifiers + + +# -------------------------------------------------------------------------------------- +# Recursive descent parser for marker expression +# -------------------------------------------------------------------------------------- +def parse_marker(source: str) -> MarkerList: + return _parse_full_marker(Tokenizer(source, rules=DEFAULT_RULES)) + + +def _parse_full_marker(tokenizer: Tokenizer) -> MarkerList: + retval = _parse_marker(tokenizer) + tokenizer.expect("END", expected="end of marker expression") + return retval + + +def _parse_marker(tokenizer: Tokenizer) -> MarkerList: + """ + marker = marker_atom (BOOLOP marker_atom)+ + """ + expression = [_parse_marker_atom(tokenizer)] + while tokenizer.check("BOOLOP"): + token = tokenizer.read() + expr_right = _parse_marker_atom(tokenizer) + expression.extend((token.text, expr_right)) + return expression + + +def _parse_marker_atom(tokenizer: Tokenizer) -> MarkerAtom: + """ + marker_atom = WS? LEFT_PARENTHESIS WS? marker WS? RIGHT_PARENTHESIS WS? + | WS? marker_item WS? + """ + + tokenizer.consume("WS") + if tokenizer.check("LEFT_PARENTHESIS", peek=True): + with tokenizer.enclosing_tokens( + "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", + around="marker expression", + ): + tokenizer.consume("WS") + marker: MarkerAtom = _parse_marker(tokenizer) + tokenizer.consume("WS") + else: + marker = _parse_marker_item(tokenizer) + tokenizer.consume("WS") + return marker + + +def _parse_marker_item(tokenizer: Tokenizer) -> MarkerItem: + """ + marker_item = WS? marker_var WS? marker_op WS? marker_var WS? + """ + tokenizer.consume("WS") + marker_var_left = _parse_marker_var(tokenizer) + tokenizer.consume("WS") + marker_op = _parse_marker_op(tokenizer) + tokenizer.consume("WS") + marker_var_right = _parse_marker_var(tokenizer) + tokenizer.consume("WS") + return (marker_var_left, marker_op, marker_var_right) + + +def _parse_marker_var(tokenizer: Tokenizer) -> MarkerVar: + """ + marker_var = VARIABLE | QUOTED_STRING + """ + if tokenizer.check("VARIABLE"): + return process_env_var(tokenizer.read().text.replace(".", "_")) + elif tokenizer.check("QUOTED_STRING"): + return process_python_str(tokenizer.read().text) + else: + tokenizer.raise_syntax_error( + message="Expected a marker variable or quoted string" + ) + + +def process_env_var(env_var: str) -> Variable: + if env_var in ("platform_python_implementation", "python_implementation"): + return Variable("platform_python_implementation") + else: + return Variable(env_var) + + +def process_python_str(python_str: str) -> Value: + value = ast.literal_eval(python_str) + return Value(str(value)) + + +def _parse_marker_op(tokenizer: Tokenizer) -> Op: + """ + marker_op = IN | NOT IN | OP + """ + if tokenizer.check("IN"): + tokenizer.read() + return Op("in") + elif tokenizer.check("NOT"): + tokenizer.read() + tokenizer.expect("WS", expected="whitespace after 'not'") + tokenizer.expect("IN", expected="'in' after 'not'") + return Op("not in") + elif tokenizer.check("OP"): + return Op(tokenizer.read().text) + else: + return tokenizer.raise_syntax_error( + "Expected marker operator, one of <=, <, !=, ==, >=, >, ~=, ===, in, not in" + ) diff --git a/lib/python3.12/site-packages/packaging/_structures.py b/lib/python3.12/site-packages/packaging/_structures.py new file mode 100644 index 0000000000000000000000000000000000000000..90a6465f9682c886363eea5327dac64bf623a6ff --- /dev/null +++ b/lib/python3.12/site-packages/packaging/_structures.py @@ -0,0 +1,61 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + + +class InfinityType: + def __repr__(self) -> str: + return "Infinity" + + def __hash__(self) -> int: + return hash(repr(self)) + + def __lt__(self, other: object) -> bool: + return False + + def __le__(self, other: object) -> bool: + return False + + def __eq__(self, other: object) -> bool: + return isinstance(other, self.__class__) + + def __gt__(self, other: object) -> bool: + return True + + def __ge__(self, other: object) -> bool: + return True + + def __neg__(self: object) -> "NegativeInfinityType": + return NegativeInfinity + + +Infinity = InfinityType() + + +class NegativeInfinityType: + def __repr__(self) -> str: + return "-Infinity" + + def __hash__(self) -> int: + return hash(repr(self)) + + def __lt__(self, other: object) -> bool: + return True + + def __le__(self, other: object) -> bool: + return True + + def __eq__(self, other: object) -> bool: + return isinstance(other, self.__class__) + + def __gt__(self, other: object) -> bool: + return False + + def __ge__(self, other: object) -> bool: + return False + + def __neg__(self: object) -> InfinityType: + return Infinity + + +NegativeInfinity = NegativeInfinityType() diff --git a/lib/python3.12/site-packages/packaging/_tokenizer.py b/lib/python3.12/site-packages/packaging/_tokenizer.py new file mode 100644 index 0000000000000000000000000000000000000000..d28a9b6cf5daca9fa3ce5a8c8ae583a57ee84f12 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/_tokenizer.py @@ -0,0 +1,195 @@ +from __future__ import annotations + +import contextlib +import re +from dataclasses import dataclass +from typing import Iterator, NoReturn + +from .specifiers import Specifier + + +@dataclass +class Token: + name: str + text: str + position: int + + +class ParserSyntaxError(Exception): + """The provided source text could not be parsed correctly.""" + + def __init__( + self, + message: str, + *, + source: str, + span: tuple[int, int], + ) -> None: + self.span = span + self.message = message + self.source = source + + super().__init__() + + def __str__(self) -> str: + marker = " " * self.span[0] + "~" * (self.span[1] - self.span[0]) + "^" + return "\n ".join([self.message, self.source, marker]) + + +DEFAULT_RULES: dict[str, str | re.Pattern[str]] = { + "LEFT_PARENTHESIS": r"\(", + "RIGHT_PARENTHESIS": r"\)", + "LEFT_BRACKET": r"\[", + "RIGHT_BRACKET": r"\]", + "SEMICOLON": r";", + "COMMA": r",", + "QUOTED_STRING": re.compile( + r""" + ( + ('[^']*') + | + ("[^"]*") + ) + """, + re.VERBOSE, + ), + "OP": r"(===|==|~=|!=|<=|>=|<|>)", + "BOOLOP": r"\b(or|and)\b", + "IN": r"\bin\b", + "NOT": r"\bnot\b", + "VARIABLE": re.compile( + r""" + \b( + python_version + |python_full_version + |os[._]name + |sys[._]platform + |platform_(release|system) + |platform[._](version|machine|python_implementation) + |python_implementation + |implementation_(name|version) + |extras? + |dependency_groups + )\b + """, + re.VERBOSE, + ), + "SPECIFIER": re.compile( + Specifier._operator_regex_str + Specifier._version_regex_str, + re.VERBOSE | re.IGNORECASE, + ), + "AT": r"\@", + "URL": r"[^ \t]+", + "IDENTIFIER": r"\b[a-zA-Z0-9][a-zA-Z0-9._-]*\b", + "VERSION_PREFIX_TRAIL": r"\.\*", + "VERSION_LOCAL_LABEL_TRAIL": r"\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*", + "WS": r"[ \t]+", + "END": r"$", +} + + +class Tokenizer: + """Context-sensitive token parsing. + + Provides methods to examine the input stream to check whether the next token + matches. + """ + + def __init__( + self, + source: str, + *, + rules: dict[str, str | re.Pattern[str]], + ) -> None: + self.source = source + self.rules: dict[str, re.Pattern[str]] = { + name: re.compile(pattern) for name, pattern in rules.items() + } + self.next_token: Token | None = None + self.position = 0 + + def consume(self, name: str) -> None: + """Move beyond provided token name, if at current position.""" + if self.check(name): + self.read() + + def check(self, name: str, *, peek: bool = False) -> bool: + """Check whether the next token has the provided name. + + By default, if the check succeeds, the token *must* be read before + another check. If `peek` is set to `True`, the token is not loaded and + would need to be checked again. + """ + assert self.next_token is None, ( + f"Cannot check for {name!r}, already have {self.next_token!r}" + ) + assert name in self.rules, f"Unknown token name: {name!r}" + + expression = self.rules[name] + + match = expression.match(self.source, self.position) + if match is None: + return False + if not peek: + self.next_token = Token(name, match[0], self.position) + return True + + def expect(self, name: str, *, expected: str) -> Token: + """Expect a certain token name next, failing with a syntax error otherwise. + + The token is *not* read. + """ + if not self.check(name): + raise self.raise_syntax_error(f"Expected {expected}") + return self.read() + + def read(self) -> Token: + """Consume the next token and return it.""" + token = self.next_token + assert token is not None + + self.position += len(token.text) + self.next_token = None + + return token + + def raise_syntax_error( + self, + message: str, + *, + span_start: int | None = None, + span_end: int | None = None, + ) -> NoReturn: + """Raise ParserSyntaxError at the given position.""" + span = ( + self.position if span_start is None else span_start, + self.position if span_end is None else span_end, + ) + raise ParserSyntaxError( + message, + source=self.source, + span=span, + ) + + @contextlib.contextmanager + def enclosing_tokens( + self, open_token: str, close_token: str, *, around: str + ) -> Iterator[None]: + if self.check(open_token): + open_position = self.position + self.read() + else: + open_position = None + + yield + + if open_position is None: + return + + if not self.check(close_token): + self.raise_syntax_error( + f"Expected matching {close_token} for {open_token}, after {around}", + span_start=open_position, + ) + + self.read() diff --git a/lib/python3.12/site-packages/packaging/licenses/__init__.py b/lib/python3.12/site-packages/packaging/licenses/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..6f7f9e6289dabe5bbc45cc8f01ac2449da890d02 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/licenses/__init__.py @@ -0,0 +1,145 @@ +####################################################################################### +# +# Adapted from: +# https://github.com/pypa/hatch/blob/5352e44/backend/src/hatchling/licenses/parse.py +# +# MIT License +# +# Copyright (c) 2017-present Ofek Lev +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this +# software and associated documentation files (the "Software"), to deal in the Software +# without restriction, including without limitation the rights to use, copy, modify, +# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be included in all copies +# or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# +# With additional allowance of arbitrary `LicenseRef-` identifiers, not just +# `LicenseRef-Public-Domain` and `LicenseRef-Proprietary`. +# +####################################################################################### +from __future__ import annotations + +import re +from typing import NewType, cast + +from packaging.licenses._spdx import EXCEPTIONS, LICENSES + +__all__ = [ + "InvalidLicenseExpression", + "NormalizedLicenseExpression", + "canonicalize_license_expression", +] + +license_ref_allowed = re.compile("^[A-Za-z0-9.-]*$") + +NormalizedLicenseExpression = NewType("NormalizedLicenseExpression", str) + + +class InvalidLicenseExpression(ValueError): + """Raised when a license-expression string is invalid + + >>> canonicalize_license_expression("invalid") + Traceback (most recent call last): + ... + packaging.licenses.InvalidLicenseExpression: Invalid license expression: 'invalid' + """ + + +def canonicalize_license_expression( + raw_license_expression: str, +) -> NormalizedLicenseExpression: + if not raw_license_expression: + message = f"Invalid license expression: {raw_license_expression!r}" + raise InvalidLicenseExpression(message) + + # Pad any parentheses so tokenization can be achieved by merely splitting on + # whitespace. + license_expression = raw_license_expression.replace("(", " ( ").replace(")", " ) ") + licenseref_prefix = "LicenseRef-" + license_refs = { + ref.lower(): "LicenseRef-" + ref[len(licenseref_prefix) :] + for ref in license_expression.split() + if ref.lower().startswith(licenseref_prefix.lower()) + } + + # Normalize to lower case so we can look up licenses/exceptions + # and so boolean operators are Python-compatible. + license_expression = license_expression.lower() + + tokens = license_expression.split() + + # Rather than implementing boolean logic, we create an expression that Python can + # parse. Everything that is not involved with the grammar itself is treated as + # `False` and the expression should evaluate as such. + python_tokens = [] + for token in tokens: + if token not in {"or", "and", "with", "(", ")"}: + python_tokens.append("False") + elif token == "with": + python_tokens.append("or") + elif token == "(" and python_tokens and python_tokens[-1] not in {"or", "and"}: + message = f"Invalid license expression: {raw_license_expression!r}" + raise InvalidLicenseExpression(message) + else: + python_tokens.append(token) + + python_expression = " ".join(python_tokens) + try: + invalid = eval(python_expression, globals(), locals()) + except Exception: + invalid = True + + if invalid is not False: + message = f"Invalid license expression: {raw_license_expression!r}" + raise InvalidLicenseExpression(message) from None + + # Take a final pass to check for unknown licenses/exceptions. + normalized_tokens = [] + for token in tokens: + if token in {"or", "and", "with", "(", ")"}: + normalized_tokens.append(token.upper()) + continue + + if normalized_tokens and normalized_tokens[-1] == "WITH": + if token not in EXCEPTIONS: + message = f"Unknown license exception: {token!r}" + raise InvalidLicenseExpression(message) + + normalized_tokens.append(EXCEPTIONS[token]["id"]) + else: + if token.endswith("+"): + final_token = token[:-1] + suffix = "+" + else: + final_token = token + suffix = "" + + if final_token.startswith("licenseref-"): + if not license_ref_allowed.match(final_token): + message = f"Invalid licenseref: {final_token!r}" + raise InvalidLicenseExpression(message) + normalized_tokens.append(license_refs[final_token] + suffix) + else: + if final_token not in LICENSES: + message = f"Unknown license: {final_token!r}" + raise InvalidLicenseExpression(message) + normalized_tokens.append(LICENSES[final_token]["id"] + suffix) + + normalized_expression = " ".join(normalized_tokens) + + return cast( + NormalizedLicenseExpression, + normalized_expression.replace("( ", "(").replace(" )", ")"), + ) diff --git a/lib/python3.12/site-packages/packaging/licenses/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/packaging/licenses/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5804034a906364bd7724356a91c9c20d77d14bc0 Binary files /dev/null and b/lib/python3.12/site-packages/packaging/licenses/__pycache__/__init__.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/licenses/__pycache__/_spdx.cpython-312.pyc b/lib/python3.12/site-packages/packaging/licenses/__pycache__/_spdx.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..391a26cc144dbadab8c376e14101acaf08601f5b Binary files /dev/null and b/lib/python3.12/site-packages/packaging/licenses/__pycache__/_spdx.cpython-312.pyc differ diff --git a/lib/python3.12/site-packages/packaging/licenses/_spdx.py b/lib/python3.12/site-packages/packaging/licenses/_spdx.py new file mode 100644 index 0000000000000000000000000000000000000000..eac22276a34ccd73fc9d70c67ca318a49eb11e77 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/licenses/_spdx.py @@ -0,0 +1,759 @@ + +from __future__ import annotations + +from typing import TypedDict + +class SPDXLicense(TypedDict): + id: str + deprecated: bool + +class SPDXException(TypedDict): + id: str + deprecated: bool + + +VERSION = '3.25.0' + +LICENSES: dict[str, SPDXLicense] = { + '0bsd': {'id': '0BSD', 'deprecated': False}, + '3d-slicer-1.0': {'id': '3D-Slicer-1.0', 'deprecated': False}, + 'aal': {'id': 'AAL', 'deprecated': False}, + 'abstyles': {'id': 'Abstyles', 'deprecated': False}, + 'adacore-doc': {'id': 'AdaCore-doc', 'deprecated': False}, + 'adobe-2006': {'id': 'Adobe-2006', 'deprecated': False}, + 'adobe-display-postscript': {'id': 'Adobe-Display-PostScript', 'deprecated': False}, + 'adobe-glyph': {'id': 'Adobe-Glyph', 'deprecated': False}, + 'adobe-utopia': {'id': 'Adobe-Utopia', 'deprecated': False}, + 'adsl': {'id': 'ADSL', 'deprecated': False}, + 'afl-1.1': {'id': 'AFL-1.1', 'deprecated': False}, + 'afl-1.2': {'id': 'AFL-1.2', 'deprecated': False}, + 'afl-2.0': {'id': 'AFL-2.0', 'deprecated': False}, + 'afl-2.1': {'id': 'AFL-2.1', 'deprecated': False}, + 'afl-3.0': {'id': 'AFL-3.0', 'deprecated': False}, + 'afmparse': {'id': 'Afmparse', 'deprecated': False}, + 'agpl-1.0': {'id': 'AGPL-1.0', 'deprecated': True}, + 'agpl-1.0-only': {'id': 'AGPL-1.0-only', 'deprecated': False}, + 'agpl-1.0-or-later': {'id': 'AGPL-1.0-or-later', 'deprecated': False}, + 'agpl-3.0': {'id': 'AGPL-3.0', 'deprecated': True}, + 'agpl-3.0-only': {'id': 'AGPL-3.0-only', 'deprecated': False}, + 'agpl-3.0-or-later': {'id': 'AGPL-3.0-or-later', 'deprecated': False}, + 'aladdin': {'id': 'Aladdin', 'deprecated': False}, + 'amd-newlib': {'id': 'AMD-newlib', 'deprecated': False}, + 'amdplpa': {'id': 'AMDPLPA', 'deprecated': False}, + 'aml': {'id': 'AML', 'deprecated': False}, + 'aml-glslang': {'id': 'AML-glslang', 'deprecated': False}, + 'ampas': {'id': 'AMPAS', 'deprecated': False}, + 'antlr-pd': {'id': 'ANTLR-PD', 'deprecated': False}, + 'antlr-pd-fallback': {'id': 'ANTLR-PD-fallback', 'deprecated': False}, + 'any-osi': {'id': 'any-OSI', 'deprecated': False}, + 'apache-1.0': {'id': 'Apache-1.0', 'deprecated': False}, + 'apache-1.1': {'id': 'Apache-1.1', 'deprecated': False}, + 'apache-2.0': {'id': 'Apache-2.0', 'deprecated': False}, + 'apafml': {'id': 'APAFML', 'deprecated': False}, + 'apl-1.0': {'id': 'APL-1.0', 'deprecated': False}, + 'app-s2p': {'id': 'App-s2p', 'deprecated': False}, + 'apsl-1.0': {'id': 'APSL-1.0', 'deprecated': False}, + 'apsl-1.1': {'id': 'APSL-1.1', 'deprecated': False}, + 'apsl-1.2': {'id': 'APSL-1.2', 'deprecated': False}, + 'apsl-2.0': {'id': 'APSL-2.0', 'deprecated': False}, + 'arphic-1999': {'id': 'Arphic-1999', 'deprecated': False}, + 'artistic-1.0': {'id': 'Artistic-1.0', 'deprecated': False}, + 'artistic-1.0-cl8': {'id': 'Artistic-1.0-cl8', 'deprecated': False}, + 'artistic-1.0-perl': {'id': 'Artistic-1.0-Perl', 'deprecated': False}, + 'artistic-2.0': {'id': 'Artistic-2.0', 'deprecated': False}, + 'aswf-digital-assets-1.0': {'id': 'ASWF-Digital-Assets-1.0', 'deprecated': False}, + 'aswf-digital-assets-1.1': {'id': 'ASWF-Digital-Assets-1.1', 'deprecated': False}, + 'baekmuk': {'id': 'Baekmuk', 'deprecated': False}, + 'bahyph': {'id': 'Bahyph', 'deprecated': False}, + 'barr': {'id': 'Barr', 'deprecated': False}, + 'bcrypt-solar-designer': {'id': 'bcrypt-Solar-Designer', 'deprecated': False}, + 'beerware': {'id': 'Beerware', 'deprecated': False}, + 'bitstream-charter': {'id': 'Bitstream-Charter', 'deprecated': False}, + 'bitstream-vera': {'id': 'Bitstream-Vera', 'deprecated': False}, + 'bittorrent-1.0': {'id': 'BitTorrent-1.0', 'deprecated': False}, + 'bittorrent-1.1': {'id': 'BitTorrent-1.1', 'deprecated': False}, + 'blessing': {'id': 'blessing', 'deprecated': False}, + 'blueoak-1.0.0': {'id': 'BlueOak-1.0.0', 'deprecated': False}, + 'boehm-gc': {'id': 'Boehm-GC', 'deprecated': False}, + 'borceux': {'id': 'Borceux', 'deprecated': False}, + 'brian-gladman-2-clause': {'id': 'Brian-Gladman-2-Clause', 'deprecated': False}, + 'brian-gladman-3-clause': {'id': 'Brian-Gladman-3-Clause', 'deprecated': False}, + 'bsd-1-clause': {'id': 'BSD-1-Clause', 'deprecated': False}, + 'bsd-2-clause': {'id': 'BSD-2-Clause', 'deprecated': False}, + 'bsd-2-clause-darwin': {'id': 'BSD-2-Clause-Darwin', 'deprecated': False}, + 'bsd-2-clause-first-lines': {'id': 'BSD-2-Clause-first-lines', 'deprecated': False}, + 'bsd-2-clause-freebsd': {'id': 'BSD-2-Clause-FreeBSD', 'deprecated': True}, + 'bsd-2-clause-netbsd': {'id': 'BSD-2-Clause-NetBSD', 'deprecated': True}, + 'bsd-2-clause-patent': {'id': 'BSD-2-Clause-Patent', 'deprecated': False}, + 'bsd-2-clause-views': {'id': 'BSD-2-Clause-Views', 'deprecated': False}, + 'bsd-3-clause': {'id': 'BSD-3-Clause', 'deprecated': False}, + 'bsd-3-clause-acpica': {'id': 'BSD-3-Clause-acpica', 'deprecated': False}, + 'bsd-3-clause-attribution': {'id': 'BSD-3-Clause-Attribution', 'deprecated': False}, + 'bsd-3-clause-clear': {'id': 'BSD-3-Clause-Clear', 'deprecated': False}, + 'bsd-3-clause-flex': {'id': 'BSD-3-Clause-flex', 'deprecated': False}, + 'bsd-3-clause-hp': {'id': 'BSD-3-Clause-HP', 'deprecated': False}, + 'bsd-3-clause-lbnl': {'id': 'BSD-3-Clause-LBNL', 'deprecated': False}, + 'bsd-3-clause-modification': {'id': 'BSD-3-Clause-Modification', 'deprecated': False}, + 'bsd-3-clause-no-military-license': {'id': 'BSD-3-Clause-No-Military-License', 'deprecated': False}, + 'bsd-3-clause-no-nuclear-license': {'id': 'BSD-3-Clause-No-Nuclear-License', 'deprecated': False}, + 'bsd-3-clause-no-nuclear-license-2014': {'id': 'BSD-3-Clause-No-Nuclear-License-2014', 'deprecated': False}, + 'bsd-3-clause-no-nuclear-warranty': {'id': 'BSD-3-Clause-No-Nuclear-Warranty', 'deprecated': False}, + 'bsd-3-clause-open-mpi': {'id': 'BSD-3-Clause-Open-MPI', 'deprecated': False}, + 'bsd-3-clause-sun': {'id': 'BSD-3-Clause-Sun', 'deprecated': False}, + 'bsd-4-clause': {'id': 'BSD-4-Clause', 'deprecated': False}, + 'bsd-4-clause-shortened': {'id': 'BSD-4-Clause-Shortened', 'deprecated': False}, + 'bsd-4-clause-uc': {'id': 'BSD-4-Clause-UC', 'deprecated': False}, + 'bsd-4.3reno': {'id': 'BSD-4.3RENO', 'deprecated': False}, + 'bsd-4.3tahoe': {'id': 'BSD-4.3TAHOE', 'deprecated': False}, + 'bsd-advertising-acknowledgement': {'id': 'BSD-Advertising-Acknowledgement', 'deprecated': False}, + 'bsd-attribution-hpnd-disclaimer': {'id': 'BSD-Attribution-HPND-disclaimer', 'deprecated': False}, + 'bsd-inferno-nettverk': {'id': 'BSD-Inferno-Nettverk', 'deprecated': False}, + 'bsd-protection': {'id': 'BSD-Protection', 'deprecated': False}, + 'bsd-source-beginning-file': {'id': 'BSD-Source-beginning-file', 'deprecated': False}, + 'bsd-source-code': {'id': 'BSD-Source-Code', 'deprecated': False}, + 'bsd-systemics': {'id': 'BSD-Systemics', 'deprecated': False}, + 'bsd-systemics-w3works': {'id': 'BSD-Systemics-W3Works', 'deprecated': False}, + 'bsl-1.0': {'id': 'BSL-1.0', 'deprecated': False}, + 'busl-1.1': {'id': 'BUSL-1.1', 'deprecated': False}, + 'bzip2-1.0.5': {'id': 'bzip2-1.0.5', 'deprecated': True}, + 'bzip2-1.0.6': {'id': 'bzip2-1.0.6', 'deprecated': False}, + 'c-uda-1.0': {'id': 'C-UDA-1.0', 'deprecated': False}, + 'cal-1.0': {'id': 'CAL-1.0', 'deprecated': False}, + 'cal-1.0-combined-work-exception': {'id': 'CAL-1.0-Combined-Work-Exception', 'deprecated': False}, + 'caldera': {'id': 'Caldera', 'deprecated': False}, + 'caldera-no-preamble': {'id': 'Caldera-no-preamble', 'deprecated': False}, + 'catharon': {'id': 'Catharon', 'deprecated': False}, + 'catosl-1.1': {'id': 'CATOSL-1.1', 'deprecated': False}, + 'cc-by-1.0': {'id': 'CC-BY-1.0', 'deprecated': False}, + 'cc-by-2.0': {'id': 'CC-BY-2.0', 'deprecated': False}, + 'cc-by-2.5': {'id': 'CC-BY-2.5', 'deprecated': False}, + 'cc-by-2.5-au': {'id': 'CC-BY-2.5-AU', 'deprecated': False}, + 'cc-by-3.0': {'id': 'CC-BY-3.0', 'deprecated': False}, + 'cc-by-3.0-at': {'id': 'CC-BY-3.0-AT', 'deprecated': False}, + 'cc-by-3.0-au': {'id': 'CC-BY-3.0-AU', 'deprecated': False}, + 'cc-by-3.0-de': {'id': 'CC-BY-3.0-DE', 'deprecated': False}, + 'cc-by-3.0-igo': {'id': 'CC-BY-3.0-IGO', 'deprecated': False}, + 'cc-by-3.0-nl': {'id': 'CC-BY-3.0-NL', 'deprecated': False}, + 'cc-by-3.0-us': {'id': 'CC-BY-3.0-US', 'deprecated': False}, + 'cc-by-4.0': {'id': 'CC-BY-4.0', 'deprecated': False}, + 'cc-by-nc-1.0': {'id': 'CC-BY-NC-1.0', 'deprecated': False}, + 'cc-by-nc-2.0': {'id': 'CC-BY-NC-2.0', 'deprecated': False}, + 'cc-by-nc-2.5': {'id': 'CC-BY-NC-2.5', 'deprecated': False}, + 'cc-by-nc-3.0': {'id': 'CC-BY-NC-3.0', 'deprecated': False}, + 'cc-by-nc-3.0-de': {'id': 'CC-BY-NC-3.0-DE', 'deprecated': False}, + 'cc-by-nc-4.0': {'id': 'CC-BY-NC-4.0', 'deprecated': False}, + 'cc-by-nc-nd-1.0': {'id': 'CC-BY-NC-ND-1.0', 'deprecated': False}, + 'cc-by-nc-nd-2.0': {'id': 'CC-BY-NC-ND-2.0', 'deprecated': False}, + 'cc-by-nc-nd-2.5': {'id': 'CC-BY-NC-ND-2.5', 'deprecated': False}, + 'cc-by-nc-nd-3.0': {'id': 'CC-BY-NC-ND-3.0', 'deprecated': False}, + 'cc-by-nc-nd-3.0-de': {'id': 'CC-BY-NC-ND-3.0-DE', 'deprecated': False}, + 'cc-by-nc-nd-3.0-igo': {'id': 'CC-BY-NC-ND-3.0-IGO', 'deprecated': False}, + 'cc-by-nc-nd-4.0': {'id': 'CC-BY-NC-ND-4.0', 'deprecated': False}, + 'cc-by-nc-sa-1.0': {'id': 'CC-BY-NC-SA-1.0', 'deprecated': False}, + 'cc-by-nc-sa-2.0': {'id': 'CC-BY-NC-SA-2.0', 'deprecated': False}, + 'cc-by-nc-sa-2.0-de': {'id': 'CC-BY-NC-SA-2.0-DE', 'deprecated': False}, + 'cc-by-nc-sa-2.0-fr': {'id': 'CC-BY-NC-SA-2.0-FR', 'deprecated': False}, + 'cc-by-nc-sa-2.0-uk': {'id': 'CC-BY-NC-SA-2.0-UK', 'deprecated': False}, + 'cc-by-nc-sa-2.5': {'id': 'CC-BY-NC-SA-2.5', 'deprecated': False}, + 'cc-by-nc-sa-3.0': {'id': 'CC-BY-NC-SA-3.0', 'deprecated': False}, + 'cc-by-nc-sa-3.0-de': {'id': 'CC-BY-NC-SA-3.0-DE', 'deprecated': False}, + 'cc-by-nc-sa-3.0-igo': {'id': 'CC-BY-NC-SA-3.0-IGO', 'deprecated': False}, + 'cc-by-nc-sa-4.0': {'id': 'CC-BY-NC-SA-4.0', 'deprecated': False}, + 'cc-by-nd-1.0': {'id': 'CC-BY-ND-1.0', 'deprecated': False}, + 'cc-by-nd-2.0': {'id': 'CC-BY-ND-2.0', 'deprecated': False}, + 'cc-by-nd-2.5': {'id': 'CC-BY-ND-2.5', 'deprecated': False}, + 'cc-by-nd-3.0': {'id': 'CC-BY-ND-3.0', 'deprecated': False}, + 'cc-by-nd-3.0-de': {'id': 'CC-BY-ND-3.0-DE', 'deprecated': False}, + 'cc-by-nd-4.0': {'id': 'CC-BY-ND-4.0', 'deprecated': False}, + 'cc-by-sa-1.0': {'id': 'CC-BY-SA-1.0', 'deprecated': False}, + 'cc-by-sa-2.0': {'id': 'CC-BY-SA-2.0', 'deprecated': False}, + 'cc-by-sa-2.0-uk': {'id': 'CC-BY-SA-2.0-UK', 'deprecated': False}, + 'cc-by-sa-2.1-jp': {'id': 'CC-BY-SA-2.1-JP', 'deprecated': False}, + 'cc-by-sa-2.5': {'id': 'CC-BY-SA-2.5', 'deprecated': False}, + 'cc-by-sa-3.0': {'id': 'CC-BY-SA-3.0', 'deprecated': False}, + 'cc-by-sa-3.0-at': {'id': 'CC-BY-SA-3.0-AT', 'deprecated': False}, + 'cc-by-sa-3.0-de': {'id': 'CC-BY-SA-3.0-DE', 'deprecated': False}, + 'cc-by-sa-3.0-igo': {'id': 'CC-BY-SA-3.0-IGO', 'deprecated': False}, + 'cc-by-sa-4.0': {'id': 'CC-BY-SA-4.0', 'deprecated': False}, + 'cc-pddc': {'id': 'CC-PDDC', 'deprecated': False}, + 'cc0-1.0': {'id': 'CC0-1.0', 'deprecated': False}, + 'cddl-1.0': {'id': 'CDDL-1.0', 'deprecated': False}, + 'cddl-1.1': {'id': 'CDDL-1.1', 'deprecated': False}, + 'cdl-1.0': {'id': 'CDL-1.0', 'deprecated': False}, + 'cdla-permissive-1.0': {'id': 'CDLA-Permissive-1.0', 'deprecated': False}, + 'cdla-permissive-2.0': {'id': 'CDLA-Permissive-2.0', 'deprecated': False}, + 'cdla-sharing-1.0': {'id': 'CDLA-Sharing-1.0', 'deprecated': False}, + 'cecill-1.0': {'id': 'CECILL-1.0', 'deprecated': False}, + 'cecill-1.1': {'id': 'CECILL-1.1', 'deprecated': False}, + 'cecill-2.0': {'id': 'CECILL-2.0', 'deprecated': False}, + 'cecill-2.1': {'id': 'CECILL-2.1', 'deprecated': False}, + 'cecill-b': {'id': 'CECILL-B', 'deprecated': False}, + 'cecill-c': {'id': 'CECILL-C', 'deprecated': False}, + 'cern-ohl-1.1': {'id': 'CERN-OHL-1.1', 'deprecated': False}, + 'cern-ohl-1.2': {'id': 'CERN-OHL-1.2', 'deprecated': False}, + 'cern-ohl-p-2.0': {'id': 'CERN-OHL-P-2.0', 'deprecated': False}, + 'cern-ohl-s-2.0': {'id': 'CERN-OHL-S-2.0', 'deprecated': False}, + 'cern-ohl-w-2.0': {'id': 'CERN-OHL-W-2.0', 'deprecated': False}, + 'cfitsio': {'id': 'CFITSIO', 'deprecated': False}, + 'check-cvs': {'id': 'check-cvs', 'deprecated': False}, + 'checkmk': {'id': 'checkmk', 'deprecated': False}, + 'clartistic': {'id': 'ClArtistic', 'deprecated': False}, + 'clips': {'id': 'Clips', 'deprecated': False}, + 'cmu-mach': {'id': 'CMU-Mach', 'deprecated': False}, + 'cmu-mach-nodoc': {'id': 'CMU-Mach-nodoc', 'deprecated': False}, + 'cnri-jython': {'id': 'CNRI-Jython', 'deprecated': False}, + 'cnri-python': {'id': 'CNRI-Python', 'deprecated': False}, + 'cnri-python-gpl-compatible': {'id': 'CNRI-Python-GPL-Compatible', 'deprecated': False}, + 'coil-1.0': {'id': 'COIL-1.0', 'deprecated': False}, + 'community-spec-1.0': {'id': 'Community-Spec-1.0', 'deprecated': False}, + 'condor-1.1': {'id': 'Condor-1.1', 'deprecated': False}, + 'copyleft-next-0.3.0': {'id': 'copyleft-next-0.3.0', 'deprecated': False}, + 'copyleft-next-0.3.1': {'id': 'copyleft-next-0.3.1', 'deprecated': False}, + 'cornell-lossless-jpeg': {'id': 'Cornell-Lossless-JPEG', 'deprecated': False}, + 'cpal-1.0': {'id': 'CPAL-1.0', 'deprecated': False}, + 'cpl-1.0': {'id': 'CPL-1.0', 'deprecated': False}, + 'cpol-1.02': {'id': 'CPOL-1.02', 'deprecated': False}, + 'cronyx': {'id': 'Cronyx', 'deprecated': False}, + 'crossword': {'id': 'Crossword', 'deprecated': False}, + 'crystalstacker': {'id': 'CrystalStacker', 'deprecated': False}, + 'cua-opl-1.0': {'id': 'CUA-OPL-1.0', 'deprecated': False}, + 'cube': {'id': 'Cube', 'deprecated': False}, + 'curl': {'id': 'curl', 'deprecated': False}, + 'cve-tou': {'id': 'cve-tou', 'deprecated': False}, + 'd-fsl-1.0': {'id': 'D-FSL-1.0', 'deprecated': False}, + 'dec-3-clause': {'id': 'DEC-3-Clause', 'deprecated': False}, + 'diffmark': {'id': 'diffmark', 'deprecated': False}, + 'dl-de-by-2.0': {'id': 'DL-DE-BY-2.0', 'deprecated': False}, + 'dl-de-zero-2.0': {'id': 'DL-DE-ZERO-2.0', 'deprecated': False}, + 'doc': {'id': 'DOC', 'deprecated': False}, + 'docbook-schema': {'id': 'DocBook-Schema', 'deprecated': False}, + 'docbook-xml': {'id': 'DocBook-XML', 'deprecated': False}, + 'dotseqn': {'id': 'Dotseqn', 'deprecated': False}, + 'drl-1.0': {'id': 'DRL-1.0', 'deprecated': False}, + 'drl-1.1': {'id': 'DRL-1.1', 'deprecated': False}, + 'dsdp': {'id': 'DSDP', 'deprecated': False}, + 'dtoa': {'id': 'dtoa', 'deprecated': False}, + 'dvipdfm': {'id': 'dvipdfm', 'deprecated': False}, + 'ecl-1.0': {'id': 'ECL-1.0', 'deprecated': False}, + 'ecl-2.0': {'id': 'ECL-2.0', 'deprecated': False}, + 'ecos-2.0': {'id': 'eCos-2.0', 'deprecated': True}, + 'efl-1.0': {'id': 'EFL-1.0', 'deprecated': False}, + 'efl-2.0': {'id': 'EFL-2.0', 'deprecated': False}, + 'egenix': {'id': 'eGenix', 'deprecated': False}, + 'elastic-2.0': {'id': 'Elastic-2.0', 'deprecated': False}, + 'entessa': {'id': 'Entessa', 'deprecated': False}, + 'epics': {'id': 'EPICS', 'deprecated': False}, + 'epl-1.0': {'id': 'EPL-1.0', 'deprecated': False}, + 'epl-2.0': {'id': 'EPL-2.0', 'deprecated': False}, + 'erlpl-1.1': {'id': 'ErlPL-1.1', 'deprecated': False}, + 'etalab-2.0': {'id': 'etalab-2.0', 'deprecated': False}, + 'eudatagrid': {'id': 'EUDatagrid', 'deprecated': False}, + 'eupl-1.0': {'id': 'EUPL-1.0', 'deprecated': False}, + 'eupl-1.1': {'id': 'EUPL-1.1', 'deprecated': False}, + 'eupl-1.2': {'id': 'EUPL-1.2', 'deprecated': False}, + 'eurosym': {'id': 'Eurosym', 'deprecated': False}, + 'fair': {'id': 'Fair', 'deprecated': False}, + 'fbm': {'id': 'FBM', 'deprecated': False}, + 'fdk-aac': {'id': 'FDK-AAC', 'deprecated': False}, + 'ferguson-twofish': {'id': 'Ferguson-Twofish', 'deprecated': False}, + 'frameworx-1.0': {'id': 'Frameworx-1.0', 'deprecated': False}, + 'freebsd-doc': {'id': 'FreeBSD-DOC', 'deprecated': False}, + 'freeimage': {'id': 'FreeImage', 'deprecated': False}, + 'fsfap': {'id': 'FSFAP', 'deprecated': False}, + 'fsfap-no-warranty-disclaimer': {'id': 'FSFAP-no-warranty-disclaimer', 'deprecated': False}, + 'fsful': {'id': 'FSFUL', 'deprecated': False}, + 'fsfullr': {'id': 'FSFULLR', 'deprecated': False}, + 'fsfullrwd': {'id': 'FSFULLRWD', 'deprecated': False}, + 'ftl': {'id': 'FTL', 'deprecated': False}, + 'furuseth': {'id': 'Furuseth', 'deprecated': False}, + 'fwlw': {'id': 'fwlw', 'deprecated': False}, + 'gcr-docs': {'id': 'GCR-docs', 'deprecated': False}, + 'gd': {'id': 'GD', 'deprecated': False}, + 'gfdl-1.1': {'id': 'GFDL-1.1', 'deprecated': True}, + 'gfdl-1.1-invariants-only': {'id': 'GFDL-1.1-invariants-only', 'deprecated': False}, + 'gfdl-1.1-invariants-or-later': {'id': 'GFDL-1.1-invariants-or-later', 'deprecated': False}, + 'gfdl-1.1-no-invariants-only': {'id': 'GFDL-1.1-no-invariants-only', 'deprecated': False}, + 'gfdl-1.1-no-invariants-or-later': {'id': 'GFDL-1.1-no-invariants-or-later', 'deprecated': False}, + 'gfdl-1.1-only': {'id': 'GFDL-1.1-only', 'deprecated': False}, + 'gfdl-1.1-or-later': {'id': 'GFDL-1.1-or-later', 'deprecated': False}, + 'gfdl-1.2': {'id': 'GFDL-1.2', 'deprecated': True}, + 'gfdl-1.2-invariants-only': {'id': 'GFDL-1.2-invariants-only', 'deprecated': False}, + 'gfdl-1.2-invariants-or-later': {'id': 'GFDL-1.2-invariants-or-later', 'deprecated': False}, + 'gfdl-1.2-no-invariants-only': {'id': 'GFDL-1.2-no-invariants-only', 'deprecated': False}, + 'gfdl-1.2-no-invariants-or-later': {'id': 'GFDL-1.2-no-invariants-or-later', 'deprecated': False}, + 'gfdl-1.2-only': {'id': 'GFDL-1.2-only', 'deprecated': False}, + 'gfdl-1.2-or-later': {'id': 'GFDL-1.2-or-later', 'deprecated': False}, + 'gfdl-1.3': {'id': 'GFDL-1.3', 'deprecated': True}, + 'gfdl-1.3-invariants-only': {'id': 'GFDL-1.3-invariants-only', 'deprecated': False}, + 'gfdl-1.3-invariants-or-later': {'id': 'GFDL-1.3-invariants-or-later', 'deprecated': False}, + 'gfdl-1.3-no-invariants-only': {'id': 'GFDL-1.3-no-invariants-only', 'deprecated': False}, + 'gfdl-1.3-no-invariants-or-later': {'id': 'GFDL-1.3-no-invariants-or-later', 'deprecated': False}, + 'gfdl-1.3-only': {'id': 'GFDL-1.3-only', 'deprecated': False}, + 'gfdl-1.3-or-later': {'id': 'GFDL-1.3-or-later', 'deprecated': False}, + 'giftware': {'id': 'Giftware', 'deprecated': False}, + 'gl2ps': {'id': 'GL2PS', 'deprecated': False}, + 'glide': {'id': 'Glide', 'deprecated': False}, + 'glulxe': {'id': 'Glulxe', 'deprecated': False}, + 'glwtpl': {'id': 'GLWTPL', 'deprecated': False}, + 'gnuplot': {'id': 'gnuplot', 'deprecated': False}, + 'gpl-1.0': {'id': 'GPL-1.0', 'deprecated': True}, + 'gpl-1.0+': {'id': 'GPL-1.0+', 'deprecated': True}, + 'gpl-1.0-only': {'id': 'GPL-1.0-only', 'deprecated': False}, + 'gpl-1.0-or-later': {'id': 'GPL-1.0-or-later', 'deprecated': False}, + 'gpl-2.0': {'id': 'GPL-2.0', 'deprecated': True}, + 'gpl-2.0+': {'id': 'GPL-2.0+', 'deprecated': True}, + 'gpl-2.0-only': {'id': 'GPL-2.0-only', 'deprecated': False}, + 'gpl-2.0-or-later': {'id': 'GPL-2.0-or-later', 'deprecated': False}, + 'gpl-2.0-with-autoconf-exception': {'id': 'GPL-2.0-with-autoconf-exception', 'deprecated': True}, + 'gpl-2.0-with-bison-exception': {'id': 'GPL-2.0-with-bison-exception', 'deprecated': True}, + 'gpl-2.0-with-classpath-exception': {'id': 'GPL-2.0-with-classpath-exception', 'deprecated': True}, + 'gpl-2.0-with-font-exception': {'id': 'GPL-2.0-with-font-exception', 'deprecated': True}, + 'gpl-2.0-with-gcc-exception': {'id': 'GPL-2.0-with-GCC-exception', 'deprecated': True}, + 'gpl-3.0': {'id': 'GPL-3.0', 'deprecated': True}, + 'gpl-3.0+': {'id': 'GPL-3.0+', 'deprecated': True}, + 'gpl-3.0-only': {'id': 'GPL-3.0-only', 'deprecated': False}, + 'gpl-3.0-or-later': {'id': 'GPL-3.0-or-later', 'deprecated': False}, + 'gpl-3.0-with-autoconf-exception': {'id': 'GPL-3.0-with-autoconf-exception', 'deprecated': True}, + 'gpl-3.0-with-gcc-exception': {'id': 'GPL-3.0-with-GCC-exception', 'deprecated': True}, + 'graphics-gems': {'id': 'Graphics-Gems', 'deprecated': False}, + 'gsoap-1.3b': {'id': 'gSOAP-1.3b', 'deprecated': False}, + 'gtkbook': {'id': 'gtkbook', 'deprecated': False}, + 'gutmann': {'id': 'Gutmann', 'deprecated': False}, + 'haskellreport': {'id': 'HaskellReport', 'deprecated': False}, + 'hdparm': {'id': 'hdparm', 'deprecated': False}, + 'hidapi': {'id': 'HIDAPI', 'deprecated': False}, + 'hippocratic-2.1': {'id': 'Hippocratic-2.1', 'deprecated': False}, + 'hp-1986': {'id': 'HP-1986', 'deprecated': False}, + 'hp-1989': {'id': 'HP-1989', 'deprecated': False}, + 'hpnd': {'id': 'HPND', 'deprecated': False}, + 'hpnd-dec': {'id': 'HPND-DEC', 'deprecated': False}, + 'hpnd-doc': {'id': 'HPND-doc', 'deprecated': False}, + 'hpnd-doc-sell': {'id': 'HPND-doc-sell', 'deprecated': False}, + 'hpnd-export-us': {'id': 'HPND-export-US', 'deprecated': False}, + 'hpnd-export-us-acknowledgement': {'id': 'HPND-export-US-acknowledgement', 'deprecated': False}, + 'hpnd-export-us-modify': {'id': 'HPND-export-US-modify', 'deprecated': False}, + 'hpnd-export2-us': {'id': 'HPND-export2-US', 'deprecated': False}, + 'hpnd-fenneberg-livingston': {'id': 'HPND-Fenneberg-Livingston', 'deprecated': False}, + 'hpnd-inria-imag': {'id': 'HPND-INRIA-IMAG', 'deprecated': False}, + 'hpnd-intel': {'id': 'HPND-Intel', 'deprecated': False}, + 'hpnd-kevlin-henney': {'id': 'HPND-Kevlin-Henney', 'deprecated': False}, + 'hpnd-markus-kuhn': {'id': 'HPND-Markus-Kuhn', 'deprecated': False}, + 'hpnd-merchantability-variant': {'id': 'HPND-merchantability-variant', 'deprecated': False}, + 'hpnd-mit-disclaimer': {'id': 'HPND-MIT-disclaimer', 'deprecated': False}, + 'hpnd-netrek': {'id': 'HPND-Netrek', 'deprecated': False}, + 'hpnd-pbmplus': {'id': 'HPND-Pbmplus', 'deprecated': False}, + 'hpnd-sell-mit-disclaimer-xserver': {'id': 'HPND-sell-MIT-disclaimer-xserver', 'deprecated': False}, + 'hpnd-sell-regexpr': {'id': 'HPND-sell-regexpr', 'deprecated': False}, + 'hpnd-sell-variant': {'id': 'HPND-sell-variant', 'deprecated': False}, + 'hpnd-sell-variant-mit-disclaimer': {'id': 'HPND-sell-variant-MIT-disclaimer', 'deprecated': False}, + 'hpnd-sell-variant-mit-disclaimer-rev': {'id': 'HPND-sell-variant-MIT-disclaimer-rev', 'deprecated': False}, + 'hpnd-uc': {'id': 'HPND-UC', 'deprecated': False}, + 'hpnd-uc-export-us': {'id': 'HPND-UC-export-US', 'deprecated': False}, + 'htmltidy': {'id': 'HTMLTIDY', 'deprecated': False}, + 'ibm-pibs': {'id': 'IBM-pibs', 'deprecated': False}, + 'icu': {'id': 'ICU', 'deprecated': False}, + 'iec-code-components-eula': {'id': 'IEC-Code-Components-EULA', 'deprecated': False}, + 'ijg': {'id': 'IJG', 'deprecated': False}, + 'ijg-short': {'id': 'IJG-short', 'deprecated': False}, + 'imagemagick': {'id': 'ImageMagick', 'deprecated': False}, + 'imatix': {'id': 'iMatix', 'deprecated': False}, + 'imlib2': {'id': 'Imlib2', 'deprecated': False}, + 'info-zip': {'id': 'Info-ZIP', 'deprecated': False}, + 'inner-net-2.0': {'id': 'Inner-Net-2.0', 'deprecated': False}, + 'intel': {'id': 'Intel', 'deprecated': False}, + 'intel-acpi': {'id': 'Intel-ACPI', 'deprecated': False}, + 'interbase-1.0': {'id': 'Interbase-1.0', 'deprecated': False}, + 'ipa': {'id': 'IPA', 'deprecated': False}, + 'ipl-1.0': {'id': 'IPL-1.0', 'deprecated': False}, + 'isc': {'id': 'ISC', 'deprecated': False}, + 'isc-veillard': {'id': 'ISC-Veillard', 'deprecated': False}, + 'jam': {'id': 'Jam', 'deprecated': False}, + 'jasper-2.0': {'id': 'JasPer-2.0', 'deprecated': False}, + 'jpl-image': {'id': 'JPL-image', 'deprecated': False}, + 'jpnic': {'id': 'JPNIC', 'deprecated': False}, + 'json': {'id': 'JSON', 'deprecated': False}, + 'kastrup': {'id': 'Kastrup', 'deprecated': False}, + 'kazlib': {'id': 'Kazlib', 'deprecated': False}, + 'knuth-ctan': {'id': 'Knuth-CTAN', 'deprecated': False}, + 'lal-1.2': {'id': 'LAL-1.2', 'deprecated': False}, + 'lal-1.3': {'id': 'LAL-1.3', 'deprecated': False}, + 'latex2e': {'id': 'Latex2e', 'deprecated': False}, + 'latex2e-translated-notice': {'id': 'Latex2e-translated-notice', 'deprecated': False}, + 'leptonica': {'id': 'Leptonica', 'deprecated': False}, + 'lgpl-2.0': {'id': 'LGPL-2.0', 'deprecated': True}, + 'lgpl-2.0+': {'id': 'LGPL-2.0+', 'deprecated': True}, + 'lgpl-2.0-only': {'id': 'LGPL-2.0-only', 'deprecated': False}, + 'lgpl-2.0-or-later': {'id': 'LGPL-2.0-or-later', 'deprecated': False}, + 'lgpl-2.1': {'id': 'LGPL-2.1', 'deprecated': True}, + 'lgpl-2.1+': {'id': 'LGPL-2.1+', 'deprecated': True}, + 'lgpl-2.1-only': {'id': 'LGPL-2.1-only', 'deprecated': False}, + 'lgpl-2.1-or-later': {'id': 'LGPL-2.1-or-later', 'deprecated': False}, + 'lgpl-3.0': {'id': 'LGPL-3.0', 'deprecated': True}, + 'lgpl-3.0+': {'id': 'LGPL-3.0+', 'deprecated': True}, + 'lgpl-3.0-only': {'id': 'LGPL-3.0-only', 'deprecated': False}, + 'lgpl-3.0-or-later': {'id': 'LGPL-3.0-or-later', 'deprecated': False}, + 'lgpllr': {'id': 'LGPLLR', 'deprecated': False}, + 'libpng': {'id': 'Libpng', 'deprecated': False}, + 'libpng-2.0': {'id': 'libpng-2.0', 'deprecated': False}, + 'libselinux-1.0': {'id': 'libselinux-1.0', 'deprecated': False}, + 'libtiff': {'id': 'libtiff', 'deprecated': False}, + 'libutil-david-nugent': {'id': 'libutil-David-Nugent', 'deprecated': False}, + 'liliq-p-1.1': {'id': 'LiLiQ-P-1.1', 'deprecated': False}, + 'liliq-r-1.1': {'id': 'LiLiQ-R-1.1', 'deprecated': False}, + 'liliq-rplus-1.1': {'id': 'LiLiQ-Rplus-1.1', 'deprecated': False}, + 'linux-man-pages-1-para': {'id': 'Linux-man-pages-1-para', 'deprecated': False}, + 'linux-man-pages-copyleft': {'id': 'Linux-man-pages-copyleft', 'deprecated': False}, + 'linux-man-pages-copyleft-2-para': {'id': 'Linux-man-pages-copyleft-2-para', 'deprecated': False}, + 'linux-man-pages-copyleft-var': {'id': 'Linux-man-pages-copyleft-var', 'deprecated': False}, + 'linux-openib': {'id': 'Linux-OpenIB', 'deprecated': False}, + 'loop': {'id': 'LOOP', 'deprecated': False}, + 'lpd-document': {'id': 'LPD-document', 'deprecated': False}, + 'lpl-1.0': {'id': 'LPL-1.0', 'deprecated': False}, + 'lpl-1.02': {'id': 'LPL-1.02', 'deprecated': False}, + 'lppl-1.0': {'id': 'LPPL-1.0', 'deprecated': False}, + 'lppl-1.1': {'id': 'LPPL-1.1', 'deprecated': False}, + 'lppl-1.2': {'id': 'LPPL-1.2', 'deprecated': False}, + 'lppl-1.3a': {'id': 'LPPL-1.3a', 'deprecated': False}, + 'lppl-1.3c': {'id': 'LPPL-1.3c', 'deprecated': False}, + 'lsof': {'id': 'lsof', 'deprecated': False}, + 'lucida-bitmap-fonts': {'id': 'Lucida-Bitmap-Fonts', 'deprecated': False}, + 'lzma-sdk-9.11-to-9.20': {'id': 'LZMA-SDK-9.11-to-9.20', 'deprecated': False}, + 'lzma-sdk-9.22': {'id': 'LZMA-SDK-9.22', 'deprecated': False}, + 'mackerras-3-clause': {'id': 'Mackerras-3-Clause', 'deprecated': False}, + 'mackerras-3-clause-acknowledgment': {'id': 'Mackerras-3-Clause-acknowledgment', 'deprecated': False}, + 'magaz': {'id': 'magaz', 'deprecated': False}, + 'mailprio': {'id': 'mailprio', 'deprecated': False}, + 'makeindex': {'id': 'MakeIndex', 'deprecated': False}, + 'martin-birgmeier': {'id': 'Martin-Birgmeier', 'deprecated': False}, + 'mcphee-slideshow': {'id': 'McPhee-slideshow', 'deprecated': False}, + 'metamail': {'id': 'metamail', 'deprecated': False}, + 'minpack': {'id': 'Minpack', 'deprecated': False}, + 'miros': {'id': 'MirOS', 'deprecated': False}, + 'mit': {'id': 'MIT', 'deprecated': False}, + 'mit-0': {'id': 'MIT-0', 'deprecated': False}, + 'mit-advertising': {'id': 'MIT-advertising', 'deprecated': False}, + 'mit-cmu': {'id': 'MIT-CMU', 'deprecated': False}, + 'mit-enna': {'id': 'MIT-enna', 'deprecated': False}, + 'mit-feh': {'id': 'MIT-feh', 'deprecated': False}, + 'mit-festival': {'id': 'MIT-Festival', 'deprecated': False}, + 'mit-khronos-old': {'id': 'MIT-Khronos-old', 'deprecated': False}, + 'mit-modern-variant': {'id': 'MIT-Modern-Variant', 'deprecated': False}, + 'mit-open-group': {'id': 'MIT-open-group', 'deprecated': False}, + 'mit-testregex': {'id': 'MIT-testregex', 'deprecated': False}, + 'mit-wu': {'id': 'MIT-Wu', 'deprecated': False}, + 'mitnfa': {'id': 'MITNFA', 'deprecated': False}, + 'mmixware': {'id': 'MMIXware', 'deprecated': False}, + 'motosoto': {'id': 'Motosoto', 'deprecated': False}, + 'mpeg-ssg': {'id': 'MPEG-SSG', 'deprecated': False}, + 'mpi-permissive': {'id': 'mpi-permissive', 'deprecated': False}, + 'mpich2': {'id': 'mpich2', 'deprecated': False}, + 'mpl-1.0': {'id': 'MPL-1.0', 'deprecated': False}, + 'mpl-1.1': {'id': 'MPL-1.1', 'deprecated': False}, + 'mpl-2.0': {'id': 'MPL-2.0', 'deprecated': False}, + 'mpl-2.0-no-copyleft-exception': {'id': 'MPL-2.0-no-copyleft-exception', 'deprecated': False}, + 'mplus': {'id': 'mplus', 'deprecated': False}, + 'ms-lpl': {'id': 'MS-LPL', 'deprecated': False}, + 'ms-pl': {'id': 'MS-PL', 'deprecated': False}, + 'ms-rl': {'id': 'MS-RL', 'deprecated': False}, + 'mtll': {'id': 'MTLL', 'deprecated': False}, + 'mulanpsl-1.0': {'id': 'MulanPSL-1.0', 'deprecated': False}, + 'mulanpsl-2.0': {'id': 'MulanPSL-2.0', 'deprecated': False}, + 'multics': {'id': 'Multics', 'deprecated': False}, + 'mup': {'id': 'Mup', 'deprecated': False}, + 'naist-2003': {'id': 'NAIST-2003', 'deprecated': False}, + 'nasa-1.3': {'id': 'NASA-1.3', 'deprecated': False}, + 'naumen': {'id': 'Naumen', 'deprecated': False}, + 'nbpl-1.0': {'id': 'NBPL-1.0', 'deprecated': False}, + 'ncbi-pd': {'id': 'NCBI-PD', 'deprecated': False}, + 'ncgl-uk-2.0': {'id': 'NCGL-UK-2.0', 'deprecated': False}, + 'ncl': {'id': 'NCL', 'deprecated': False}, + 'ncsa': {'id': 'NCSA', 'deprecated': False}, + 'net-snmp': {'id': 'Net-SNMP', 'deprecated': True}, + 'netcdf': {'id': 'NetCDF', 'deprecated': False}, + 'newsletr': {'id': 'Newsletr', 'deprecated': False}, + 'ngpl': {'id': 'NGPL', 'deprecated': False}, + 'nicta-1.0': {'id': 'NICTA-1.0', 'deprecated': False}, + 'nist-pd': {'id': 'NIST-PD', 'deprecated': False}, + 'nist-pd-fallback': {'id': 'NIST-PD-fallback', 'deprecated': False}, + 'nist-software': {'id': 'NIST-Software', 'deprecated': False}, + 'nlod-1.0': {'id': 'NLOD-1.0', 'deprecated': False}, + 'nlod-2.0': {'id': 'NLOD-2.0', 'deprecated': False}, + 'nlpl': {'id': 'NLPL', 'deprecated': False}, + 'nokia': {'id': 'Nokia', 'deprecated': False}, + 'nosl': {'id': 'NOSL', 'deprecated': False}, + 'noweb': {'id': 'Noweb', 'deprecated': False}, + 'npl-1.0': {'id': 'NPL-1.0', 'deprecated': False}, + 'npl-1.1': {'id': 'NPL-1.1', 'deprecated': False}, + 'nposl-3.0': {'id': 'NPOSL-3.0', 'deprecated': False}, + 'nrl': {'id': 'NRL', 'deprecated': False}, + 'ntp': {'id': 'NTP', 'deprecated': False}, + 'ntp-0': {'id': 'NTP-0', 'deprecated': False}, + 'nunit': {'id': 'Nunit', 'deprecated': True}, + 'o-uda-1.0': {'id': 'O-UDA-1.0', 'deprecated': False}, + 'oar': {'id': 'OAR', 'deprecated': False}, + 'occt-pl': {'id': 'OCCT-PL', 'deprecated': False}, + 'oclc-2.0': {'id': 'OCLC-2.0', 'deprecated': False}, + 'odbl-1.0': {'id': 'ODbL-1.0', 'deprecated': False}, + 'odc-by-1.0': {'id': 'ODC-By-1.0', 'deprecated': False}, + 'offis': {'id': 'OFFIS', 'deprecated': False}, + 'ofl-1.0': {'id': 'OFL-1.0', 'deprecated': False}, + 'ofl-1.0-no-rfn': {'id': 'OFL-1.0-no-RFN', 'deprecated': False}, + 'ofl-1.0-rfn': {'id': 'OFL-1.0-RFN', 'deprecated': False}, + 'ofl-1.1': {'id': 'OFL-1.1', 'deprecated': False}, + 'ofl-1.1-no-rfn': {'id': 'OFL-1.1-no-RFN', 'deprecated': False}, + 'ofl-1.1-rfn': {'id': 'OFL-1.1-RFN', 'deprecated': False}, + 'ogc-1.0': {'id': 'OGC-1.0', 'deprecated': False}, + 'ogdl-taiwan-1.0': {'id': 'OGDL-Taiwan-1.0', 'deprecated': False}, + 'ogl-canada-2.0': {'id': 'OGL-Canada-2.0', 'deprecated': False}, + 'ogl-uk-1.0': {'id': 'OGL-UK-1.0', 'deprecated': False}, + 'ogl-uk-2.0': {'id': 'OGL-UK-2.0', 'deprecated': False}, + 'ogl-uk-3.0': {'id': 'OGL-UK-3.0', 'deprecated': False}, + 'ogtsl': {'id': 'OGTSL', 'deprecated': False}, + 'oldap-1.1': {'id': 'OLDAP-1.1', 'deprecated': False}, + 'oldap-1.2': {'id': 'OLDAP-1.2', 'deprecated': False}, + 'oldap-1.3': {'id': 'OLDAP-1.3', 'deprecated': False}, + 'oldap-1.4': {'id': 'OLDAP-1.4', 'deprecated': False}, + 'oldap-2.0': {'id': 'OLDAP-2.0', 'deprecated': False}, + 'oldap-2.0.1': {'id': 'OLDAP-2.0.1', 'deprecated': False}, + 'oldap-2.1': {'id': 'OLDAP-2.1', 'deprecated': False}, + 'oldap-2.2': {'id': 'OLDAP-2.2', 'deprecated': False}, + 'oldap-2.2.1': {'id': 'OLDAP-2.2.1', 'deprecated': False}, + 'oldap-2.2.2': {'id': 'OLDAP-2.2.2', 'deprecated': False}, + 'oldap-2.3': {'id': 'OLDAP-2.3', 'deprecated': False}, + 'oldap-2.4': {'id': 'OLDAP-2.4', 'deprecated': False}, + 'oldap-2.5': {'id': 'OLDAP-2.5', 'deprecated': False}, + 'oldap-2.6': {'id': 'OLDAP-2.6', 'deprecated': False}, + 'oldap-2.7': {'id': 'OLDAP-2.7', 'deprecated': False}, + 'oldap-2.8': {'id': 'OLDAP-2.8', 'deprecated': False}, + 'olfl-1.3': {'id': 'OLFL-1.3', 'deprecated': False}, + 'oml': {'id': 'OML', 'deprecated': False}, + 'openpbs-2.3': {'id': 'OpenPBS-2.3', 'deprecated': False}, + 'openssl': {'id': 'OpenSSL', 'deprecated': False}, + 'openssl-standalone': {'id': 'OpenSSL-standalone', 'deprecated': False}, + 'openvision': {'id': 'OpenVision', 'deprecated': False}, + 'opl-1.0': {'id': 'OPL-1.0', 'deprecated': False}, + 'opl-uk-3.0': {'id': 'OPL-UK-3.0', 'deprecated': False}, + 'opubl-1.0': {'id': 'OPUBL-1.0', 'deprecated': False}, + 'oset-pl-2.1': {'id': 'OSET-PL-2.1', 'deprecated': False}, + 'osl-1.0': {'id': 'OSL-1.0', 'deprecated': False}, + 'osl-1.1': {'id': 'OSL-1.1', 'deprecated': False}, + 'osl-2.0': {'id': 'OSL-2.0', 'deprecated': False}, + 'osl-2.1': {'id': 'OSL-2.1', 'deprecated': False}, + 'osl-3.0': {'id': 'OSL-3.0', 'deprecated': False}, + 'padl': {'id': 'PADL', 'deprecated': False}, + 'parity-6.0.0': {'id': 'Parity-6.0.0', 'deprecated': False}, + 'parity-7.0.0': {'id': 'Parity-7.0.0', 'deprecated': False}, + 'pddl-1.0': {'id': 'PDDL-1.0', 'deprecated': False}, + 'php-3.0': {'id': 'PHP-3.0', 'deprecated': False}, + 'php-3.01': {'id': 'PHP-3.01', 'deprecated': False}, + 'pixar': {'id': 'Pixar', 'deprecated': False}, + 'pkgconf': {'id': 'pkgconf', 'deprecated': False}, + 'plexus': {'id': 'Plexus', 'deprecated': False}, + 'pnmstitch': {'id': 'pnmstitch', 'deprecated': False}, + 'polyform-noncommercial-1.0.0': {'id': 'PolyForm-Noncommercial-1.0.0', 'deprecated': False}, + 'polyform-small-business-1.0.0': {'id': 'PolyForm-Small-Business-1.0.0', 'deprecated': False}, + 'postgresql': {'id': 'PostgreSQL', 'deprecated': False}, + 'ppl': {'id': 'PPL', 'deprecated': False}, + 'psf-2.0': {'id': 'PSF-2.0', 'deprecated': False}, + 'psfrag': {'id': 'psfrag', 'deprecated': False}, + 'psutils': {'id': 'psutils', 'deprecated': False}, + 'python-2.0': {'id': 'Python-2.0', 'deprecated': False}, + 'python-2.0.1': {'id': 'Python-2.0.1', 'deprecated': False}, + 'python-ldap': {'id': 'python-ldap', 'deprecated': False}, + 'qhull': {'id': 'Qhull', 'deprecated': False}, + 'qpl-1.0': {'id': 'QPL-1.0', 'deprecated': False}, + 'qpl-1.0-inria-2004': {'id': 'QPL-1.0-INRIA-2004', 'deprecated': False}, + 'radvd': {'id': 'radvd', 'deprecated': False}, + 'rdisc': {'id': 'Rdisc', 'deprecated': False}, + 'rhecos-1.1': {'id': 'RHeCos-1.1', 'deprecated': False}, + 'rpl-1.1': {'id': 'RPL-1.1', 'deprecated': False}, + 'rpl-1.5': {'id': 'RPL-1.5', 'deprecated': False}, + 'rpsl-1.0': {'id': 'RPSL-1.0', 'deprecated': False}, + 'rsa-md': {'id': 'RSA-MD', 'deprecated': False}, + 'rscpl': {'id': 'RSCPL', 'deprecated': False}, + 'ruby': {'id': 'Ruby', 'deprecated': False}, + 'ruby-pty': {'id': 'Ruby-pty', 'deprecated': False}, + 'sax-pd': {'id': 'SAX-PD', 'deprecated': False}, + 'sax-pd-2.0': {'id': 'SAX-PD-2.0', 'deprecated': False}, + 'saxpath': {'id': 'Saxpath', 'deprecated': False}, + 'scea': {'id': 'SCEA', 'deprecated': False}, + 'schemereport': {'id': 'SchemeReport', 'deprecated': False}, + 'sendmail': {'id': 'Sendmail', 'deprecated': False}, + 'sendmail-8.23': {'id': 'Sendmail-8.23', 'deprecated': False}, + 'sgi-b-1.0': {'id': 'SGI-B-1.0', 'deprecated': False}, + 'sgi-b-1.1': {'id': 'SGI-B-1.1', 'deprecated': False}, + 'sgi-b-2.0': {'id': 'SGI-B-2.0', 'deprecated': False}, + 'sgi-opengl': {'id': 'SGI-OpenGL', 'deprecated': False}, + 'sgp4': {'id': 'SGP4', 'deprecated': False}, + 'shl-0.5': {'id': 'SHL-0.5', 'deprecated': False}, + 'shl-0.51': {'id': 'SHL-0.51', 'deprecated': False}, + 'simpl-2.0': {'id': 'SimPL-2.0', 'deprecated': False}, + 'sissl': {'id': 'SISSL', 'deprecated': False}, + 'sissl-1.2': {'id': 'SISSL-1.2', 'deprecated': False}, + 'sl': {'id': 'SL', 'deprecated': False}, + 'sleepycat': {'id': 'Sleepycat', 'deprecated': False}, + 'smlnj': {'id': 'SMLNJ', 'deprecated': False}, + 'smppl': {'id': 'SMPPL', 'deprecated': False}, + 'snia': {'id': 'SNIA', 'deprecated': False}, + 'snprintf': {'id': 'snprintf', 'deprecated': False}, + 'softsurfer': {'id': 'softSurfer', 'deprecated': False}, + 'soundex': {'id': 'Soundex', 'deprecated': False}, + 'spencer-86': {'id': 'Spencer-86', 'deprecated': False}, + 'spencer-94': {'id': 'Spencer-94', 'deprecated': False}, + 'spencer-99': {'id': 'Spencer-99', 'deprecated': False}, + 'spl-1.0': {'id': 'SPL-1.0', 'deprecated': False}, + 'ssh-keyscan': {'id': 'ssh-keyscan', 'deprecated': False}, + 'ssh-openssh': {'id': 'SSH-OpenSSH', 'deprecated': False}, + 'ssh-short': {'id': 'SSH-short', 'deprecated': False}, + 'ssleay-standalone': {'id': 'SSLeay-standalone', 'deprecated': False}, + 'sspl-1.0': {'id': 'SSPL-1.0', 'deprecated': False}, + 'standardml-nj': {'id': 'StandardML-NJ', 'deprecated': True}, + 'sugarcrm-1.1.3': {'id': 'SugarCRM-1.1.3', 'deprecated': False}, + 'sun-ppp': {'id': 'Sun-PPP', 'deprecated': False}, + 'sun-ppp-2000': {'id': 'Sun-PPP-2000', 'deprecated': False}, + 'sunpro': {'id': 'SunPro', 'deprecated': False}, + 'swl': {'id': 'SWL', 'deprecated': False}, + 'swrule': {'id': 'swrule', 'deprecated': False}, + 'symlinks': {'id': 'Symlinks', 'deprecated': False}, + 'tapr-ohl-1.0': {'id': 'TAPR-OHL-1.0', 'deprecated': False}, + 'tcl': {'id': 'TCL', 'deprecated': False}, + 'tcp-wrappers': {'id': 'TCP-wrappers', 'deprecated': False}, + 'termreadkey': {'id': 'TermReadKey', 'deprecated': False}, + 'tgppl-1.0': {'id': 'TGPPL-1.0', 'deprecated': False}, + 'threeparttable': {'id': 'threeparttable', 'deprecated': False}, + 'tmate': {'id': 'TMate', 'deprecated': False}, + 'torque-1.1': {'id': 'TORQUE-1.1', 'deprecated': False}, + 'tosl': {'id': 'TOSL', 'deprecated': False}, + 'tpdl': {'id': 'TPDL', 'deprecated': False}, + 'tpl-1.0': {'id': 'TPL-1.0', 'deprecated': False}, + 'ttwl': {'id': 'TTWL', 'deprecated': False}, + 'ttyp0': {'id': 'TTYP0', 'deprecated': False}, + 'tu-berlin-1.0': {'id': 'TU-Berlin-1.0', 'deprecated': False}, + 'tu-berlin-2.0': {'id': 'TU-Berlin-2.0', 'deprecated': False}, + 'ubuntu-font-1.0': {'id': 'Ubuntu-font-1.0', 'deprecated': False}, + 'ucar': {'id': 'UCAR', 'deprecated': False}, + 'ucl-1.0': {'id': 'UCL-1.0', 'deprecated': False}, + 'ulem': {'id': 'ulem', 'deprecated': False}, + 'umich-merit': {'id': 'UMich-Merit', 'deprecated': False}, + 'unicode-3.0': {'id': 'Unicode-3.0', 'deprecated': False}, + 'unicode-dfs-2015': {'id': 'Unicode-DFS-2015', 'deprecated': False}, + 'unicode-dfs-2016': {'id': 'Unicode-DFS-2016', 'deprecated': False}, + 'unicode-tou': {'id': 'Unicode-TOU', 'deprecated': False}, + 'unixcrypt': {'id': 'UnixCrypt', 'deprecated': False}, + 'unlicense': {'id': 'Unlicense', 'deprecated': False}, + 'upl-1.0': {'id': 'UPL-1.0', 'deprecated': False}, + 'urt-rle': {'id': 'URT-RLE', 'deprecated': False}, + 'vim': {'id': 'Vim', 'deprecated': False}, + 'vostrom': {'id': 'VOSTROM', 'deprecated': False}, + 'vsl-1.0': {'id': 'VSL-1.0', 'deprecated': False}, + 'w3c': {'id': 'W3C', 'deprecated': False}, + 'w3c-19980720': {'id': 'W3C-19980720', 'deprecated': False}, + 'w3c-20150513': {'id': 'W3C-20150513', 'deprecated': False}, + 'w3m': {'id': 'w3m', 'deprecated': False}, + 'watcom-1.0': {'id': 'Watcom-1.0', 'deprecated': False}, + 'widget-workshop': {'id': 'Widget-Workshop', 'deprecated': False}, + 'wsuipa': {'id': 'Wsuipa', 'deprecated': False}, + 'wtfpl': {'id': 'WTFPL', 'deprecated': False}, + 'wxwindows': {'id': 'wxWindows', 'deprecated': True}, + 'x11': {'id': 'X11', 'deprecated': False}, + 'x11-distribute-modifications-variant': {'id': 'X11-distribute-modifications-variant', 'deprecated': False}, + 'x11-swapped': {'id': 'X11-swapped', 'deprecated': False}, + 'xdebug-1.03': {'id': 'Xdebug-1.03', 'deprecated': False}, + 'xerox': {'id': 'Xerox', 'deprecated': False}, + 'xfig': {'id': 'Xfig', 'deprecated': False}, + 'xfree86-1.1': {'id': 'XFree86-1.1', 'deprecated': False}, + 'xinetd': {'id': 'xinetd', 'deprecated': False}, + 'xkeyboard-config-zinoviev': {'id': 'xkeyboard-config-Zinoviev', 'deprecated': False}, + 'xlock': {'id': 'xlock', 'deprecated': False}, + 'xnet': {'id': 'Xnet', 'deprecated': False}, + 'xpp': {'id': 'xpp', 'deprecated': False}, + 'xskat': {'id': 'XSkat', 'deprecated': False}, + 'xzoom': {'id': 'xzoom', 'deprecated': False}, + 'ypl-1.0': {'id': 'YPL-1.0', 'deprecated': False}, + 'ypl-1.1': {'id': 'YPL-1.1', 'deprecated': False}, + 'zed': {'id': 'Zed', 'deprecated': False}, + 'zeeff': {'id': 'Zeeff', 'deprecated': False}, + 'zend-2.0': {'id': 'Zend-2.0', 'deprecated': False}, + 'zimbra-1.3': {'id': 'Zimbra-1.3', 'deprecated': False}, + 'zimbra-1.4': {'id': 'Zimbra-1.4', 'deprecated': False}, + 'zlib': {'id': 'Zlib', 'deprecated': False}, + 'zlib-acknowledgement': {'id': 'zlib-acknowledgement', 'deprecated': False}, + 'zpl-1.1': {'id': 'ZPL-1.1', 'deprecated': False}, + 'zpl-2.0': {'id': 'ZPL-2.0', 'deprecated': False}, + 'zpl-2.1': {'id': 'ZPL-2.1', 'deprecated': False}, +} + +EXCEPTIONS: dict[str, SPDXException] = { + '389-exception': {'id': '389-exception', 'deprecated': False}, + 'asterisk-exception': {'id': 'Asterisk-exception', 'deprecated': False}, + 'asterisk-linking-protocols-exception': {'id': 'Asterisk-linking-protocols-exception', 'deprecated': False}, + 'autoconf-exception-2.0': {'id': 'Autoconf-exception-2.0', 'deprecated': False}, + 'autoconf-exception-3.0': {'id': 'Autoconf-exception-3.0', 'deprecated': False}, + 'autoconf-exception-generic': {'id': 'Autoconf-exception-generic', 'deprecated': False}, + 'autoconf-exception-generic-3.0': {'id': 'Autoconf-exception-generic-3.0', 'deprecated': False}, + 'autoconf-exception-macro': {'id': 'Autoconf-exception-macro', 'deprecated': False}, + 'bison-exception-1.24': {'id': 'Bison-exception-1.24', 'deprecated': False}, + 'bison-exception-2.2': {'id': 'Bison-exception-2.2', 'deprecated': False}, + 'bootloader-exception': {'id': 'Bootloader-exception', 'deprecated': False}, + 'classpath-exception-2.0': {'id': 'Classpath-exception-2.0', 'deprecated': False}, + 'clisp-exception-2.0': {'id': 'CLISP-exception-2.0', 'deprecated': False}, + 'cryptsetup-openssl-exception': {'id': 'cryptsetup-OpenSSL-exception', 'deprecated': False}, + 'digirule-foss-exception': {'id': 'DigiRule-FOSS-exception', 'deprecated': False}, + 'ecos-exception-2.0': {'id': 'eCos-exception-2.0', 'deprecated': False}, + 'erlang-otp-linking-exception': {'id': 'erlang-otp-linking-exception', 'deprecated': False}, + 'fawkes-runtime-exception': {'id': 'Fawkes-Runtime-exception', 'deprecated': False}, + 'fltk-exception': {'id': 'FLTK-exception', 'deprecated': False}, + 'fmt-exception': {'id': 'fmt-exception', 'deprecated': False}, + 'font-exception-2.0': {'id': 'Font-exception-2.0', 'deprecated': False}, + 'freertos-exception-2.0': {'id': 'freertos-exception-2.0', 'deprecated': False}, + 'gcc-exception-2.0': {'id': 'GCC-exception-2.0', 'deprecated': False}, + 'gcc-exception-2.0-note': {'id': 'GCC-exception-2.0-note', 'deprecated': False}, + 'gcc-exception-3.1': {'id': 'GCC-exception-3.1', 'deprecated': False}, + 'gmsh-exception': {'id': 'Gmsh-exception', 'deprecated': False}, + 'gnat-exception': {'id': 'GNAT-exception', 'deprecated': False}, + 'gnome-examples-exception': {'id': 'GNOME-examples-exception', 'deprecated': False}, + 'gnu-compiler-exception': {'id': 'GNU-compiler-exception', 'deprecated': False}, + 'gnu-javamail-exception': {'id': 'gnu-javamail-exception', 'deprecated': False}, + 'gpl-3.0-interface-exception': {'id': 'GPL-3.0-interface-exception', 'deprecated': False}, + 'gpl-3.0-linking-exception': {'id': 'GPL-3.0-linking-exception', 'deprecated': False}, + 'gpl-3.0-linking-source-exception': {'id': 'GPL-3.0-linking-source-exception', 'deprecated': False}, + 'gpl-cc-1.0': {'id': 'GPL-CC-1.0', 'deprecated': False}, + 'gstreamer-exception-2005': {'id': 'GStreamer-exception-2005', 'deprecated': False}, + 'gstreamer-exception-2008': {'id': 'GStreamer-exception-2008', 'deprecated': False}, + 'i2p-gpl-java-exception': {'id': 'i2p-gpl-java-exception', 'deprecated': False}, + 'kicad-libraries-exception': {'id': 'KiCad-libraries-exception', 'deprecated': False}, + 'lgpl-3.0-linking-exception': {'id': 'LGPL-3.0-linking-exception', 'deprecated': False}, + 'libpri-openh323-exception': {'id': 'libpri-OpenH323-exception', 'deprecated': False}, + 'libtool-exception': {'id': 'Libtool-exception', 'deprecated': False}, + 'linux-syscall-note': {'id': 'Linux-syscall-note', 'deprecated': False}, + 'llgpl': {'id': 'LLGPL', 'deprecated': False}, + 'llvm-exception': {'id': 'LLVM-exception', 'deprecated': False}, + 'lzma-exception': {'id': 'LZMA-exception', 'deprecated': False}, + 'mif-exception': {'id': 'mif-exception', 'deprecated': False}, + 'nokia-qt-exception-1.1': {'id': 'Nokia-Qt-exception-1.1', 'deprecated': True}, + 'ocaml-lgpl-linking-exception': {'id': 'OCaml-LGPL-linking-exception', 'deprecated': False}, + 'occt-exception-1.0': {'id': 'OCCT-exception-1.0', 'deprecated': False}, + 'openjdk-assembly-exception-1.0': {'id': 'OpenJDK-assembly-exception-1.0', 'deprecated': False}, + 'openvpn-openssl-exception': {'id': 'openvpn-openssl-exception', 'deprecated': False}, + 'pcre2-exception': {'id': 'PCRE2-exception', 'deprecated': False}, + 'ps-or-pdf-font-exception-20170817': {'id': 'PS-or-PDF-font-exception-20170817', 'deprecated': False}, + 'qpl-1.0-inria-2004-exception': {'id': 'QPL-1.0-INRIA-2004-exception', 'deprecated': False}, + 'qt-gpl-exception-1.0': {'id': 'Qt-GPL-exception-1.0', 'deprecated': False}, + 'qt-lgpl-exception-1.1': {'id': 'Qt-LGPL-exception-1.1', 'deprecated': False}, + 'qwt-exception-1.0': {'id': 'Qwt-exception-1.0', 'deprecated': False}, + 'romic-exception': {'id': 'romic-exception', 'deprecated': False}, + 'rrdtool-floss-exception-2.0': {'id': 'RRDtool-FLOSS-exception-2.0', 'deprecated': False}, + 'sane-exception': {'id': 'SANE-exception', 'deprecated': False}, + 'shl-2.0': {'id': 'SHL-2.0', 'deprecated': False}, + 'shl-2.1': {'id': 'SHL-2.1', 'deprecated': False}, + 'stunnel-exception': {'id': 'stunnel-exception', 'deprecated': False}, + 'swi-exception': {'id': 'SWI-exception', 'deprecated': False}, + 'swift-exception': {'id': 'Swift-exception', 'deprecated': False}, + 'texinfo-exception': {'id': 'Texinfo-exception', 'deprecated': False}, + 'u-boot-exception-2.0': {'id': 'u-boot-exception-2.0', 'deprecated': False}, + 'ubdl-exception': {'id': 'UBDL-exception', 'deprecated': False}, + 'universal-foss-exception-1.0': {'id': 'Universal-FOSS-exception-1.0', 'deprecated': False}, + 'vsftpd-openssl-exception': {'id': 'vsftpd-openssl-exception', 'deprecated': False}, + 'wxwindows-exception-3.1': {'id': 'WxWindows-exception-3.1', 'deprecated': False}, + 'x11vnc-openssl-exception': {'id': 'x11vnc-openssl-exception', 'deprecated': False}, +} diff --git a/lib/python3.12/site-packages/packaging/markers.py b/lib/python3.12/site-packages/packaging/markers.py new file mode 100644 index 0000000000000000000000000000000000000000..e7cea57297a23809548fcd0d344740796bae945b --- /dev/null +++ b/lib/python3.12/site-packages/packaging/markers.py @@ -0,0 +1,362 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import operator +import os +import platform +import sys +from typing import AbstractSet, Any, Callable, Literal, TypedDict, Union, cast + +from ._parser import MarkerAtom, MarkerList, Op, Value, Variable +from ._parser import parse_marker as _parse_marker +from ._tokenizer import ParserSyntaxError +from .specifiers import InvalidSpecifier, Specifier +from .utils import canonicalize_name + +__all__ = [ + "EvaluateContext", + "InvalidMarker", + "Marker", + "UndefinedComparison", + "UndefinedEnvironmentName", + "default_environment", +] + +Operator = Callable[[str, Union[str, AbstractSet[str]]], bool] +EvaluateContext = Literal["metadata", "lock_file", "requirement"] +MARKERS_ALLOWING_SET = {"extras", "dependency_groups"} + + +class InvalidMarker(ValueError): + """ + An invalid marker was found, users should refer to PEP 508. + """ + + +class UndefinedComparison(ValueError): + """ + An invalid operation was attempted on a value that doesn't support it. + """ + + +class UndefinedEnvironmentName(ValueError): + """ + A name was attempted to be used that does not exist inside of the + environment. + """ + + +class Environment(TypedDict): + implementation_name: str + """The implementation's identifier, e.g. ``'cpython'``.""" + + implementation_version: str + """ + The implementation's version, e.g. ``'3.13.0a2'`` for CPython 3.13.0a2, or + ``'7.3.13'`` for PyPy3.10 v7.3.13. + """ + + os_name: str + """ + The value of :py:data:`os.name`. The name of the operating system dependent module + imported, e.g. ``'posix'``. + """ + + platform_machine: str + """ + Returns the machine type, e.g. ``'i386'``. + + An empty string if the value cannot be determined. + """ + + platform_release: str + """ + The system's release, e.g. ``'2.2.0'`` or ``'NT'``. + + An empty string if the value cannot be determined. + """ + + platform_system: str + """ + The system/OS name, e.g. ``'Linux'``, ``'Windows'`` or ``'Java'``. + + An empty string if the value cannot be determined. + """ + + platform_version: str + """ + The system's release version, e.g. ``'#3 on degas'``. + + An empty string if the value cannot be determined. + """ + + python_full_version: str + """ + The Python version as string ``'major.minor.patchlevel'``. + + Note that unlike the Python :py:data:`sys.version`, this value will always include + the patchlevel (it defaults to 0). + """ + + platform_python_implementation: str + """ + A string identifying the Python implementation, e.g. ``'CPython'``. + """ + + python_version: str + """The Python version as string ``'major.minor'``.""" + + sys_platform: str + """ + This string contains a platform identifier that can be used to append + platform-specific components to :py:data:`sys.path`, for instance. + + For Unix systems, except on Linux and AIX, this is the lowercased OS name as + returned by ``uname -s`` with the first part of the version as returned by + ``uname -r`` appended, e.g. ``'sunos5'`` or ``'freebsd8'``, at the time when Python + was built. + """ + + +def _normalize_extra_values(results: Any) -> Any: + """ + Normalize extra values. + """ + if isinstance(results[0], tuple): + lhs, op, rhs = results[0] + if isinstance(lhs, Variable) and lhs.value == "extra": + normalized_extra = canonicalize_name(rhs.value) + rhs = Value(normalized_extra) + elif isinstance(rhs, Variable) and rhs.value == "extra": + normalized_extra = canonicalize_name(lhs.value) + lhs = Value(normalized_extra) + results[0] = lhs, op, rhs + return results + + +def _format_marker( + marker: list[str] | MarkerAtom | str, first: bool | None = True +) -> str: + assert isinstance(marker, (list, tuple, str)) + + # Sometimes we have a structure like [[...]] which is a single item list + # where the single item is itself it's own list. In that case we want skip + # the rest of this function so that we don't get extraneous () on the + # outside. + if ( + isinstance(marker, list) + and len(marker) == 1 + and isinstance(marker[0], (list, tuple)) + ): + return _format_marker(marker[0]) + + if isinstance(marker, list): + inner = (_format_marker(m, first=False) for m in marker) + if first: + return " ".join(inner) + else: + return "(" + " ".join(inner) + ")" + elif isinstance(marker, tuple): + return " ".join([m.serialize() for m in marker]) + else: + return marker + + +_operators: dict[str, Operator] = { + "in": lambda lhs, rhs: lhs in rhs, + "not in": lambda lhs, rhs: lhs not in rhs, + "<": operator.lt, + "<=": operator.le, + "==": operator.eq, + "!=": operator.ne, + ">=": operator.ge, + ">": operator.gt, +} + + +def _eval_op(lhs: str, op: Op, rhs: str | AbstractSet[str]) -> bool: + if isinstance(rhs, str): + try: + spec = Specifier("".join([op.serialize(), rhs])) + except InvalidSpecifier: + pass + else: + return spec.contains(lhs, prereleases=True) + + oper: Operator | None = _operators.get(op.serialize()) + if oper is None: + raise UndefinedComparison(f"Undefined {op!r} on {lhs!r} and {rhs!r}.") + + return oper(lhs, rhs) + + +def _normalize( + lhs: str, rhs: str | AbstractSet[str], key: str +) -> tuple[str, str | AbstractSet[str]]: + # PEP 685 – Comparison of extra names for optional distribution dependencies + # https://peps.python.org/pep-0685/ + # > When comparing extra names, tools MUST normalize the names being + # > compared using the semantics outlined in PEP 503 for names + if key == "extra": + assert isinstance(rhs, str), "extra value must be a string" + return (canonicalize_name(lhs), canonicalize_name(rhs)) + if key in MARKERS_ALLOWING_SET: + if isinstance(rhs, str): # pragma: no cover + return (canonicalize_name(lhs), canonicalize_name(rhs)) + else: + return (canonicalize_name(lhs), {canonicalize_name(v) for v in rhs}) + + # other environment markers don't have such standards + return lhs, rhs + + +def _evaluate_markers( + markers: MarkerList, environment: dict[str, str | AbstractSet[str]] +) -> bool: + groups: list[list[bool]] = [[]] + + for marker in markers: + assert isinstance(marker, (list, tuple, str)) + + if isinstance(marker, list): + groups[-1].append(_evaluate_markers(marker, environment)) + elif isinstance(marker, tuple): + lhs, op, rhs = marker + + if isinstance(lhs, Variable): + environment_key = lhs.value + lhs_value = environment[environment_key] + rhs_value = rhs.value + else: + lhs_value = lhs.value + environment_key = rhs.value + rhs_value = environment[environment_key] + assert isinstance(lhs_value, str), "lhs must be a string" + lhs_value, rhs_value = _normalize(lhs_value, rhs_value, key=environment_key) + groups[-1].append(_eval_op(lhs_value, op, rhs_value)) + else: + assert marker in ["and", "or"] + if marker == "or": + groups.append([]) + + return any(all(item) for item in groups) + + +def format_full_version(info: sys._version_info) -> str: + version = f"{info.major}.{info.minor}.{info.micro}" + kind = info.releaselevel + if kind != "final": + version += kind[0] + str(info.serial) + return version + + +def default_environment() -> Environment: + iver = format_full_version(sys.implementation.version) + implementation_name = sys.implementation.name + return { + "implementation_name": implementation_name, + "implementation_version": iver, + "os_name": os.name, + "platform_machine": platform.machine(), + "platform_release": platform.release(), + "platform_system": platform.system(), + "platform_version": platform.version(), + "python_full_version": platform.python_version(), + "platform_python_implementation": platform.python_implementation(), + "python_version": ".".join(platform.python_version_tuple()[:2]), + "sys_platform": sys.platform, + } + + +class Marker: + def __init__(self, marker: str) -> None: + # Note: We create a Marker object without calling this constructor in + # packaging.requirements.Requirement. If any additional logic is + # added here, make sure to mirror/adapt Requirement. + try: + self._markers = _normalize_extra_values(_parse_marker(marker)) + # The attribute `_markers` can be described in terms of a recursive type: + # MarkerList = List[Union[Tuple[Node, ...], str, MarkerList]] + # + # For example, the following expression: + # python_version > "3.6" or (python_version == "3.6" and os_name == "unix") + # + # is parsed into: + # [ + # (, ')>, ), + # 'and', + # [ + # (, , ), + # 'or', + # (, , ) + # ] + # ] + except ParserSyntaxError as e: + raise InvalidMarker(str(e)) from e + + def __str__(self) -> str: + return _format_marker(self._markers) + + def __repr__(self) -> str: + return f"" + + def __hash__(self) -> int: + return hash((self.__class__.__name__, str(self))) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Marker): + return NotImplemented + + return str(self) == str(other) + + def evaluate( + self, + environment: dict[str, str] | None = None, + context: EvaluateContext = "metadata", + ) -> bool: + """Evaluate a marker. + + Return the boolean from evaluating the given marker against the + environment. environment is an optional argument to override all or + part of the determined environment. The *context* parameter specifies what + context the markers are being evaluated for, which influences what markers + are considered valid. Acceptable values are "metadata" (for core metadata; + default), "lock_file", and "requirement" (i.e. all other situations). + + The environment is determined from the current Python process. + """ + current_environment = cast( + "dict[str, str | AbstractSet[str]]", default_environment() + ) + if context == "lock_file": + current_environment.update( + extras=frozenset(), dependency_groups=frozenset() + ) + elif context == "metadata": + current_environment["extra"] = "" + if environment is not None: + current_environment.update(environment) + # The API used to allow setting extra to None. We need to handle this + # case for backwards compatibility. + if "extra" in current_environment and current_environment["extra"] is None: + current_environment["extra"] = "" + + return _evaluate_markers( + self._markers, _repair_python_full_version(current_environment) + ) + + +def _repair_python_full_version( + env: dict[str, str | AbstractSet[str]], +) -> dict[str, str | AbstractSet[str]]: + """ + Work around platform.python_version() returning something that is not PEP 440 + compliant for non-tagged Python builds. + """ + python_full_version = cast(str, env["python_full_version"]) + if python_full_version.endswith("+"): + env["python_full_version"] = f"{python_full_version}local" + return env diff --git a/lib/python3.12/site-packages/packaging/metadata.py b/lib/python3.12/site-packages/packaging/metadata.py new file mode 100644 index 0000000000000000000000000000000000000000..3bd8602d36c53374f1f10a0716d28fdc64e2d3ac --- /dev/null +++ b/lib/python3.12/site-packages/packaging/metadata.py @@ -0,0 +1,862 @@ +from __future__ import annotations + +import email.feedparser +import email.header +import email.message +import email.parser +import email.policy +import pathlib +import sys +import typing +from typing import ( + Any, + Callable, + Generic, + Literal, + TypedDict, + cast, +) + +from . import licenses, requirements, specifiers, utils +from . import version as version_module +from .licenses import NormalizedLicenseExpression + +T = typing.TypeVar("T") + + +if sys.version_info >= (3, 11): # pragma: no cover + ExceptionGroup = ExceptionGroup +else: # pragma: no cover + + class ExceptionGroup(Exception): + """A minimal implementation of :external:exc:`ExceptionGroup` from Python 3.11. + + If :external:exc:`ExceptionGroup` is already defined by Python itself, + that version is used instead. + """ + + message: str + exceptions: list[Exception] + + def __init__(self, message: str, exceptions: list[Exception]) -> None: + self.message = message + self.exceptions = exceptions + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})" + + +class InvalidMetadata(ValueError): + """A metadata field contains invalid data.""" + + field: str + """The name of the field that contains invalid data.""" + + def __init__(self, field: str, message: str) -> None: + self.field = field + super().__init__(message) + + +# The RawMetadata class attempts to make as few assumptions about the underlying +# serialization formats as possible. The idea is that as long as a serialization +# formats offer some very basic primitives in *some* way then we can support +# serializing to and from that format. +class RawMetadata(TypedDict, total=False): + """A dictionary of raw core metadata. + + Each field in core metadata maps to a key of this dictionary (when data is + provided). The key is lower-case and underscores are used instead of dashes + compared to the equivalent core metadata field. Any core metadata field that + can be specified multiple times or can hold multiple values in a single + field have a key with a plural name. See :class:`Metadata` whose attributes + match the keys of this dictionary. + + Core metadata fields that can be specified multiple times are stored as a + list or dict depending on which is appropriate for the field. Any fields + which hold multiple values in a single field are stored as a list. + + """ + + # Metadata 1.0 - PEP 241 + metadata_version: str + name: str + version: str + platforms: list[str] + summary: str + description: str + keywords: list[str] + home_page: str + author: str + author_email: str + license: str + + # Metadata 1.1 - PEP 314 + supported_platforms: list[str] + download_url: str + classifiers: list[str] + requires: list[str] + provides: list[str] + obsoletes: list[str] + + # Metadata 1.2 - PEP 345 + maintainer: str + maintainer_email: str + requires_dist: list[str] + provides_dist: list[str] + obsoletes_dist: list[str] + requires_python: str + requires_external: list[str] + project_urls: dict[str, str] + + # Metadata 2.0 + # PEP 426 attempted to completely revamp the metadata format + # but got stuck without ever being able to build consensus on + # it and ultimately ended up withdrawn. + # + # However, a number of tools had started emitting METADATA with + # `2.0` Metadata-Version, so for historical reasons, this version + # was skipped. + + # Metadata 2.1 - PEP 566 + description_content_type: str + provides_extra: list[str] + + # Metadata 2.2 - PEP 643 + dynamic: list[str] + + # Metadata 2.3 - PEP 685 + # No new fields were added in PEP 685, just some edge case were + # tightened up to provide better interoptability. + + # Metadata 2.4 - PEP 639 + license_expression: str + license_files: list[str] + + +_STRING_FIELDS = { + "author", + "author_email", + "description", + "description_content_type", + "download_url", + "home_page", + "license", + "license_expression", + "maintainer", + "maintainer_email", + "metadata_version", + "name", + "requires_python", + "summary", + "version", +} + +_LIST_FIELDS = { + "classifiers", + "dynamic", + "license_files", + "obsoletes", + "obsoletes_dist", + "platforms", + "provides", + "provides_dist", + "provides_extra", + "requires", + "requires_dist", + "requires_external", + "supported_platforms", +} + +_DICT_FIELDS = { + "project_urls", +} + + +def _parse_keywords(data: str) -> list[str]: + """Split a string of comma-separated keywords into a list of keywords.""" + return [k.strip() for k in data.split(",")] + + +def _parse_project_urls(data: list[str]) -> dict[str, str]: + """Parse a list of label/URL string pairings separated by a comma.""" + urls = {} + for pair in data: + # Our logic is slightly tricky here as we want to try and do + # *something* reasonable with malformed data. + # + # The main thing that we have to worry about, is data that does + # not have a ',' at all to split the label from the Value. There + # isn't a singular right answer here, and we will fail validation + # later on (if the caller is validating) so it doesn't *really* + # matter, but since the missing value has to be an empty str + # and our return value is dict[str, str], if we let the key + # be the missing value, then they'd have multiple '' values that + # overwrite each other in a accumulating dict. + # + # The other potentional issue is that it's possible to have the + # same label multiple times in the metadata, with no solid "right" + # answer with what to do in that case. As such, we'll do the only + # thing we can, which is treat the field as unparseable and add it + # to our list of unparsed fields. + parts = [p.strip() for p in pair.split(",", 1)] + parts.extend([""] * (max(0, 2 - len(parts)))) # Ensure 2 items + + # TODO: The spec doesn't say anything about if the keys should be + # considered case sensitive or not... logically they should + # be case-preserving and case-insensitive, but doing that + # would open up more cases where we might have duplicate + # entries. + label, url = parts + if label in urls: + # The label already exists in our set of urls, so this field + # is unparseable, and we can just add the whole thing to our + # unparseable data and stop processing it. + raise KeyError("duplicate labels in project urls") + urls[label] = url + + return urls + + +def _get_payload(msg: email.message.Message, source: bytes | str) -> str: + """Get the body of the message.""" + # If our source is a str, then our caller has managed encodings for us, + # and we don't need to deal with it. + if isinstance(source, str): + payload = msg.get_payload() + assert isinstance(payload, str) + return payload + # If our source is a bytes, then we're managing the encoding and we need + # to deal with it. + else: + bpayload = msg.get_payload(decode=True) + assert isinstance(bpayload, bytes) + try: + return bpayload.decode("utf8", "strict") + except UnicodeDecodeError as exc: + raise ValueError("payload in an invalid encoding") from exc + + +# The various parse_FORMAT functions here are intended to be as lenient as +# possible in their parsing, while still returning a correctly typed +# RawMetadata. +# +# To aid in this, we also generally want to do as little touching of the +# data as possible, except where there are possibly some historic holdovers +# that make valid data awkward to work with. +# +# While this is a lower level, intermediate format than our ``Metadata`` +# class, some light touch ups can make a massive difference in usability. + +# Map METADATA fields to RawMetadata. +_EMAIL_TO_RAW_MAPPING = { + "author": "author", + "author-email": "author_email", + "classifier": "classifiers", + "description": "description", + "description-content-type": "description_content_type", + "download-url": "download_url", + "dynamic": "dynamic", + "home-page": "home_page", + "keywords": "keywords", + "license": "license", + "license-expression": "license_expression", + "license-file": "license_files", + "maintainer": "maintainer", + "maintainer-email": "maintainer_email", + "metadata-version": "metadata_version", + "name": "name", + "obsoletes": "obsoletes", + "obsoletes-dist": "obsoletes_dist", + "platform": "platforms", + "project-url": "project_urls", + "provides": "provides", + "provides-dist": "provides_dist", + "provides-extra": "provides_extra", + "requires": "requires", + "requires-dist": "requires_dist", + "requires-external": "requires_external", + "requires-python": "requires_python", + "summary": "summary", + "supported-platform": "supported_platforms", + "version": "version", +} +_RAW_TO_EMAIL_MAPPING = {raw: email for email, raw in _EMAIL_TO_RAW_MAPPING.items()} + + +def parse_email(data: bytes | str) -> tuple[RawMetadata, dict[str, list[str]]]: + """Parse a distribution's metadata stored as email headers (e.g. from ``METADATA``). + + This function returns a two-item tuple of dicts. The first dict is of + recognized fields from the core metadata specification. Fields that can be + parsed and translated into Python's built-in types are converted + appropriately. All other fields are left as-is. Fields that are allowed to + appear multiple times are stored as lists. + + The second dict contains all other fields from the metadata. This includes + any unrecognized fields. It also includes any fields which are expected to + be parsed into a built-in type but were not formatted appropriately. Finally, + any fields that are expected to appear only once but are repeated are + included in this dict. + + """ + raw: dict[str, str | list[str] | dict[str, str]] = {} + unparsed: dict[str, list[str]] = {} + + if isinstance(data, str): + parsed = email.parser.Parser(policy=email.policy.compat32).parsestr(data) + else: + parsed = email.parser.BytesParser(policy=email.policy.compat32).parsebytes(data) + + # We have to wrap parsed.keys() in a set, because in the case of multiple + # values for a key (a list), the key will appear multiple times in the + # list of keys, but we're avoiding that by using get_all(). + for name in frozenset(parsed.keys()): + # Header names in RFC are case insensitive, so we'll normalize to all + # lower case to make comparisons easier. + name = name.lower() + + # We use get_all() here, even for fields that aren't multiple use, + # because otherwise someone could have e.g. two Name fields, and we + # would just silently ignore it rather than doing something about it. + headers = parsed.get_all(name) or [] + + # The way the email module works when parsing bytes is that it + # unconditionally decodes the bytes as ascii using the surrogateescape + # handler. When you pull that data back out (such as with get_all() ), + # it looks to see if the str has any surrogate escapes, and if it does + # it wraps it in a Header object instead of returning the string. + # + # As such, we'll look for those Header objects, and fix up the encoding. + value = [] + # Flag if we have run into any issues processing the headers, thus + # signalling that the data belongs in 'unparsed'. + valid_encoding = True + for h in headers: + # It's unclear if this can return more types than just a Header or + # a str, so we'll just assert here to make sure. + assert isinstance(h, (email.header.Header, str)) + + # If it's a header object, we need to do our little dance to get + # the real data out of it. In cases where there is invalid data + # we're going to end up with mojibake, but there's no obvious, good + # way around that without reimplementing parts of the Header object + # ourselves. + # + # That should be fine since, if mojibacked happens, this key is + # going into the unparsed dict anyways. + if isinstance(h, email.header.Header): + # The Header object stores it's data as chunks, and each chunk + # can be independently encoded, so we'll need to check each + # of them. + chunks: list[tuple[bytes, str | None]] = [] + for bin, encoding in email.header.decode_header(h): + try: + bin.decode("utf8", "strict") + except UnicodeDecodeError: + # Enable mojibake. + encoding = "latin1" + valid_encoding = False + else: + encoding = "utf8" + chunks.append((bin, encoding)) + + # Turn our chunks back into a Header object, then let that + # Header object do the right thing to turn them into a + # string for us. + value.append(str(email.header.make_header(chunks))) + # This is already a string, so just add it. + else: + value.append(h) + + # We've processed all of our values to get them into a list of str, + # but we may have mojibake data, in which case this is an unparsed + # field. + if not valid_encoding: + unparsed[name] = value + continue + + raw_name = _EMAIL_TO_RAW_MAPPING.get(name) + if raw_name is None: + # This is a bit of a weird situation, we've encountered a key that + # we don't know what it means, so we don't know whether it's meant + # to be a list or not. + # + # Since we can't really tell one way or another, we'll just leave it + # as a list, even though it may be a single item list, because that's + # what makes the most sense for email headers. + unparsed[name] = value + continue + + # If this is one of our string fields, then we'll check to see if our + # value is a list of a single item. If it is then we'll assume that + # it was emitted as a single string, and unwrap the str from inside + # the list. + # + # If it's any other kind of data, then we haven't the faintest clue + # what we should parse it as, and we have to just add it to our list + # of unparsed stuff. + if raw_name in _STRING_FIELDS and len(value) == 1: + raw[raw_name] = value[0] + # If this is one of our list of string fields, then we can just assign + # the value, since email *only* has strings, and our get_all() call + # above ensures that this is a list. + elif raw_name in _LIST_FIELDS: + raw[raw_name] = value + # Special Case: Keywords + # The keywords field is implemented in the metadata spec as a str, + # but it conceptually is a list of strings, and is serialized using + # ", ".join(keywords), so we'll do some light data massaging to turn + # this into what it logically is. + elif raw_name == "keywords" and len(value) == 1: + raw[raw_name] = _parse_keywords(value[0]) + # Special Case: Project-URL + # The project urls is implemented in the metadata spec as a list of + # specially-formatted strings that represent a key and a value, which + # is fundamentally a mapping, however the email format doesn't support + # mappings in a sane way, so it was crammed into a list of strings + # instead. + # + # We will do a little light data massaging to turn this into a map as + # it logically should be. + elif raw_name == "project_urls": + try: + raw[raw_name] = _parse_project_urls(value) + except KeyError: + unparsed[name] = value + # Nothing that we've done has managed to parse this, so it'll just + # throw it in our unparseable data and move on. + else: + unparsed[name] = value + + # We need to support getting the Description from the message payload in + # addition to getting it from the the headers. This does mean, though, there + # is the possibility of it being set both ways, in which case we put both + # in 'unparsed' since we don't know which is right. + try: + payload = _get_payload(parsed, data) + except ValueError: + unparsed.setdefault("description", []).append( + parsed.get_payload(decode=isinstance(data, bytes)) # type: ignore[call-overload] + ) + else: + if payload: + # Check to see if we've already got a description, if so then both + # it, and this body move to unparseable. + if "description" in raw: + description_header = cast(str, raw.pop("description")) + unparsed.setdefault("description", []).extend( + [description_header, payload] + ) + elif "description" in unparsed: + unparsed["description"].append(payload) + else: + raw["description"] = payload + + # We need to cast our `raw` to a metadata, because a TypedDict only support + # literal key names, but we're computing our key names on purpose, but the + # way this function is implemented, our `TypedDict` can only have valid key + # names. + return cast(RawMetadata, raw), unparsed + + +_NOT_FOUND = object() + + +# Keep the two values in sync. +_VALID_METADATA_VERSIONS = ["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4"] +_MetadataVersion = Literal["1.0", "1.1", "1.2", "2.1", "2.2", "2.3", "2.4"] + +_REQUIRED_ATTRS = frozenset(["metadata_version", "name", "version"]) + + +class _Validator(Generic[T]): + """Validate a metadata field. + + All _process_*() methods correspond to a core metadata field. The method is + called with the field's raw value. If the raw value is valid it is returned + in its "enriched" form (e.g. ``version.Version`` for the ``Version`` field). + If the raw value is invalid, :exc:`InvalidMetadata` is raised (with a cause + as appropriate). + """ + + name: str + raw_name: str + added: _MetadataVersion + + def __init__( + self, + *, + added: _MetadataVersion = "1.0", + ) -> None: + self.added = added + + def __set_name__(self, _owner: Metadata, name: str) -> None: + self.name = name + self.raw_name = _RAW_TO_EMAIL_MAPPING[name] + + def __get__(self, instance: Metadata, _owner: type[Metadata]) -> T: + # With Python 3.8, the caching can be replaced with functools.cached_property(). + # No need to check the cache as attribute lookup will resolve into the + # instance's __dict__ before __get__ is called. + cache = instance.__dict__ + value = instance._raw.get(self.name) + + # To make the _process_* methods easier, we'll check if the value is None + # and if this field is NOT a required attribute, and if both of those + # things are true, we'll skip the the converter. This will mean that the + # converters never have to deal with the None union. + if self.name in _REQUIRED_ATTRS or value is not None: + try: + converter: Callable[[Any], T] = getattr(self, f"_process_{self.name}") + except AttributeError: + pass + else: + value = converter(value) + + cache[self.name] = value + try: + del instance._raw[self.name] # type: ignore[misc] + except KeyError: + pass + + return cast(T, value) + + def _invalid_metadata( + self, msg: str, cause: Exception | None = None + ) -> InvalidMetadata: + exc = InvalidMetadata( + self.raw_name, msg.format_map({"field": repr(self.raw_name)}) + ) + exc.__cause__ = cause + return exc + + def _process_metadata_version(self, value: str) -> _MetadataVersion: + # Implicitly makes Metadata-Version required. + if value not in _VALID_METADATA_VERSIONS: + raise self._invalid_metadata(f"{value!r} is not a valid metadata version") + return cast(_MetadataVersion, value) + + def _process_name(self, value: str) -> str: + if not value: + raise self._invalid_metadata("{field} is a required field") + # Validate the name as a side-effect. + try: + utils.canonicalize_name(value, validate=True) + except utils.InvalidName as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) from exc + else: + return value + + def _process_version(self, value: str) -> version_module.Version: + if not value: + raise self._invalid_metadata("{field} is a required field") + try: + return version_module.parse(value) + except version_module.InvalidVersion as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) from exc + + def _process_summary(self, value: str) -> str: + """Check the field contains no newlines.""" + if "\n" in value: + raise self._invalid_metadata("{field} must be a single line") + return value + + def _process_description_content_type(self, value: str) -> str: + content_types = {"text/plain", "text/x-rst", "text/markdown"} + message = email.message.EmailMessage() + message["content-type"] = value + + content_type, parameters = ( + # Defaults to `text/plain` if parsing failed. + message.get_content_type().lower(), + message["content-type"].params, + ) + # Check if content-type is valid or defaulted to `text/plain` and thus was + # not parseable. + if content_type not in content_types or content_type not in value.lower(): + raise self._invalid_metadata( + f"{{field}} must be one of {list(content_types)}, not {value!r}" + ) + + charset = parameters.get("charset", "UTF-8") + if charset != "UTF-8": + raise self._invalid_metadata( + f"{{field}} can only specify the UTF-8 charset, not {list(charset)}" + ) + + markdown_variants = {"GFM", "CommonMark"} + variant = parameters.get("variant", "GFM") # Use an acceptable default. + if content_type == "text/markdown" and variant not in markdown_variants: + raise self._invalid_metadata( + f"valid Markdown variants for {{field}} are {list(markdown_variants)}, " + f"not {variant!r}", + ) + return value + + def _process_dynamic(self, value: list[str]) -> list[str]: + for dynamic_field in map(str.lower, value): + if dynamic_field in {"name", "version", "metadata-version"}: + raise self._invalid_metadata( + f"{dynamic_field!r} is not allowed as a dynamic field" + ) + elif dynamic_field not in _EMAIL_TO_RAW_MAPPING: + raise self._invalid_metadata( + f"{dynamic_field!r} is not a valid dynamic field" + ) + return list(map(str.lower, value)) + + def _process_provides_extra( + self, + value: list[str], + ) -> list[utils.NormalizedName]: + normalized_names = [] + try: + for name in value: + normalized_names.append(utils.canonicalize_name(name, validate=True)) + except utils.InvalidName as exc: + raise self._invalid_metadata( + f"{name!r} is invalid for {{field}}", cause=exc + ) from exc + else: + return normalized_names + + def _process_requires_python(self, value: str) -> specifiers.SpecifierSet: + try: + return specifiers.SpecifierSet(value) + except specifiers.InvalidSpecifier as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) from exc + + def _process_requires_dist( + self, + value: list[str], + ) -> list[requirements.Requirement]: + reqs = [] + try: + for req in value: + reqs.append(requirements.Requirement(req)) + except requirements.InvalidRequirement as exc: + raise self._invalid_metadata( + f"{req!r} is invalid for {{field}}", cause=exc + ) from exc + else: + return reqs + + def _process_license_expression( + self, value: str + ) -> NormalizedLicenseExpression | None: + try: + return licenses.canonicalize_license_expression(value) + except ValueError as exc: + raise self._invalid_metadata( + f"{value!r} is invalid for {{field}}", cause=exc + ) from exc + + def _process_license_files(self, value: list[str]) -> list[str]: + paths = [] + for path in value: + if ".." in path: + raise self._invalid_metadata( + f"{path!r} is invalid for {{field}}, " + "parent directory indicators are not allowed" + ) + if "*" in path: + raise self._invalid_metadata( + f"{path!r} is invalid for {{field}}, paths must be resolved" + ) + if ( + pathlib.PurePosixPath(path).is_absolute() + or pathlib.PureWindowsPath(path).is_absolute() + ): + raise self._invalid_metadata( + f"{path!r} is invalid for {{field}}, paths must be relative" + ) + if pathlib.PureWindowsPath(path).as_posix() != path: + raise self._invalid_metadata( + f"{path!r} is invalid for {{field}}, paths must use '/' delimiter" + ) + paths.append(path) + return paths + + +class Metadata: + """Representation of distribution metadata. + + Compared to :class:`RawMetadata`, this class provides objects representing + metadata fields instead of only using built-in types. Any invalid metadata + will cause :exc:`InvalidMetadata` to be raised (with a + :py:attr:`~BaseException.__cause__` attribute as appropriate). + """ + + _raw: RawMetadata + + @classmethod + def from_raw(cls, data: RawMetadata, *, validate: bool = True) -> Metadata: + """Create an instance from :class:`RawMetadata`. + + If *validate* is true, all metadata will be validated. All exceptions + related to validation will be gathered and raised as an :class:`ExceptionGroup`. + """ + ins = cls() + ins._raw = data.copy() # Mutations occur due to caching enriched values. + + if validate: + exceptions: list[Exception] = [] + try: + metadata_version = ins.metadata_version + metadata_age = _VALID_METADATA_VERSIONS.index(metadata_version) + except InvalidMetadata as metadata_version_exc: + exceptions.append(metadata_version_exc) + metadata_version = None + + # Make sure to check for the fields that are present, the required + # fields (so their absence can be reported). + fields_to_check = frozenset(ins._raw) | _REQUIRED_ATTRS + # Remove fields that have already been checked. + fields_to_check -= {"metadata_version"} + + for key in fields_to_check: + try: + if metadata_version: + # Can't use getattr() as that triggers descriptor protocol which + # will fail due to no value for the instance argument. + try: + field_metadata_version = cls.__dict__[key].added + except KeyError: + exc = InvalidMetadata(key, f"unrecognized field: {key!r}") + exceptions.append(exc) + continue + field_age = _VALID_METADATA_VERSIONS.index( + field_metadata_version + ) + if field_age > metadata_age: + field = _RAW_TO_EMAIL_MAPPING[key] + exc = InvalidMetadata( + field, + f"{field} introduced in metadata version " + f"{field_metadata_version}, not {metadata_version}", + ) + exceptions.append(exc) + continue + getattr(ins, key) + except InvalidMetadata as exc: + exceptions.append(exc) + + if exceptions: + raise ExceptionGroup("invalid metadata", exceptions) + + return ins + + @classmethod + def from_email(cls, data: bytes | str, *, validate: bool = True) -> Metadata: + """Parse metadata from email headers. + + If *validate* is true, the metadata will be validated. All exceptions + related to validation will be gathered and raised as an :class:`ExceptionGroup`. + """ + raw, unparsed = parse_email(data) + + if validate: + exceptions: list[Exception] = [] + for unparsed_key in unparsed: + if unparsed_key in _EMAIL_TO_RAW_MAPPING: + message = f"{unparsed_key!r} has invalid data" + else: + message = f"unrecognized field: {unparsed_key!r}" + exceptions.append(InvalidMetadata(unparsed_key, message)) + + if exceptions: + raise ExceptionGroup("unparsed", exceptions) + + try: + return cls.from_raw(raw, validate=validate) + except ExceptionGroup as exc_group: + raise ExceptionGroup( + "invalid or unparsed metadata", exc_group.exceptions + ) from None + + metadata_version: _Validator[_MetadataVersion] = _Validator() + """:external:ref:`core-metadata-metadata-version` + (required; validated to be a valid metadata version)""" + # `name` is not normalized/typed to NormalizedName so as to provide access to + # the original/raw name. + name: _Validator[str] = _Validator() + """:external:ref:`core-metadata-name` + (required; validated using :func:`~packaging.utils.canonicalize_name` and its + *validate* parameter)""" + version: _Validator[version_module.Version] = _Validator() + """:external:ref:`core-metadata-version` (required)""" + dynamic: _Validator[list[str] | None] = _Validator( + added="2.2", + ) + """:external:ref:`core-metadata-dynamic` + (validated against core metadata field names and lowercased)""" + platforms: _Validator[list[str] | None] = _Validator() + """:external:ref:`core-metadata-platform`""" + supported_platforms: _Validator[list[str] | None] = _Validator(added="1.1") + """:external:ref:`core-metadata-supported-platform`""" + summary: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-summary` (validated to contain no newlines)""" + description: _Validator[str | None] = _Validator() # TODO 2.1: can be in body + """:external:ref:`core-metadata-description`""" + description_content_type: _Validator[str | None] = _Validator(added="2.1") + """:external:ref:`core-metadata-description-content-type` (validated)""" + keywords: _Validator[list[str] | None] = _Validator() + """:external:ref:`core-metadata-keywords`""" + home_page: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-home-page`""" + download_url: _Validator[str | None] = _Validator(added="1.1") + """:external:ref:`core-metadata-download-url`""" + author: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-author`""" + author_email: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-author-email`""" + maintainer: _Validator[str | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-maintainer`""" + maintainer_email: _Validator[str | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-maintainer-email`""" + license: _Validator[str | None] = _Validator() + """:external:ref:`core-metadata-license`""" + license_expression: _Validator[NormalizedLicenseExpression | None] = _Validator( + added="2.4" + ) + """:external:ref:`core-metadata-license-expression`""" + license_files: _Validator[list[str] | None] = _Validator(added="2.4") + """:external:ref:`core-metadata-license-file`""" + classifiers: _Validator[list[str] | None] = _Validator(added="1.1") + """:external:ref:`core-metadata-classifier`""" + requires_dist: _Validator[list[requirements.Requirement] | None] = _Validator( + added="1.2" + ) + """:external:ref:`core-metadata-requires-dist`""" + requires_python: _Validator[specifiers.SpecifierSet | None] = _Validator( + added="1.2" + ) + """:external:ref:`core-metadata-requires-python`""" + # Because `Requires-External` allows for non-PEP 440 version specifiers, we + # don't do any processing on the values. + requires_external: _Validator[list[str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-requires-external`""" + project_urls: _Validator[dict[str, str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-project-url`""" + # PEP 685 lets us raise an error if an extra doesn't pass `Name` validation + # regardless of metadata version. + provides_extra: _Validator[list[utils.NormalizedName] | None] = _Validator( + added="2.1", + ) + """:external:ref:`core-metadata-provides-extra`""" + provides_dist: _Validator[list[str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-provides-dist`""" + obsoletes_dist: _Validator[list[str] | None] = _Validator(added="1.2") + """:external:ref:`core-metadata-obsoletes-dist`""" + requires: _Validator[list[str] | None] = _Validator(added="1.1") + """``Requires`` (deprecated)""" + provides: _Validator[list[str] | None] = _Validator(added="1.1") + """``Provides`` (deprecated)""" + obsoletes: _Validator[list[str] | None] = _Validator(added="1.1") + """``Obsoletes`` (deprecated)""" diff --git a/lib/python3.12/site-packages/packaging/py.typed b/lib/python3.12/site-packages/packaging/py.typed new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lib/python3.12/site-packages/packaging/requirements.py b/lib/python3.12/site-packages/packaging/requirements.py new file mode 100644 index 0000000000000000000000000000000000000000..4e068c9567def3564f238a76fe7ab46b569f33e5 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/requirements.py @@ -0,0 +1,91 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +from __future__ import annotations + +from typing import Any, Iterator + +from ._parser import parse_requirement as _parse_requirement +from ._tokenizer import ParserSyntaxError +from .markers import Marker, _normalize_extra_values +from .specifiers import SpecifierSet +from .utils import canonicalize_name + + +class InvalidRequirement(ValueError): + """ + An invalid requirement was found, users should refer to PEP 508. + """ + + +class Requirement: + """Parse a requirement. + + Parse a given requirement string into its parts, such as name, specifier, + URL, and extras. Raises InvalidRequirement on a badly-formed requirement + string. + """ + + # TODO: Can we test whether something is contained within a requirement? + # If so how do we do that? Do we need to test against the _name_ of + # the thing as well as the version? What about the markers? + # TODO: Can we normalize the name and extra name? + + def __init__(self, requirement_string: str) -> None: + try: + parsed = _parse_requirement(requirement_string) + except ParserSyntaxError as e: + raise InvalidRequirement(str(e)) from e + + self.name: str = parsed.name + self.url: str | None = parsed.url or None + self.extras: set[str] = set(parsed.extras or []) + self.specifier: SpecifierSet = SpecifierSet(parsed.specifier) + self.marker: Marker | None = None + if parsed.marker is not None: + self.marker = Marker.__new__(Marker) + self.marker._markers = _normalize_extra_values(parsed.marker) + + def _iter_parts(self, name: str) -> Iterator[str]: + yield name + + if self.extras: + formatted_extras = ",".join(sorted(self.extras)) + yield f"[{formatted_extras}]" + + if self.specifier: + yield str(self.specifier) + + if self.url: + yield f"@ {self.url}" + if self.marker: + yield " " + + if self.marker: + yield f"; {self.marker}" + + def __str__(self) -> str: + return "".join(self._iter_parts(self.name)) + + def __repr__(self) -> str: + return f"" + + def __hash__(self) -> int: + return hash( + ( + self.__class__.__name__, + *self._iter_parts(canonicalize_name(self.name)), + ) + ) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Requirement): + return NotImplemented + + return ( + canonicalize_name(self.name) == canonicalize_name(other.name) + and self.extras == other.extras + and self.specifier == other.specifier + and self.url == other.url + and self.marker == other.marker + ) diff --git a/lib/python3.12/site-packages/packaging/specifiers.py b/lib/python3.12/site-packages/packaging/specifiers.py new file mode 100644 index 0000000000000000000000000000000000000000..c8448043006f1c60ee92df69da47986d10229b1d --- /dev/null +++ b/lib/python3.12/site-packages/packaging/specifiers.py @@ -0,0 +1,1019 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +""" +.. testsetup:: + + from packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier + from packaging.version import Version +""" + +from __future__ import annotations + +import abc +import itertools +import re +from typing import Callable, Iterable, Iterator, TypeVar, Union + +from .utils import canonicalize_version +from .version import Version + +UnparsedVersion = Union[Version, str] +UnparsedVersionVar = TypeVar("UnparsedVersionVar", bound=UnparsedVersion) +CallableOperator = Callable[[Version, str], bool] + + +def _coerce_version(version: UnparsedVersion) -> Version: + if not isinstance(version, Version): + version = Version(version) + return version + + +class InvalidSpecifier(ValueError): + """ + Raised when attempting to create a :class:`Specifier` with a specifier + string that is invalid. + + >>> Specifier("lolwat") + Traceback (most recent call last): + ... + packaging.specifiers.InvalidSpecifier: Invalid specifier: 'lolwat' + """ + + +class BaseSpecifier(metaclass=abc.ABCMeta): + @abc.abstractmethod + def __str__(self) -> str: + """ + Returns the str representation of this Specifier-like object. This + should be representative of the Specifier itself. + """ + + @abc.abstractmethod + def __hash__(self) -> int: + """ + Returns a hash value for this Specifier-like object. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Returns a boolean representing whether or not the two Specifier-like + objects are equal. + + :param other: The other object to check against. + """ + + @property + @abc.abstractmethod + def prereleases(self) -> bool | None: + """Whether or not pre-releases as a whole are allowed. + + This can be set to either ``True`` or ``False`` to explicitly enable or disable + prereleases or it can be set to ``None`` (the default) to use default semantics. + """ + + @prereleases.setter + def prereleases(self, value: bool) -> None: + """Setter for :attr:`prereleases`. + + :param value: The value to set. + """ + + @abc.abstractmethod + def contains(self, item: str, prereleases: bool | None = None) -> bool: + """ + Determines if the given item is contained within this specifier. + """ + + @abc.abstractmethod + def filter( + self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None + ) -> Iterator[UnparsedVersionVar]: + """ + Takes an iterable of items and filters them so that only items which + are contained within this specifier are allowed in it. + """ + + +class Specifier(BaseSpecifier): + """This class abstracts handling of version specifiers. + + .. tip:: + + It is generally not required to instantiate this manually. You should instead + prefer to work with :class:`SpecifierSet` instead, which can parse + comma-separated version specifiers (which is what package metadata contains). + """ + + _operator_regex_str = r""" + (?P(~=|==|!=|<=|>=|<|>|===)) + """ + _version_regex_str = r""" + (?P + (?: + # The identity operators allow for an escape hatch that will + # do an exact string match of the version you wish to install. + # This will not be parsed by PEP 440 and we cannot determine + # any semantic meaning from it. This operator is discouraged + # but included entirely as an escape hatch. + (?<====) # Only match for the identity operator + \s* + [^\s;)]* # The arbitrary version can be just about anything, + # we match everything except for whitespace, a + # semi-colon for marker support, and a closing paren + # since versions can be enclosed in them. + ) + | + (?: + # The (non)equality operators allow for wild card and local + # versions to be specified so we have to define these two + # operators separately to enable that. + (?<===|!=) # Only match for equals and not equals + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + + # You cannot use a wild card and a pre-release, post-release, a dev or + # local version together so group them with a | and make them optional. + (?: + \.\* # Wild card syntax of .* + | + (?: # pre release + [-_\.]? + (alpha|beta|preview|pre|a|b|c|rc) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local + )? + ) + | + (?: + # The compatible operator requires at least two digits in the + # release segment. + (?<=~=) # Only match for the compatible operator + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) + (?: # pre release + [-_\.]? + (alpha|beta|preview|pre|a|b|c|rc) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + | + (?: + # All other operators only allow a sub set of what the + # (non)equality operators do. Specifically they do not allow + # local versions to be specified nor do they allow the prefix + # matching wild cards. + (?=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + "===": "arbitrary", + } + + def __init__(self, spec: str = "", prereleases: bool | None = None) -> None: + """Initialize a Specifier instance. + + :param spec: + The string representation of a specifier which will be parsed and + normalized before use. + :param prereleases: + This tells the specifier if it should accept prerelease versions if + applicable or not. The default of ``None`` will autodetect it from the + given specifiers. + :raises InvalidSpecifier: + If the given specifier is invalid (i.e. bad syntax). + """ + match = self._regex.search(spec) + if not match: + raise InvalidSpecifier(f"Invalid specifier: {spec!r}") + + self._spec: tuple[str, str] = ( + match.group("operator").strip(), + match.group("version").strip(), + ) + + # Store whether or not this Specifier should accept prereleases + self._prereleases = prereleases + + # https://github.com/python/mypy/pull/13475#pullrequestreview-1079784515 + @property # type: ignore[override] + def prereleases(self) -> bool: + # If there is an explicit prereleases set for this, then we'll just + # blindly use that. + if self._prereleases is not None: + return self._prereleases + + # Look at all of our specifiers and determine if they are inclusive + # operators, and if they are if they are including an explicit + # prerelease. + operator, version = self._spec + if operator in ["==", ">=", "<=", "~=", "===", ">", "<"]: + # The == specifier can include a trailing .*, if it does we + # want to remove before parsing. + if operator == "==" and version.endswith(".*"): + version = version[:-2] + + # Parse the version, and if it is a pre-release than this + # specifier allows pre-releases. + if Version(version).is_prerelease: + return True + + return False + + @prereleases.setter + def prereleases(self, value: bool) -> None: + self._prereleases = value + + @property + def operator(self) -> str: + """The operator of this specifier. + + >>> Specifier("==1.2.3").operator + '==' + """ + return self._spec[0] + + @property + def version(self) -> str: + """The version of this specifier. + + >>> Specifier("==1.2.3").version + '1.2.3' + """ + return self._spec[1] + + def __repr__(self) -> str: + """A representation of the Specifier that shows all internal state. + + >>> Specifier('>=1.0.0') + =1.0.0')> + >>> Specifier('>=1.0.0', prereleases=False) + =1.0.0', prereleases=False)> + >>> Specifier('>=1.0.0', prereleases=True) + =1.0.0', prereleases=True)> + """ + pre = ( + f", prereleases={self.prereleases!r}" + if self._prereleases is not None + else "" + ) + + return f"<{self.__class__.__name__}({str(self)!r}{pre})>" + + def __str__(self) -> str: + """A string representation of the Specifier that can be round-tripped. + + >>> str(Specifier('>=1.0.0')) + '>=1.0.0' + >>> str(Specifier('>=1.0.0', prereleases=False)) + '>=1.0.0' + """ + return "{}{}".format(*self._spec) + + @property + def _canonical_spec(self) -> tuple[str, str]: + canonical_version = canonicalize_version( + self._spec[1], + strip_trailing_zero=(self._spec[0] != "~="), + ) + return self._spec[0], canonical_version + + def __hash__(self) -> int: + return hash(self._canonical_spec) + + def __eq__(self, other: object) -> bool: + """Whether or not the two Specifier-like objects are equal. + + :param other: The other object to check against. + + The value of :attr:`prereleases` is ignored. + + >>> Specifier("==1.2.3") == Specifier("== 1.2.3.0") + True + >>> (Specifier("==1.2.3", prereleases=False) == + ... Specifier("==1.2.3", prereleases=True)) + True + >>> Specifier("==1.2.3") == "==1.2.3" + True + >>> Specifier("==1.2.3") == Specifier("==1.2.4") + False + >>> Specifier("==1.2.3") == Specifier("~=1.2.3") + False + """ + if isinstance(other, str): + try: + other = self.__class__(str(other)) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._canonical_spec == other._canonical_spec + + def _get_operator(self, op: str) -> CallableOperator: + operator_callable: CallableOperator = getattr( + self, f"_compare_{self._operators[op]}" + ) + return operator_callable + + def _compare_compatible(self, prospective: Version, spec: str) -> bool: + # Compatible releases have an equivalent combination of >= and ==. That + # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to + # implement this in terms of the other specifiers instead of + # implementing it ourselves. The only thing we need to do is construct + # the other specifiers. + + # We want everything but the last item in the version, but we want to + # ignore suffix segments. + prefix = _version_join( + list(itertools.takewhile(_is_not_suffix, _version_split(spec)))[:-1] + ) + + # Add the prefix notation to the end of our string + prefix += ".*" + + return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( + prospective, prefix + ) + + def _compare_equal(self, prospective: Version, spec: str) -> bool: + # We need special logic to handle prefix matching + if spec.endswith(".*"): + # In the case of prefix matching we want to ignore local segment. + normalized_prospective = canonicalize_version( + prospective.public, strip_trailing_zero=False + ) + # Get the normalized version string ignoring the trailing .* + normalized_spec = canonicalize_version(spec[:-2], strip_trailing_zero=False) + # Split the spec out by bangs and dots, and pretend that there is + # an implicit dot in between a release segment and a pre-release segment. + split_spec = _version_split(normalized_spec) + + # Split the prospective version out by bangs and dots, and pretend + # that there is an implicit dot in between a release segment and + # a pre-release segment. + split_prospective = _version_split(normalized_prospective) + + # 0-pad the prospective version before shortening it to get the correct + # shortened version. + padded_prospective, _ = _pad_version(split_prospective, split_spec) + + # Shorten the prospective version to be the same length as the spec + # so that we can determine if the specifier is a prefix of the + # prospective version or not. + shortened_prospective = padded_prospective[: len(split_spec)] + + return shortened_prospective == split_spec + else: + # Convert our spec string into a Version + spec_version = Version(spec) + + # If the specifier does not have a local segment, then we want to + # act as if the prospective version also does not have a local + # segment. + if not spec_version.local: + prospective = Version(prospective.public) + + return prospective == spec_version + + def _compare_not_equal(self, prospective: Version, spec: str) -> bool: + return not self._compare_equal(prospective, spec) + + def _compare_less_than_equal(self, prospective: Version, spec: str) -> bool: + # NB: Local version identifiers are NOT permitted in the version + # specifier, so local version labels can be universally removed from + # the prospective version. + return Version(prospective.public) <= Version(spec) + + def _compare_greater_than_equal(self, prospective: Version, spec: str) -> bool: + # NB: Local version identifiers are NOT permitted in the version + # specifier, so local version labels can be universally removed from + # the prospective version. + return Version(prospective.public) >= Version(spec) + + def _compare_less_than(self, prospective: Version, spec_str: str) -> bool: + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec_str) + + # Check to see if the prospective version is less than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective < spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a pre-release version, that we do not accept pre-release + # versions for the version mentioned in the specifier (e.g. <3.1 should + # not match 3.1.dev0, but should match 3.0.dev0). + if not spec.is_prerelease and prospective.is_prerelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # less than the spec version *and* it's not a pre-release of the same + # version in the spec. + return True + + def _compare_greater_than(self, prospective: Version, spec_str: str) -> bool: + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec_str) + + # Check to see if the prospective version is greater than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective > spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a post-release version, that we do not accept + # post-release versions for the version mentioned in the specifier + # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). + if not spec.is_postrelease and prospective.is_postrelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # Ensure that we do not allow a local version of the version mentioned + # in the specifier, which is technically greater than, to match. + if prospective.local is not None: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # greater than the spec version *and* it's not a pre-release of the + # same version in the spec. + return True + + def _compare_arbitrary(self, prospective: Version, spec: str) -> bool: + return str(prospective).lower() == str(spec).lower() + + def __contains__(self, item: str | Version) -> bool: + """Return whether or not the item is contained in this specifier. + + :param item: The item to check for. + + This is used for the ``in`` operator and behaves the same as + :meth:`contains` with no ``prereleases`` argument passed. + + >>> "1.2.3" in Specifier(">=1.2.3") + True + >>> Version("1.2.3") in Specifier(">=1.2.3") + True + >>> "1.0.0" in Specifier(">=1.2.3") + False + >>> "1.3.0a1" in Specifier(">=1.2.3") + False + >>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True) + True + """ + return self.contains(item) + + def contains(self, item: UnparsedVersion, prereleases: bool | None = None) -> bool: + """Return whether or not the item is contained in this specifier. + + :param item: + The item to check for, which can be a version string or a + :class:`Version` instance. + :param prereleases: + Whether or not to match prereleases with this Specifier. If set to + ``None`` (the default), it uses :attr:`prereleases` to determine + whether or not prereleases are allowed. + + >>> Specifier(">=1.2.3").contains("1.2.3") + True + >>> Specifier(">=1.2.3").contains(Version("1.2.3")) + True + >>> Specifier(">=1.2.3").contains("1.0.0") + False + >>> Specifier(">=1.2.3").contains("1.3.0a1") + False + >>> Specifier(">=1.2.3", prereleases=True).contains("1.3.0a1") + True + >>> Specifier(">=1.2.3").contains("1.3.0a1", prereleases=True) + True + """ + + # Determine if prereleases are to be allowed or not. + if prereleases is None: + prereleases = self.prereleases + + # Normalize item to a Version, this allows us to have a shortcut for + # "2.0" in Specifier(">=2") + normalized_item = _coerce_version(item) + + # Determine if we should be supporting prereleases in this specifier + # or not, if we do not support prereleases than we can short circuit + # logic if this version is a prereleases. + if normalized_item.is_prerelease and not prereleases: + return False + + # Actually do the comparison to determine if this item is contained + # within this Specifier or not. + operator_callable: CallableOperator = self._get_operator(self.operator) + return operator_callable(normalized_item, self.version) + + def filter( + self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None + ) -> Iterator[UnparsedVersionVar]: + """Filter items in the given iterable, that match the specifier. + + :param iterable: + An iterable that can contain version strings and :class:`Version` instances. + The items in the iterable will be filtered according to the specifier. + :param prereleases: + Whether or not to allow prereleases in the returned iterator. If set to + ``None`` (the default), it will be intelligently decide whether to allow + prereleases or not (based on the :attr:`prereleases` attribute, and + whether the only versions matching are prereleases). + + This method is smarter than just ``filter(Specifier().contains, [...])`` + because it implements the rule from :pep:`440` that a prerelease item + SHOULD be accepted if no other versions match the given specifier. + + >>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) + ['1.3'] + >>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")])) + ['1.2.3', '1.3', ] + >>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"])) + ['1.5a1'] + >>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) + ['1.3', '1.5a1'] + >>> list(Specifier(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"])) + ['1.3', '1.5a1'] + """ + + yielded = False + found_prereleases = [] + + kw = {"prereleases": prereleases if prereleases is not None else True} + + # Attempt to iterate over all the values in the iterable and if any of + # them match, yield them. + for version in iterable: + parsed_version = _coerce_version(version) + + if self.contains(parsed_version, **kw): + # If our version is a prerelease, and we were not set to allow + # prereleases, then we'll store it for later in case nothing + # else matches this specifier. + if parsed_version.is_prerelease and not ( + prereleases or self.prereleases + ): + found_prereleases.append(version) + # Either this is not a prerelease, or we should have been + # accepting prereleases from the beginning. + else: + yielded = True + yield version + + # Now that we've iterated over everything, determine if we've yielded + # any values, and if we have not and we have any prereleases stored up + # then we will go ahead and yield the prereleases. + if not yielded and found_prereleases: + for version in found_prereleases: + yield version + + +_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") + + +def _version_split(version: str) -> list[str]: + """Split version into components. + + The split components are intended for version comparison. The logic does + not attempt to retain the original version string, so joining the + components back with :func:`_version_join` may not produce the original + version string. + """ + result: list[str] = [] + + epoch, _, rest = version.rpartition("!") + result.append(epoch or "0") + + for item in rest.split("."): + match = _prefix_regex.search(item) + if match: + result.extend(match.groups()) + else: + result.append(item) + return result + + +def _version_join(components: list[str]) -> str: + """Join split version components into a version string. + + This function assumes the input came from :func:`_version_split`, where the + first component must be the epoch (either empty or numeric), and all other + components numeric. + """ + epoch, *rest = components + return f"{epoch}!{'.'.join(rest)}" + + +def _is_not_suffix(segment: str) -> bool: + return not any( + segment.startswith(prefix) for prefix in ("dev", "a", "b", "rc", "post") + ) + + +def _pad_version(left: list[str], right: list[str]) -> tuple[list[str], list[str]]: + left_split, right_split = [], [] + + # Get the release segment of our versions + left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) + right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) + + # Get the rest of our versions + left_split.append(left[len(left_split[0]) :]) + right_split.append(right[len(right_split[0]) :]) + + # Insert our padding + left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) + right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) + + return ( + list(itertools.chain.from_iterable(left_split)), + list(itertools.chain.from_iterable(right_split)), + ) + + +class SpecifierSet(BaseSpecifier): + """This class abstracts handling of a set of version specifiers. + + It can be passed a single specifier (``>=3.0``), a comma-separated list of + specifiers (``>=3.0,!=3.1``), or no specifier at all. + """ + + def __init__( + self, + specifiers: str | Iterable[Specifier] = "", + prereleases: bool | None = None, + ) -> None: + """Initialize a SpecifierSet instance. + + :param specifiers: + The string representation of a specifier or a comma-separated list of + specifiers which will be parsed and normalized before use. + May also be an iterable of ``Specifier`` instances, which will be used + as is. + :param prereleases: + This tells the SpecifierSet if it should accept prerelease versions if + applicable or not. The default of ``None`` will autodetect it from the + given specifiers. + + :raises InvalidSpecifier: + If the given ``specifiers`` are not parseable than this exception will be + raised. + """ + + if isinstance(specifiers, str): + # Split on `,` to break each individual specifier into its own item, and + # strip each item to remove leading/trailing whitespace. + split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] + + # Make each individual specifier a Specifier and save in a frozen set + # for later. + self._specs = frozenset(map(Specifier, split_specifiers)) + else: + # Save the supplied specifiers in a frozen set. + self._specs = frozenset(specifiers) + + # Store our prereleases value so we can use it later to determine if + # we accept prereleases or not. + self._prereleases = prereleases + + @property + def prereleases(self) -> bool | None: + # If we have been given an explicit prerelease modifier, then we'll + # pass that through here. + if self._prereleases is not None: + return self._prereleases + + # If we don't have any specifiers, and we don't have a forced value, + # then we'll just return None since we don't know if this should have + # pre-releases or not. + if not self._specs: + return None + + # Otherwise we'll see if any of the given specifiers accept + # prereleases, if any of them do we'll return True, otherwise False. + return any(s.prereleases for s in self._specs) + + @prereleases.setter + def prereleases(self, value: bool) -> None: + self._prereleases = value + + def __repr__(self) -> str: + """A representation of the specifier set that shows all internal state. + + Note that the ordering of the individual specifiers within the set may not + match the input string. + + >>> SpecifierSet('>=1.0.0,!=2.0.0') + =1.0.0')> + >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False) + =1.0.0', prereleases=False)> + >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True) + =1.0.0', prereleases=True)> + """ + pre = ( + f", prereleases={self.prereleases!r}" + if self._prereleases is not None + else "" + ) + + return f"" + + def __str__(self) -> str: + """A string representation of the specifier set that can be round-tripped. + + Note that the ordering of the individual specifiers within the set may not + match the input string. + + >>> str(SpecifierSet(">=1.0.0,!=1.0.1")) + '!=1.0.1,>=1.0.0' + >>> str(SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False)) + '!=1.0.1,>=1.0.0' + """ + return ",".join(sorted(str(s) for s in self._specs)) + + def __hash__(self) -> int: + return hash(self._specs) + + def __and__(self, other: SpecifierSet | str) -> SpecifierSet: + """Return a SpecifierSet which is a combination of the two sets. + + :param other: The other object to combine with. + + >>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1' + =1.0.0')> + >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1') + =1.0.0')> + """ + if isinstance(other, str): + other = SpecifierSet(other) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + specifier = SpecifierSet() + specifier._specs = frozenset(self._specs | other._specs) + + if self._prereleases is None and other._prereleases is not None: + specifier._prereleases = other._prereleases + elif self._prereleases is not None and other._prereleases is None: + specifier._prereleases = self._prereleases + elif self._prereleases == other._prereleases: + specifier._prereleases = self._prereleases + else: + raise ValueError( + "Cannot combine SpecifierSets with True and False prerelease overrides." + ) + + return specifier + + def __eq__(self, other: object) -> bool: + """Whether or not the two SpecifierSet-like objects are equal. + + :param other: The other object to check against. + + The value of :attr:`prereleases` is ignored. + + >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1") + True + >>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) == + ... SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True)) + True + >>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1" + True + >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0") + False + >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.2") + False + """ + if isinstance(other, (str, Specifier)): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs == other._specs + + def __len__(self) -> int: + """Returns the number of specifiers in this specifier set.""" + return len(self._specs) + + def __iter__(self) -> Iterator[Specifier]: + """ + Returns an iterator over all the underlying :class:`Specifier` instances + in this specifier set. + + >>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str) + [, =1.0.0')>] + """ + return iter(self._specs) + + def __contains__(self, item: UnparsedVersion) -> bool: + """Return whether or not the item is contained in this specifier. + + :param item: The item to check for. + + This is used for the ``in`` operator and behaves the same as + :meth:`contains` with no ``prereleases`` argument passed. + + >>> "1.2.3" in SpecifierSet(">=1.0.0,!=1.0.1") + True + >>> Version("1.2.3") in SpecifierSet(">=1.0.0,!=1.0.1") + True + >>> "1.0.1" in SpecifierSet(">=1.0.0,!=1.0.1") + False + >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1") + False + >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True) + True + """ + return self.contains(item) + + def contains( + self, + item: UnparsedVersion, + prereleases: bool | None = None, + installed: bool | None = None, + ) -> bool: + """Return whether or not the item is contained in this SpecifierSet. + + :param item: + The item to check for, which can be a version string or a + :class:`Version` instance. + :param prereleases: + Whether or not to match prereleases with this SpecifierSet. If set to + ``None`` (the default), it uses :attr:`prereleases` to determine + whether or not prereleases are allowed. + + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.2.3") + True + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains(Version("1.2.3")) + True + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.0.1") + False + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1") + False + >>> SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True).contains("1.3.0a1") + True + >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1", prereleases=True) + True + """ + # Ensure that our item is a Version instance. + if not isinstance(item, Version): + item = Version(item) + + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # We can determine if we're going to allow pre-releases by looking to + # see if any of the underlying items supports them. If none of them do + # and this item is a pre-release then we do not allow it and we can + # short circuit that here. + # Note: This means that 1.0.dev1 would not be contained in something + # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 + if not prereleases and item.is_prerelease: + return False + + if installed and item.is_prerelease: + item = Version(item.base_version) + + # We simply dispatch to the underlying specs here to make sure that the + # given version is contained within all of them. + # Note: This use of all() here means that an empty set of specifiers + # will always return True, this is an explicit design decision. + return all(s.contains(item, prereleases=prereleases) for s in self._specs) + + def filter( + self, iterable: Iterable[UnparsedVersionVar], prereleases: bool | None = None + ) -> Iterator[UnparsedVersionVar]: + """Filter items in the given iterable, that match the specifiers in this set. + + :param iterable: + An iterable that can contain version strings and :class:`Version` instances. + The items in the iterable will be filtered according to the specifier. + :param prereleases: + Whether or not to allow prereleases in the returned iterator. If set to + ``None`` (the default), it will be intelligently decide whether to allow + prereleases or not (based on the :attr:`prereleases` attribute, and + whether the only versions matching are prereleases). + + This method is smarter than just ``filter(SpecifierSet(...).contains, [...])`` + because it implements the rule from :pep:`440` that a prerelease item + SHOULD be accepted if no other versions match the given specifier. + + >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) + ['1.3'] + >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")])) + ['1.3', ] + >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"])) + [] + >>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) + ['1.3', '1.5a1'] + >>> list(SpecifierSet(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"])) + ['1.3', '1.5a1'] + + An "empty" SpecifierSet will filter items based on the presence of prerelease + versions in the set. + + >>> list(SpecifierSet("").filter(["1.3", "1.5a1"])) + ['1.3'] + >>> list(SpecifierSet("").filter(["1.5a1"])) + ['1.5a1'] + >>> list(SpecifierSet("", prereleases=True).filter(["1.3", "1.5a1"])) + ['1.3', '1.5a1'] + >>> list(SpecifierSet("").filter(["1.3", "1.5a1"], prereleases=True)) + ['1.3', '1.5a1'] + """ + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # If we have any specifiers, then we want to wrap our iterable in the + # filter method for each one, this will act as a logical AND amongst + # each specifier. + if self._specs: + for spec in self._specs: + iterable = spec.filter(iterable, prereleases=bool(prereleases)) + return iter(iterable) + # If we do not have any specifiers, then we need to have a rough filter + # which will filter out any pre-releases, unless there are no final + # releases. + else: + filtered: list[UnparsedVersionVar] = [] + found_prereleases: list[UnparsedVersionVar] = [] + + for item in iterable: + parsed_version = _coerce_version(item) + + # Store any item which is a pre-release for later unless we've + # already found a final version or we are accepting prereleases + if parsed_version.is_prerelease and not prereleases: + if not filtered: + found_prereleases.append(item) + else: + filtered.append(item) + + # If we've found no items except for pre-releases, then we'll go + # ahead and use the pre-releases + if not filtered and found_prereleases and prereleases is None: + return iter(found_prereleases) + + return iter(filtered) diff --git a/lib/python3.12/site-packages/packaging/tags.py b/lib/python3.12/site-packages/packaging/tags.py new file mode 100644 index 0000000000000000000000000000000000000000..8522f59c4f2d0039c1a02ea9aef66fe017dbdb20 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/tags.py @@ -0,0 +1,656 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import logging +import platform +import re +import struct +import subprocess +import sys +import sysconfig +from importlib.machinery import EXTENSION_SUFFIXES +from typing import ( + Iterable, + Iterator, + Sequence, + Tuple, + cast, +) + +from . import _manylinux, _musllinux + +logger = logging.getLogger(__name__) + +PythonVersion = Sequence[int] +AppleVersion = Tuple[int, int] + +INTERPRETER_SHORT_NAMES: dict[str, str] = { + "python": "py", # Generic. + "cpython": "cp", + "pypy": "pp", + "ironpython": "ip", + "jython": "jy", +} + + +_32_BIT_INTERPRETER = struct.calcsize("P") == 4 + + +class Tag: + """ + A representation of the tag triple for a wheel. + + Instances are considered immutable and thus are hashable. Equality checking + is also supported. + """ + + __slots__ = ["_abi", "_hash", "_interpreter", "_platform"] + + def __init__(self, interpreter: str, abi: str, platform: str) -> None: + self._interpreter = interpreter.lower() + self._abi = abi.lower() + self._platform = platform.lower() + # The __hash__ of every single element in a Set[Tag] will be evaluated each time + # that a set calls its `.disjoint()` method, which may be called hundreds of + # times when scanning a page of links for packages with tags matching that + # Set[Tag]. Pre-computing the value here produces significant speedups for + # downstream consumers. + self._hash = hash((self._interpreter, self._abi, self._platform)) + + @property + def interpreter(self) -> str: + return self._interpreter + + @property + def abi(self) -> str: + return self._abi + + @property + def platform(self) -> str: + return self._platform + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Tag): + return NotImplemented + + return ( + (self._hash == other._hash) # Short-circuit ASAP for perf reasons. + and (self._platform == other._platform) + and (self._abi == other._abi) + and (self._interpreter == other._interpreter) + ) + + def __hash__(self) -> int: + return self._hash + + def __str__(self) -> str: + return f"{self._interpreter}-{self._abi}-{self._platform}" + + def __repr__(self) -> str: + return f"<{self} @ {id(self)}>" + + +def parse_tag(tag: str) -> frozenset[Tag]: + """ + Parses the provided tag (e.g. `py3-none-any`) into a frozenset of Tag instances. + + Returning a set is required due to the possibility that the tag is a + compressed tag set. + """ + tags = set() + interpreters, abis, platforms = tag.split("-") + for interpreter in interpreters.split("."): + for abi in abis.split("."): + for platform_ in platforms.split("."): + tags.add(Tag(interpreter, abi, platform_)) + return frozenset(tags) + + +def _get_config_var(name: str, warn: bool = False) -> int | str | None: + value: int | str | None = sysconfig.get_config_var(name) + if value is None and warn: + logger.debug( + "Config variable '%s' is unset, Python ABI tag may be incorrect", name + ) + return value + + +def _normalize_string(string: str) -> str: + return string.replace(".", "_").replace("-", "_").replace(" ", "_") + + +def _is_threaded_cpython(abis: list[str]) -> bool: + """ + Determine if the ABI corresponds to a threaded (`--disable-gil`) build. + + The threaded builds are indicated by a "t" in the abiflags. + """ + if len(abis) == 0: + return False + # expect e.g., cp313 + m = re.match(r"cp\d+(.*)", abis[0]) + if not m: + return False + abiflags = m.group(1) + return "t" in abiflags + + +def _abi3_applies(python_version: PythonVersion, threading: bool) -> bool: + """ + Determine if the Python version supports abi3. + + PEP 384 was first implemented in Python 3.2. The threaded (`--disable-gil`) + builds do not support abi3. + """ + return len(python_version) > 1 and tuple(python_version) >= (3, 2) and not threading + + +def _cpython_abis(py_version: PythonVersion, warn: bool = False) -> list[str]: + py_version = tuple(py_version) # To allow for version comparison. + abis = [] + version = _version_nodot(py_version[:2]) + threading = debug = pymalloc = ucs4 = "" + with_debug = _get_config_var("Py_DEBUG", warn) + has_refcount = hasattr(sys, "gettotalrefcount") + # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled + # extension modules is the best option. + # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 + has_ext = "_d.pyd" in EXTENSION_SUFFIXES + if with_debug or (with_debug is None and (has_refcount or has_ext)): + debug = "d" + if py_version >= (3, 13) and _get_config_var("Py_GIL_DISABLED", warn): + threading = "t" + if py_version < (3, 8): + with_pymalloc = _get_config_var("WITH_PYMALLOC", warn) + if with_pymalloc or with_pymalloc is None: + pymalloc = "m" + if py_version < (3, 3): + unicode_size = _get_config_var("Py_UNICODE_SIZE", warn) + if unicode_size == 4 or ( + unicode_size is None and sys.maxunicode == 0x10FFFF + ): + ucs4 = "u" + elif debug: + # Debug builds can also load "normal" extension modules. + # We can also assume no UCS-4 or pymalloc requirement. + abis.append(f"cp{version}{threading}") + abis.insert(0, f"cp{version}{threading}{debug}{pymalloc}{ucs4}") + return abis + + +def cpython_tags( + python_version: PythonVersion | None = None, + abis: Iterable[str] | None = None, + platforms: Iterable[str] | None = None, + *, + warn: bool = False, +) -> Iterator[Tag]: + """ + Yields the tags for a CPython interpreter. + + The tags consist of: + - cp-- + - cp-abi3- + - cp-none- + - cp-abi3- # Older Python versions down to 3.2. + + If python_version only specifies a major version then user-provided ABIs and + the 'none' ABItag will be used. + + If 'abi3' or 'none' are specified in 'abis' then they will be yielded at + their normal position and not at the beginning. + """ + if not python_version: + python_version = sys.version_info[:2] + + interpreter = f"cp{_version_nodot(python_version[:2])}" + + if abis is None: + if len(python_version) > 1: + abis = _cpython_abis(python_version, warn) + else: + abis = [] + abis = list(abis) + # 'abi3' and 'none' are explicitly handled later. + for explicit_abi in ("abi3", "none"): + try: + abis.remove(explicit_abi) + except ValueError: + pass + + platforms = list(platforms or platform_tags()) + for abi in abis: + for platform_ in platforms: + yield Tag(interpreter, abi, platform_) + + threading = _is_threaded_cpython(abis) + use_abi3 = _abi3_applies(python_version, threading) + if use_abi3: + yield from (Tag(interpreter, "abi3", platform_) for platform_ in platforms) + yield from (Tag(interpreter, "none", platform_) for platform_ in platforms) + + if use_abi3: + for minor_version in range(python_version[1] - 1, 1, -1): + for platform_ in platforms: + version = _version_nodot((python_version[0], minor_version)) + interpreter = f"cp{version}" + yield Tag(interpreter, "abi3", platform_) + + +def _generic_abi() -> list[str]: + """ + Return the ABI tag based on EXT_SUFFIX. + """ + # The following are examples of `EXT_SUFFIX`. + # We want to keep the parts which are related to the ABI and remove the + # parts which are related to the platform: + # - linux: '.cpython-310-x86_64-linux-gnu.so' => cp310 + # - mac: '.cpython-310-darwin.so' => cp310 + # - win: '.cp310-win_amd64.pyd' => cp310 + # - win: '.pyd' => cp37 (uses _cpython_abis()) + # - pypy: '.pypy38-pp73-x86_64-linux-gnu.so' => pypy38_pp73 + # - graalpy: '.graalpy-38-native-x86_64-darwin.dylib' + # => graalpy_38_native + + ext_suffix = _get_config_var("EXT_SUFFIX", warn=True) + if not isinstance(ext_suffix, str) or ext_suffix[0] != ".": + raise SystemError("invalid sysconfig.get_config_var('EXT_SUFFIX')") + parts = ext_suffix.split(".") + if len(parts) < 3: + # CPython3.7 and earlier uses ".pyd" on Windows. + return _cpython_abis(sys.version_info[:2]) + soabi = parts[1] + if soabi.startswith("cpython"): + # non-windows + abi = "cp" + soabi.split("-")[1] + elif soabi.startswith("cp"): + # windows + abi = soabi.split("-")[0] + elif soabi.startswith("pypy"): + abi = "-".join(soabi.split("-")[:2]) + elif soabi.startswith("graalpy"): + abi = "-".join(soabi.split("-")[:3]) + elif soabi: + # pyston, ironpython, others? + abi = soabi + else: + return [] + return [_normalize_string(abi)] + + +def generic_tags( + interpreter: str | None = None, + abis: Iterable[str] | None = None, + platforms: Iterable[str] | None = None, + *, + warn: bool = False, +) -> Iterator[Tag]: + """ + Yields the tags for a generic interpreter. + + The tags consist of: + - -- + + The "none" ABI will be added if it was not explicitly provided. + """ + if not interpreter: + interp_name = interpreter_name() + interp_version = interpreter_version(warn=warn) + interpreter = "".join([interp_name, interp_version]) + if abis is None: + abis = _generic_abi() + else: + abis = list(abis) + platforms = list(platforms or platform_tags()) + if "none" not in abis: + abis.append("none") + for abi in abis: + for platform_ in platforms: + yield Tag(interpreter, abi, platform_) + + +def _py_interpreter_range(py_version: PythonVersion) -> Iterator[str]: + """ + Yields Python versions in descending order. + + After the latest version, the major-only version will be yielded, and then + all previous versions of that major version. + """ + if len(py_version) > 1: + yield f"py{_version_nodot(py_version[:2])}" + yield f"py{py_version[0]}" + if len(py_version) > 1: + for minor in range(py_version[1] - 1, -1, -1): + yield f"py{_version_nodot((py_version[0], minor))}" + + +def compatible_tags( + python_version: PythonVersion | None = None, + interpreter: str | None = None, + platforms: Iterable[str] | None = None, +) -> Iterator[Tag]: + """ + Yields the sequence of tags that are compatible with a specific version of Python. + + The tags consist of: + - py*-none- + - -none-any # ... if `interpreter` is provided. + - py*-none-any + """ + if not python_version: + python_version = sys.version_info[:2] + platforms = list(platforms or platform_tags()) + for version in _py_interpreter_range(python_version): + for platform_ in platforms: + yield Tag(version, "none", platform_) + if interpreter: + yield Tag(interpreter, "none", "any") + for version in _py_interpreter_range(python_version): + yield Tag(version, "none", "any") + + +def _mac_arch(arch: str, is_32bit: bool = _32_BIT_INTERPRETER) -> str: + if not is_32bit: + return arch + + if arch.startswith("ppc"): + return "ppc" + + return "i386" + + +def _mac_binary_formats(version: AppleVersion, cpu_arch: str) -> list[str]: + formats = [cpu_arch] + if cpu_arch == "x86_64": + if version < (10, 4): + return [] + formats.extend(["intel", "fat64", "fat32"]) + + elif cpu_arch == "i386": + if version < (10, 4): + return [] + formats.extend(["intel", "fat32", "fat"]) + + elif cpu_arch == "ppc64": + # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? + if version > (10, 5) or version < (10, 4): + return [] + formats.append("fat64") + + elif cpu_arch == "ppc": + if version > (10, 6): + return [] + formats.extend(["fat32", "fat"]) + + if cpu_arch in {"arm64", "x86_64"}: + formats.append("universal2") + + if cpu_arch in {"x86_64", "i386", "ppc64", "ppc", "intel"}: + formats.append("universal") + + return formats + + +def mac_platforms( + version: AppleVersion | None = None, arch: str | None = None +) -> Iterator[str]: + """ + Yields the platform tags for a macOS system. + + The `version` parameter is a two-item tuple specifying the macOS version to + generate platform tags for. The `arch` parameter is the CPU architecture to + generate platform tags for. Both parameters default to the appropriate value + for the current system. + """ + version_str, _, cpu_arch = platform.mac_ver() + if version is None: + version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2]))) + if version == (10, 16): + # When built against an older macOS SDK, Python will report macOS 10.16 + # instead of the real version. + version_str = subprocess.run( + [ + sys.executable, + "-sS", + "-c", + "import platform; print(platform.mac_ver()[0])", + ], + check=True, + env={"SYSTEM_VERSION_COMPAT": "0"}, + stdout=subprocess.PIPE, + text=True, + ).stdout + version = cast("AppleVersion", tuple(map(int, version_str.split(".")[:2]))) + else: + version = version + if arch is None: + arch = _mac_arch(cpu_arch) + else: + arch = arch + + if (10, 0) <= version and version < (11, 0): + # Prior to Mac OS 11, each yearly release of Mac OS bumped the + # "minor" version number. The major version was always 10. + major_version = 10 + for minor_version in range(version[1], -1, -1): + compat_version = major_version, minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield f"macosx_{major_version}_{minor_version}_{binary_format}" + + if version >= (11, 0): + # Starting with Mac OS 11, each yearly release bumps the major version + # number. The minor versions are now the midyear updates. + minor_version = 0 + for major_version in range(version[0], 10, -1): + compat_version = major_version, minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield f"macosx_{major_version}_{minor_version}_{binary_format}" + + if version >= (11, 0): + # Mac OS 11 on x86_64 is compatible with binaries from previous releases. + # Arm64 support was introduced in 11.0, so no Arm binaries from previous + # releases exist. + # + # However, the "universal2" binary format can have a + # macOS version earlier than 11.0 when the x86_64 part of the binary supports + # that version of macOS. + major_version = 10 + if arch == "x86_64": + for minor_version in range(16, 3, -1): + compat_version = major_version, minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + yield f"macosx_{major_version}_{minor_version}_{binary_format}" + else: + for minor_version in range(16, 3, -1): + compat_version = major_version, minor_version + binary_format = "universal2" + yield f"macosx_{major_version}_{minor_version}_{binary_format}" + + +def ios_platforms( + version: AppleVersion | None = None, multiarch: str | None = None +) -> Iterator[str]: + """ + Yields the platform tags for an iOS system. + + :param version: A two-item tuple specifying the iOS version to generate + platform tags for. Defaults to the current iOS version. + :param multiarch: The CPU architecture+ABI to generate platform tags for - + (the value used by `sys.implementation._multiarch` e.g., + `arm64_iphoneos` or `x84_64_iphonesimulator`). Defaults to the current + multiarch value. + """ + if version is None: + # if iOS is the current platform, ios_ver *must* be defined. However, + # it won't exist for CPython versions before 3.13, which causes a mypy + # error. + _, release, _, _ = platform.ios_ver() # type: ignore[attr-defined, unused-ignore] + version = cast("AppleVersion", tuple(map(int, release.split(".")[:2]))) + + if multiarch is None: + multiarch = sys.implementation._multiarch + multiarch = multiarch.replace("-", "_") + + ios_platform_template = "ios_{major}_{minor}_{multiarch}" + + # Consider any iOS major.minor version from the version requested, down to + # 12.0. 12.0 is the first iOS version that is known to have enough features + # to support CPython. Consider every possible minor release up to X.9. There + # highest the minor has ever gone is 8 (14.8 and 15.8) but having some extra + # candidates that won't ever match doesn't really hurt, and it saves us from + # having to keep an explicit list of known iOS versions in the code. Return + # the results descending order of version number. + + # If the requested major version is less than 12, there won't be any matches. + if version[0] < 12: + return + + # Consider the actual X.Y version that was requested. + yield ios_platform_template.format( + major=version[0], minor=version[1], multiarch=multiarch + ) + + # Consider every minor version from X.0 to the minor version prior to the + # version requested by the platform. + for minor in range(version[1] - 1, -1, -1): + yield ios_platform_template.format( + major=version[0], minor=minor, multiarch=multiarch + ) + + for major in range(version[0] - 1, 11, -1): + for minor in range(9, -1, -1): + yield ios_platform_template.format( + major=major, minor=minor, multiarch=multiarch + ) + + +def android_platforms( + api_level: int | None = None, abi: str | None = None +) -> Iterator[str]: + """ + Yields the :attr:`~Tag.platform` tags for Android. If this function is invoked on + non-Android platforms, the ``api_level`` and ``abi`` arguments are required. + + :param int api_level: The maximum `API level + `__ to return. Defaults + to the current system's version, as returned by ``platform.android_ver``. + :param str abi: The `Android ABI `__, + e.g. ``arm64_v8a``. Defaults to the current system's ABI , as returned by + ``sysconfig.get_platform``. Hyphens and periods will be replaced with + underscores. + """ + if platform.system() != "Android" and (api_level is None or abi is None): + raise TypeError( + "on non-Android platforms, the api_level and abi arguments are required" + ) + + if api_level is None: + # Python 3.13 was the first version to return platform.system() == "Android", + # and also the first version to define platform.android_ver(). + api_level = platform.android_ver().api_level # type: ignore[attr-defined] + + if abi is None: + abi = sysconfig.get_platform().split("-")[-1] + abi = _normalize_string(abi) + + # 16 is the minimum API level known to have enough features to support CPython + # without major patching. Yield every API level from the maximum down to the + # minimum, inclusive. + min_api_level = 16 + for ver in range(api_level, min_api_level - 1, -1): + yield f"android_{ver}_{abi}" + + +def _linux_platforms(is_32bit: bool = _32_BIT_INTERPRETER) -> Iterator[str]: + linux = _normalize_string(sysconfig.get_platform()) + if not linux.startswith("linux_"): + # we should never be here, just yield the sysconfig one and return + yield linux + return + if is_32bit: + if linux == "linux_x86_64": + linux = "linux_i686" + elif linux == "linux_aarch64": + linux = "linux_armv8l" + _, arch = linux.split("_", 1) + archs = {"armv8l": ["armv8l", "armv7l"]}.get(arch, [arch]) + yield from _manylinux.platform_tags(archs) + yield from _musllinux.platform_tags(archs) + for arch in archs: + yield f"linux_{arch}" + + +def _generic_platforms() -> Iterator[str]: + yield _normalize_string(sysconfig.get_platform()) + + +def platform_tags() -> Iterator[str]: + """ + Provides the platform tags for this installation. + """ + if platform.system() == "Darwin": + return mac_platforms() + elif platform.system() == "iOS": + return ios_platforms() + elif platform.system() == "Android": + return android_platforms() + elif platform.system() == "Linux": + return _linux_platforms() + else: + return _generic_platforms() + + +def interpreter_name() -> str: + """ + Returns the name of the running interpreter. + + Some implementations have a reserved, two-letter abbreviation which will + be returned when appropriate. + """ + name = sys.implementation.name + return INTERPRETER_SHORT_NAMES.get(name) or name + + +def interpreter_version(*, warn: bool = False) -> str: + """ + Returns the version of the running interpreter. + """ + version = _get_config_var("py_version_nodot", warn=warn) + if version: + version = str(version) + else: + version = _version_nodot(sys.version_info[:2]) + return version + + +def _version_nodot(version: PythonVersion) -> str: + return "".join(map(str, version)) + + +def sys_tags(*, warn: bool = False) -> Iterator[Tag]: + """ + Returns the sequence of tag triples for the running interpreter. + + The order of the sequence corresponds to priority order for the + interpreter, from most to least important. + """ + + interp_name = interpreter_name() + if interp_name == "cp": + yield from cpython_tags(warn=warn) + else: + yield from generic_tags() + + if interp_name == "pp": + interp = "pp3" + elif interp_name == "cp": + interp = "cp" + interpreter_version(warn=warn) + else: + interp = None + yield from compatible_tags(interpreter=interp) diff --git a/lib/python3.12/site-packages/packaging/utils.py b/lib/python3.12/site-packages/packaging/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..23450953df74eccd9c13cd2a955ce09d1f968565 --- /dev/null +++ b/lib/python3.12/site-packages/packaging/utils.py @@ -0,0 +1,163 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import functools +import re +from typing import NewType, Tuple, Union, cast + +from .tags import Tag, parse_tag +from .version import InvalidVersion, Version, _TrimmedRelease + +BuildTag = Union[Tuple[()], Tuple[int, str]] +NormalizedName = NewType("NormalizedName", str) + + +class InvalidName(ValueError): + """ + An invalid distribution name; users should refer to the packaging user guide. + """ + + +class InvalidWheelFilename(ValueError): + """ + An invalid wheel filename was found, users should refer to PEP 427. + """ + + +class InvalidSdistFilename(ValueError): + """ + An invalid sdist filename was found, users should refer to the packaging user guide. + """ + + +# Core metadata spec for `Name` +_validate_regex = re.compile( + r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.IGNORECASE +) +_canonicalize_regex = re.compile(r"[-_.]+") +_normalized_regex = re.compile(r"^([a-z0-9]|[a-z0-9]([a-z0-9-](?!--))*[a-z0-9])$") +# PEP 427: The build number must start with a digit. +_build_tag_regex = re.compile(r"(\d+)(.*)") + + +def canonicalize_name(name: str, *, validate: bool = False) -> NormalizedName: + if validate and not _validate_regex.match(name): + raise InvalidName(f"name is invalid: {name!r}") + # This is taken from PEP 503. + value = _canonicalize_regex.sub("-", name).lower() + return cast(NormalizedName, value) + + +def is_normalized_name(name: str) -> bool: + return _normalized_regex.match(name) is not None + + +@functools.singledispatch +def canonicalize_version( + version: Version | str, *, strip_trailing_zero: bool = True +) -> str: + """ + Return a canonical form of a version as a string. + + >>> canonicalize_version('1.0.1') + '1.0.1' + + Per PEP 625, versions may have multiple canonical forms, differing + only by trailing zeros. + + >>> canonicalize_version('1.0.0') + '1' + >>> canonicalize_version('1.0.0', strip_trailing_zero=False) + '1.0.0' + + Invalid versions are returned unaltered. + + >>> canonicalize_version('foo bar baz') + 'foo bar baz' + """ + return str(_TrimmedRelease(str(version)) if strip_trailing_zero else version) + + +@canonicalize_version.register +def _(version: str, *, strip_trailing_zero: bool = True) -> str: + try: + parsed = Version(version) + except InvalidVersion: + # Legacy versions cannot be normalized + return version + return canonicalize_version(parsed, strip_trailing_zero=strip_trailing_zero) + + +def parse_wheel_filename( + filename: str, +) -> tuple[NormalizedName, Version, BuildTag, frozenset[Tag]]: + if not filename.endswith(".whl"): + raise InvalidWheelFilename( + f"Invalid wheel filename (extension must be '.whl'): {filename!r}" + ) + + filename = filename[:-4] + dashes = filename.count("-") + if dashes not in (4, 5): + raise InvalidWheelFilename( + f"Invalid wheel filename (wrong number of parts): {filename!r}" + ) + + parts = filename.split("-", dashes - 2) + name_part = parts[0] + # See PEP 427 for the rules on escaping the project name. + if "__" in name_part or re.match(r"^[\w\d._]*$", name_part, re.UNICODE) is None: + raise InvalidWheelFilename(f"Invalid project name: {filename!r}") + name = canonicalize_name(name_part) + + try: + version = Version(parts[1]) + except InvalidVersion as e: + raise InvalidWheelFilename( + f"Invalid wheel filename (invalid version): {filename!r}" + ) from e + + if dashes == 5: + build_part = parts[2] + build_match = _build_tag_regex.match(build_part) + if build_match is None: + raise InvalidWheelFilename( + f"Invalid build number: {build_part} in {filename!r}" + ) + build = cast(BuildTag, (int(build_match.group(1)), build_match.group(2))) + else: + build = () + tags = parse_tag(parts[-1]) + return (name, version, build, tags) + + +def parse_sdist_filename(filename: str) -> tuple[NormalizedName, Version]: + if filename.endswith(".tar.gz"): + file_stem = filename[: -len(".tar.gz")] + elif filename.endswith(".zip"): + file_stem = filename[: -len(".zip")] + else: + raise InvalidSdistFilename( + f"Invalid sdist filename (extension must be '.tar.gz' or '.zip'):" + f" {filename!r}" + ) + + # We are requiring a PEP 440 version, which cannot contain dashes, + # so we split on the last dash. + name_part, sep, version_part = file_stem.rpartition("-") + if not sep: + raise InvalidSdistFilename(f"Invalid sdist filename: {filename!r}") + + name = canonicalize_name(name_part) + + try: + version = Version(version_part) + except InvalidVersion as e: + raise InvalidSdistFilename( + f"Invalid sdist filename (invalid version): {filename!r}" + ) from e + + return (name, version) diff --git a/lib/python3.12/site-packages/packaging/version.py b/lib/python3.12/site-packages/packaging/version.py new file mode 100644 index 0000000000000000000000000000000000000000..c9bbda20e463b8d9389ecd65f74af33810a02bdd --- /dev/null +++ b/lib/python3.12/site-packages/packaging/version.py @@ -0,0 +1,582 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +""" +.. testsetup:: + + from packaging.version import parse, Version +""" + +from __future__ import annotations + +import itertools +import re +from typing import Any, Callable, NamedTuple, SupportsInt, Tuple, Union + +from ._structures import Infinity, InfinityType, NegativeInfinity, NegativeInfinityType + +__all__ = ["VERSION_PATTERN", "InvalidVersion", "Version", "parse"] + +LocalType = Tuple[Union[int, str], ...] + +CmpPrePostDevType = Union[InfinityType, NegativeInfinityType, Tuple[str, int]] +CmpLocalType = Union[ + NegativeInfinityType, + Tuple[Union[Tuple[int, str], Tuple[NegativeInfinityType, Union[int, str]]], ...], +] +CmpKey = Tuple[ + int, + Tuple[int, ...], + CmpPrePostDevType, + CmpPrePostDevType, + CmpPrePostDevType, + CmpLocalType, +] +VersionComparisonMethod = Callable[[CmpKey, CmpKey], bool] + + +class _Version(NamedTuple): + epoch: int + release: tuple[int, ...] + dev: tuple[str, int] | None + pre: tuple[str, int] | None + post: tuple[str, int] | None + local: LocalType | None + + +def parse(version: str) -> Version: + """Parse the given version string. + + >>> parse('1.0.dev1') + + + :param version: The version string to parse. + :raises InvalidVersion: When the version string is not a valid version. + """ + return Version(version) + + +class InvalidVersion(ValueError): + """Raised when a version string is not a valid version. + + >>> Version("invalid") + Traceback (most recent call last): + ... + packaging.version.InvalidVersion: Invalid version: 'invalid' + """ + + +class _BaseVersion: + _key: tuple[Any, ...] + + def __hash__(self) -> int: + return hash(self._key) + + # Please keep the duplicated `isinstance` check + # in the six comparisons hereunder + # unless you find a way to avoid adding overhead function calls. + def __lt__(self, other: _BaseVersion) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key < other._key + + def __le__(self, other: _BaseVersion) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key <= other._key + + def __eq__(self, other: object) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key == other._key + + def __ge__(self, other: _BaseVersion) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key >= other._key + + def __gt__(self, other: _BaseVersion) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key > other._key + + def __ne__(self, other: object) -> bool: + if not isinstance(other, _BaseVersion): + return NotImplemented + + return self._key != other._key + + +# Deliberately not anchored to the start and end of the string, to make it +# easier for 3rd party code to reuse +_VERSION_PATTERN = r""" + v? + (?: + (?:(?P[0-9]+)!)? # epoch + (?P[0-9]+(?:\.[0-9]+)*) # release segment + (?P
                                          # pre-release
+            [-_\.]?
+            (?Palpha|a|beta|b|preview|pre|c|rc)
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+        (?P                                         # post release
+            (?:-(?P[0-9]+))
+            |
+            (?:
+                [-_\.]?
+                (?Ppost|rev|r)
+                [-_\.]?
+                (?P[0-9]+)?
+            )
+        )?
+        (?P                                          # dev release
+            [-_\.]?
+            (?Pdev)
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+    )
+    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
+"""
+
+VERSION_PATTERN = _VERSION_PATTERN
+"""
+A string containing the regular expression used to match a valid version.
+
+The pattern is not anchored at either end, and is intended for embedding in larger
+expressions (for example, matching a version number as part of a file name). The
+regular expression should be compiled with the ``re.VERBOSE`` and ``re.IGNORECASE``
+flags set.
+
+:meta hide-value:
+"""
+
+
+class Version(_BaseVersion):
+    """This class abstracts handling of a project's versions.
+
+    A :class:`Version` instance is comparison aware and can be compared and
+    sorted using the standard Python interfaces.
+
+    >>> v1 = Version("1.0a5")
+    >>> v2 = Version("1.0")
+    >>> v1
+    
+    >>> v2
+    
+    >>> v1 < v2
+    True
+    >>> v1 == v2
+    False
+    >>> v1 > v2
+    False
+    >>> v1 >= v2
+    False
+    >>> v1 <= v2
+    True
+    """
+
+    _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
+    _key: CmpKey
+
+    def __init__(self, version: str) -> None:
+        """Initialize a Version object.
+
+        :param version:
+            The string representation of a version which will be parsed and normalized
+            before use.
+        :raises InvalidVersion:
+            If the ``version`` does not conform to PEP 440 in any way then this
+            exception will be raised.
+        """
+
+        # Validate the version and parse it into pieces
+        match = self._regex.search(version)
+        if not match:
+            raise InvalidVersion(f"Invalid version: {version!r}")
+
+        # Store the parsed out pieces of the version
+        self._version = _Version(
+            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
+            release=tuple(int(i) for i in match.group("release").split(".")),
+            pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
+            post=_parse_letter_version(
+                match.group("post_l"), match.group("post_n1") or match.group("post_n2")
+            ),
+            dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
+            local=_parse_local_version(match.group("local")),
+        )
+
+        # Generate a key which will be used for sorting
+        self._key = _cmpkey(
+            self._version.epoch,
+            self._version.release,
+            self._version.pre,
+            self._version.post,
+            self._version.dev,
+            self._version.local,
+        )
+
+    def __repr__(self) -> str:
+        """A representation of the Version that shows all internal state.
+
+        >>> Version('1.0.0')
+        
+        """
+        return f""
+
+    def __str__(self) -> str:
+        """A string representation of the version that can be round-tripped.
+
+        >>> str(Version("1.0a5"))
+        '1.0a5'
+        """
+        parts = []
+
+        # Epoch
+        if self.epoch != 0:
+            parts.append(f"{self.epoch}!")
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self.release))
+
+        # Pre-release
+        if self.pre is not None:
+            parts.append("".join(str(x) for x in self.pre))
+
+        # Post-release
+        if self.post is not None:
+            parts.append(f".post{self.post}")
+
+        # Development release
+        if self.dev is not None:
+            parts.append(f".dev{self.dev}")
+
+        # Local version segment
+        if self.local is not None:
+            parts.append(f"+{self.local}")
+
+        return "".join(parts)
+
+    @property
+    def epoch(self) -> int:
+        """The epoch of the version.
+
+        >>> Version("2.0.0").epoch
+        0
+        >>> Version("1!2.0.0").epoch
+        1
+        """
+        return self._version.epoch
+
+    @property
+    def release(self) -> tuple[int, ...]:
+        """The components of the "release" segment of the version.
+
+        >>> Version("1.2.3").release
+        (1, 2, 3)
+        >>> Version("2.0.0").release
+        (2, 0, 0)
+        >>> Version("1!2.0.0.post0").release
+        (2, 0, 0)
+
+        Includes trailing zeroes but not the epoch or any pre-release / development /
+        post-release suffixes.
+        """
+        return self._version.release
+
+    @property
+    def pre(self) -> tuple[str, int] | None:
+        """The pre-release segment of the version.
+
+        >>> print(Version("1.2.3").pre)
+        None
+        >>> Version("1.2.3a1").pre
+        ('a', 1)
+        >>> Version("1.2.3b1").pre
+        ('b', 1)
+        >>> Version("1.2.3rc1").pre
+        ('rc', 1)
+        """
+        return self._version.pre
+
+    @property
+    def post(self) -> int | None:
+        """The post-release number of the version.
+
+        >>> print(Version("1.2.3").post)
+        None
+        >>> Version("1.2.3.post1").post
+        1
+        """
+        return self._version.post[1] if self._version.post else None
+
+    @property
+    def dev(self) -> int | None:
+        """The development number of the version.
+
+        >>> print(Version("1.2.3").dev)
+        None
+        >>> Version("1.2.3.dev1").dev
+        1
+        """
+        return self._version.dev[1] if self._version.dev else None
+
+    @property
+    def local(self) -> str | None:
+        """The local version segment of the version.
+
+        >>> print(Version("1.2.3").local)
+        None
+        >>> Version("1.2.3+abc").local
+        'abc'
+        """
+        if self._version.local:
+            return ".".join(str(x) for x in self._version.local)
+        else:
+            return None
+
+    @property
+    def public(self) -> str:
+        """The public portion of the version.
+
+        >>> Version("1.2.3").public
+        '1.2.3'
+        >>> Version("1.2.3+abc").public
+        '1.2.3'
+        >>> Version("1!1.2.3dev1+abc").public
+        '1!1.2.3.dev1'
+        """
+        return str(self).split("+", 1)[0]
+
+    @property
+    def base_version(self) -> str:
+        """The "base version" of the version.
+
+        >>> Version("1.2.3").base_version
+        '1.2.3'
+        >>> Version("1.2.3+abc").base_version
+        '1.2.3'
+        >>> Version("1!1.2.3dev1+abc").base_version
+        '1!1.2.3'
+
+        The "base version" is the public version of the project without any pre or post
+        release markers.
+        """
+        parts = []
+
+        # Epoch
+        if self.epoch != 0:
+            parts.append(f"{self.epoch}!")
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self.release))
+
+        return "".join(parts)
+
+    @property
+    def is_prerelease(self) -> bool:
+        """Whether this version is a pre-release.
+
+        >>> Version("1.2.3").is_prerelease
+        False
+        >>> Version("1.2.3a1").is_prerelease
+        True
+        >>> Version("1.2.3b1").is_prerelease
+        True
+        >>> Version("1.2.3rc1").is_prerelease
+        True
+        >>> Version("1.2.3dev1").is_prerelease
+        True
+        """
+        return self.dev is not None or self.pre is not None
+
+    @property
+    def is_postrelease(self) -> bool:
+        """Whether this version is a post-release.
+
+        >>> Version("1.2.3").is_postrelease
+        False
+        >>> Version("1.2.3.post1").is_postrelease
+        True
+        """
+        return self.post is not None
+
+    @property
+    def is_devrelease(self) -> bool:
+        """Whether this version is a development release.
+
+        >>> Version("1.2.3").is_devrelease
+        False
+        >>> Version("1.2.3.dev1").is_devrelease
+        True
+        """
+        return self.dev is not None
+
+    @property
+    def major(self) -> int:
+        """The first item of :attr:`release` or ``0`` if unavailable.
+
+        >>> Version("1.2.3").major
+        1
+        """
+        return self.release[0] if len(self.release) >= 1 else 0
+
+    @property
+    def minor(self) -> int:
+        """The second item of :attr:`release` or ``0`` if unavailable.
+
+        >>> Version("1.2.3").minor
+        2
+        >>> Version("1").minor
+        0
+        """
+        return self.release[1] if len(self.release) >= 2 else 0
+
+    @property
+    def micro(self) -> int:
+        """The third item of :attr:`release` or ``0`` if unavailable.
+
+        >>> Version("1.2.3").micro
+        3
+        >>> Version("1").micro
+        0
+        """
+        return self.release[2] if len(self.release) >= 3 else 0
+
+
+class _TrimmedRelease(Version):
+    @property
+    def release(self) -> tuple[int, ...]:
+        """
+        Release segment without any trailing zeros.
+
+        >>> _TrimmedRelease('1.0.0').release
+        (1,)
+        >>> _TrimmedRelease('0.0').release
+        (0,)
+        """
+        rel = super().release
+        nonzeros = (index for index, val in enumerate(rel) if val)
+        last_nonzero = max(nonzeros, default=0)
+        return rel[: last_nonzero + 1]
+
+
+def _parse_letter_version(
+    letter: str | None, number: str | bytes | SupportsInt | None
+) -> tuple[str, int] | None:
+    if letter:
+        # We consider there to be an implicit 0 in a pre-release if there is
+        # not a numeral associated with it.
+        if number is None:
+            number = 0
+
+        # We normalize any letters to their lower case form
+        letter = letter.lower()
+
+        # We consider some words to be alternate spellings of other words and
+        # in those cases we want to normalize the spellings to our preferred
+        # spelling.
+        if letter == "alpha":
+            letter = "a"
+        elif letter == "beta":
+            letter = "b"
+        elif letter in ["c", "pre", "preview"]:
+            letter = "rc"
+        elif letter in ["rev", "r"]:
+            letter = "post"
+
+        return letter, int(number)
+
+    assert not letter
+    if number:
+        # We assume if we are given a number, but we are not given a letter
+        # then this is using the implicit post release syntax (e.g. 1.0-1)
+        letter = "post"
+
+        return letter, int(number)
+
+    return None
+
+
+_local_version_separators = re.compile(r"[\._-]")
+
+
+def _parse_local_version(local: str | None) -> LocalType | None:
+    """
+    Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
+    """
+    if local is not None:
+        return tuple(
+            part.lower() if not part.isdigit() else int(part)
+            for part in _local_version_separators.split(local)
+        )
+    return None
+
+
+def _cmpkey(
+    epoch: int,
+    release: tuple[int, ...],
+    pre: tuple[str, int] | None,
+    post: tuple[str, int] | None,
+    dev: tuple[str, int] | None,
+    local: LocalType | None,
+) -> CmpKey:
+    # When we compare a release version, we want to compare it with all of the
+    # trailing zeros removed. So we'll use a reverse the list, drop all the now
+    # leading zeros until we come to something non zero, then take the rest
+    # re-reverse it back into the correct order and make it a tuple and use
+    # that for our sorting key.
+    _release = tuple(
+        reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
+    )
+
+    # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
+    # We'll do this by abusing the pre segment, but we _only_ want to do this
+    # if there is not a pre or a post segment. If we have one of those then
+    # the normal sorting rules will handle this case correctly.
+    if pre is None and post is None and dev is not None:
+        _pre: CmpPrePostDevType = NegativeInfinity
+    # Versions without a pre-release (except as noted above) should sort after
+    # those with one.
+    elif pre is None:
+        _pre = Infinity
+    else:
+        _pre = pre
+
+    # Versions without a post segment should sort before those with one.
+    if post is None:
+        _post: CmpPrePostDevType = NegativeInfinity
+
+    else:
+        _post = post
+
+    # Versions without a development segment should sort after those with one.
+    if dev is None:
+        _dev: CmpPrePostDevType = Infinity
+
+    else:
+        _dev = dev
+
+    if local is None:
+        # Versions without a local segment should sort before those with one.
+        _local: CmpLocalType = NegativeInfinity
+    else:
+        # Versions with a local segment need that segment parsed to implement
+        # the sorting rules in PEP440.
+        # - Alpha numeric segments sort before numeric segments
+        # - Alpha numeric segments sort lexicographically
+        # - Numeric segments sort numerically
+        # - Shorter versions sort before longer versions when the prefixes
+        #   match exactly
+        _local = tuple(
+            (i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
+        )
+
+    return epoch, _release, _pre, _post, _dev, _local
diff --git a/lib/python3.12/site-packages/pip-25.0.1.dist-info/AUTHORS.txt b/lib/python3.12/site-packages/pip-25.0.1.dist-info/AUTHORS.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f42daec02e222ccf1badd81f348a76e4f4641115
--- /dev/null
+++ b/lib/python3.12/site-packages/pip-25.0.1.dist-info/AUTHORS.txt
@@ -0,0 +1,806 @@
+@Switch01
+A_Rog
+Aakanksha Agrawal
+Abhinav Sagar
+ABHYUDAY PRATAP SINGH
+abs51295
+AceGentile
+Adam Chainz
+Adam Tse
+Adam Wentz
+admin
+Adolfo Ochagavía
+Adrien Morison
+Agus
+ahayrapetyan
+Ahilya
+AinsworthK
+Akash Srivastava
+Alan Yee
+Albert Tugushev
+Albert-Guan
+albertg
+Alberto Sottile
+Aleks Bunin
+Ales Erjavec
+Alethea Flowers
+Alex Gaynor
+Alex Grönholm
+Alex Hedges
+Alex Loosley
+Alex Morega
+Alex Stachowiak
+Alexander Shtyrov
+Alexandre Conrad
+Alexey Popravka
+Aleš Erjavec
+Alli
+Ami Fischman
+Ananya Maiti
+Anatoly Techtonik
+Anders Kaseorg
+Andre Aguiar
+Andreas Lutro
+Andrei Geacar
+Andrew Gaul
+Andrew Shymanel
+Andrey Bienkowski
+Andrey Bulgakov
+Andrés Delfino
+Andy Freeland
+Andy Kluger
+Ani Hayrapetyan
+Aniruddha Basak
+Anish Tambe
+Anrs Hu
+Anthony Sottile
+Antoine Musso
+Anton Ovchinnikov
+Anton Patrushev
+Anton Zelenov
+Antonio Alvarado Hernandez
+Antony Lee
+Antti Kaihola
+Anubhav Patel
+Anudit Nagar
+Anuj Godase
+AQNOUCH Mohammed
+AraHaan
+arena
+arenasys
+Arindam Choudhury
+Armin Ronacher
+Arnon Yaari
+Artem
+Arun Babu Neelicattu
+Ashley Manton
+Ashwin Ramaswami
+atse
+Atsushi Odagiri
+Avinash Karhana
+Avner Cohen
+Awit (Ah-Wit) Ghirmai
+Baptiste Mispelon
+Barney Gale
+barneygale
+Bartek Ogryczak
+Bastian Venthur
+Ben Bodenmiller
+Ben Darnell
+Ben Hoyt
+Ben Mares
+Ben Rosser
+Bence Nagy
+Benjamin Peterson
+Benjamin VanEvery
+Benoit Pierre
+Berker Peksag
+Bernard
+Bernard Tyers
+Bernardo B. Marques
+Bernhard M. Wiedemann
+Bertil Hatt
+Bhavam Vidyarthi
+Blazej Michalik
+Bogdan Opanchuk
+BorisZZZ
+Brad Erickson
+Bradley Ayers
+Branch Vincent
+Brandon L. Reiss
+Brandt Bucher
+Brannon Dorsey
+Brett Randall
+Brett Rosen
+Brian Cristante
+Brian Rosner
+briantracy
+BrownTruck
+Bruno Oliveira
+Bruno Renié
+Bruno S
+Bstrdsmkr
+Buck Golemon
+burrows
+Bussonnier Matthias
+bwoodsend
+c22
+Caleb Brown
+Caleb Martinez
+Calvin Smith
+Carl Meyer
+Carlos Liam
+Carol Willing
+Carter Thayer
+Cass
+Chandrasekhar Atina
+Charlie Marsh
+charwick
+Chih-Hsuan Yen
+Chris Brinker
+Chris Hunt
+Chris Jerdonek
+Chris Kuehl
+Chris Markiewicz
+Chris McDonough
+Chris Pawley
+Chris Pryer
+Chris Wolfe
+Christian Clauss
+Christian Heimes
+Christian Oudard
+Christoph Reiter
+Christopher Hunt
+Christopher Snyder
+chrysle
+cjc7373
+Clark Boylan
+Claudio Jolowicz
+Clay McClure
+Cody
+Cody Soyland
+Colin Watson
+Collin Anderson
+Connor Osborn
+Cooper Lees
+Cooper Ry Lees
+Cory Benfield
+Cory Wright
+Craig Kerstiens
+Cristian Sorinel
+Cristina
+Cristina Muñoz
+ctg123
+Curtis Doty
+cytolentino
+Daan De Meyer
+Dale
+Damian
+Damian Quiroga
+Damian Shaw
+Dan Black
+Dan Savilonis
+Dan Sully
+Dane Hillard
+daniel
+Daniel Collins
+Daniel Hahler
+Daniel Holth
+Daniel Jost
+Daniel Katz
+Daniel Shaulov
+Daniele Esposti
+Daniele Nicolodi
+Daniele Procida
+Daniil Konovalenko
+Danny Hermes
+Danny McClanahan
+Darren Kavanagh
+Dav Clark
+Dave Abrahams
+Dave Jones
+David Aguilar
+David Black
+David Bordeynik
+David Caro
+David D Lowe
+David Evans
+David Hewitt
+David Linke
+David Poggi
+David Poznik
+David Pursehouse
+David Runge
+David Tucker
+David Wales
+Davidovich
+ddelange
+Deepak Sharma
+Deepyaman Datta
+Denise Yu
+dependabot[bot]
+derwolfe
+Desetude
+Devesh Kumar Singh
+devsagul
+Diego Caraballo
+Diego Ramirez
+DiegoCaraballo
+Dimitri Merejkowsky
+Dimitri Papadopoulos
+Dimitri Papadopoulos Orfanos
+Dirk Stolle
+Dmitry Gladkov
+Dmitry Volodin
+Domen Kožar
+Dominic Davis-Foster
+Donald Stufft
+Dongweiming
+doron zarhi
+Dos Moonen
+Douglas Thor
+DrFeathers
+Dustin Ingram
+Dustin Rodrigues
+Dwayne Bailey
+Ed Morley
+Edgar Ramírez
+Edgar Ramírez Mondragón
+Ee Durbin
+Efflam Lemaillet
+efflamlemaillet
+Eitan Adler
+ekristina
+elainechan
+Eli Schwartz
+Elisha Hollander
+Ellen Marie Dash
+Emil Burzo
+Emil Styrke
+Emmanuel Arias
+Endoh Takanao
+enoch
+Erdinc Mutlu
+Eric Cousineau
+Eric Gillingham
+Eric Hanchrow
+Eric Hopper
+Erik M. Bray
+Erik Rose
+Erwin Janssen
+Eugene Vereshchagin
+everdimension
+Federico
+Felipe Peter
+Felix Yan
+fiber-space
+Filip Kokosiński
+Filipe Laíns
+Finn Womack
+finnagin
+Flavio Amurrio
+Florian Briand
+Florian Rathgeber
+Francesco
+Francesco Montesano
+Fredrik Orderud
+Frost Ming
+Gabriel Curio
+Gabriel de Perthuis
+Garry Polley
+gavin
+gdanielson
+Geoffrey Sneddon
+George Song
+Georgi Valkov
+Georgy Pchelkin
+ghost
+Giftlin Rajaiah
+gizmoguy1
+gkdoc
+Godefroid Chapelle
+Gopinath M
+GOTO Hayato
+gousaiyang
+gpiks
+Greg Roodt
+Greg Ward
+Guilherme Espada
+Guillaume Seguin
+gutsytechster
+Guy Rozendorn
+Guy Tuval
+gzpan123
+Hanjun Kim
+Hari Charan
+Harsh Vardhan
+harupy
+Harutaka Kawamura
+hauntsaninja
+Henrich Hartzer
+Henry Schreiner
+Herbert Pfennig
+Holly Stotelmyer
+Honnix
+Hsiaoming Yang
+Hugo Lopes Tavares
+Hugo van Kemenade
+Hugues Bruant
+Hynek Schlawack
+Ian Bicking
+Ian Cordasco
+Ian Lee
+Ian Stapleton Cordasco
+Ian Wienand
+Igor Kuzmitshov
+Igor Sobreira
+Ikko Ashimine
+Ilan Schnell
+Illia Volochii
+Ilya Baryshev
+Inada Naoki
+Ionel Cristian Mărieș
+Ionel Maries Cristian
+Itamar Turner-Trauring
+Ivan Pozdeev
+J. Nick Koston
+Jacob Kim
+Jacob Walls
+Jaime Sanz
+jakirkham
+Jakub Kuczys
+Jakub Stasiak
+Jakub Vysoky
+Jakub Wilk
+James Cleveland
+James Curtin
+James Firth
+James Gerity
+James Polley
+Jan Pokorný
+Jannis Leidel
+Jarek Potiuk
+jarondl
+Jason Curtis
+Jason R. Coombs
+JasonMo
+JasonMo1
+Jay Graves
+Jean Abou Samra
+Jean-Christophe Fillion-Robin
+Jeff Barber
+Jeff Dairiki
+Jeff Widman
+Jelmer Vernooij
+jenix21
+Jeremy Fleischman
+Jeremy Stanley
+Jeremy Zafran
+Jesse Rittner
+Jiashuo Li
+Jim Fisher
+Jim Garrison
+Jinzhe Zeng
+Jiun Bae
+Jivan Amara
+Joe Bylund
+Joe Michelini
+John Paton
+John Sirois
+John T. Wodder II
+John-Scott Atlakson
+johnthagen
+Jon Banafato
+Jon Dufresne
+Jon Parise
+Jonas Nockert
+Jonathan Herbert
+Joonatan Partanen
+Joost Molenaar
+Jorge Niedbalski
+Joseph Bylund
+Joseph Long
+Josh Bronson
+Josh Cannon
+Josh Hansen
+Josh Schneier
+Joshua
+JoshuaPerdue
+Juan Luis Cano Rodríguez
+Juanjo Bazán
+Judah Rand
+Julian Berman
+Julian Gethmann
+Julien Demoor
+July Tikhonov
+Jussi Kukkonen
+Justin van Heek
+jwg4
+Jyrki Pulliainen
+Kai Chen
+Kai Mueller
+Kamal Bin Mustafa
+Karolina Surma
+kasium
+kaustav haldar
+keanemind
+Keith Maxwell
+Kelsey Hightower
+Kenneth Belitzky
+Kenneth Reitz
+Kevin Burke
+Kevin Carter
+Kevin Frommelt
+Kevin R Patterson
+Kexuan Sun
+Kit Randel
+Klaas van Schelven
+KOLANICH
+konstin
+kpinc
+Krishna Oza
+Kumar McMillan
+Kuntal Majumder
+Kurt McKee
+Kyle Persohn
+lakshmanaram
+Laszlo Kiss-Kollar
+Laurent Bristiel
+Laurent LAPORTE
+Laurie O
+Laurie Opperman
+layday
+Leon Sasson
+Lev Givon
+Lincoln de Sousa
+Lipis
+lorddavidiii
+Loren Carvalho
+Lucas Cimon
+Ludovic Gasc
+Luis Medel
+Lukas Geiger
+Lukas Juhrich
+Luke Macken
+Luo Jiebin
+luojiebin
+luz.paz
+László Kiss Kollár
+M00nL1ght
+Marc Abramowitz
+Marc Tamlyn
+Marcus Smith
+Mariatta
+Mark Kohler
+Mark McLoughlin
+Mark Williams
+Markus Hametner
+Martey Dodoo
+Martin Fischer
+Martin Häcker
+Martin Pavlasek
+Masaki
+Masklinn
+Matej Stuchlik
+Mathew Jennings
+Mathieu Bridon
+Mathieu Kniewallner
+Matt Bacchi
+Matt Good
+Matt Maker
+Matt Robenolt
+Matt Wozniski
+matthew
+Matthew Einhorn
+Matthew Feickert
+Matthew Gilliard
+Matthew Hughes
+Matthew Iversen
+Matthew Treinish
+Matthew Trumbell
+Matthew Willson
+Matthias Bussonnier
+mattip
+Maurits van Rees
+Max W Chase
+Maxim Kurnikov
+Maxime Rouyrre
+mayeut
+mbaluna
+mdebi
+memoselyk
+meowmeowcat
+Michael
+Michael Aquilina
+Michael E. Karpeles
+Michael Klich
+Michael Mintz
+Michael Williamson
+michaelpacer
+Michał Górny
+Mickaël Schoentgen
+Miguel Araujo Perez
+Mihir Singh
+Mike
+Mike Hendricks
+Min RK
+MinRK
+Miro Hrončok
+Monica Baluna
+montefra
+Monty Taylor
+morotti
+mrKazzila
+Muha Ajjan
+Nadav Wexler
+Nahuel Ambrosini
+Nate Coraor
+Nate Prewitt
+Nathan Houghton
+Nathaniel J. Smith
+Nehal J Wani
+Neil Botelho
+Nguyễn Gia Phong
+Nicholas Serra
+Nick Coghlan
+Nick Stenning
+Nick Timkovich
+Nicolas Bock
+Nicole Harris
+Nikhil Benesch
+Nikhil Ladha
+Nikita Chepanov
+Nikolay Korolev
+Nipunn Koorapati
+Nitesh Sharma
+Niyas Sait
+Noah
+Noah Gorny
+Nowell Strite
+NtaleGrey
+nvdv
+OBITORASU
+Ofek Lev
+ofrinevo
+Oliver Freund
+Oliver Jeeves
+Oliver Mannion
+Oliver Tonnhofer
+Olivier Girardot
+Olivier Grisel
+Ollie Rutherfurd
+OMOTO Kenji
+Omry Yadan
+onlinejudge95
+Oren Held
+Oscar Benjamin
+Oz N Tiram
+Pachwenko
+Patrick Dubroy
+Patrick Jenkins
+Patrick Lawson
+patricktokeeffe
+Patrik Kopkan
+Paul Ganssle
+Paul Kehrer
+Paul Moore
+Paul Nasrat
+Paul Oswald
+Paul van der Linden
+Paulus Schoutsen
+Pavel Safronov
+Pavithra Eswaramoorthy
+Pawel Jasinski
+Paweł Szramowski
+Pekka Klärck
+Peter Gessler
+Peter Lisák
+Peter Shen
+Peter Waller
+Petr Viktorin
+petr-tik
+Phaneendra Chiruvella
+Phil Elson
+Phil Freo
+Phil Pennock
+Phil Whelan
+Philip Jägenstedt
+Philip Molloy
+Philippe Ombredanne
+Pi Delport
+Pierre-Yves Rofes
+Pieter Degroote
+pip
+Prabakaran Kumaresshan
+Prabhjyotsing Surjit Singh Sodhi
+Prabhu Marappan
+Pradyun Gedam
+Prashant Sharma
+Pratik Mallya
+pre-commit-ci[bot]
+Preet Thakkar
+Preston Holmes
+Przemek Wrzos
+Pulkit Goyal
+q0w
+Qiangning Hong
+Qiming Xu
+Quentin Lee
+Quentin Pradet
+R. David Murray
+Rafael Caricio
+Ralf Schmitt
+Ran Benita
+Randy Döring
+Razzi Abuissa
+rdb
+Reece Dunham
+Remi Rampin
+Rene Dudfield
+Riccardo Magliocchetti
+Riccardo Schirone
+Richard Jones
+Richard Si
+Ricky Ng-Adam
+Rishi
+rmorotti
+RobberPhex
+Robert Collins
+Robert McGibbon
+Robert Pollak
+Robert T. McGibbon
+robin elisha robinson
+Roey Berman
+Rohan Jain
+Roman Bogorodskiy
+Roman Donchenko
+Romuald Brunet
+ronaudinho
+Ronny Pfannschmidt
+Rory McCann
+Ross Brattain
+Roy Wellington Ⅳ
+Ruairidh MacLeod
+Russell Keith-Magee
+Ryan Shepherd
+Ryan Wooden
+ryneeverett
+S. Guliaev
+Sachi King
+Salvatore Rinchiera
+sandeepkiran-js
+Sander Van Balen
+Savio Jomton
+schlamar
+Scott Kitterman
+Sean
+seanj
+Sebastian Jordan
+Sebastian Schaetz
+Segev Finer
+SeongSoo Cho
+Sergey Vasilyev
+Seth Michael Larson
+Seth Woodworth
+Shahar Epstein
+Shantanu
+shenxianpeng
+shireenrao
+Shivansh-007
+Shixian Sheng
+Shlomi Fish
+Shovan Maity
+Simeon Visser
+Simon Cross
+Simon Pichugin
+sinoroc
+sinscary
+snook92
+socketubs
+Sorin Sbarnea
+Srinivas Nyayapati
+Srishti Hegde
+Stavros Korokithakis
+Stefan Scherfke
+Stefano Rivera
+Stephan Erb
+Stephen Rosen
+stepshal
+Steve (Gadget) Barnes
+Steve Barnes
+Steve Dower
+Steve Kowalik
+Steven Myint
+Steven Silvester
+stonebig
+studioj
+Stéphane Bidoul
+Stéphane Bidoul (ACSONE)
+Stéphane Klein
+Sumana Harihareswara
+Surbhi Sharma
+Sviatoslav Sydorenko
+Sviatoslav Sydorenko (Святослав Сидоренко)
+Swat009
+Sylvain
+Takayuki SHIMIZUKAWA
+Taneli Hukkinen
+tbeswick
+Thiago
+Thijs Triemstra
+Thomas Fenzl
+Thomas Grainger
+Thomas Guettler
+Thomas Johansson
+Thomas Kluyver
+Thomas Smith
+Thomas VINCENT
+Tim D. Smith
+Tim Gates
+Tim Harder
+Tim Heap
+tim smith
+tinruufu
+Tobias Hermann
+Tom Forbes
+Tom Freudenheim
+Tom V
+Tomas Hrnciar
+Tomas Orsava
+Tomer Chachamu
+Tommi Enenkel | AnB
+Tomáš Hrnčiar
+Tony Beswick
+Tony Narlock
+Tony Zhaocheng Tan
+TonyBeswick
+toonarmycaptain
+Toshio Kuratomi
+toxinu
+Travis Swicegood
+Tushar Sadhwani
+Tzu-ping Chung
+Valentin Haenel
+Victor Stinner
+victorvpaulo
+Vikram - Google
+Viktor Szépe
+Ville Skyttä
+Vinay Sajip
+Vincent Philippon
+Vinicyus Macedo
+Vipul Kumar
+Vitaly Babiy
+Vladimir Fokow
+Vladimir Rutsky
+W. Trevor King
+Wil Tan
+Wilfred Hughes
+William Edwards
+William ML Leslie
+William T Olson
+William Woodruff
+Wilson Mo
+wim glenn
+Winson Luk
+Wolfgang Maier
+Wu Zhenyu
+XAMES3
+Xavier Fernandez
+Xianpeng Shen
+xoviat
+xtreak
+YAMAMOTO Takashi
+Yen Chi Hsuan
+Yeray Diaz Diaz
+Yoval P
+Yu Jian
+Yuan Jing Vincent Yan
+Yusuke Hayashi
+Zearin
+Zhiping Deng
+ziebam
+Zvezdan Petkovic
+Łukasz Langa
+Роман Донченко
+Семён Марьясин
diff --git a/lib/python3.12/site-packages/pip-25.0.1.dist-info/INSTALLER b/lib/python3.12/site-packages/pip-25.0.1.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/lib/python3.12/site-packages/pip-25.0.1.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/lib/python3.12/site-packages/pip-25.0.1.dist-info/LICENSE.txt b/lib/python3.12/site-packages/pip-25.0.1.dist-info/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8e7b65eaf628360e6f32f4140fcdd7ec7c2b7077
--- /dev/null
+++ b/lib/python3.12/site-packages/pip-25.0.1.dist-info/LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2008-present The pip developers (see AUTHORS.txt file)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/lib/python3.12/site-packages/pip-25.0.1.dist-info/METADATA b/lib/python3.12/site-packages/pip-25.0.1.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..3315c0635745a36012b57aa783435b0bfa425789
--- /dev/null
+++ b/lib/python3.12/site-packages/pip-25.0.1.dist-info/METADATA
@@ -0,0 +1,90 @@
+Metadata-Version: 2.2
+Name: pip
+Version: 25.0.1
+Summary: The PyPA recommended tool for installing Python packages.
+Author-email: The pip developers 
+License: MIT
+Project-URL: Homepage, https://pip.pypa.io/
+Project-URL: Documentation, https://pip.pypa.io
+Project-URL: Source, https://github.com/pypa/pip
+Project-URL: Changelog, https://pip.pypa.io/en/stable/news/
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Topic :: Software Development :: Build Tools
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Requires-Python: >=3.8
+Description-Content-Type: text/x-rst
+License-File: LICENSE.txt
+License-File: AUTHORS.txt
+
+pip - The Python Package Installer
+==================================
+
+.. |pypi-version| image:: https://img.shields.io/pypi/v/pip.svg
+   :target: https://pypi.org/project/pip/
+   :alt: PyPI
+
+.. |python-versions| image:: https://img.shields.io/pypi/pyversions/pip
+   :target: https://pypi.org/project/pip
+   :alt: PyPI - Python Version
+
+.. |docs-badge| image:: https://readthedocs.org/projects/pip/badge/?version=latest
+   :target: https://pip.pypa.io/en/latest
+   :alt: Documentation
+
+|pypi-version| |python-versions| |docs-badge|
+
+pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.
+
+Please take a look at our documentation for how to install and use pip:
+
+* `Installation`_
+* `Usage`_
+
+We release updates regularly, with a new version every 3 months. Find more details in our documentation:
+
+* `Release notes`_
+* `Release process`_
+
+If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:
+
+* `Issue tracking`_
+* `Discourse channel`_
+* `User IRC`_
+
+If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:
+
+* `GitHub page`_
+* `Development documentation`_
+* `Development IRC`_
+
+Code of Conduct
+---------------
+
+Everyone interacting in the pip project's codebases, issue trackers, chat
+rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.
+
+.. _package installer: https://packaging.python.org/guides/tool-recommendations/
+.. _Python Package Index: https://pypi.org
+.. _Installation: https://pip.pypa.io/en/stable/installation/
+.. _Usage: https://pip.pypa.io/en/stable/
+.. _Release notes: https://pip.pypa.io/en/stable/news.html
+.. _Release process: https://pip.pypa.io/en/latest/development/release-process/
+.. _GitHub page: https://github.com/pypa/pip
+.. _Development documentation: https://pip.pypa.io/en/latest/development
+.. _Issue tracking: https://github.com/pypa/pip/issues
+.. _Discourse channel: https://discuss.python.org/c/packaging
+.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa
+.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev
+.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md
diff --git a/lib/python3.12/site-packages/pip-25.0.1.dist-info/RECORD b/lib/python3.12/site-packages/pip-25.0.1.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..30109f8261b7a60b7f8addc879c955837f8746af
--- /dev/null
+++ b/lib/python3.12/site-packages/pip-25.0.1.dist-info/RECORD
@@ -0,0 +1,854 @@
+../../../bin/pip,sha256=DtWiF5XVBFx0GL9DgcTAnRKEChG_TADzYDEZLiZCMfQ,257
+../../../bin/pip3,sha256=DtWiF5XVBFx0GL9DgcTAnRKEChG_TADzYDEZLiZCMfQ,257
+../../../bin/pip3.12,sha256=DtWiF5XVBFx0GL9DgcTAnRKEChG_TADzYDEZLiZCMfQ,257
+pip-25.0.1.dist-info/AUTHORS.txt,sha256=HqzpBVLfT1lBthqQfiDlVeFkg65hJ7ZQvvWhoq-BAsA,11018
+pip-25.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+pip-25.0.1.dist-info/LICENSE.txt,sha256=Y0MApmnUmurmWxLGxIySTFGkzfPR_whtw0VtyLyqIQQ,1093
+pip-25.0.1.dist-info/METADATA,sha256=T6cxjPMPl523zsRcEsu8K0-IoV8S7vv1mmKR0KA6-SY,3677
+pip-25.0.1.dist-info/RECORD,,
+pip-25.0.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip-25.0.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
+pip-25.0.1.dist-info/entry_points.txt,sha256=eeIjuzfnfR2PrhbjnbzFU6MnSS70kZLxwaHHq6M-bD0,87
+pip-25.0.1.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+pip/__init__.py,sha256=aKiv_sTe7UbE7qmtCinJutFjqN0MndZQZ1fKLNwFFLE,357
+pip/__main__.py,sha256=WzbhHXTbSE6gBY19mNN9m4s5o_365LOvTYSgqgbdBhE,854
+pip/__pip-runner__.py,sha256=cPPWuJ6NK_k-GzfvlejLFgwzmYUROmpAR6QC3Q-vkXQ,1450
+pip/__pycache__/__init__.cpython-312.pyc,,
+pip/__pycache__/__main__.cpython-312.pyc,,
+pip/__pycache__/__pip-runner__.cpython-312.pyc,,
+pip/_internal/__init__.py,sha256=MfcoOluDZ8QMCFYal04IqOJ9q6m2V7a0aOsnI-WOxUo,513
+pip/_internal/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/__pycache__/build_env.cpython-312.pyc,,
+pip/_internal/__pycache__/cache.cpython-312.pyc,,
+pip/_internal/__pycache__/configuration.cpython-312.pyc,,
+pip/_internal/__pycache__/exceptions.cpython-312.pyc,,
+pip/_internal/__pycache__/main.cpython-312.pyc,,
+pip/_internal/__pycache__/pyproject.cpython-312.pyc,,
+pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc,,
+pip/_internal/__pycache__/wheel_builder.cpython-312.pyc,,
+pip/_internal/build_env.py,sha256=Dv4UCClSg4uNaal_hL-trg5-zl3Is9CuIDxkChCkXF4,10700
+pip/_internal/cache.py,sha256=Jb698p5PNigRtpW5o26wQNkkUv4MnQ94mc471wL63A0,10369
+pip/_internal/cli/__init__.py,sha256=FkHBgpxxb-_gd6r1FjnNhfMOzAUYyXoXKJ6abijfcFU,132
+pip/_internal/cli/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/base_command.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/command_context.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/index_command.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/main.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/parser.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/req_command.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/spinners.cpython-312.pyc,,
+pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc,,
+pip/_internal/cli/autocompletion.py,sha256=Lli3Mr6aDNu7ZkJJFFvwD2-hFxNI6Avz8OwMyS5TVrs,6865
+pip/_internal/cli/base_command.py,sha256=NZin6KMzW9NSYzKk4Tc8isb_TQYKR4CKd5j9mSm46PI,8625
+pip/_internal/cli/cmdoptions.py,sha256=V3BB22F4_v_RkHaZ5onWnszhbBtjYZvNhbn9M0NO0HI,30116
+pip/_internal/cli/command_context.py,sha256=RHgIPwtObh5KhMrd3YZTkl8zbVG-6Okml7YbFX4Ehg0,774
+pip/_internal/cli/index_command.py,sha256=i_sgNlPmXC5iHUaY-dmmrHKKTgc5O4hWzisr5Al1rr0,5677
+pip/_internal/cli/main.py,sha256=BDZef-bWe9g9Jpr4OVs4dDf-845HJsKw835T7AqEnAc,2817
+pip/_internal/cli/main_parser.py,sha256=laDpsuBDl6kyfywp9eMMA9s84jfH2TJJn-vmL0GG90w,4338
+pip/_internal/cli/parser.py,sha256=VCMtduzECUV87KaHNu-xJ-wLNL82yT3x16V4XBxOAqI,10825
+pip/_internal/cli/progress_bars.py,sha256=9GcgusWtwfqou2zhAQp1XNbQHIDslqyyz9UwLzw7Jgc,2717
+pip/_internal/cli/req_command.py,sha256=DqeFhmUMs6o6Ev8qawAcOoYNdAZsfyKS0MZI5jsJYwQ,12250
+pip/_internal/cli/spinners.py,sha256=hIJ83GerdFgFCdobIA23Jggetegl_uC4Sp586nzFbPE,5118
+pip/_internal/cli/status_codes.py,sha256=sEFHUaUJbqv8iArL3HAtcztWZmGOFX01hTesSytDEh0,116
+pip/_internal/commands/__init__.py,sha256=5oRO9O3dM2vGuh0bFw4HOVletryrz5HHMmmPWwJrH9U,3882
+pip/_internal/commands/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/cache.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/check.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/completion.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/configuration.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/debug.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/download.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/freeze.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/hash.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/help.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/index.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/inspect.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/install.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/list.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/search.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/show.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc,,
+pip/_internal/commands/__pycache__/wheel.cpython-312.pyc,,
+pip/_internal/commands/cache.py,sha256=IOezTicHjGE5sWdBx2nwPVgbjuJHM3s-BZEkpZLemuY,8107
+pip/_internal/commands/check.py,sha256=Hr_4eiMd9cgVDgEvjtIdw915NmL7ROIWW8enkr8slPQ,2268
+pip/_internal/commands/completion.py,sha256=HT4lD0bgsflHq2IDgYfiEdp7IGGtE7s6MgI3xn0VQEw,4287
+pip/_internal/commands/configuration.py,sha256=n98enwp6y0b5G6fiRQjaZo43FlJKYve_daMhN-4BRNc,9766
+pip/_internal/commands/debug.py,sha256=DNDRgE9YsKrbYzU0s3VKi8rHtKF4X13CJ_br_8PUXO0,6797
+pip/_internal/commands/download.py,sha256=0qB0nys6ZEPsog451lDsjL5Bx7Z97t-B80oFZKhpzKM,5273
+pip/_internal/commands/freeze.py,sha256=2Vt72BYTSm9rzue6d8dNzt8idxWK4Db6Hd-anq7GQ80,3203
+pip/_internal/commands/hash.py,sha256=EVVOuvGtoPEdFi8SNnmdqlCQrhCxV-kJsdwtdcCnXGQ,1703
+pip/_internal/commands/help.py,sha256=gcc6QDkcgHMOuAn5UxaZwAStsRBrnGSn_yxjS57JIoM,1132
+pip/_internal/commands/index.py,sha256=RAXxmJwFhVb5S1BYzb5ifX3sn9Na8v2CCVYwSMP8pao,4731
+pip/_internal/commands/inspect.py,sha256=PGrY9TRTRCM3y5Ml8Bdk8DEOXquWRfscr4DRo1LOTPc,3189
+pip/_internal/commands/install.py,sha256=r3yHQUxvxt7gD5j9n6zRDslAvtx9CT_whLuQJcktp6M,29390
+pip/_internal/commands/list.py,sha256=oiIzSjLP6__d7dIS3q0Xb5ywsaOThBWRqMyjjKzkPdM,12769
+pip/_internal/commands/search.py,sha256=fWkUQVx_gm8ebbFAlCgqtxKXT9rNahpJ-BI__3HNZpg,5626
+pip/_internal/commands/show.py,sha256=0YBhCga3PAd81vT3l7UWflktSpB5-aYqQcJxBVPazVM,7857
+pip/_internal/commands/uninstall.py,sha256=7pOR7enK76gimyxQbzxcG1OsyLXL3DvX939xmM8Fvtg,3892
+pip/_internal/commands/wheel.py,sha256=eJRhr_qoNNxWAkkdJCNiQM7CXd4E1_YyQhsqJnBPGGg,6414
+pip/_internal/configuration.py,sha256=-KOok6jh3hFzXMPQFPJ1_EFjBpAsge-RSreQuLHLmzo,14005
+pip/_internal/distributions/__init__.py,sha256=Hq6kt6gXBgjNit5hTTWLAzeCNOKoB-N0pGYSqehrli8,858
+pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/distributions/__pycache__/base.cpython-312.pyc,,
+pip/_internal/distributions/__pycache__/installed.cpython-312.pyc,,
+pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc,,
+pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc,,
+pip/_internal/distributions/base.py,sha256=QeB9qvKXDIjLdPBDE5fMgpfGqMMCr-govnuoQnGuiF8,1783
+pip/_internal/distributions/installed.py,sha256=QinHFbWAQ8oE0pbD8MFZWkwlnfU1QYTccA1vnhrlYOU,842
+pip/_internal/distributions/sdist.py,sha256=PlcP4a6-R6c98XnOM-b6Lkb3rsvh9iG4ok8shaanrzs,6751
+pip/_internal/distributions/wheel.py,sha256=THBYfnv7VVt8mYhMYUtH13S1E7FDwtDyDfmUcl8ai0E,1317
+pip/_internal/exceptions.py,sha256=2_byISIv3kSnI_9T-Esfxrt0LnTRgcUHyxu0twsHjQY,26481
+pip/_internal/index/__init__.py,sha256=vpt-JeTZefh8a-FC22ZeBSXFVbuBcXSGiILhQZJaNpQ,30
+pip/_internal/index/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/index/__pycache__/collector.cpython-312.pyc,,
+pip/_internal/index/__pycache__/package_finder.cpython-312.pyc,,
+pip/_internal/index/__pycache__/sources.cpython-312.pyc,,
+pip/_internal/index/collector.py,sha256=RdPO0JLAlmyBWPAWYHPyRoGjz3GNAeTngCNkbGey_mE,16265
+pip/_internal/index/package_finder.py,sha256=mJHAljlHeHuclyuxtjvBZO6DtovKjsZjF_tCh_wux5E,38076
+pip/_internal/index/sources.py,sha256=lPBLK5Xiy8Q6IQMio26Wl7ocfZOKkgGklIBNyUJ23fI,8632
+pip/_internal/locations/__init__.py,sha256=UaAxeZ_f93FyouuFf4p7SXYF-4WstXuEvd3LbmPCAno,14925
+pip/_internal/locations/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc,,
+pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc,,
+pip/_internal/locations/__pycache__/base.cpython-312.pyc,,
+pip/_internal/locations/_distutils.py,sha256=x6nyVLj7X11Y4khIdf-mFlxMl2FWadtVEgeb8upc_WI,6013
+pip/_internal/locations/_sysconfig.py,sha256=IGzds60qsFneRogC-oeBaY7bEh3lPt_v47kMJChQXsU,7724
+pip/_internal/locations/base.py,sha256=RQiPi1d4FVM2Bxk04dQhXZ2PqkeljEL2fZZ9SYqIQ78,2556
+pip/_internal/main.py,sha256=r-UnUe8HLo5XFJz8inTcOOTiu_sxNhgHb6VwlGUllOI,340
+pip/_internal/metadata/__init__.py,sha256=CU8jK1TZso7jOLdr0sX9xDjrcs5iy8d7IRK-hvaIO5Y,4337
+pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/metadata/__pycache__/_json.cpython-312.pyc,,
+pip/_internal/metadata/__pycache__/base.cpython-312.pyc,,
+pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc,,
+pip/_internal/metadata/_json.py,sha256=ezrIYazHCINM2QUk1eA9wEAMj3aeGWeDVgGalgUzKpc,2707
+pip/_internal/metadata/base.py,sha256=ft0K5XNgI4ETqZnRv2-CtvgYiMOMAeGMAzxT-f6VLJA,25298
+pip/_internal/metadata/importlib/__init__.py,sha256=jUUidoxnHcfITHHaAWG1G2i5fdBYklv_uJcjo2x7VYE,135
+pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc,,
+pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc,,
+pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc,,
+pip/_internal/metadata/importlib/_compat.py,sha256=c6av8sP8BBjAZuFSJow1iWfygUXNM3xRTCn5nqw6B9M,2796
+pip/_internal/metadata/importlib/_dists.py,sha256=ftmYiyfUGUIjnVwt6W-Ijsimy5c28KgmXly5Q5IQ2P4,8279
+pip/_internal/metadata/importlib/_envs.py,sha256=UUB980XSrDWrMpQ1_G45i0r8Hqlg_tg3IPQ63mEqbNc,7431
+pip/_internal/metadata/pkg_resources.py,sha256=U07ETAINSGeSRBfWUG93E4tZZbaW_f7PGzEqZN0hulc,10542
+pip/_internal/models/__init__.py,sha256=3DHUd_qxpPozfzouoqa9g9ts1Czr5qaHfFxbnxriepM,63
+pip/_internal/models/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/models/__pycache__/candidate.cpython-312.pyc,,
+pip/_internal/models/__pycache__/direct_url.cpython-312.pyc,,
+pip/_internal/models/__pycache__/format_control.cpython-312.pyc,,
+pip/_internal/models/__pycache__/index.cpython-312.pyc,,
+pip/_internal/models/__pycache__/installation_report.cpython-312.pyc,,
+pip/_internal/models/__pycache__/link.cpython-312.pyc,,
+pip/_internal/models/__pycache__/scheme.cpython-312.pyc,,
+pip/_internal/models/__pycache__/search_scope.cpython-312.pyc,,
+pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc,,
+pip/_internal/models/__pycache__/target_python.cpython-312.pyc,,
+pip/_internal/models/__pycache__/wheel.cpython-312.pyc,,
+pip/_internal/models/candidate.py,sha256=zzgFRuw_kWPjKpGw7LC0ZUMD2CQ2EberUIYs8izjdCA,753
+pip/_internal/models/direct_url.py,sha256=uBtY2HHd3TO9cKQJWh0ThvE5FRr-MWRYChRU4IG9HZE,6578
+pip/_internal/models/format_control.py,sha256=wtsQqSK9HaUiNxQEuB-C62eVimw6G4_VQFxV9-_KDBE,2486
+pip/_internal/models/index.py,sha256=tYnL8oxGi4aSNWur0mG8DAP7rC6yuha_MwJO8xw0crI,1030
+pip/_internal/models/installation_report.py,sha256=zRVZoaz-2vsrezj_H3hLOhMZCK9c7TbzWgC-jOalD00,2818
+pip/_internal/models/link.py,sha256=GQ8hq7x-FDFPv25Nbn2veIM-MlBrGZDGLd7aZeF4Xrg,21448
+pip/_internal/models/scheme.py,sha256=PakmHJM3e8OOWSZFtfz1Az7f1meONJnkGuQxFlt3wBE,575
+pip/_internal/models/search_scope.py,sha256=67NEnsYY84784S-MM7ekQuo9KXLH-7MzFntXjapvAo0,4531
+pip/_internal/models/selection_prefs.py,sha256=qaFfDs3ciqoXPg6xx45N1jPLqccLJw4N0s4P0PyHTQ8,2015
+pip/_internal/models/target_python.py,sha256=2XaH2rZ5ZF-K5wcJbEMGEl7SqrTToDDNkrtQ2v_v_-Q,4271
+pip/_internal/models/wheel.py,sha256=G7dND_s4ebPkEL7RJ1qCY0QhUUWIIK6AnjWgRATF5no,4539
+pip/_internal/network/__init__.py,sha256=jf6Tt5nV_7zkARBrKojIXItgejvoegVJVKUbhAa5Ioc,50
+pip/_internal/network/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/network/__pycache__/auth.cpython-312.pyc,,
+pip/_internal/network/__pycache__/cache.cpython-312.pyc,,
+pip/_internal/network/__pycache__/download.cpython-312.pyc,,
+pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc,,
+pip/_internal/network/__pycache__/session.cpython-312.pyc,,
+pip/_internal/network/__pycache__/utils.cpython-312.pyc,,
+pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc,,
+pip/_internal/network/auth.py,sha256=D4gASjUrqoDFlSt6gQ767KAAjv6PUyJU0puDlhXNVRE,20809
+pip/_internal/network/cache.py,sha256=0yGMA3Eet59xBSLtbPAenvI53dl29oUOeqZ2c0QL2Ss,4614
+pip/_internal/network/download.py,sha256=FLOP29dPYECBiAi7eEjvAbNkyzaKNqbyjOT2m8HPW8U,6048
+pip/_internal/network/lazy_wheel.py,sha256=PBdoMoNQQIA84Fhgne38jWF52W4x_KtsHjxgv4dkRKA,7622
+pip/_internal/network/session.py,sha256=msM4es16LmmNEYNkrYyg8fTc7gAHbKFltawfKP27LOI,18771
+pip/_internal/network/utils.py,sha256=Inaxel-NxBu4PQWkjyErdnfewsFCcgHph7dzR1-FboY,4088
+pip/_internal/network/xmlrpc.py,sha256=sAxzOacJ-N1NXGPvap9jC3zuYWSnnv3GXtgR2-E2APA,1838
+pip/_internal/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_internal/operations/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/operations/__pycache__/check.cpython-312.pyc,,
+pip/_internal/operations/__pycache__/freeze.cpython-312.pyc,,
+pip/_internal/operations/__pycache__/prepare.cpython-312.pyc,,
+pip/_internal/operations/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc,,
+pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc,,
+pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc,,
+pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc,,
+pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc,,
+pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc,,
+pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc,,
+pip/_internal/operations/build/build_tracker.py,sha256=-ARW_TcjHCOX7D2NUOGntB4Fgc6b4aolsXkAK6BWL7w,4774
+pip/_internal/operations/build/metadata.py,sha256=9S0CUD8U3QqZeXp-Zyt8HxwU90lE4QrnYDgrqZDzBnc,1422
+pip/_internal/operations/build/metadata_editable.py,sha256=xlAwcP9q_8_fmv_3I39w9EZ7SQV9hnJZr9VuTsq2Y68,1510
+pip/_internal/operations/build/metadata_legacy.py,sha256=8i6i1QZX9m_lKPStEFsHKM0MT4a-CD408JOw99daLmo,2190
+pip/_internal/operations/build/wheel.py,sha256=sT12FBLAxDC6wyrDorh8kvcZ1jG5qInCRWzzP-UkJiQ,1075
+pip/_internal/operations/build/wheel_editable.py,sha256=yOtoH6zpAkoKYEUtr8FhzrYnkNHQaQBjWQ2HYae1MQg,1417
+pip/_internal/operations/build/wheel_legacy.py,sha256=K-6kNhmj-1xDF45ny1yheMerF0ui4EoQCLzEoHh6-tc,3045
+pip/_internal/operations/check.py,sha256=L24vRL8VWbyywdoeAhM89WCd8zLTnjIbULlKelUgIec,5912
+pip/_internal/operations/freeze.py,sha256=1_M79jAQKnCxWr-KCCmHuVXOVFGaUJHmoWLfFzgh7K4,9843
+pip/_internal/operations/install/__init__.py,sha256=mX7hyD2GNBO2mFGokDQ30r_GXv7Y_PLdtxcUv144e-s,51
+pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc,,
+pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc,,
+pip/_internal/operations/install/editable_legacy.py,sha256=PoEsNEPGbIZ2yQphPsmYTKLOCMs4gv5OcCdzW124NcA,1283
+pip/_internal/operations/install/wheel.py,sha256=X5Iz9yUg5LlK5VNQ9g2ikc6dcRu8EPi_SUi5iuEDRgo,27615
+pip/_internal/operations/prepare.py,sha256=joWJwPkuqGscQgVNImLK71e9hRapwKvRCM8HclysmvU,28118
+pip/_internal/pyproject.py,sha256=GLJ6rWRS5_2noKdajohoLyDty57Z7QXhcUAYghmTnWc,7286
+pip/_internal/req/__init__.py,sha256=HxBFtZy_BbCclLgr26waMtpzYdO5T3vxePvpGAXSt5s,2653
+pip/_internal/req/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/req/__pycache__/constructors.cpython-312.pyc,,
+pip/_internal/req/__pycache__/req_file.cpython-312.pyc,,
+pip/_internal/req/__pycache__/req_install.cpython-312.pyc,,
+pip/_internal/req/__pycache__/req_set.cpython-312.pyc,,
+pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc,,
+pip/_internal/req/constructors.py,sha256=v1qzCN1mIldwx-nCrPc8JO4lxkm3Fv8M5RWvt8LISjc,18430
+pip/_internal/req/req_file.py,sha256=eys82McgaICOGic2UZRHjD720piKJPwmeSYdXlWwl6w,20234
+pip/_internal/req/req_install.py,sha256=BMptxHYg2uG_b-7HFEULPb3nuw0FMAbuea8zTq2rE7w,35786
+pip/_internal/req/req_set.py,sha256=j3esG0s6SzoVReX9rWn4rpYNtyET_fwxbwJPRimvRxo,2858
+pip/_internal/req/req_uninstall.py,sha256=qzDIxJo-OETWqGais7tSMCDcWbATYABT-Tid3ityF0s,23853
+pip/_internal/resolution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/resolution/__pycache__/base.cpython-312.pyc,,
+pip/_internal/resolution/base.py,sha256=qlmh325SBVfvG6Me9gc5Nsh5sdwHBwzHBq6aEXtKsLA,583
+pip/_internal/resolution/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc,,
+pip/_internal/resolution/legacy/resolver.py,sha256=3HZiJBRd1FTN6jQpI4qRO8-TbLYeIbUTS6PFvXnXs2w,24068
+pip/_internal/resolution/resolvelib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc,,
+pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc,,
+pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc,,
+pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc,,
+pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc,,
+pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc,,
+pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc,,
+pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc,,
+pip/_internal/resolution/resolvelib/base.py,sha256=DCf669FsqyQY5uqXeePDHQY1e4QO-pBzWH8O0s9-K94,5023
+pip/_internal/resolution/resolvelib/candidates.py,sha256=5UZ1upNnmqsP-nmEZaDYxaBgCoejw_e2WVGmmAvBxXc,20001
+pip/_internal/resolution/resolvelib/factory.py,sha256=MJOLSZJY8_28PPdcutoQ6gjJ_1eBDt6Z1edtfTJyR4E,32659
+pip/_internal/resolution/resolvelib/found_candidates.py,sha256=9hrTyQqFvl9I7Tji79F1AxHv39Qh1rkJ_7deSHSMfQc,6383
+pip/_internal/resolution/resolvelib/provider.py,sha256=bcsFnYvlmtB80cwVdW1fIwgol8ZNr1f1VHyRTkz47SM,9935
+pip/_internal/resolution/resolvelib/reporter.py,sha256=00JtoXEkTlw0-rl_sl54d71avwOsJHt9GGHcrj5Sza0,3168
+pip/_internal/resolution/resolvelib/requirements.py,sha256=7JG4Z72e5Yk4vU0S5ulGvbqTy4FMQGYhY5zQhX9zTtY,8065
+pip/_internal/resolution/resolvelib/resolver.py,sha256=nLJOsVMEVi2gQUVJoUFKMZAeu2f7GRMjGMvNSWyz0Bc,12592
+pip/_internal/self_outdated_check.py,sha256=1PFtttvLAeyCVR3tPoBq2sOlPD0IJ-KSqU6bc1HUk9c,8318
+pip/_internal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_internal/utils/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/_log.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/compat.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/datetime.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/glibc.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/hashes.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/logging.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/misc.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/packaging.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/retry.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/urls.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc,,
+pip/_internal/utils/__pycache__/wheel.cpython-312.pyc,,
+pip/_internal/utils/_jaraco_text.py,sha256=M15uUPIh5NpP1tdUGBxRau6q1ZAEtI8-XyLEETscFfE,3350
+pip/_internal/utils/_log.py,sha256=-jHLOE_THaZz5BFcCnoSL9EYAtJ0nXem49s9of4jvKw,1015
+pip/_internal/utils/appdirs.py,sha256=swgcTKOm3daLeXTW6v5BUS2Ti2RvEnGRQYH_yDXklAo,1665
+pip/_internal/utils/compat.py,sha256=ckkFveBiYQjRWjkNsajt_oWPS57tJvE8XxoC4OIYgCY,2399
+pip/_internal/utils/compatibility_tags.py,sha256=OWq5axHpW-MEEPztGdvgADrgJPAcV9a88Rxm4Z8VBs8,6272
+pip/_internal/utils/datetime.py,sha256=m21Y3wAtQc-ji6Veb6k_M5g6A0ZyFI4egchTdnwh-pQ,242
+pip/_internal/utils/deprecation.py,sha256=k7Qg_UBAaaTdyq82YVARA6D7RmcGTXGv7fnfcgigj4Q,3707
+pip/_internal/utils/direct_url_helpers.py,sha256=r2MRtkVDACv9AGqYODBUC9CjwgtsUU1s68hmgfCJMtA,3196
+pip/_internal/utils/egg_link.py,sha256=0FePZoUYKv4RGQ2t6x7w5Z427wbA_Uo3WZnAkrgsuqo,2463
+pip/_internal/utils/entrypoints.py,sha256=YlhLTRl2oHBAuqhc-zmL7USS67TPWVHImjeAQHreZTQ,3064
+pip/_internal/utils/filesystem.py,sha256=ajvA-q4ocliW9kPp8Yquh-4vssXbu-UKbo5FV9V4X64,4950
+pip/_internal/utils/filetypes.py,sha256=i8XAQ0eFCog26Fw9yV0Yb1ygAqKYB1w9Cz9n0fj8gZU,716
+pip/_internal/utils/glibc.py,sha256=vUkWq_1pJuzcYNcGKLlQmABoUiisK8noYY1yc8Wq4w4,3734
+pip/_internal/utils/hashes.py,sha256=XGGLL0AG8-RhWnyz87xF6MFZ--BKadHU35D47eApCKI,4972
+pip/_internal/utils/logging.py,sha256=ONfbrhaD248akkosK79if97n20EABxwjOxp5dE5RCRY,11845
+pip/_internal/utils/misc.py,sha256=DWnYxBUItjRp7hhxEg4ih6P6YpKrykM86dbi_EcU8SQ,23450
+pip/_internal/utils/packaging.py,sha256=cm-X_0HVHV_jRwUVZh6AuEWqSitzf8EpaJ7Uv2UGu6A,2142
+pip/_internal/utils/retry.py,sha256=mhFbykXjhTnZfgzeuy-vl9c8nECnYn_CMtwNJX2tYzQ,1392
+pip/_internal/utils/setuptools_build.py,sha256=ouXpud-jeS8xPyTPsXJ-m34NPvK5os45otAzdSV_IJE,4435
+pip/_internal/utils/subprocess.py,sha256=EsvqSRiSMHF98T8Txmu6NLU3U--MpTTQjtNgKP0P--M,8988
+pip/_internal/utils/temp_dir.py,sha256=5qOXe8M4JeY6vaFQM867d5zkp1bSwMZ-KT5jymmP0Zg,9310
+pip/_internal/utils/unpacking.py,sha256=_gVdyzTRDMYktpnYljn4OoxrZTtMCf4xknSm4rK0WaA,11967
+pip/_internal/utils/urls.py,sha256=qceSOZb5lbNDrHNsv7_S4L4Ytszja5NwPKUMnZHbYnM,1599
+pip/_internal/utils/virtualenv.py,sha256=S6f7csYorRpiD6cvn3jISZYc3I8PJC43H5iMFpRAEDU,3456
+pip/_internal/utils/wheel.py,sha256=b442jkydFHjXzDy6cMR7MpzWBJ1Q82hR5F33cmcHV3g,4494
+pip/_internal/vcs/__init__.py,sha256=UAqvzpbi0VbZo3Ub6skEeZAw-ooIZR-zX_WpCbxyCoU,596
+pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc,,
+pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc,,
+pip/_internal/vcs/__pycache__/git.cpython-312.pyc,,
+pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc,,
+pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc,,
+pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc,,
+pip/_internal/vcs/bazaar.py,sha256=EKStcQaKpNu0NK4p5Q10Oc4xb3DUxFw024XrJy40bFQ,3528
+pip/_internal/vcs/git.py,sha256=3tpc9LQA_J4IVW5r5NvWaaSeDzcmJOrSFZN0J8vIKfU,18177
+pip/_internal/vcs/mercurial.py,sha256=oULOhzJ2Uie-06d1omkL-_Gc6meGaUkyogvqG9ZCyPs,5249
+pip/_internal/vcs/subversion.py,sha256=ddTugHBqHzV3ebKlU5QXHPN4gUqlyXbOx8q8NgXKvs8,11735
+pip/_internal/vcs/versioncontrol.py,sha256=cvf_-hnTAjQLXJ3d17FMNhQfcO1AcKWUF10tfrYyP-c,22440
+pip/_internal/wheel_builder.py,sha256=DL3A8LKeRj_ACp11WS5wSgASgPFqeyAeXJKdXfmaWXU,11799
+pip/_vendor/__init__.py,sha256=JYuAXvClhInxIrA2FTp5p-uuWVL7WV6-vEpTs46-Qh4,4873
+pip/_vendor/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc,,
+pip/_vendor/cachecontrol/__init__.py,sha256=LMC5CBe94ZRL5xhlzwyPDmHXvBD0p7lT4R3Z73D6a_I,677
+pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc,,
+pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc,,
+pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc,,
+pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc,,
+pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc,,
+pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc,,
+pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc,,
+pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc,,
+pip/_vendor/cachecontrol/_cmd.py,sha256=iist2EpzJvDVIhMAxXq8iFnTBsiZAd6iplxfmNboNyk,1737
+pip/_vendor/cachecontrol/adapter.py,sha256=febjY4LV87iiCIK3jcl8iH58iaSA7b9WkovsByIDK0Y,6348
+pip/_vendor/cachecontrol/cache.py,sha256=OXwv7Fn2AwnKNiahJHnjtvaKLndvVLv_-zO-ltlV9qI,1953
+pip/_vendor/cachecontrol/caches/__init__.py,sha256=dtrrroK5BnADR1GWjCZ19aZ0tFsMfvFBtLQQU1sp_ag,303
+pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc,,
+pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc,,
+pip/_vendor/cachecontrol/caches/file_cache.py,sha256=b7oMgsRSqPmEsonVJw6uFEYUlFgD6GF8TyacOGG1x3M,5399
+pip/_vendor/cachecontrol/caches/redis_cache.py,sha256=9rmqwtYu_ljVkW6_oLqbC7EaX_a8YT_yLuna-eS0dgo,1386
+pip/_vendor/cachecontrol/controller.py,sha256=glbPj2iZlGqdBg8z09D2DtQOzoOGXnWvy7K2LEyBsEQ,18576
+pip/_vendor/cachecontrol/filewrapper.py,sha256=2ktXNPE0KqnyzF24aOsKCA58HQq1xeC6l2g6_zwjghc,4291
+pip/_vendor/cachecontrol/heuristics.py,sha256=gqMXU8w0gQuEQiSdu3Yg-0vd9kW7nrWKbLca75rheGE,4881
+pip/_vendor/cachecontrol/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/cachecontrol/serialize.py,sha256=HQd2IllQ05HzPkVLMXTF2uX5mjEQjDBkxCqUJUODpZk,5163
+pip/_vendor/cachecontrol/wrapper.py,sha256=hsGc7g8QGQTT-4f8tgz3AM5qwScg6FO0BSdLSRdEvpU,1417
+pip/_vendor/certifi/__init__.py,sha256=p_GYZrjUwPBUhpLlCZoGb0miKBKSqDAyZC5DvIuqbHQ,94
+pip/_vendor/certifi/__main__.py,sha256=1k3Cr95vCxxGRGDljrW3wMdpZdL3Nhf0u1n-k2qdsCY,255
+pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc,,
+pip/_vendor/certifi/__pycache__/core.cpython-312.pyc,,
+pip/_vendor/certifi/cacert.pem,sha256=lO3rZukXdPyuk6BWUJFOKQliWaXH6HGh9l1GGrUgG0c,299427
+pip/_vendor/certifi/core.py,sha256=2SRT5rIcQChFDbe37BQa-kULxAgJ8qN6l1jfqTp4HIs,4486
+pip/_vendor/certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/distlib/__init__.py,sha256=dcwgYGYGQqAEawBXPDtIx80DO_3cOmFv8HTc8JMzknQ,625
+pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/database.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/index.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/util.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/version.cpython-312.pyc,,
+pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc,,
+pip/_vendor/distlib/compat.py,sha256=2jRSjRI4o-vlXeTK2BCGIUhkc6e9ZGhSsacRM5oseTw,41467
+pip/_vendor/distlib/database.py,sha256=mHy_LxiXIsIVRb-T0-idBrVLw3Ffij5teHCpbjmJ9YU,51160
+pip/_vendor/distlib/index.py,sha256=lTbw268rRhj8dw1sib3VZ_0EhSGgoJO3FKJzSFMOaeA,20797
+pip/_vendor/distlib/locators.py,sha256=oBeAZpFuPQSY09MgNnLfQGGAXXvVO96BFpZyKMuK4tM,51026
+pip/_vendor/distlib/manifest.py,sha256=3qfmAmVwxRqU1o23AlfXrQGZzh6g_GGzTAP_Hb9C5zQ,14168
+pip/_vendor/distlib/markers.py,sha256=X6sDvkFGcYS8gUW8hfsWuKEKAqhQZAJ7iXOMLxRYjYk,5164
+pip/_vendor/distlib/metadata.py,sha256=zil3sg2EUfLXVigljY2d_03IJt-JSs7nX-73fECMX2s,38724
+pip/_vendor/distlib/resources.py,sha256=LwbPksc0A1JMbi6XnuPdMBUn83X7BPuFNWqPGEKI698,10820
+pip/_vendor/distlib/scripts.py,sha256=BJliaDAZaVB7WAkwokgC3HXwLD2iWiHaVI50H7C6eG8,18608
+pip/_vendor/distlib/t32.exe,sha256=a0GV5kCoWsMutvliiCKmIgV98eRZ33wXoS-XrqvJQVs,97792
+pip/_vendor/distlib/t64-arm.exe,sha256=68TAa32V504xVBnufojh0PcenpR3U4wAqTqf-MZqbPw,182784
+pip/_vendor/distlib/t64.exe,sha256=gaYY8hy4fbkHYTTnA4i26ct8IQZzkBG2pRdy0iyuBrc,108032
+pip/_vendor/distlib/util.py,sha256=vMPGvsS4j9hF6Y9k3Tyom1aaHLb0rFmZAEyzeAdel9w,66682
+pip/_vendor/distlib/version.py,sha256=s5VIs8wBn0fxzGxWM_aA2ZZyx525HcZbMvcTlTyZ3Rg,23727
+pip/_vendor/distlib/w32.exe,sha256=R4csx3-OGM9kL4aPIzQKRo5TfmRSHZo6QWyLhDhNBks,91648
+pip/_vendor/distlib/w64-arm.exe,sha256=xdyYhKj0WDcVUOCb05blQYvzdYIKMbmJn2SZvzkcey4,168448
+pip/_vendor/distlib/w64.exe,sha256=ejGf-rojoBfXseGLpya6bFTFPWRG21X5KvU8J5iU-K0,101888
+pip/_vendor/distlib/wheel.py,sha256=DFIVguEQHCdxnSdAO0dfFsgMcvVZitg7bCOuLwZ7A_s,43979
+pip/_vendor/distro/__init__.py,sha256=2fHjF-SfgPvjyNZ1iHh_wjqWdR_Yo5ODHwZC0jLBPhc,981
+pip/_vendor/distro/__main__.py,sha256=bu9d3TifoKciZFcqRBuygV3GSuThnVD_m2IK4cz96Vs,64
+pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc,,
+pip/_vendor/distro/__pycache__/distro.cpython-312.pyc,,
+pip/_vendor/distro/distro.py,sha256=XqbefacAhDT4zr_trnbA15eY8vdK4GTghgmvUGrEM_4,49430
+pip/_vendor/distro/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/idna/__init__.py,sha256=MPqNDLZbXqGaNdXxAFhiqFPKEQXju2jNQhCey6-5eJM,868
+pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/idna/__pycache__/codec.cpython-312.pyc,,
+pip/_vendor/idna/__pycache__/compat.cpython-312.pyc,,
+pip/_vendor/idna/__pycache__/core.cpython-312.pyc,,
+pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc,,
+pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc,,
+pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc,,
+pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc,,
+pip/_vendor/idna/codec.py,sha256=PEew3ItwzjW4hymbasnty2N2OXvNcgHB-JjrBuxHPYY,3422
+pip/_vendor/idna/compat.py,sha256=RzLy6QQCdl9784aFhb2EX9EKGCJjg0P3PilGdeXXcx8,316
+pip/_vendor/idna/core.py,sha256=YJYyAMnwiQEPjVC4-Fqu_p4CJ6yKKuDGmppBNQNQpFs,13239
+pip/_vendor/idna/idnadata.py,sha256=W30GcIGvtOWYwAjZj4ZjuouUutC6ffgNuyjJy7fZ-lo,78306
+pip/_vendor/idna/intranges.py,sha256=amUtkdhYcQG8Zr-CoMM_kVRacxkivC1WgxN1b63KKdU,1898
+pip/_vendor/idna/package_data.py,sha256=q59S3OXsc5VI8j6vSD0sGBMyk6zZ4vWFREE88yCJYKs,21
+pip/_vendor/idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/idna/uts46data.py,sha256=rt90K9J40gUSwppDPCrhjgi5AA6pWM65dEGRSf6rIhM,239289
+pip/_vendor/msgpack/__init__.py,sha256=reRaiOtEzSjPnr7TpxjgIvbfln5pV66FhricAs2eC-g,1109
+pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc,,
+pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc,,
+pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc,,
+pip/_vendor/msgpack/exceptions.py,sha256=dCTWei8dpkrMsQDcjQk74ATl9HsIBH0ybt8zOPNqMYc,1081
+pip/_vendor/msgpack/ext.py,sha256=kteJv03n9tYzd5oo3xYopVTo4vRaAxonBQQJhXohZZo,5726
+pip/_vendor/msgpack/fallback.py,sha256=0g1Pzp0vtmBEmJ5w9F3s_-JMVURP8RS4G1cc5TRaAsI,32390
+pip/_vendor/packaging/__init__.py,sha256=dk4Ta_vmdVJxYHDcfyhvQNw8V3PgSBomKNXqg-D2JDY,494
+pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/_elffile.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/_parser.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/_tokenizer.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/metadata.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc,,
+pip/_vendor/packaging/__pycache__/version.cpython-312.pyc,,
+pip/_vendor/packaging/_elffile.py,sha256=cflAQAkE25tzhYmq_aCi72QfbT_tn891tPzfpbeHOwE,3306
+pip/_vendor/packaging/_manylinux.py,sha256=vl5OCoz4kx80H5rwXKeXWjl9WNISGmr4ZgTpTP9lU9c,9612
+pip/_vendor/packaging/_musllinux.py,sha256=p9ZqNYiOItGee8KcZFeHF_YcdhVwGHdK6r-8lgixvGQ,2694
+pip/_vendor/packaging/_parser.py,sha256=s_TvTvDNK0NrM2QB3VKThdWFM4Nc0P6JnkObkl3MjpM,10236
+pip/_vendor/packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431
+pip/_vendor/packaging/_tokenizer.py,sha256=J6v5H7Jzvb-g81xp_2QACKwO7LxHQA6ikryMU7zXwN8,5273
+pip/_vendor/packaging/licenses/__init__.py,sha256=A116-FU49_Dz4162M4y1uAiZN4Rgdc83FxNd8EjlfqI,5727
+pip/_vendor/packaging/licenses/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/packaging/licenses/__pycache__/_spdx.cpython-312.pyc,,
+pip/_vendor/packaging/licenses/_spdx.py,sha256=oAm1ztPFwlsmCKe7lAAsv_OIOfS1cWDu9bNBkeu-2ns,48398
+pip/_vendor/packaging/markers.py,sha256=c89TNzB7ZdGYhkovm6PYmqGyHxXlYVaLW591PHUNKD8,10561
+pip/_vendor/packaging/metadata.py,sha256=YJibM7GYe4re8-0a3OlXmGS-XDgTEoO4tlBt2q25Bng,34762
+pip/_vendor/packaging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/packaging/requirements.py,sha256=gYyRSAdbrIyKDY66ugIDUQjRMvxkH2ALioTmX3tnL6o,2947
+pip/_vendor/packaging/specifiers.py,sha256=hGU6kuCd77bL-msIL6yLCp6MNT75RSMUKZDuju26c8U,40098
+pip/_vendor/packaging/tags.py,sha256=CFqrJzAzc2XNGexerH__T-Y5Iwq7WbsYXsiLERLWxY0,21014
+pip/_vendor/packaging/utils.py,sha256=0F3Hh9OFuRgrhTgGZUl5K22Fv1YP2tZl1z_2gO6kJiA,5050
+pip/_vendor/packaging/version.py,sha256=oiHqzTUv_p12hpjgsLDVcaF5hT7pDaSOViUNMD4GTW0,16688
+pip/_vendor/pkg_resources/__init__.py,sha256=jrhDRbOubP74QuPXxd7U7Po42PH2l-LZ2XfcO7llpZ4,124463
+pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/platformdirs/__init__.py,sha256=JueR2cRLkxY7iwik-qNWJCwKOrAlBgVgcZ_IHQzqGLE,22344
+pip/_vendor/platformdirs/__main__.py,sha256=jBJ8zb7Mpx5ebcqF83xrpO94MaeCpNGHVf9cvDN2JLg,1505
+pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc,,
+pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc,,
+pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc,,
+pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc,,
+pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc,,
+pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc,,
+pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc,,
+pip/_vendor/platformdirs/android.py,sha256=kV5oL3V3DZ6WZKu9yFiQupv18yp_jlSV2ChH1TmPcds,9007
+pip/_vendor/platformdirs/api.py,sha256=2dfUDNbEXeDhDKarqtR5NY7oUikUZ4RZhs3ozstmhBQ,9246
+pip/_vendor/platformdirs/macos.py,sha256=UlbyFZ8Rzu3xndCqQEHrfsYTeHwYdFap1Ioz-yxveT4,6154
+pip/_vendor/platformdirs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/platformdirs/unix.py,sha256=uRPJWRyQEtv7yOSvU94rUmsblo5XKDLA1SzFg55kbK0,10393
+pip/_vendor/platformdirs/version.py,sha256=oH4KgTfK4AklbTYVcV_yynvJ9JLI3pyvDVay0hRsLCs,411
+pip/_vendor/platformdirs/windows.py,sha256=IFpiohUBwxPtCzlyKwNtxyW4Jk8haa6W8o59mfrDXVo,10125
+pip/_vendor/pygments/__init__.py,sha256=7N1oiaWulw_nCsTY4EEixYLz15pWY5u4uPAFFi-ielU,2983
+pip/_vendor/pygments/__main__.py,sha256=isIhBxLg65nLlXukG4VkMuPfNdd7gFzTZ_R_z3Q8diY,353
+pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/console.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/style.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/token.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc,,
+pip/_vendor/pygments/__pycache__/util.cpython-312.pyc,,
+pip/_vendor/pygments/cmdline.py,sha256=LIVzmAunlk9sRJJp54O4KRy9GDIN4Wu13v9p9QzfGPM,23656
+pip/_vendor/pygments/console.py,sha256=yhP9UsLAVmWKVQf2446JJewkA7AiXeeTf4Ieg3Oi2fU,1718
+pip/_vendor/pygments/filter.py,sha256=_ADNPCskD8_GmodHi6_LoVgPU3Zh336aBCT5cOeTMs0,1910
+pip/_vendor/pygments/filters/__init__.py,sha256=RdedK2KWKXlKwR7cvkfr3NUj9YiZQgMgilRMFUg2jPA,40392
+pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/pygments/formatter.py,sha256=jDWBTndlBH2Z5IYZFVDnP0qn1CaTQjTWt7iAGtCnJEg,4390
+pip/_vendor/pygments/formatters/__init__.py,sha256=8No-NUs8rBTSSBJIv4hSEQt2M0cFB4hwAT0snVc2QGE,5385
+pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc,,
+pip/_vendor/pygments/formatters/_mapping.py,sha256=1Cw37FuQlNacnxRKmtlPX4nyLoX9_ttko5ZwscNUZZ4,4176
+pip/_vendor/pygments/formatters/bbcode.py,sha256=3JQLI45tcrQ_kRUMjuab6C7Hb0XUsbVWqqbSn9cMjkI,3320
+pip/_vendor/pygments/formatters/groff.py,sha256=M39k0PaSSZRnxWjqBSVPkF0mu1-Vr7bm6RsFvs-CNN4,5106
+pip/_vendor/pygments/formatters/html.py,sha256=SE2jc3YCqbMS3rZW9EAmDlAUhdVxJ52gA4dileEvCGU,35669
+pip/_vendor/pygments/formatters/img.py,sha256=MwA4xWPLOwh6j7Yc6oHzjuqSPt0M1fh5r-5BTIIUfsU,23287
+pip/_vendor/pygments/formatters/irc.py,sha256=dp1Z0l_ObJ5NFh9MhqLGg5ptG5hgJqedT2Vkutt9v0M,4981
+pip/_vendor/pygments/formatters/latex.py,sha256=XMmhOCqUKDBQtG5mGJNAFYxApqaC5puo5cMmPfK3944,19306
+pip/_vendor/pygments/formatters/other.py,sha256=56PMJOliin-rAUdnRM0i1wsV1GdUPd_dvQq0_UPfF9c,5034
+pip/_vendor/pygments/formatters/pangomarkup.py,sha256=y16U00aVYYEFpeCfGXlYBSMacG425CbfoG8oKbKegIg,2218
+pip/_vendor/pygments/formatters/rtf.py,sha256=ZT90dmcKyJboIB0mArhL7IhE467GXRN0G7QAUgG03To,11957
+pip/_vendor/pygments/formatters/svg.py,sha256=KKsiophPupHuxm0So-MsbQEWOT54IAiSF7hZPmxtKXE,7174
+pip/_vendor/pygments/formatters/terminal.py,sha256=AojNG4MlKq2L6IsC_VnXHu4AbHCBn9Otog6u45XvxeI,4674
+pip/_vendor/pygments/formatters/terminal256.py,sha256=kGkNUVo3FpwjytIDS0if79EuUoroAprcWt3igrcIqT0,11753
+pip/_vendor/pygments/lexer.py,sha256=TYHDt___gNW4axTl2zvPZff-VQi8fPaIh5OKRcVSjUM,35349
+pip/_vendor/pygments/lexers/__init__.py,sha256=pIlxyQJuu_syh9lE080cq8ceVbEVcKp0osAFU5fawJU,12115
+pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc,,
+pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc,,
+pip/_vendor/pygments/lexers/_mapping.py,sha256=61-h3zr103m01OS5BUq_AfUiL9YI06Ves9ipQ7k4vr4,76097
+pip/_vendor/pygments/lexers/python.py,sha256=2J_YJrPTr_A6fJY_qKiKv0GpgPwHMrlMSeo59qN3fe4,53687
+pip/_vendor/pygments/modeline.py,sha256=gtRYZBS-CKOCDXHhGZqApboHBaZwGH8gznN3O6nuxj4,1005
+pip/_vendor/pygments/plugin.py,sha256=ioeJ3QeoJ-UQhZpY9JL7vbxsTVuwwM7BCu-Jb8nN0AU,1891
+pip/_vendor/pygments/regexopt.py,sha256=Hky4EB13rIXEHQUNkwmCrYqtIlnXDehNR3MztafZ43w,3072
+pip/_vendor/pygments/scanner.py,sha256=NDy3ofK_fHRFK4hIDvxpamG871aewqcsIb6sgTi7Fhk,3092
+pip/_vendor/pygments/sphinxext.py,sha256=iOptJBcqOGPwMEJ2p70PvwpZPIGdvdZ8dxvq6kzxDgA,7981
+pip/_vendor/pygments/style.py,sha256=rSCZWFpg1_DwFMXDU0nEVmAcBHpuQGf9RxvOPPQvKLQ,6420
+pip/_vendor/pygments/styles/__init__.py,sha256=qUk6_1z5KmT8EdJFZYgESmG6P_HJF_2vVrDD7HSCGYY,2042
+pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-312.pyc,,
+pip/_vendor/pygments/styles/_mapping.py,sha256=6lovFUE29tz6EsV3XYY4hgozJ7q1JL7cfO3UOlgnS8w,3312
+pip/_vendor/pygments/token.py,sha256=qZwT7LSPy5YBY3JgDjut642CCy7JdQzAfmqD9NmT5j0,6226
+pip/_vendor/pygments/unistring.py,sha256=p5c1i-HhoIhWemy9CUsaN9o39oomYHNxXll0Xfw6tEA,63208
+pip/_vendor/pygments/util.py,sha256=2tj2nS1X9_OpcuSjf8dOET2bDVZhs8cEKd_uT6-Fgg8,10031
+pip/_vendor/pyproject_hooks/__init__.py,sha256=cPB_a9LXz5xvsRbX1o2qyAdjLatZJdQ_Lc5McNX-X7Y,691
+pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc,,
+pip/_vendor/pyproject_hooks/_impl.py,sha256=jY-raxnmyRyB57ruAitrJRUzEexuAhGTpgMygqx67Z4,14936
+pip/_vendor/pyproject_hooks/_in_process/__init__.py,sha256=MJNPpfIxcO-FghxpBbxkG1rFiQf6HOUbV4U5mq0HFns,557
+pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc,,
+pip/_vendor/pyproject_hooks/_in_process/_in_process.py,sha256=qcXMhmx__MIJq10gGHW3mA4Tl8dy8YzHMccwnNoKlw0,12216
+pip/_vendor/pyproject_hooks/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/requests/__init__.py,sha256=HlB_HzhrzGtfD_aaYUwUh1zWXLZ75_YCLyit75d0Vz8,5057
+pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/api.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/auth.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/certs.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/compat.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/help.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/models.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/packages.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/structures.cpython-312.pyc,,
+pip/_vendor/requests/__pycache__/utils.cpython-312.pyc,,
+pip/_vendor/requests/__version__.py,sha256=FVfglgZmNQnmYPXpOohDU58F5EUb_-VnSTaAesS187g,435
+pip/_vendor/requests/_internal_utils.py,sha256=nMQymr4hs32TqVo5AbCrmcJEhvPUh7xXlluyqwslLiQ,1495
+pip/_vendor/requests/adapters.py,sha256=J7VeVxKBvawbtlX2DERVo05J9BXTcWYLMHNd1Baa-bk,27607
+pip/_vendor/requests/api.py,sha256=_Zb9Oa7tzVIizTKwFrPjDEY9ejtm_OnSRERnADxGsQs,6449
+pip/_vendor/requests/auth.py,sha256=kF75tqnLctZ9Mf_hm9TZIj4cQWnN5uxRz8oWsx5wmR0,10186
+pip/_vendor/requests/certs.py,sha256=kHDlkK_beuHXeMPc5jta2wgl8gdKeUWt5f2nTDVrvt8,441
+pip/_vendor/requests/compat.py,sha256=Mo9f9xZpefod8Zm-n9_StJcVTmwSukXR2p3IQyyVXvU,1485
+pip/_vendor/requests/cookies.py,sha256=bNi-iqEj4NPZ00-ob-rHvzkvObzN3lEpgw3g6paS3Xw,18590
+pip/_vendor/requests/exceptions.py,sha256=D1wqzYWne1mS2rU43tP9CeN1G7QAy7eqL9o1god6Ejw,4272
+pip/_vendor/requests/help.py,sha256=hRKaf9u0G7fdwrqMHtF3oG16RKktRf6KiwtSq2Fo1_0,3813
+pip/_vendor/requests/hooks.py,sha256=CiuysiHA39V5UfcCBXFIx83IrDpuwfN9RcTUgv28ftQ,733
+pip/_vendor/requests/models.py,sha256=x4K4CmH-lC0l2Kb-iPfMN4dRXxHEcbOaEWBL_i09AwI,35483
+pip/_vendor/requests/packages.py,sha256=_ZQDCJTJ8SP3kVWunSqBsRZNPzj2c1WFVqbdr08pz3U,1057
+pip/_vendor/requests/sessions.py,sha256=ykTI8UWGSltOfH07HKollH7kTBGw4WhiBVaQGmckTw4,30495
+pip/_vendor/requests/status_codes.py,sha256=iJUAeA25baTdw-6PfD0eF4qhpINDJRJI-yaMqxs4LEI,4322
+pip/_vendor/requests/structures.py,sha256=-IbmhVz06S-5aPSZuUthZ6-6D9XOjRuTXHOabY041XM,2912
+pip/_vendor/requests/utils.py,sha256=L79vnFbzJ3SFLKtJwpoWe41Tozi3RlZv94pY1TFIyow,33631
+pip/_vendor/resolvelib/__init__.py,sha256=h509TdEcpb5-44JonaU3ex2TM15GVBLjM9CNCPwnTTs,537
+pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc,,
+pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc,,
+pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc,,
+pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc,,
+pip/_vendor/resolvelib/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc,,
+pip/_vendor/resolvelib/compat/collections_abc.py,sha256=uy8xUZ-NDEw916tugUXm8HgwCGiMO0f-RcdnpkfXfOs,156
+pip/_vendor/resolvelib/providers.py,sha256=fuuvVrCetu5gsxPB43ERyjfO8aReS3rFQHpDgiItbs4,5871
+pip/_vendor/resolvelib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/resolvelib/reporters.py,sha256=TSbRmWzTc26w0ggsV1bxVpeWDB8QNIre6twYl7GIZBE,1601
+pip/_vendor/resolvelib/resolvers.py,sha256=G8rsLZSq64g5VmIq-lB7UcIJ1gjAxIQJmTF4REZleQ0,20511
+pip/_vendor/resolvelib/structs.py,sha256=0_1_XO8z_CLhegP3Vpf9VJ3zJcfLm0NOHRM-i0Ykz3o,4963
+pip/_vendor/rich/__init__.py,sha256=dRxjIL-SbFVY0q3IjSMrfgBTHrm1LZDgLOygVBwiYZc,6090
+pip/_vendor/rich/__main__.py,sha256=eO7Cq8JnrgG8zVoeImiAs92q3hXNMIfp0w5lMsO7Q2Y,8477
+pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/abc.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/align.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/bar.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/box.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/cells.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/color.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/columns.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/console.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/containers.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/control.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/errors.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/json.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/layout.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/live.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/logging.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/markup.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/measure.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/padding.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/pager.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/palette.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/panel.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/progress.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/region.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/repr.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/rule.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/scope.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/screen.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/segment.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/status.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/style.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/styled.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/table.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/text.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/theme.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/themes.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc,,
+pip/_vendor/rich/__pycache__/tree.cpython-312.pyc,,
+pip/_vendor/rich/_cell_widths.py,sha256=fbmeyetEdHjzE_Vx2l1uK7tnPOhMs2X1lJfO3vsKDpA,10209
+pip/_vendor/rich/_emoji_codes.py,sha256=hu1VL9nbVdppJrVoijVshRlcRRe_v3dju3Mmd2sKZdY,140235
+pip/_vendor/rich/_emoji_replace.py,sha256=n-kcetsEUx2ZUmhQrfeMNc-teeGhpuSQ5F8VPBsyvDo,1064
+pip/_vendor/rich/_export_format.py,sha256=RI08pSrm5tBSzPMvnbTqbD9WIalaOoN5d4M1RTmLq1Y,2128
+pip/_vendor/rich/_extension.py,sha256=Xt47QacCKwYruzjDi-gOBq724JReDj9Cm9xUi5fr-34,265
+pip/_vendor/rich/_fileno.py,sha256=HWZxP5C2ajMbHryvAQZseflVfQoGzsKOHzKGsLD8ynQ,799
+pip/_vendor/rich/_inspect.py,sha256=QM05lEFnFoTaFqpnbx-zBEI6k8oIKrD3cvjEOQNhKig,9655
+pip/_vendor/rich/_log_render.py,sha256=1ByI0PA1ZpxZY3CGJOK54hjlq4X-Bz_boIjIqCd8Kns,3225
+pip/_vendor/rich/_loop.py,sha256=hV_6CLdoPm0va22Wpw4zKqM0RYsz3TZxXj0PoS-9eDQ,1236
+pip/_vendor/rich/_null_file.py,sha256=ADGKp1yt-k70FMKV6tnqCqecB-rSJzp-WQsD7LPL-kg,1394
+pip/_vendor/rich/_palettes.py,sha256=cdev1JQKZ0JvlguV9ipHgznTdnvlIzUFDBb0It2PzjI,7063
+pip/_vendor/rich/_pick.py,sha256=evDt8QN4lF5CiwrUIXlOJCntitBCOsI3ZLPEIAVRLJU,423
+pip/_vendor/rich/_ratio.py,sha256=Zt58apszI6hAAcXPpgdWKpu3c31UBWebOeR4mbyptvU,5471
+pip/_vendor/rich/_spinners.py,sha256=U2r1_g_1zSjsjiUdAESc2iAMc3i4ri_S8PYP6kQ5z1I,19919
+pip/_vendor/rich/_stack.py,sha256=-C8OK7rxn3sIUdVwxZBBpeHhIzX0eI-VM3MemYfaXm0,351
+pip/_vendor/rich/_timer.py,sha256=zelxbT6oPFZnNrwWPpc1ktUeAT-Vc4fuFcRZLQGLtMI,417
+pip/_vendor/rich/_win32_console.py,sha256=BSaDRIMwBLITn_m0mTRLPqME5q-quGdSMuYMpYeYJwc,22755
+pip/_vendor/rich/_windows.py,sha256=aBwaD_S56SbgopIvayVmpk0Y28uwY2C5Bab1wl3Bp-I,1925
+pip/_vendor/rich/_windows_renderer.py,sha256=t74ZL3xuDCP3nmTp9pH1L5LiI2cakJuQRQleHCJerlk,2783
+pip/_vendor/rich/_wrap.py,sha256=FlSsom5EX0LVkA3KWy34yHnCfLtqX-ZIepXKh-70rpc,3404
+pip/_vendor/rich/abc.py,sha256=ON-E-ZqSSheZ88VrKX2M3PXpFbGEUUZPMa_Af0l-4f0,890
+pip/_vendor/rich/align.py,sha256=Rh-3adnDaN1Ao07EjR2PhgE62PGLPgO8SMwJBku1urQ,10469
+pip/_vendor/rich/ansi.py,sha256=Avs1LHbSdcyOvDOdpELZUoULcBiYewY76eNBp6uFBhs,6921
+pip/_vendor/rich/bar.py,sha256=ldbVHOzKJOnflVNuv1xS7g6dLX2E3wMnXkdPbpzJTcs,3263
+pip/_vendor/rich/box.py,sha256=nr5fYIUghB_iUCEq6y0Z3LlCT8gFPDrzN9u2kn7tJl4,10831
+pip/_vendor/rich/cells.py,sha256=KrQkj5-LghCCpJLSNQIyAZjndc4bnEqOEmi5YuZ9UCY,5130
+pip/_vendor/rich/color.py,sha256=3HSULVDj7qQkXUdFWv78JOiSZzfy5y1nkcYhna296V0,18211
+pip/_vendor/rich/color_triplet.py,sha256=3lhQkdJbvWPoLDO-AnYImAWmJvV5dlgYNCVZ97ORaN4,1054
+pip/_vendor/rich/columns.py,sha256=HUX0KcMm9dsKNi11fTbiM_h2iDtl8ySCaVcxlalEzq8,7131
+pip/_vendor/rich/console.py,sha256=nKjrEx_7xy8KGmDVT-BgNII0R5hm1cexhAHDwdwNVqg,100156
+pip/_vendor/rich/constrain.py,sha256=1VIPuC8AgtKWrcncQrjBdYqA3JVWysu6jZo1rrh7c7Q,1288
+pip/_vendor/rich/containers.py,sha256=c_56TxcedGYqDepHBMTuZdUIijitAQgnox-Qde0Z1qo,5502
+pip/_vendor/rich/control.py,sha256=DSkHTUQLorfSERAKE_oTAEUFefZnZp4bQb4q8rHbKws,6630
+pip/_vendor/rich/default_styles.py,sha256=dZxgaSD9VUy7SXQShO33aLYiAWspCr2sCQZFX_JK1j4,8159
+pip/_vendor/rich/diagnose.py,sha256=an6uouwhKPAlvQhYpNNpGq9EJysfMIOvvCbO3oSoR24,972
+pip/_vendor/rich/emoji.py,sha256=omTF9asaAnsM4yLY94eR_9dgRRSm1lHUszX20D1yYCQ,2501
+pip/_vendor/rich/errors.py,sha256=5pP3Kc5d4QJ_c0KFsxrfyhjiPVe7J1zOqSFbFAzcV-Y,642
+pip/_vendor/rich/file_proxy.py,sha256=Tl9THMDZ-Pk5Wm8sI1gGg_U5DhusmxD-FZ0fUbcU0W0,1683
+pip/_vendor/rich/filesize.py,sha256=_iz9lIpRgvW7MNSeCZnLg-HwzbP4GETg543WqD8SFs0,2484
+pip/_vendor/rich/highlighter.py,sha256=G_sn-8DKjM1sEjLG_oc4ovkWmiUpWvj8bXi0yed2LnY,9586
+pip/_vendor/rich/json.py,sha256=vVEoKdawoJRjAFayPwXkMBPLy7RSTs-f44wSQDR2nJ0,5031
+pip/_vendor/rich/jupyter.py,sha256=QyoKoE_8IdCbrtiSHp9TsTSNyTHY0FO5whE7jOTd9UE,3252
+pip/_vendor/rich/layout.py,sha256=ajkSFAtEVv9EFTcFs-w4uZfft7nEXhNzL7ZVdgrT5rI,14004
+pip/_vendor/rich/live.py,sha256=DhzAPEnjTxQuq9_0Y2xh2MUwQcP_aGPkenLfKETslwM,14270
+pip/_vendor/rich/live_render.py,sha256=zJtB471jGziBtEwxc54x12wEQtH4BuQr1SA8v9kU82w,3666
+pip/_vendor/rich/logging.py,sha256=ZgpKMMBY_BuMAI_BYzo-UtXak6t5oH9VK8m9Q2Lm0f4,12458
+pip/_vendor/rich/markup.py,sha256=3euGKP5s41NCQwaSjTnJxus5iZMHjxpIM0W6fCxra38,8451
+pip/_vendor/rich/measure.py,sha256=HmrIJX8sWRTHbgh8MxEay_83VkqNW_70s8aKP5ZcYI8,5305
+pip/_vendor/rich/padding.py,sha256=KVEI3tOwo9sgK1YNSuH__M1_jUWmLZwRVV_KmOtVzyM,4908
+pip/_vendor/rich/pager.py,sha256=SO_ETBFKbg3n_AgOzXm41Sv36YxXAyI3_R-KOY2_uSc,828
+pip/_vendor/rich/palette.py,sha256=lInvR1ODDT2f3UZMfL1grq7dY_pDdKHw4bdUgOGaM4Y,3396
+pip/_vendor/rich/panel.py,sha256=fFRHcviXvWhk3V3zx5Zwmsb_RL9KJ3esD-sU0NYEVyw,11235
+pip/_vendor/rich/pretty.py,sha256=gy3S72u4FRg2ytoo7N1ZDWDIvB4unbzd5iUGdgm-8fc,36391
+pip/_vendor/rich/progress.py,sha256=MtmCjTk5zYU_XtRHxRHTAEHG6hF9PeF7EMWbEPleIC0,60357
+pip/_vendor/rich/progress_bar.py,sha256=mZTPpJUwcfcdgQCTTz3kyY-fc79ddLwtx6Ghhxfo064,8162
+pip/_vendor/rich/prompt.py,sha256=l0RhQU-0UVTV9e08xW1BbIj0Jq2IXyChX4lC0lFNzt4,12447
+pip/_vendor/rich/protocol.py,sha256=5hHHDDNHckdk8iWH5zEbi-zuIVSF5hbU2jIo47R7lTE,1391
+pip/_vendor/rich/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/rich/region.py,sha256=rNT9xZrVZTYIXZC0NYn41CJQwYNbR-KecPOxTgQvB8Y,166
+pip/_vendor/rich/repr.py,sha256=5MZJZmONgC6kud-QW-_m1okXwL2aR6u6y-pUcUCJz28,4431
+pip/_vendor/rich/rule.py,sha256=0fNaS_aERa3UMRc3T5WMpN_sumtDxfaor2y3of1ftBk,4602
+pip/_vendor/rich/scope.py,sha256=TMUU8qo17thyqQCPqjDLYpg_UU1k5qVd-WwiJvnJVas,2843
+pip/_vendor/rich/screen.py,sha256=YoeReESUhx74grqb0mSSb9lghhysWmFHYhsbMVQjXO8,1591
+pip/_vendor/rich/segment.py,sha256=otnKeKGEV-WRlQVosfJVeFDcDxAKHpvJ_hLzSu5lumM,24743
+pip/_vendor/rich/spinner.py,sha256=PT5qgXPG3ZpqRj7n3EZQ6NW56mx3ldZqZCU7gEMyZk4,4364
+pip/_vendor/rich/status.py,sha256=kkPph3YeAZBo-X-4wPp8gTqZyU466NLwZBA4PZTTewo,4424
+pip/_vendor/rich/style.py,sha256=aSoUNbVgfP1PAnduAqgbbl4AMQy668qs2S1FEwr3Oqs,27067
+pip/_vendor/rich/styled.py,sha256=eZNnzGrI4ki_54pgY3Oj0T-x3lxdXTYh4_ryDB24wBU,1258
+pip/_vendor/rich/syntax.py,sha256=qqAnEUZ4K57Po81_5RBxnsuU4KRzSdvDPAhKw8ma_3E,35763
+pip/_vendor/rich/table.py,sha256=yXYUr0YsPpG466N50HCAw2bpb5ZUuuzdc-G66Zk-oTc,40103
+pip/_vendor/rich/terminal_theme.py,sha256=1j5-ufJfnvlAo5Qsi_ACZiXDmwMXzqgmFByObT9-yJY,3370
+pip/_vendor/rich/text.py,sha256=AO7JPCz6-gaN1thVLXMBntEmDPVYFgFNG1oM61_sanU,47552
+pip/_vendor/rich/theme.py,sha256=oNyhXhGagtDlbDye3tVu3esWOWk0vNkuxFw-_unlaK0,3771
+pip/_vendor/rich/themes.py,sha256=0xgTLozfabebYtcJtDdC5QkX5IVUEaviqDUJJh4YVFk,102
+pip/_vendor/rich/traceback.py,sha256=z8UoN7NbTQKW6YDDUVwOh7F8snZf6gYnUWtOrKsLE1w,31797
+pip/_vendor/rich/tree.py,sha256=yWnQ6rAvRGJ3qZGqBrxS2SW2TKBTNrP0SdY8QxOFPuw,9451
+pip/_vendor/tomli/__init__.py,sha256=PhNw_eyLgdn7McJ6nrAN8yIm3dXC75vr1sVGVVwDSpA,314
+pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc,,
+pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc,,
+pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc,,
+pip/_vendor/tomli/_parser.py,sha256=9w8LG0jB7fwmZZWB0vVXbeejDHcl4ANIJxB2scEnDlA,25591
+pip/_vendor/tomli/_re.py,sha256=sh4sBDRgO94KJZwNIrgdcyV_qQast50YvzOAUGpRDKA,3171
+pip/_vendor/tomli/_types.py,sha256=-GTG2VUqkpxwMqzmVO4F7ybKddIbAnuAHXfmWQcTi3Q,254
+pip/_vendor/tomli/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
+pip/_vendor/truststore/__init__.py,sha256=WIDeyzWm7EVX44g354M25vpRXbeY1lsPH6EmUJUcq4o,1264
+pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc,,
+pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc,,
+pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc,,
+pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc,,
+pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc,,
+pip/_vendor/truststore/_api.py,sha256=GeXRNTlxPZ3kif4kNoh6JY0oE4QRzTGcgXr6l_X_Gk0,10555
+pip/_vendor/truststore/_macos.py,sha256=nZlLkOmszUE0g6ryRwBVGY5COzPyudcsiJtDWarM5LQ,20503
+pip/_vendor/truststore/_openssl.py,sha256=LLUZ7ZGaio-i5dpKKjKCSeSufmn6T8pi9lDcFnvSyq0,2324
+pip/_vendor/truststore/_ssl_constants.py,sha256=NUD4fVKdSD02ri7-db0tnO0VqLP9aHuzmStcW7tAl08,1130
+pip/_vendor/truststore/_windows.py,sha256=rAHyKYD8M7t-bXfG8VgOVa3TpfhVhbt4rZQlO45YuP8,17993
+pip/_vendor/truststore/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/typing_extensions.py,sha256=78hFl0HpDY-ylHUVCnWdU5nTHxUP2-S-3wEZk6CQmLk,134499
+pip/_vendor/urllib3/__init__.py,sha256=iXLcYiJySn0GNbWOOZDDApgBL1JgP44EZ8i1760S8Mc,3333
+pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc,,
+pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc,,
+pip/_vendor/urllib3/_collections.py,sha256=pyASJJhW7wdOpqJj9QJA8FyGRfr8E8uUUhqUvhF0728,11372
+pip/_vendor/urllib3/_version.py,sha256=t9wGB6ooOTXXgiY66K1m6BZS1CJyXHAU8EoWDTe6Shk,64
+pip/_vendor/urllib3/connection.py,sha256=ttIA909BrbTUzwkqEe_TzZVh4JOOj7g61Ysei2mrwGg,20314
+pip/_vendor/urllib3/connectionpool.py,sha256=e2eiAwNbFNCKxj4bwDKNK-w7HIdSz3OmMxU_TIt-evQ,40408
+pip/_vendor/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/_appengine_environ.py,sha256=bDbyOEhW2CKLJcQqAKAyrEHN-aklsyHFKq6vF8ZFsmk,957
+pip/_vendor/urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc,,
+pip/_vendor/urllib3/contrib/_securetransport/bindings.py,sha256=4Xk64qIkPBt09A5q-RIFUuDhNc9mXilVapm7WnYnzRw,17632
+pip/_vendor/urllib3/contrib/_securetransport/low_level.py,sha256=B2JBB2_NRP02xK6DCa1Pa9IuxrPwxzDzZbixQkb7U9M,13922
+pip/_vendor/urllib3/contrib/appengine.py,sha256=VR68eAVE137lxTgjBDwCna5UiBZTOKa01Aj_-5BaCz4,11036
+pip/_vendor/urllib3/contrib/ntlmpool.py,sha256=NlfkW7WMdW8ziqudopjHoW299og1BTWi0IeIibquFwk,4528
+pip/_vendor/urllib3/contrib/pyopenssl.py,sha256=hDJh4MhyY_p-oKlFcYcQaVQRDv6GMmBGuW9yjxyeejM,17081
+pip/_vendor/urllib3/contrib/securetransport.py,sha256=Fef1IIUUFHqpevzXiDPbIGkDKchY2FVKeVeLGR1Qq3g,34446
+pip/_vendor/urllib3/contrib/socks.py,sha256=aRi9eWXo9ZEb95XUxef4Z21CFlnnjbEiAo9HOseoMt4,7097
+pip/_vendor/urllib3/exceptions.py,sha256=0Mnno3KHTNfXRfY7638NufOPkUb6mXOm-Lqj-4x2w8A,8217
+pip/_vendor/urllib3/fields.py,sha256=kvLDCg_JmH1lLjUUEY_FLS8UhY7hBvDPuVETbY8mdrM,8579
+pip/_vendor/urllib3/filepost.py,sha256=5b_qqgRHVlL7uLtdAYBzBh-GHmU5AfJVt_2N0XS3PeY,2440
+pip/_vendor/urllib3/packages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc,,
+pip/_vendor/urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc,,
+pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc,,
+pip/_vendor/urllib3/packages/backports/makefile.py,sha256=nbzt3i0agPVP07jqqgjhaYjMmuAi_W5E0EywZivVO8E,1417
+pip/_vendor/urllib3/packages/backports/weakref_finalize.py,sha256=tRCal5OAhNSRyb0DhHp-38AtIlCsRP8BxF3NX-6rqIA,5343
+pip/_vendor/urllib3/packages/six.py,sha256=b9LM0wBXv7E7SrbCjAm4wwN-hrH-iNxv18LgWNMMKPo,34665
+pip/_vendor/urllib3/poolmanager.py,sha256=aWyhXRtNO4JUnCSVVqKTKQd8EXTvUm1VN9pgs2bcONo,19990
+pip/_vendor/urllib3/request.py,sha256=YTWFNr7QIwh7E1W9dde9LM77v2VWTJ5V78XuTTw7D1A,6691
+pip/_vendor/urllib3/response.py,sha256=fmDJAFkG71uFTn-sVSTh2Iw0WmcXQYqkbRjihvwBjU8,30641
+pip/_vendor/urllib3/util/__init__.py,sha256=JEmSmmqqLyaw8P51gUImZh8Gwg9i1zSe-DoqAitn2nc,1155
+pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc,,
+pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc,,
+pip/_vendor/urllib3/util/connection.py,sha256=5Lx2B1PW29KxBn2T0xkN1CBgRBa3gGVJBKoQoRogEVk,4901
+pip/_vendor/urllib3/util/proxy.py,sha256=zUvPPCJrp6dOF0N4GAVbOcl6o-4uXKSrGiTkkr5vUS4,1605
+pip/_vendor/urllib3/util/queue.py,sha256=nRgX8_eX-_VkvxoX096QWoz8Ps0QHUAExILCY_7PncM,498
+pip/_vendor/urllib3/util/request.py,sha256=C0OUt2tcU6LRiQJ7YYNP9GvPrSvl7ziIBekQ-5nlBZk,3997
+pip/_vendor/urllib3/util/response.py,sha256=GJpg3Egi9qaJXRwBh5wv-MNuRWan5BIu40oReoxWP28,3510
+pip/_vendor/urllib3/util/retry.py,sha256=6ENvOZ8PBDzh8kgixpql9lIrb2dxH-k7ZmBanJF2Ng4,22050
+pip/_vendor/urllib3/util/ssl_.py,sha256=QDuuTxPSCj1rYtZ4xpD7Ux-r20TD50aHyqKyhQ7Bq4A,17460
+pip/_vendor/urllib3/util/ssl_match_hostname.py,sha256=Ir4cZVEjmAk8gUAIHWSi7wtOO83UCYABY2xFD1Ql_WA,5758
+pip/_vendor/urllib3/util/ssltransport.py,sha256=NA-u5rMTrDFDFC8QzRKUEKMG0561hOD4qBTr3Z4pv6E,6895
+pip/_vendor/urllib3/util/timeout.py,sha256=cwq4dMk87mJHSBktK1miYJ-85G-3T3RmT20v7SFCpno,10168
+pip/_vendor/urllib3/util/url.py,sha256=lCAE7M5myA8EDdW0sJuyyZhVB9K_j38ljWhHAnFaWoE,14296
+pip/_vendor/urllib3/util/wait.py,sha256=fOX0_faozG2P7iVojQoE1mbydweNyTcm-hXEfFrTtLI,5403
+pip/_vendor/vendor.txt,sha256=EW-E3cE5XEAtVFzGInikArOMDxGP0DLUWzXpY4RZfFY,333
+pip/py.typed,sha256=EBVvvPRTn_eIpz5e5QztSCdrMX7Qwd7VP93RSoIlZ2I,286
diff --git a/lib/python3.12/site-packages/pip-25.0.1.dist-info/REQUESTED b/lib/python3.12/site-packages/pip-25.0.1.dist-info/REQUESTED
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/pip-25.0.1.dist-info/WHEEL b/lib/python3.12/site-packages/pip-25.0.1.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..505164bc02d63fe6b0b3299f849a77c5f1beeb41
--- /dev/null
+++ b/lib/python3.12/site-packages/pip-25.0.1.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: setuptools (75.8.0)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/lib/python3.12/site-packages/pip-25.0.1.dist-info/entry_points.txt b/lib/python3.12/site-packages/pip-25.0.1.dist-info/entry_points.txt
new file mode 100644
index 0000000000000000000000000000000000000000..25fcf7e2cdf0943ad5c074d4777c721cd3340986
--- /dev/null
+++ b/lib/python3.12/site-packages/pip-25.0.1.dist-info/entry_points.txt
@@ -0,0 +1,3 @@
+[console_scripts]
+pip = pip._internal.cli.main:main
+pip3 = pip._internal.cli.main:main
diff --git a/lib/python3.12/site-packages/pip-25.0.1.dist-info/top_level.txt b/lib/python3.12/site-packages/pip-25.0.1.dist-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/lib/python3.12/site-packages/pip-25.0.1.dist-info/top_level.txt
@@ -0,0 +1 @@
+pip
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..00943651947e1ef997595e62d8170dd0d54c988c
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_batcher.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_batcher.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..241c8159b238e3ecdc2dbb0faa817ce84271ed64
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_batcher.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_compat.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_compat.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6d41b39fe5adfe64559f2fe0d00c58c0ca8ddd8b
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_compat.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_init_implementation.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_init_implementation.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1494e6f9b97112e6a3f973c96483108e7c7b0b94
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_init_implementation.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_log_batcher.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_log_batcher.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e385ae961c969aef60300ae2c2aaf9d5fab552b4
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_log_batcher.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_lru_cache.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_lru_cache.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bb9eeeeee22e342824fb94df971b1d2e2804dd18
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_lru_cache.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_metrics_batcher.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_metrics_batcher.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cf9039cc102b3016937af51e5cd602a5ba45ef88
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_metrics_batcher.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_queue.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_queue.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ed73a26db9684fc1d6d61cfc207724e49545118a
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_queue.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_span_batcher.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_span_batcher.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a7f9cc3292b71520c8220373e68f823f1652515d
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_span_batcher.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_types.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_types.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..431075cf7d682e32ede56454b9a1cdb0595dbad4
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_types.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/_werkzeug.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_werkzeug.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c7c930f4bc19fa4d38600be6b9cd20d496f5632b
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/_werkzeug.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/api.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/api.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d2169b46e95c332bf526334d6b6947a4586ca1a9
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/api.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/attachments.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/attachments.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..86eba7c6a72e32b1d9808abb71508ab3d6c6905f
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/attachments.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/client.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/client.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6f852adf2a0405d2c876aad4b8e35e1b6a62e427
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/client.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/consts.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/consts.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bb83d4f4b76acbe27266cbed753bed772c64a588
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/consts.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/debug.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/debug.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..57f909343a986c7ddbdeeb1ec9a900403c22f07b
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/debug.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/envelope.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/envelope.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..306bf60b7c218bfa5284afadbf92ec9688bfd742
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/envelope.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/feature_flags.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/feature_flags.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..679f13ea1555c8152d975457dcd62e93fac256c9
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/feature_flags.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/hub.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/hub.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..257c62f36619382fad51b0c9a377aa93a6cbf69a
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/hub.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/logger.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/logger.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8825a0ee057d0b71463a6a583ed5744e8488a259
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/logger.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/metrics.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/metrics.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..35c2d2d95f8b4df20663d9924a25aa1603cfd982
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/metrics.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/monitor.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/monitor.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7206bf6c97d003b6e561d823a31d24ae4dade196
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/monitor.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/scope.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/scope.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2ae044978d234ef5fa684bf2322f2f14ae327ad9
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/scope.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/scrubber.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/scrubber.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..52da66f91894714ab626c5498e1ca123282efefc
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/scrubber.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/serializer.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/serializer.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5d52f2d5933216acbb261853dbb5e2945c303b70
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/serializer.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/session.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/session.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..81681ec650e59d0b4575479408d0e0c30108f4ed
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/session.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/sessions.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/sessions.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ec61906fa94a8791cea86ebae14c69d3d566b75a
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/sessions.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/spotlight.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/spotlight.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3a98e8ee474141f9da47689a93194695b5f13bd6
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/spotlight.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/traces.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/traces.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..900268fb291b83bc812e4b04ea20a959a5be5fdf
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/traces.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/tracing.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/tracing.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7634e7e18c1a2a81d452778b24059f155c461fe8
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/tracing.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/tracing_utils.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/tracing_utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7d9b9764a62b353cf11b089769109a7fcfa0664a
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/tracing_utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/transport.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/transport.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4132667ec696801b0fbbd3eb2c1687232486099c
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/transport.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/types.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/types.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3f27d1e6b048bc7b4b07c9b7ddad2669df73179a
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/types.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..fa8fca39d21b88dae9e09192c1f2e1b74dd724dc
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/__pycache__/worker.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/__pycache__/worker.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c757c8ec61e25deb6a28f16f65fc2769bf6e7e87
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/__pycache__/worker.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/__init__.py b/lib/python3.12/site-packages/sentry_sdk/ai/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f0d9f92f70280212f507c0b4753d11fff723206
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/ai/__init__.py
@@ -0,0 +1,8 @@
+from .utils import (
+    set_data_normalized,
+    GEN_AI_MESSAGE_ROLE_MAPPING,
+    GEN_AI_MESSAGE_ROLE_REVERSE_MAPPING,
+    normalize_message_role,
+    normalize_message_roles,
+    set_conversation_id,
+)  # noqa: F401
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a818d8c5dc8b9d5b529921454700be6c805fa953
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/_openai_completions_api.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/_openai_completions_api.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..97e896db31ef951b06fdb26b1f2682a1089329b8
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/_openai_completions_api.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/_openai_responses_api.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/_openai_responses_api.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ffa448ffd43e6613afadf3abbe527aae87d657ff
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/_openai_responses_api.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/monitoring.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/monitoring.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..699524c3043ac56269edbc31097ac7fbc979e6f0
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/monitoring.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..759bd405693e6563b3ccc2ef0a94ef31efc7a9f0
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/ai/__pycache__/utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/_openai_completions_api.py b/lib/python3.12/site-packages/sentry_sdk/ai/_openai_completions_api.py
new file mode 100644
index 0000000000000000000000000000000000000000..2902af304ba3a5aa71a9cd5a17d264322fc8e30e
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/ai/_openai_completions_api.py
@@ -0,0 +1,66 @@
+from collections.abc import Iterable
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from sentry_sdk._types import TextPart
+    from typing import Union
+
+    from openai.types.chat import (
+        ChatCompletionMessageParam,
+        ChatCompletionSystemMessageParam,
+        ChatCompletionContentPartParam,
+    )
+
+
+def _is_system_instruction(message: "ChatCompletionMessageParam") -> bool:
+    return isinstance(message, dict) and message.get("role") == "system"
+
+
+def _get_system_instructions(
+    messages: "Iterable[ChatCompletionMessageParam]",
+) -> "list[ChatCompletionMessageParam]":
+    if not isinstance(messages, Iterable):
+        return []
+
+    return [message for message in messages if _is_system_instruction(message)]
+
+
+def _get_text_items(
+    content: "Union[str, Iterable[ChatCompletionContentPartParam]]",
+) -> "list[str]":
+    if isinstance(content, str):
+        return [content]
+
+    if not isinstance(content, Iterable):
+        return []
+
+    text_items = []
+    for part in content:
+        if isinstance(part, dict) and part.get("type") == "text":
+            text = part.get("text", None)
+            if text is not None:
+                text_items.append(text)
+
+    return text_items
+
+
+def _transform_system_instructions(
+    system_instructions: "list[ChatCompletionSystemMessageParam]",
+) -> "list[TextPart]":
+    instruction_text_parts: "list[TextPart]" = []
+
+    for instruction in system_instructions:
+        if not isinstance(instruction, dict):
+            continue
+
+        content = instruction.get("content")
+        if content is None:
+            continue
+
+        text_parts: "list[TextPart]" = [
+            {"type": "text", "content": text} for text in _get_text_items(content)
+        ]
+        instruction_text_parts += text_parts
+
+    return instruction_text_parts
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/_openai_responses_api.py b/lib/python3.12/site-packages/sentry_sdk/ai/_openai_responses_api.py
new file mode 100644
index 0000000000000000000000000000000000000000..50fddf1d2f21da1762d17e4d41c4f1dff81c4439
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/ai/_openai_responses_api.py
@@ -0,0 +1,22 @@
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import Union
+
+    from openai.types.responses import ResponseInputParam, ResponseInputItemParam
+
+
+def _is_system_instruction(message: "ResponseInputItemParam") -> bool:
+    if not isinstance(message, dict) or not message.get("role") == "system":
+        return False
+
+    return "type" not in message or message["type"] == "message"
+
+
+def _get_system_instructions(
+    messages: "Union[str, ResponseInputParam]",
+) -> "list[ResponseInputItemParam]":
+    if not isinstance(messages, list):
+        return []
+
+    return [message for message in messages if _is_system_instruction(message)]
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/monitoring.py b/lib/python3.12/site-packages/sentry_sdk/ai/monitoring.py
new file mode 100644
index 0000000000000000000000000000000000000000..581e967bd41536eddd82367687de33fb43384c42
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/ai/monitoring.py
@@ -0,0 +1,141 @@
+import inspect
+import sys
+from functools import wraps
+
+from sentry_sdk.consts import SPANDATA
+import sentry_sdk.utils
+from sentry_sdk import start_span
+from sentry_sdk.tracing import Span
+from sentry_sdk.utils import ContextVar, reraise, capture_internal_exceptions
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import Optional, Callable, Awaitable, Any, Union, TypeVar
+
+    F = TypeVar("F", bound=Union[Callable[..., Any], Callable[..., Awaitable[Any]]])
+
+_ai_pipeline_name = ContextVar("ai_pipeline_name", default=None)
+
+
+def set_ai_pipeline_name(name: "Optional[str]") -> None:
+    _ai_pipeline_name.set(name)
+
+
+def get_ai_pipeline_name() -> "Optional[str]":
+    return _ai_pipeline_name.get()
+
+
+def ai_track(description: str, **span_kwargs: "Any") -> "Callable[[F], F]":
+    def decorator(f: "F") -> "F":
+        def sync_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
+            curr_pipeline = _ai_pipeline_name.get()
+            op = span_kwargs.pop("op", "ai.run" if curr_pipeline else "ai.pipeline")
+
+            with start_span(name=description, op=op, **span_kwargs) as span:
+                for k, v in kwargs.pop("sentry_tags", {}).items():
+                    span.set_tag(k, v)
+                for k, v in kwargs.pop("sentry_data", {}).items():
+                    span.set_data(k, v)
+                if curr_pipeline:
+                    span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline)
+                    return f(*args, **kwargs)
+                else:
+                    _ai_pipeline_name.set(description)
+                    try:
+                        res = f(*args, **kwargs)
+                    except Exception as e:
+                        exc_info = sys.exc_info()
+                        with capture_internal_exceptions():
+                            event, hint = sentry_sdk.utils.event_from_exception(
+                                e,
+                                client_options=sentry_sdk.get_client().options,
+                                mechanism={"type": "ai_monitoring", "handled": False},
+                            )
+                            sentry_sdk.capture_event(event, hint=hint)
+                        reraise(*exc_info)
+                    finally:
+                        _ai_pipeline_name.set(None)
+                    return res
+
+        async def async_wrapped(*args: "Any", **kwargs: "Any") -> "Any":
+            curr_pipeline = _ai_pipeline_name.get()
+            op = span_kwargs.pop("op", "ai.run" if curr_pipeline else "ai.pipeline")
+
+            with start_span(name=description, op=op, **span_kwargs) as span:
+                for k, v in kwargs.pop("sentry_tags", {}).items():
+                    span.set_tag(k, v)
+                for k, v in kwargs.pop("sentry_data", {}).items():
+                    span.set_data(k, v)
+                if curr_pipeline:
+                    span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, curr_pipeline)
+                    return await f(*args, **kwargs)
+                else:
+                    _ai_pipeline_name.set(description)
+                    try:
+                        res = await f(*args, **kwargs)
+                    except Exception as e:
+                        exc_info = sys.exc_info()
+                        with capture_internal_exceptions():
+                            event, hint = sentry_sdk.utils.event_from_exception(
+                                e,
+                                client_options=sentry_sdk.get_client().options,
+                                mechanism={"type": "ai_monitoring", "handled": False},
+                            )
+                            sentry_sdk.capture_event(event, hint=hint)
+                        reraise(*exc_info)
+                    finally:
+                        _ai_pipeline_name.set(None)
+                    return res
+
+        if inspect.iscoroutinefunction(f):
+            return wraps(f)(async_wrapped)  # type: ignore
+        else:
+            return wraps(f)(sync_wrapped)  # type: ignore
+
+    return decorator
+
+
+def record_token_usage(
+    span: "Span",
+    input_tokens: "Optional[int]" = None,
+    input_tokens_cached: "Optional[int]" = None,
+    input_tokens_cache_write: "Optional[int]" = None,
+    output_tokens: "Optional[int]" = None,
+    output_tokens_reasoning: "Optional[int]" = None,
+    total_tokens: "Optional[int]" = None,
+) -> None:
+    # TODO: move pipeline name elsewhere
+    ai_pipeline_name = get_ai_pipeline_name()
+    if ai_pipeline_name:
+        span.set_data(SPANDATA.GEN_AI_PIPELINE_NAME, ai_pipeline_name)
+
+    if input_tokens is not None:
+        span.set_data(SPANDATA.GEN_AI_USAGE_INPUT_TOKENS, input_tokens)
+
+    if input_tokens_cached is not None:
+        span.set_data(
+            SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHED,
+            input_tokens_cached,
+        )
+
+    if input_tokens_cache_write is not None:
+        span.set_data(
+            SPANDATA.GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE,
+            input_tokens_cache_write,
+        )
+
+    if output_tokens is not None:
+        span.set_data(SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens)
+
+    if output_tokens_reasoning is not None:
+        span.set_data(
+            SPANDATA.GEN_AI_USAGE_OUTPUT_TOKENS_REASONING,
+            output_tokens_reasoning,
+        )
+
+    if total_tokens is None and input_tokens is not None and output_tokens is not None:
+        total_tokens = input_tokens + output_tokens
+
+    if total_tokens is not None:
+        span.set_data(SPANDATA.GEN_AI_USAGE_TOTAL_TOKENS, total_tokens)
diff --git a/lib/python3.12/site-packages/sentry_sdk/ai/utils.py b/lib/python3.12/site-packages/sentry_sdk/ai/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..5acc5011725b5acf243b6f8a8b8cc0d8200ab2bd
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/ai/utils.py
@@ -0,0 +1,727 @@
+import inspect
+import json
+from collections import deque
+from copy import deepcopy
+from sys import getsizeof
+from typing import TYPE_CHECKING
+
+from sentry_sdk._types import BLOB_DATA_SUBSTITUTE
+
+if TYPE_CHECKING:
+    from typing import Any, Callable, Dict, List, Optional, Tuple
+
+    from sentry_sdk.tracing import Span
+
+import sentry_sdk
+from sentry_sdk.utils import logger
+
+MAX_GEN_AI_MESSAGE_BYTES = 20_000  # 20KB
+# Maximum characters when only a single message is left after bytes truncation
+MAX_SINGLE_MESSAGE_CONTENT_CHARS = 10_000
+
+
+class GEN_AI_ALLOWED_MESSAGE_ROLES:
+    SYSTEM = "system"
+    USER = "user"
+    ASSISTANT = "assistant"
+    TOOL = "tool"
+
+
+GEN_AI_MESSAGE_ROLE_REVERSE_MAPPING = {
+    GEN_AI_ALLOWED_MESSAGE_ROLES.SYSTEM: ["system"],
+    GEN_AI_ALLOWED_MESSAGE_ROLES.USER: ["user", "human"],
+    GEN_AI_ALLOWED_MESSAGE_ROLES.ASSISTANT: ["assistant", "ai"],
+    GEN_AI_ALLOWED_MESSAGE_ROLES.TOOL: ["tool", "tool_call"],
+}
+
+GEN_AI_MESSAGE_ROLE_MAPPING = {}
+for target_role, source_roles in GEN_AI_MESSAGE_ROLE_REVERSE_MAPPING.items():
+    for source_role in source_roles:
+        GEN_AI_MESSAGE_ROLE_MAPPING[source_role] = target_role
+
+
+def parse_data_uri(url: str) -> "Tuple[str, str]":
+    """
+    Parse a data URI and return (mime_type, content).
+
+    Data URI format (RFC 2397): data:[][;base64],
+
+    Examples:
+        data:image/jpeg;base64,/9j/4AAQ... → ("image/jpeg", "/9j/4AAQ...")
+        data:text/plain,Hello → ("text/plain", "Hello")
+        data:;base64,SGVsbG8= → ("", "SGVsbG8=")
+
+    Raises:
+        ValueError: If the URL is not a valid data URI (missing comma separator)
+    """
+    if "," not in url:
+        raise ValueError("Invalid data URI: missing comma separator")
+
+    header, content = url.split(",", 1)
+
+    # Extract mime type from header
+    # Format: "data:[;param1][;param2]..." e.g. "data:image/jpeg;base64"
+    # Remove "data:" prefix, then take everything before the first semicolon
+    if header.startswith("data:"):
+        mime_part = header[5:]  # Remove "data:" prefix
+    else:
+        mime_part = header
+
+    mime_type = mime_part.split(";")[0]
+
+    return mime_type, content
+
+
+def get_modality_from_mime_type(mime_type: str) -> str:
+    """
+    Infer the content modality from a MIME type string.
+
+    Args:
+        mime_type: A MIME type string (e.g., "image/jpeg", "audio/mp3")
+
+    Returns:
+        One of: "image", "audio", "video", or "document"
+        Defaults to "image" for unknown or empty MIME types.
+
+    Examples:
+        "image/jpeg" -> "image"
+        "audio/mp3" -> "audio"
+        "video/mp4" -> "video"
+        "application/pdf" -> "document"
+        "text/plain" -> "document"
+    """
+    if not mime_type:
+        return "image"  # Default fallback
+
+    mime_lower = mime_type.lower()
+    if mime_lower.startswith("image/"):
+        return "image"
+    elif mime_lower.startswith("audio/"):
+        return "audio"
+    elif mime_lower.startswith("video/"):
+        return "video"
+    elif mime_lower.startswith("application/") or mime_lower.startswith("text/"):
+        return "document"
+    else:
+        return "image"  # Default fallback for unknown types
+
+
+def transform_openai_content_part(
+    content_part: "Dict[str, Any]",
+) -> "Optional[Dict[str, Any]]":
+    """
+    Transform an OpenAI/LiteLLM content part to Sentry's standardized format.
+
+    This handles the OpenAI image_url format used by OpenAI and LiteLLM SDKs.
+
+    Input format:
+    - {"type": "image_url", "image_url": {"url": "..."}}
+    - {"type": "image_url", "image_url": "..."} (string shorthand)
+
+    Output format (one of):
+    - {"type": "blob", "modality": "image", "mime_type": "...", "content": "..."}
+    - {"type": "uri", "modality": "image", "mime_type": "", "uri": "..."}
+
+    Args:
+        content_part: A dictionary representing a content part from OpenAI/LiteLLM
+
+    Returns:
+        A transformed dictionary in standardized format, or None if the format
+        is not OpenAI image_url format or transformation fails.
+    """
+    if not isinstance(content_part, dict):
+        return None
+
+    block_type = content_part.get("type")
+
+    if block_type != "image_url":
+        return None
+
+    image_url_data = content_part.get("image_url")
+    if isinstance(image_url_data, str):
+        url = image_url_data
+    elif isinstance(image_url_data, dict):
+        url = image_url_data.get("url", "")
+    else:
+        return None
+
+    if not url:
+        return None
+
+    # Check if it's a data URI (base64 encoded)
+    if url.startswith("data:"):
+        try:
+            mime_type, content = parse_data_uri(url)
+            return {
+                "type": "blob",
+                "modality": get_modality_from_mime_type(mime_type),
+                "mime_type": mime_type,
+                "content": content,
+            }
+        except ValueError:
+            # If parsing fails, return as URI
+            return {
+                "type": "uri",
+                "modality": "image",
+                "mime_type": "",
+                "uri": url,
+            }
+    else:
+        # Regular URL
+        return {
+            "type": "uri",
+            "modality": "image",
+            "mime_type": "",
+            "uri": url,
+        }
+
+
+def transform_anthropic_content_part(
+    content_part: "Dict[str, Any]",
+) -> "Optional[Dict[str, Any]]":
+    """
+    Transform an Anthropic content part to Sentry's standardized format.
+
+    This handles the Anthropic image and document formats with source dictionaries.
+
+    Input format:
+    - {"type": "image", "source": {"type": "base64", "media_type": "...", "data": "..."}}
+    - {"type": "image", "source": {"type": "url", "media_type": "...", "url": "..."}}
+    - {"type": "image", "source": {"type": "file", "media_type": "...", "file_id": "..."}}
+    - {"type": "document", "source": {...}} (same source formats)
+
+    Output format (one of):
+    - {"type": "blob", "modality": "...", "mime_type": "...", "content": "..."}
+    - {"type": "uri", "modality": "...", "mime_type": "...", "uri": "..."}
+    - {"type": "file", "modality": "...", "mime_type": "...", "file_id": "..."}
+
+    Args:
+        content_part: A dictionary representing a content part from Anthropic
+
+    Returns:
+        A transformed dictionary in standardized format, or None if the format
+        is not Anthropic format or transformation fails.
+    """
+    if not isinstance(content_part, dict):
+        return None
+
+    block_type = content_part.get("type")
+
+    if block_type not in ("image", "document") or "source" not in content_part:
+        return None
+
+    source = content_part.get("source")
+    if not isinstance(source, dict):
+        return None
+
+    source_type = source.get("type")
+    media_type = source.get("media_type", "")
+    modality = (
+        "document"
+        if block_type == "document"
+        else get_modality_from_mime_type(media_type)
+    )
+
+    if source_type == "base64":
+        return {
+            "type": "blob",
+            "modality": modality,
+            "mime_type": media_type,
+            "content": source.get("data", ""),
+        }
+    elif source_type == "url":
+        return {
+            "type": "uri",
+            "modality": modality,
+            "mime_type": media_type,
+            "uri": source.get("url", ""),
+        }
+    elif source_type == "file":
+        return {
+            "type": "file",
+            "modality": modality,
+            "mime_type": media_type,
+            "file_id": source.get("file_id", ""),
+        }
+
+    return None
+
+
+def transform_google_content_part(
+    content_part: "Dict[str, Any]",
+) -> "Optional[Dict[str, Any]]":
+    """
+    Transform a Google GenAI content part to Sentry's standardized format.
+
+    This handles the Google GenAI inline_data and file_data formats.
+
+    Input format:
+    - {"inline_data": {"mime_type": "...", "data": "..."}}
+    - {"file_data": {"mime_type": "...", "file_uri": "..."}}
+
+    Output format (one of):
+    - {"type": "blob", "modality": "...", "mime_type": "...", "content": "..."}
+    - {"type": "uri", "modality": "...", "mime_type": "...", "uri": "..."}
+
+    Args:
+        content_part: A dictionary representing a content part from Google GenAI
+
+    Returns:
+        A transformed dictionary in standardized format, or None if the format
+        is not Google format or transformation fails.
+    """
+    if not isinstance(content_part, dict):
+        return None
+
+    # Handle Google inline_data format
+    if "inline_data" in content_part:
+        inline_data = content_part.get("inline_data")
+        if isinstance(inline_data, dict):
+            mime_type = inline_data.get("mime_type", "")
+            return {
+                "type": "blob",
+                "modality": get_modality_from_mime_type(mime_type),
+                "mime_type": mime_type,
+                "content": inline_data.get("data", ""),
+            }
+        return None
+
+    # Handle Google file_data format
+    if "file_data" in content_part:
+        file_data = content_part.get("file_data")
+        if isinstance(file_data, dict):
+            mime_type = file_data.get("mime_type", "")
+            return {
+                "type": "uri",
+                "modality": get_modality_from_mime_type(mime_type),
+                "mime_type": mime_type,
+                "uri": file_data.get("file_uri", ""),
+            }
+        return None
+
+    return None
+
+
+def transform_generic_content_part(
+    content_part: "Dict[str, Any]",
+) -> "Optional[Dict[str, Any]]":
+    """
+    Transform a generic/LangChain-style content part to Sentry's standardized format.
+
+    This handles generic formats where the type indicates the modality and
+    the data is provided via direct base64, url, or file_id fields.
+
+    Input format:
+    - {"type": "image", "base64": "...", "mime_type": "..."}
+    - {"type": "audio", "url": "...", "mime_type": "..."}
+    - {"type": "video", "base64": "...", "mime_type": "..."}
+    - {"type": "file", "file_id": "...", "mime_type": "..."}
+
+    Output format (one of):
+    - {"type": "blob", "modality": "...", "mime_type": "...", "content": "..."}
+    - {"type": "uri", "modality": "...", "mime_type": "...", "uri": "..."}
+    - {"type": "file", "modality": "...", "mime_type": "...", "file_id": "..."}
+
+    Args:
+        content_part: A dictionary representing a content part in generic format
+
+    Returns:
+        A transformed dictionary in standardized format, or None if the format
+        is not generic format or transformation fails.
+    """
+    if not isinstance(content_part, dict):
+        return None
+
+    block_type = content_part.get("type")
+
+    if block_type not in ("image", "audio", "video", "file"):
+        return None
+
+    # Ensure it's not Anthropic format (which also uses type: "image")
+    if "source" in content_part:
+        return None
+
+    mime_type = content_part.get("mime_type", "")
+    modality = block_type if block_type != "file" else "document"
+
+    # Check for base64 encoded content
+    if "base64" in content_part:
+        return {
+            "type": "blob",
+            "modality": modality,
+            "mime_type": mime_type,
+            "content": content_part.get("base64", ""),
+        }
+    # Check for URL reference
+    elif "url" in content_part:
+        return {
+            "type": "uri",
+            "modality": modality,
+            "mime_type": mime_type,
+            "uri": content_part.get("url", ""),
+        }
+    # Check for file_id reference
+    elif "file_id" in content_part:
+        return {
+            "type": "file",
+            "modality": modality,
+            "mime_type": mime_type,
+            "file_id": content_part.get("file_id", ""),
+        }
+
+    return None
+
+
+def transform_content_part(
+    content_part: "Dict[str, Any]",
+) -> "Optional[Dict[str, Any]]":
+    """
+    Transform a content part from various AI SDK formats to Sentry's standardized format.
+
+    This is a heuristic dispatcher that detects the format and delegates to the
+    appropriate SDK-specific transformer. For direct SDK integration, prefer using
+    the specific transformers directly:
+    - transform_openai_content_part() for OpenAI/LiteLLM
+    - transform_anthropic_content_part() for Anthropic
+    - transform_google_content_part() for Google GenAI
+    - transform_generic_content_part() for LangChain and other generic formats
+
+    Detection order:
+    1. OpenAI: type == "image_url"
+    2. Google: "inline_data" or "file_data" keys present
+    3. Anthropic: type in ("image", "document") with "source" key
+    4. Generic: type in ("image", "audio", "video", "file") with base64/url/file_id
+
+    Output format (one of):
+    - {"type": "blob", "modality": "...", "mime_type": "...", "content": "..."}
+    - {"type": "uri", "modality": "...", "mime_type": "...", "uri": "..."}
+    - {"type": "file", "modality": "...", "mime_type": "...", "file_id": "..."}
+
+    Args:
+        content_part: A dictionary representing a content part from an AI SDK
+
+    Returns:
+        A transformed dictionary in standardized format, or None if the format
+        is unrecognized or transformation fails.
+    """
+    if not isinstance(content_part, dict):
+        return None
+
+    # Try OpenAI format first (most common, clear indicator)
+    result = transform_openai_content_part(content_part)
+    if result is not None:
+        return result
+
+    # Try Google format (unique keys make it easy to detect)
+    result = transform_google_content_part(content_part)
+    if result is not None:
+        return result
+
+    # Try Anthropic format (has "source" key)
+    result = transform_anthropic_content_part(content_part)
+    if result is not None:
+        return result
+
+    # Try generic format as fallback
+    result = transform_generic_content_part(content_part)
+    if result is not None:
+        return result
+
+    # Unrecognized format
+    return None
+
+
+def transform_message_content(content: "Any") -> "Any":
+    """
+    Transform message content, handling both string content and list of content blocks.
+
+    For list content, each item is transformed using transform_content_part().
+    Items that cannot be transformed (return None) are kept as-is.
+
+    Args:
+        content: Message content - can be a string, list of content blocks, or other
+
+    Returns:
+        - String content: returned as-is
+        - List content: list with each transformable item converted to standardized format
+        - Other: returned as-is
+    """
+    if isinstance(content, str):
+        return content
+
+    if isinstance(content, (list, tuple)):
+        transformed = []
+        for item in content:
+            if isinstance(item, dict):
+                result = transform_content_part(item)
+                # If transformation succeeded, use the result; otherwise keep original
+                transformed.append(result if result is not None else item)
+            else:
+                transformed.append(item)
+        return transformed
+
+    return content
+
+
+def _normalize_data(data: "Any", unpack: bool = True) -> "Any":
+    # convert pydantic data (e.g. OpenAI v1+) to json compatible format
+    if hasattr(data, "model_dump"):
+        # Check if it's a class (type) rather than an instance
+        # Model classes can be passed as arguments (e.g., for schema definitions)
+        if inspect.isclass(data):
+            return f""
+
+        try:
+            return _normalize_data(data.model_dump(), unpack=unpack)
+        except Exception as e:
+            logger.warning("Could not convert pydantic data to JSON: %s", e)
+            return data if isinstance(data, (int, float, bool, str)) else str(data)
+
+    if isinstance(data, list):
+        if unpack and len(data) == 1:
+            return _normalize_data(data[0], unpack=unpack)  # remove empty dimensions
+        return list(_normalize_data(x, unpack=unpack) for x in data)
+
+    if isinstance(data, dict):
+        return {k: _normalize_data(v, unpack=unpack) for (k, v) in data.items()}
+
+    return data if isinstance(data, (int, float, bool, str)) else str(data)
+
+
+def set_data_normalized(
+    span: "Span", key: str, value: "Any", unpack: bool = True
+) -> None:
+    normalized = _normalize_data(value, unpack=unpack)
+    if isinstance(normalized, (int, float, bool, str)):
+        span.set_data(key, normalized)
+    else:
+        span.set_data(key, json.dumps(normalized))
+
+
+def normalize_message_role(role: str) -> str:
+    """
+    Normalize a message role to one of the 4 allowed gen_ai role values.
+    Maps "ai" -> "assistant" and keeps other standard roles unchanged.
+    """
+    return GEN_AI_MESSAGE_ROLE_MAPPING.get(role, role)
+
+
+def normalize_message_roles(messages: "list[dict[str, Any]]") -> "list[dict[str, Any]]":
+    """
+    Normalize roles in a list of messages to use standard gen_ai role values.
+    Creates a deep copy to avoid modifying the original messages.
+    """
+    normalized_messages = []
+    for message in messages:
+        if not isinstance(message, dict):
+            normalized_messages.append(message)
+            continue
+        normalized_message = message.copy()
+        if "role" in message:
+            normalized_message["role"] = normalize_message_role(message["role"])
+        normalized_messages.append(normalized_message)
+
+    return normalized_messages
+
+
+def get_start_span_function() -> "Callable[..., Any]":
+    current_span = sentry_sdk.get_current_span()
+    transaction_exists = (
+        current_span is not None and current_span.containing_transaction is not None
+    )
+    return sentry_sdk.start_span if transaction_exists else sentry_sdk.start_transaction
+
+
+def _truncate_single_message_content_if_present(
+    message: "Dict[str, Any]", max_chars: int
+) -> "Dict[str, Any]":
+    """
+    Truncate a message's content to at most `max_chars` characters and append an
+    ellipsis if truncation occurs.
+    """
+    if not isinstance(message, dict) or "content" not in message:
+        return message
+    content = message["content"]
+
+    if not isinstance(content, str) or len(content) <= max_chars:
+        return message
+
+    message["content"] = content[:max_chars] + "..."
+    return message
+
+
+def _find_truncation_index(messages: "List[Dict[str, Any]]", max_bytes: int) -> int:
+    """
+    Find the index of the first message that would exceed the max bytes limit.
+    Compute the individual message sizes, and return the index of the first message from the back
+    of the list that would exceed the max bytes limit.
+    """
+    running_sum = 0
+    for idx in range(len(messages) - 1, -1, -1):
+        size = len(json.dumps(messages[idx], separators=(",", ":")).encode("utf-8"))
+        running_sum += size
+        if running_sum > max_bytes:
+            return idx + 1
+
+    return 0
+
+
+def redact_blob_message_parts(
+    messages: "List[Dict[str, Any]]",
+) -> "List[Dict[str, Any]]":
+    """
+    Redact blob message parts from the messages by replacing blob content with "[Filtered]".
+
+    This function creates a deep copy of messages that contain blob content to avoid
+    mutating the original message dictionaries. Messages without blob content are
+    returned as-is to minimize copying overhead.
+
+    e.g:
+    {
+        "role": "user",
+        "content": [
+            {
+                "text": "How many ponies do you see in the image?",
+                "type": "text"
+            },
+            {
+                "type": "blob",
+                "modality": "image",
+                "mime_type": "image/jpeg",
+                "content": "data:image/jpeg;base64,..."
+            }
+        ]
+    }
+    becomes:
+    {
+        "role": "user",
+        "content": [
+            {
+                "text": "How many ponies do you see in the image?",
+                "type": "text"
+            },
+            {
+                "type": "blob",
+                "modality": "image",
+                "mime_type": "image/jpeg",
+                "content": "[Filtered]"
+            }
+        ]
+    }
+    """
+
+    # First pass: check if any message contains blob content
+    has_blobs = False
+    for message in messages:
+        if not isinstance(message, dict):
+            continue
+        content = message.get("content")
+        if isinstance(content, list):
+            for item in content:
+                if isinstance(item, dict) and item.get("type") == "blob":
+                    has_blobs = True
+                    break
+        if has_blobs:
+            break
+
+    # If no blobs found, return original messages to avoid unnecessary copying
+    if not has_blobs:
+        return messages
+
+    # Deep copy messages to avoid mutating the original
+    messages_copy = deepcopy(messages)
+
+    # Second pass: redact blob content in the copy
+    for message in messages_copy:
+        if not isinstance(message, dict):
+            continue
+
+        content = message.get("content")
+        if isinstance(content, list):
+            for item in content:
+                if isinstance(item, dict) and item.get("type") == "blob":
+                    item["content"] = BLOB_DATA_SUBSTITUTE
+
+    return messages_copy
+
+
+def truncate_messages_by_size(
+    messages: "List[Dict[str, Any]]",
+    max_bytes: int = MAX_GEN_AI_MESSAGE_BYTES,
+    max_single_message_chars: int = MAX_SINGLE_MESSAGE_CONTENT_CHARS,
+) -> "Tuple[List[Dict[str, Any]], int]":
+    """
+    Returns a truncated messages list, consisting of
+    - the last message, with its content truncated to `max_single_message_chars` characters,
+      if the last message's size exceeds `max_bytes` bytes; otherwise,
+    - the maximum number of messages, starting from the end of the `messages` list, whose total
+      serialized size does not exceed `max_bytes` bytes.
+
+    In the single message case, the serialized message size may exceed `max_bytes`, because
+    truncation is based only on character count in that case.
+    """
+    serialized_json = json.dumps(messages, separators=(",", ":"))
+    current_size = len(serialized_json.encode("utf-8"))
+
+    if current_size <= max_bytes:
+        return messages, 0
+
+    truncation_index = _find_truncation_index(messages, max_bytes)
+    if truncation_index < len(messages):
+        truncated_messages = messages[truncation_index:]
+    else:
+        truncation_index = len(messages) - 1
+        truncated_messages = messages[-1:]
+
+    if len(truncated_messages) == 1:
+        truncated_messages[0] = _truncate_single_message_content_if_present(
+            deepcopy(truncated_messages[0]), max_chars=max_single_message_chars
+        )
+
+    return truncated_messages, truncation_index
+
+
+def truncate_and_annotate_messages(
+    messages: "Optional[List[Dict[str, Any]]]",
+    span: "Any",
+    scope: "Any",
+    max_single_message_chars: int = MAX_SINGLE_MESSAGE_CONTENT_CHARS,
+) -> "Optional[List[Dict[str, Any]]]":
+    if not messages:
+        return None
+
+    messages = redact_blob_message_parts(messages)
+
+    truncated_message = _truncate_single_message_content_if_present(
+        deepcopy(messages[-1]), max_chars=max_single_message_chars
+    )
+    if len(messages) > 1:
+        scope._gen_ai_original_message_count[span.span_id] = len(messages)
+
+    return [truncated_message]
+
+
+def truncate_and_annotate_embedding_inputs(
+    messages: "Optional[List[Dict[str, Any]]]",
+    span: "Any",
+    scope: "Any",
+    max_bytes: int = MAX_GEN_AI_MESSAGE_BYTES,
+) -> "Optional[List[Dict[str, Any]]]":
+    if not messages:
+        return None
+
+    messages = redact_blob_message_parts(messages)
+
+    truncated_messages, removed_count = truncate_messages_by_size(messages, max_bytes)
+    if removed_count > 0:
+        scope._gen_ai_original_message_count[span.span_id] = len(messages)
+
+    return truncated_messages
+
+
+def set_conversation_id(conversation_id: str) -> None:
+    """
+    Set the conversation_id in the scope.
+    """
+    scope = sentry_sdk.get_current_scope()
+    scope.set_conversation_id(conversation_id)
diff --git a/lib/python3.12/site-packages/sentry_sdk/crons/__init__.py b/lib/python3.12/site-packages/sentry_sdk/crons/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f748aaecb6b36b2d837493d5533691d8058124f
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/crons/__init__.py
@@ -0,0 +1,10 @@
+from sentry_sdk.crons.api import capture_checkin
+from sentry_sdk.crons.consts import MonitorStatus
+from sentry_sdk.crons.decorator import monitor
+
+
+__all__ = [
+    "capture_checkin",
+    "MonitorStatus",
+    "monitor",
+]
diff --git a/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f4fac656a6b102345d26fc97626f44c8be5dc7da
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/api.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/api.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dc35ada3b29e67e8ac4980f5ed1c4ff6fd0408d5
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/api.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/consts.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/consts.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..20e21fc7fe678a3c301ae1d6a8a529f1e29becc7
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/consts.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/decorator.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/decorator.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..db4b7965d0532ef98fcef70fe11de71b44a058e9
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/crons/__pycache__/decorator.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/crons/api.py b/lib/python3.12/site-packages/sentry_sdk/crons/api.py
new file mode 100644
index 0000000000000000000000000000000000000000..5b7bdc2480a395f38038b53e1b4b53f836cbfb92
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/crons/api.py
@@ -0,0 +1,60 @@
+import uuid
+
+import sentry_sdk
+from sentry_sdk.utils import logger
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import Optional
+    from sentry_sdk._types import Event, MonitorConfig
+
+
+def _create_check_in_event(
+    monitor_slug: "Optional[str]" = None,
+    check_in_id: "Optional[str]" = None,
+    status: "Optional[str]" = None,
+    duration_s: "Optional[float]" = None,
+    monitor_config: "Optional[MonitorConfig]" = None,
+) -> "Event":
+    options = sentry_sdk.get_client().options
+    check_in_id: str = check_in_id or uuid.uuid4().hex
+
+    check_in: "Event" = {
+        "type": "check_in",
+        "monitor_slug": monitor_slug,
+        "check_in_id": check_in_id,
+        "status": status,
+        "duration": duration_s,
+        "environment": options.get("environment", None),
+        "release": options.get("release", None),
+    }
+
+    if monitor_config:
+        check_in["monitor_config"] = monitor_config
+
+    return check_in
+
+
+def capture_checkin(
+    monitor_slug: "Optional[str]" = None,
+    check_in_id: "Optional[str]" = None,
+    status: "Optional[str]" = None,
+    duration: "Optional[float]" = None,
+    monitor_config: "Optional[MonitorConfig]" = None,
+) -> str:
+    check_in_event = _create_check_in_event(
+        monitor_slug=monitor_slug,
+        check_in_id=check_in_id,
+        status=status,
+        duration_s=duration,
+        monitor_config=monitor_config,
+    )
+
+    sentry_sdk.capture_event(check_in_event)
+
+    logger.debug(
+        f"[Crons] Captured check-in ({check_in_event.get('check_in_id')}): {check_in_event.get('monitor_slug')} -> {check_in_event.get('status')}"
+    )
+
+    return check_in_event["check_in_id"]
diff --git a/lib/python3.12/site-packages/sentry_sdk/crons/consts.py b/lib/python3.12/site-packages/sentry_sdk/crons/consts.py
new file mode 100644
index 0000000000000000000000000000000000000000..be686b4539439d33aa6d3f1391d2179e93d45bcf
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/crons/consts.py
@@ -0,0 +1,4 @@
+class MonitorStatus:
+    IN_PROGRESS = "in_progress"
+    OK = "ok"
+    ERROR = "error"
diff --git a/lib/python3.12/site-packages/sentry_sdk/crons/decorator.py b/lib/python3.12/site-packages/sentry_sdk/crons/decorator.py
new file mode 100644
index 0000000000000000000000000000000000000000..7032183f804945e4f6b1d284293615025711bdde
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/crons/decorator.py
@@ -0,0 +1,137 @@
+from functools import wraps
+from inspect import iscoroutinefunction
+
+from sentry_sdk.crons import capture_checkin
+from sentry_sdk.crons.consts import MonitorStatus
+from sentry_sdk.utils import now
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from collections.abc import Awaitable, Callable
+    from types import TracebackType
+    from typing import (
+        Any,
+        Optional,
+        ParamSpec,
+        Type,
+        TypeVar,
+        Union,
+        cast,
+        overload,
+    )
+    from sentry_sdk._types import MonitorConfig
+
+    P = ParamSpec("P")
+    R = TypeVar("R")
+
+
+class monitor:  # noqa: N801
+    """
+    Decorator/context manager to capture checkin events for a monitor.
+
+    Usage (as decorator):
+    ```
+    import sentry_sdk
+
+    app = Celery()
+
+    @app.task
+    @sentry_sdk.monitor(monitor_slug='my-fancy-slug')
+    def test(arg):
+        print(arg)
+    ```
+
+    This does not have to be used with Celery, but if you do use it with celery,
+    put the `@sentry_sdk.monitor` decorator below Celery's `@app.task` decorator.
+
+    Usage (as context manager):
+    ```
+    import sentry_sdk
+
+    def test(arg):
+        with sentry_sdk.monitor(monitor_slug='my-fancy-slug'):
+            print(arg)
+    ```
+    """
+
+    def __init__(
+        self,
+        monitor_slug: "Optional[str]" = None,
+        monitor_config: "Optional[MonitorConfig]" = None,
+    ) -> None:
+        self.monitor_slug = monitor_slug
+        self.monitor_config = monitor_config
+
+    def __enter__(self) -> None:
+        self.start_timestamp = now()
+        self.check_in_id = capture_checkin(
+            monitor_slug=self.monitor_slug,
+            status=MonitorStatus.IN_PROGRESS,
+            monitor_config=self.monitor_config,
+        )
+
+    def __exit__(
+        self,
+        exc_type: "Optional[Type[BaseException]]",
+        exc_value: "Optional[BaseException]",
+        traceback: "Optional[TracebackType]",
+    ) -> None:
+        duration_s = now() - self.start_timestamp
+
+        if exc_type is None and exc_value is None and traceback is None:
+            status = MonitorStatus.OK
+        else:
+            status = MonitorStatus.ERROR
+
+        capture_checkin(
+            monitor_slug=self.monitor_slug,
+            check_in_id=self.check_in_id,
+            status=status,
+            duration=duration_s,
+            monitor_config=self.monitor_config,
+        )
+
+    if TYPE_CHECKING:
+
+        @overload
+        def __call__(
+            self, fn: "Callable[P, Awaitable[Any]]"
+        ) -> "Callable[P, Awaitable[Any]]":
+            # Unfortunately, mypy does not give us any reliable way to type check the
+            # return value of an Awaitable (i.e. async function) for this overload,
+            # since calling iscouroutinefunction narrows the type to Callable[P, Awaitable[Any]].
+            ...
+
+        @overload
+        def __call__(self, fn: "Callable[P, R]") -> "Callable[P, R]": ...
+
+    def __call__(
+        self,
+        fn: "Union[Callable[P, R], Callable[P, Awaitable[Any]]]",
+    ) -> "Union[Callable[P, R], Callable[P, Awaitable[Any]]]":
+        if iscoroutinefunction(fn):
+            return self._async_wrapper(fn)
+
+        else:
+            if TYPE_CHECKING:
+                fn = cast("Callable[P, R]", fn)
+            return self._sync_wrapper(fn)
+
+    def _async_wrapper(
+        self, fn: "Callable[P, Awaitable[Any]]"
+    ) -> "Callable[P, Awaitable[Any]]":
+        @wraps(fn)
+        async def inner(*args: "P.args", **kwargs: "P.kwargs") -> "R":
+            with self:
+                return await fn(*args, **kwargs)
+
+        return inner
+
+    def _sync_wrapper(self, fn: "Callable[P, R]") -> "Callable[P, R]":
+        @wraps(fn)
+        def inner(*args: "P.args", **kwargs: "P.kwargs") -> "R":
+            with self:
+                return fn(*args, **kwargs)
+
+        return inner
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__init__.py b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3c4c1a683d27192a5e91a1f2ed8ef097ebfcb0bb
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__init__.py
@@ -0,0 +1,7 @@
+from sentry_sdk.integrations.opentelemetry.span_processor import SentrySpanProcessor
+from sentry_sdk.integrations.opentelemetry.propagator import SentryPropagator
+
+__all__ = [
+    "SentryPropagator",
+    "SentrySpanProcessor",
+]
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a8e11ef718fd8ce49157601881a41a717a89e664
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/consts.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/consts.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4213ebd82f96d20c5a340a53884c8c40293009e2
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/consts.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/integration.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/integration.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4987728a6051c6379a6225698e52fbbb3f224cfb
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/integration.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/propagator.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/propagator.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ef3de811bbd908678dceab29da6e4b5050a2e732
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/propagator.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/span_processor.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/span_processor.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..fdac794e07bde008592dccfeeb878601b490e4a5
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/__pycache__/span_processor.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/consts.py b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/consts.py
new file mode 100644
index 0000000000000000000000000000000000000000..d6733036ea74542bf8b608321d73c92311ca6728
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/consts.py
@@ -0,0 +1,9 @@
+from sentry_sdk.integrations import DidNotEnable
+
+try:
+    from opentelemetry.context import create_key
+except ImportError:
+    raise DidNotEnable("opentelemetry not installed")
+
+SENTRY_TRACE_KEY = create_key("sentry-trace")
+SENTRY_BAGGAGE_KEY = create_key("sentry-baggage")
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/integration.py b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/integration.py
new file mode 100644
index 0000000000000000000000000000000000000000..83588a2b388120b52ddc897f9565be2079e28455
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/integration.py
@@ -0,0 +1,55 @@
+"""
+IMPORTANT: The contents of this file are part of a proof of concept and as such
+are experimental and not suitable for production use. They may be changed or
+removed at any time without prior notice.
+"""
+
+from sentry_sdk.integrations import DidNotEnable, Integration
+from sentry_sdk.integrations.opentelemetry.propagator import SentryPropagator
+from sentry_sdk.integrations.opentelemetry.span_processor import SentrySpanProcessor
+from sentry_sdk.utils import logger
+
+try:
+    from opentelemetry import trace
+    from opentelemetry.propagate import set_global_textmap
+    from opentelemetry.sdk.trace import TracerProvider
+except ImportError:
+    raise DidNotEnable("opentelemetry not installed")
+
+try:
+    from opentelemetry.instrumentation.django import DjangoInstrumentor  # type: ignore[import-not-found]
+except ImportError:
+    DjangoInstrumentor = None
+
+
+CONFIGURABLE_INSTRUMENTATIONS = {
+    DjangoInstrumentor: {"is_sql_commentor_enabled": True},
+}
+
+
+class OpenTelemetryIntegration(Integration):
+    identifier = "opentelemetry"
+
+    @staticmethod
+    def setup_once() -> None:
+        logger.warning(
+            "[OTel] Initializing highly experimental OpenTelemetry support. "
+            "Use at your own risk."
+        )
+
+        _setup_sentry_tracing()
+        # _setup_instrumentors()
+
+        logger.debug("[OTel] Finished setting up OpenTelemetry integration")
+
+
+def _setup_sentry_tracing() -> None:
+    provider = TracerProvider()
+    provider.add_span_processor(SentrySpanProcessor())
+    trace.set_tracer_provider(provider)
+    set_global_textmap(SentryPropagator())
+
+
+def _setup_instrumentors() -> None:
+    for instrumentor, kwargs in CONFIGURABLE_INSTRUMENTATIONS.items():
+        instrumentor().instrument(**kwargs)
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/propagator.py b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/propagator.py
new file mode 100644
index 0000000000000000000000000000000000000000..a40f038ffab3dd6666814b73e1c452e43b42320a
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/propagator.py
@@ -0,0 +1,128 @@
+from sentry_sdk.integrations import DidNotEnable
+from sentry_sdk.integrations.opentelemetry.consts import (
+    SENTRY_BAGGAGE_KEY,
+    SENTRY_TRACE_KEY,
+)
+from sentry_sdk.integrations.opentelemetry.span_processor import (
+    SentrySpanProcessor,
+)
+from sentry_sdk.tracing import (
+    BAGGAGE_HEADER_NAME,
+    SENTRY_TRACE_HEADER_NAME,
+)
+from sentry_sdk.tracing_utils import Baggage, extract_sentrytrace_data
+
+try:
+    from opentelemetry import trace
+    from opentelemetry.context import (
+        Context,
+        get_current,
+        set_value,
+    )
+    from opentelemetry.propagators.textmap import (
+        CarrierT,
+        Getter,
+        Setter,
+        TextMapPropagator,
+        default_getter,
+        default_setter,
+    )
+    from opentelemetry.trace import (
+        NonRecordingSpan,
+        SpanContext,
+        TraceFlags,
+    )
+except ImportError:
+    raise DidNotEnable("opentelemetry not installed")
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import Optional, Set
+
+
+class SentryPropagator(TextMapPropagator):
+    """
+    Propagates tracing headers for Sentry's tracing system in a way OTel understands.
+    """
+
+    def extract(
+        self,
+        carrier: "CarrierT",
+        context: "Optional[Context]" = None,
+        getter: "Getter[CarrierT]" = default_getter,
+    ) -> "Context":
+        if context is None:
+            context = get_current()
+
+        sentry_trace = getter.get(carrier, SENTRY_TRACE_HEADER_NAME)
+        if not sentry_trace:
+            return context
+
+        sentrytrace = extract_sentrytrace_data(sentry_trace[0])
+        if not sentrytrace:
+            return context
+
+        context = set_value(SENTRY_TRACE_KEY, sentrytrace, context)
+
+        trace_id, span_id = sentrytrace["trace_id"], sentrytrace["parent_span_id"]
+
+        span_context = SpanContext(
+            trace_id=int(trace_id, 16),  # type: ignore
+            span_id=int(span_id, 16),  # type: ignore
+            # we simulate a sampled trace on the otel side and leave the sampling to sentry
+            trace_flags=TraceFlags(TraceFlags.SAMPLED),
+            is_remote=True,
+        )
+
+        baggage_header = getter.get(carrier, BAGGAGE_HEADER_NAME)
+
+        if baggage_header:
+            baggage = Baggage.from_incoming_header(baggage_header[0])
+        else:
+            # If there's an incoming sentry-trace but no incoming baggage header,
+            # for instance in traces coming from older SDKs,
+            # baggage will be empty and frozen and won't be populated as head SDK.
+            baggage = Baggage(sentry_items={})
+
+        baggage.freeze()
+        context = set_value(SENTRY_BAGGAGE_KEY, baggage, context)
+
+        span = NonRecordingSpan(span_context)
+        modified_context = trace.set_span_in_context(span, context)
+        return modified_context
+
+    def inject(
+        self,
+        carrier: "CarrierT",
+        context: "Optional[Context]" = None,
+        setter: "Setter[CarrierT]" = default_setter,
+    ) -> None:
+        if context is None:
+            context = get_current()
+
+        current_span = trace.get_current_span(context)
+        current_span_context = current_span.get_span_context()
+
+        if not current_span_context.is_valid:
+            return
+
+        span_id = trace.format_span_id(current_span_context.span_id)
+
+        span_map = SentrySpanProcessor().otel_span_map
+        sentry_span = span_map.get(span_id, None)
+        if not sentry_span:
+            return
+
+        setter.set(carrier, SENTRY_TRACE_HEADER_NAME, sentry_span.to_traceparent())
+
+        if sentry_span.containing_transaction:
+            baggage = sentry_span.containing_transaction.get_baggage()
+            if baggage:
+                baggage_data = baggage.serialize()
+                if baggage_data:
+                    setter.set(carrier, BAGGAGE_HEADER_NAME, baggage_data)
+
+    @property
+    def fields(self) -> "Set[str]":
+        return {SENTRY_TRACE_HEADER_NAME, BAGGAGE_HEADER_NAME}
diff --git a/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/span_processor.py b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/span_processor.py
new file mode 100644
index 0000000000000000000000000000000000000000..407baef61c59ebd75099405f39cdd1c13ee75a91
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/integrations/opentelemetry/span_processor.py
@@ -0,0 +1,389 @@
+from datetime import datetime, timezone
+from time import time
+from typing import TYPE_CHECKING, cast
+
+from sentry_sdk import get_client, start_transaction
+from sentry_sdk.consts import INSTRUMENTER, SPANSTATUS
+from sentry_sdk.integrations import DidNotEnable
+from sentry_sdk.integrations.opentelemetry.consts import (
+    SENTRY_BAGGAGE_KEY,
+    SENTRY_TRACE_KEY,
+)
+from sentry_sdk.scope import add_global_event_processor
+from sentry_sdk.tracing import Transaction, Span as SentrySpan
+
+from urllib3.util import parse_url as urlparse
+
+try:
+    from opentelemetry.context import get_value
+    from opentelemetry.sdk.trace import SpanProcessor, ReadableSpan as OTelSpan
+    from opentelemetry.semconv.trace import SpanAttributes
+    from opentelemetry.trace import (
+        format_span_id,
+        format_trace_id,
+        get_current_span,
+        SpanKind,
+    )
+    from opentelemetry.trace.span import (
+        INVALID_SPAN_ID,
+        INVALID_TRACE_ID,
+    )
+except ImportError:
+    raise DidNotEnable("opentelemetry not installed")
+
+if TYPE_CHECKING:
+    from typing import Any, Optional, Union
+    from opentelemetry import context as context_api
+    from sentry_sdk._types import Event, Hint
+
+OPEN_TELEMETRY_CONTEXT = "otel"
+SPAN_MAX_TIME_OPEN_MINUTES = 10
+SPAN_ORIGIN = "auto.otel"
+
+
+def link_trace_context_to_error_event(
+    event: "Event", otel_span_map: "dict[str, Union[Transaction, SentrySpan]]"
+) -> "Event":
+    client = get_client()
+
+    if client.options["instrumenter"] != INSTRUMENTER.OTEL:
+        return event
+
+    if hasattr(event, "type") and event["type"] == "transaction":
+        return event
+
+    otel_span = get_current_span()
+    if not otel_span:
+        return event
+
+    ctx = otel_span.get_span_context()
+
+    if ctx.trace_id == INVALID_TRACE_ID or ctx.span_id == INVALID_SPAN_ID:
+        return event
+
+    sentry_span = otel_span_map.get(format_span_id(ctx.span_id), None)
+    if not sentry_span:
+        return event
+
+    contexts = event.setdefault("contexts", {})
+    contexts.setdefault("trace", {}).update(sentry_span.get_trace_context())
+
+    return event
+
+
+class SentrySpanProcessor(SpanProcessor):
+    """
+    Converts OTel spans into Sentry spans so they can be sent to the Sentry backend.
+    """
+
+    # The mapping from otel span ids to sentry spans
+    otel_span_map: "dict[str, Union[Transaction, SentrySpan]]" = {}
+
+    # The currently open spans. Elements will be discarded after SPAN_MAX_TIME_OPEN_MINUTES
+    open_spans: "dict[int, set[str]]" = {}
+
+    def __new__(cls) -> "SentrySpanProcessor":
+        if not hasattr(cls, "instance"):
+            cls.instance = super().__new__(cls)
+
+        return cls.instance
+
+    def __init__(self) -> None:
+        @add_global_event_processor
+        def global_event_processor(event: "Event", hint: "Hint") -> "Event":
+            return link_trace_context_to_error_event(event, self.otel_span_map)
+
+    def _prune_old_spans(self: "SentrySpanProcessor") -> None:
+        """
+        Prune spans that have been open for too long.
+        """
+        current_time_minutes = int(time() / 60)
+        for span_start_minutes in list(
+            self.open_spans.keys()
+        ):  # making a list because we change the dict
+            # prune empty open spans buckets
+            if self.open_spans[span_start_minutes] == set():
+                self.open_spans.pop(span_start_minutes)
+
+            # prune old buckets
+            elif current_time_minutes - span_start_minutes > SPAN_MAX_TIME_OPEN_MINUTES:
+                for span_id in self.open_spans.pop(span_start_minutes):
+                    self.otel_span_map.pop(span_id, None)
+
+    def on_start(
+        self,
+        otel_span: "OTelSpan",
+        parent_context: "Optional[context_api.Context]" = None,
+    ) -> None:
+        client = get_client()
+
+        if not client.parsed_dsn:
+            return
+
+        if client.options["instrumenter"] != INSTRUMENTER.OTEL:
+            return
+
+        if not otel_span.get_span_context().is_valid:
+            return
+
+        if self._is_sentry_span(otel_span):
+            return
+
+        trace_data = self._get_trace_data(otel_span, parent_context)
+
+        parent_span_id = trace_data["parent_span_id"]
+        sentry_parent_span = (
+            self.otel_span_map.get(parent_span_id) if parent_span_id else None
+        )
+
+        start_timestamp = None
+        if otel_span.start_time is not None:
+            start_timestamp = datetime.fromtimestamp(
+                otel_span.start_time / 1e9, timezone.utc
+            )  # OTel spans have nanosecond precision
+
+        sentry_span = None
+        if sentry_parent_span:
+            sentry_span = sentry_parent_span.start_child(
+                span_id=trace_data["span_id"],
+                name=otel_span.name,
+                start_timestamp=start_timestamp,
+                instrumenter=INSTRUMENTER.OTEL,
+                origin=SPAN_ORIGIN,
+            )
+        else:
+            sentry_span = start_transaction(
+                name=otel_span.name,
+                span_id=trace_data["span_id"],
+                parent_span_id=parent_span_id,
+                trace_id=trace_data["trace_id"],
+                baggage=trace_data["baggage"],
+                start_timestamp=start_timestamp,
+                instrumenter=INSTRUMENTER.OTEL,
+                origin=SPAN_ORIGIN,
+            )
+
+        self.otel_span_map[trace_data["span_id"]] = sentry_span
+
+        if otel_span.start_time is not None:
+            span_start_in_minutes = int(
+                otel_span.start_time / 1e9 / 60
+            )  # OTel spans have nanosecond precision
+            self.open_spans.setdefault(span_start_in_minutes, set()).add(
+                trace_data["span_id"]
+            )
+
+        self._prune_old_spans()
+
+    def on_end(self, otel_span: "OTelSpan") -> None:
+        client = get_client()
+
+        if client.options["instrumenter"] != INSTRUMENTER.OTEL:
+            return
+
+        span_context = otel_span.get_span_context()
+        if not span_context.is_valid:
+            return
+
+        span_id = format_span_id(span_context.span_id)
+        sentry_span = self.otel_span_map.pop(span_id, None)
+        if not sentry_span:
+            return
+
+        sentry_span.op = otel_span.name
+
+        self._update_span_with_otel_status(sentry_span, otel_span)
+
+        if isinstance(sentry_span, Transaction):
+            sentry_span.name = otel_span.name
+            sentry_span.set_context(
+                OPEN_TELEMETRY_CONTEXT, self._get_otel_context(otel_span)
+            )
+            self._update_transaction_with_otel_data(sentry_span, otel_span)
+
+        else:
+            self._update_span_with_otel_data(sentry_span, otel_span)
+
+        end_timestamp = None
+        if otel_span.end_time is not None:
+            end_timestamp = datetime.fromtimestamp(
+                otel_span.end_time / 1e9, timezone.utc
+            )  # OTel spans have nanosecond precision
+
+        sentry_span.finish(end_timestamp=end_timestamp)
+
+        if otel_span.start_time is not None:
+            span_start_in_minutes = int(
+                otel_span.start_time / 1e9 / 60
+            )  # OTel spans have nanosecond precision
+            self.open_spans.setdefault(span_start_in_minutes, set()).discard(span_id)
+
+        self._prune_old_spans()
+
+    def _is_sentry_span(self, otel_span: "OTelSpan") -> bool:
+        """
+        Break infinite loop:
+        HTTP requests to Sentry are caught by OTel and send again to Sentry.
+        """
+        otel_span_url = None
+        if otel_span.attributes is not None:
+            otel_span_url = otel_span.attributes.get(SpanAttributes.HTTP_URL)
+        otel_span_url = cast("Optional[str]", otel_span_url)
+
+        parsed_dsn = get_client().parsed_dsn
+        dsn_url = parsed_dsn.netloc if parsed_dsn else None
+
+        if otel_span_url and dsn_url and dsn_url in otel_span_url:
+            return True
+
+        return False
+
+    def _get_otel_context(self, otel_span: "OTelSpan") -> "dict[str, Any]":
+        """
+        Returns the OTel context for Sentry.
+        See: https://develop.sentry.dev/sdk/performance/opentelemetry/#step-5-add-opentelemetry-context
+        """
+        ctx = {}
+
+        if otel_span.attributes:
+            ctx["attributes"] = dict(otel_span.attributes)
+
+        if otel_span.resource.attributes:
+            ctx["resource"] = dict(otel_span.resource.attributes)
+
+        return ctx
+
+    def _get_trace_data(
+        self, otel_span: "OTelSpan", parent_context: "Optional[context_api.Context]"
+    ) -> "dict[str, Any]":
+        """
+        Extracts tracing information from one OTel span and its parent OTel context.
+        """
+        trace_data: "dict[str, Any]" = {}
+        span_context = otel_span.get_span_context()
+
+        span_id = format_span_id(span_context.span_id)
+        trace_data["span_id"] = span_id
+
+        trace_id = format_trace_id(span_context.trace_id)
+        trace_data["trace_id"] = trace_id
+
+        parent_span_id = (
+            format_span_id(otel_span.parent.span_id) if otel_span.parent else None
+        )
+        trace_data["parent_span_id"] = parent_span_id
+
+        sentry_trace_data = get_value(SENTRY_TRACE_KEY, parent_context)
+        sentry_trace_data = cast("dict[str, Union[str, bool, None]]", sentry_trace_data)
+        trace_data["parent_sampled"] = (
+            sentry_trace_data["parent_sampled"] if sentry_trace_data else None
+        )
+
+        baggage = get_value(SENTRY_BAGGAGE_KEY, parent_context)
+        trace_data["baggage"] = baggage
+
+        return trace_data
+
+    def _update_span_with_otel_status(
+        self, sentry_span: "SentrySpan", otel_span: "OTelSpan"
+    ) -> None:
+        """
+        Set the Sentry span status from the OTel span
+        """
+        if otel_span.status.is_unset:
+            return
+
+        if otel_span.status.is_ok:
+            sentry_span.set_status(SPANSTATUS.OK)
+            return
+
+        sentry_span.set_status(SPANSTATUS.INTERNAL_ERROR)
+
+    def _update_span_with_otel_data(
+        self, sentry_span: "SentrySpan", otel_span: "OTelSpan"
+    ) -> None:
+        """
+        Convert OTel span data and update the Sentry span with it.
+        This should eventually happen on the server when ingesting the spans.
+        """
+        sentry_span.set_data("otel.kind", otel_span.kind)
+
+        op = otel_span.name
+        description = otel_span.name
+
+        if otel_span.attributes is not None:
+            for key, val in otel_span.attributes.items():
+                sentry_span.set_data(key, val)
+
+            http_method = otel_span.attributes.get(SpanAttributes.HTTP_METHOD)
+            http_method = cast("Optional[str]", http_method)
+
+            db_query = otel_span.attributes.get(SpanAttributes.DB_SYSTEM)
+
+            if http_method:
+                op = "http"
+
+                if otel_span.kind == SpanKind.SERVER:
+                    op += ".server"
+                elif otel_span.kind == SpanKind.CLIENT:
+                    op += ".client"
+
+                description = http_method
+
+                peer_name = otel_span.attributes.get(SpanAttributes.NET_PEER_NAME, None)
+                if peer_name:
+                    description += " {}".format(peer_name)
+
+                target = otel_span.attributes.get(SpanAttributes.HTTP_TARGET, None)
+                if target:
+                    description += " {}".format(target)
+
+                if not peer_name and not target:
+                    url = otel_span.attributes.get(SpanAttributes.HTTP_URL, None)
+                    url = cast("Optional[str]", url)
+                    if url:
+                        parsed_url = urlparse(url)
+                        url = "{}://{}{}".format(
+                            parsed_url.scheme, parsed_url.netloc, parsed_url.path
+                        )
+                        description += " {}".format(url)
+
+                status_code = otel_span.attributes.get(
+                    SpanAttributes.HTTP_STATUS_CODE, None
+                )
+                status_code = cast("Optional[int]", status_code)
+                if status_code:
+                    sentry_span.set_http_status(status_code)
+
+            elif db_query:
+                op = "db"
+                statement = otel_span.attributes.get(SpanAttributes.DB_STATEMENT, None)
+                statement = cast("Optional[str]", statement)
+                if statement:
+                    description = statement
+
+        sentry_span.op = op
+        sentry_span.description = description
+
+    def _update_transaction_with_otel_data(
+        self, sentry_span: "SentrySpan", otel_span: "OTelSpan"
+    ) -> None:
+        if otel_span.attributes is None:
+            return
+
+        http_method = otel_span.attributes.get(SpanAttributes.HTTP_METHOD)
+
+        if http_method:
+            status_code = otel_span.attributes.get(SpanAttributes.HTTP_STATUS_CODE)
+            status_code = cast("Optional[int]", status_code)
+            if status_code:
+                sentry_span.set_http_status(status_code)
+
+            op = "http"
+
+            if otel_span.kind == SpanKind.SERVER:
+                op += ".server"
+            elif otel_span.kind == SpanKind.CLIENT:
+                op += ".client"
+
+            sentry_span.op = op
diff --git a/lib/python3.12/site-packages/sentry_sdk/profiler/__init__.py b/lib/python3.12/site-packages/sentry_sdk/profiler/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0bc63e3a6d9d2692e577d05bb77fb549d4b0b15f
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/profiler/__init__.py
@@ -0,0 +1,49 @@
+from sentry_sdk.profiler.continuous_profiler import (
+    start_profile_session,
+    start_profiler,
+    stop_profile_session,
+    stop_profiler,
+)
+from sentry_sdk.profiler.transaction_profiler import (
+    MAX_PROFILE_DURATION_NS,
+    PROFILE_MINIMUM_SAMPLES,
+    Profile,
+    Scheduler,
+    ThreadScheduler,
+    GeventScheduler,
+    has_profiling_enabled,
+    setup_profiler,
+    teardown_profiler,
+)
+from sentry_sdk.profiler.utils import (
+    DEFAULT_SAMPLING_FREQUENCY,
+    MAX_STACK_DEPTH,
+    get_frame_name,
+    extract_frame,
+    extract_stack,
+    frame_id,
+)
+
+__all__ = [
+    "start_profile_session",  # TODO: Deprecate this in favor of `start_profiler`
+    "start_profiler",
+    "stop_profile_session",  # TODO: Deprecate this in favor of `stop_profiler`
+    "stop_profiler",
+    # DEPRECATED: The following was re-exported for backwards compatibility. It
+    # will be removed from sentry_sdk.profiler in a future release.
+    "MAX_PROFILE_DURATION_NS",
+    "PROFILE_MINIMUM_SAMPLES",
+    "Profile",
+    "Scheduler",
+    "ThreadScheduler",
+    "GeventScheduler",
+    "has_profiling_enabled",
+    "setup_profiler",
+    "teardown_profiler",
+    "DEFAULT_SAMPLING_FREQUENCY",
+    "MAX_STACK_DEPTH",
+    "get_frame_name",
+    "extract_frame",
+    "extract_stack",
+    "frame_id",
+]
diff --git a/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..19f1e65ea2bd65dc6ed606d5b1e99cfc37863aa2
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/continuous_profiler.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/continuous_profiler.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9f85c2099eaab383b152f278bf589a012dd7f399
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/continuous_profiler.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/transaction_profiler.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/transaction_profiler.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8f51a21dfbae6894723b02a1835a92dd3c4fdb68
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/transaction_profiler.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3cba7889df0ecb6181dbbd862c36a221d116d739
Binary files /dev/null and b/lib/python3.12/site-packages/sentry_sdk/profiler/__pycache__/utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/sentry_sdk/profiler/continuous_profiler.py b/lib/python3.12/site-packages/sentry_sdk/profiler/continuous_profiler.py
new file mode 100644
index 0000000000000000000000000000000000000000..a4c16a63d57f258779720e7e6bc3244006990446
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/profiler/continuous_profiler.py
@@ -0,0 +1,714 @@
+import atexit
+import os
+import random
+import sys
+import threading
+import time
+import uuid
+import warnings
+from collections import deque
+from datetime import datetime, timezone
+
+from sentry_sdk.consts import VERSION
+from sentry_sdk.envelope import Envelope
+from sentry_sdk._lru_cache import LRUCache
+from sentry_sdk.profiler.utils import (
+    DEFAULT_SAMPLING_FREQUENCY,
+    extract_stack,
+)
+from sentry_sdk.utils import (
+    capture_internal_exception,
+    is_gevent,
+    logger,
+    now,
+    set_in_app_in_frames,
+)
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import Any
+    from typing import Callable
+    from typing import Deque
+    from typing import Dict
+    from typing import List
+    from typing import Optional
+    from typing import Set
+    from typing import Type
+    from typing import Union
+    from typing_extensions import TypedDict
+    from sentry_sdk._types import ContinuousProfilerMode, SDKInfo
+    from sentry_sdk.profiler.utils import (
+        ExtractedSample,
+        FrameId,
+        StackId,
+        ThreadId,
+        ProcessedFrame,
+        ProcessedStack,
+    )
+
+    ProcessedSample = TypedDict(
+        "ProcessedSample",
+        {
+            "timestamp": float,
+            "thread_id": ThreadId,
+            "stack_id": int,
+        },
+    )
+
+
+try:
+    from gevent.monkey import get_original
+    from gevent.threadpool import ThreadPool as _ThreadPool
+
+    ThreadPool: "Optional[Type[_ThreadPool]]" = _ThreadPool
+    thread_sleep = get_original("time", "sleep")
+except ImportError:
+    thread_sleep = time.sleep
+    ThreadPool = None
+
+
+_scheduler: "Optional[ContinuousScheduler]" = None
+
+
+def setup_continuous_profiler(
+    options: "Dict[str, Any]",
+    sdk_info: "SDKInfo",
+    capture_func: "Callable[[Envelope], None]",
+) -> bool:
+    global _scheduler
+
+    already_initialized = _scheduler is not None
+
+    if already_initialized:
+        logger.debug("[Profiling] Continuous Profiler is already setup")
+        teardown_continuous_profiler()
+
+    if is_gevent():
+        # If gevent has patched the threading modules then we cannot rely on
+        # them to spawn a native thread for sampling.
+        # Instead we default to the GeventContinuousScheduler which is capable of
+        # spawning native threads within gevent.
+        default_profiler_mode = GeventContinuousScheduler.mode
+    else:
+        default_profiler_mode = ThreadContinuousScheduler.mode
+
+    if options.get("profiler_mode") is not None:
+        profiler_mode = options["profiler_mode"]
+    else:
+        # TODO: deprecate this and just use the existing `profiler_mode`
+        experiments = options.get("_experiments", {})
+
+        profiler_mode = (
+            experiments.get("continuous_profiling_mode") or default_profiler_mode
+        )
+
+    frequency = DEFAULT_SAMPLING_FREQUENCY
+
+    if profiler_mode == ThreadContinuousScheduler.mode:
+        _scheduler = ThreadContinuousScheduler(
+            frequency, options, sdk_info, capture_func
+        )
+    elif profiler_mode == GeventContinuousScheduler.mode:
+        _scheduler = GeventContinuousScheduler(
+            frequency, options, sdk_info, capture_func
+        )
+    else:
+        raise ValueError("Unknown continuous profiler mode: {}".format(profiler_mode))
+
+    logger.debug(
+        "[Profiling] Setting up continuous profiler in {mode} mode".format(
+            mode=_scheduler.mode
+        )
+    )
+
+    if not already_initialized:
+        atexit.register(teardown_continuous_profiler)
+
+    return True
+
+
+def is_profile_session_sampled() -> bool:
+    if _scheduler is None:
+        return False
+    return _scheduler.sampled
+
+
+def try_autostart_continuous_profiler() -> None:
+    # TODO: deprecate this as it'll be replaced by the auto lifecycle option
+
+    if _scheduler is None:
+        return
+
+    if not _scheduler.is_auto_start_enabled():
+        return
+
+    _scheduler.manual_start()
+
+
+def try_profile_lifecycle_trace_start() -> "Union[ContinuousProfile, None]":
+    if _scheduler is None:
+        return None
+
+    return _scheduler.auto_start()
+
+
+def start_profiler() -> None:
+    if _scheduler is None:
+        return
+
+    _scheduler.manual_start()
+
+
+def start_profile_session() -> None:
+    warnings.warn(
+        "The `start_profile_session` function is deprecated. Please use `start_profile` instead.",
+        DeprecationWarning,
+        stacklevel=2,
+    )
+    start_profiler()
+
+
+def stop_profiler() -> None:
+    if _scheduler is None:
+        return
+
+    _scheduler.manual_stop()
+
+
+def stop_profile_session() -> None:
+    warnings.warn(
+        "The `stop_profile_session` function is deprecated. Please use `stop_profile` instead.",
+        DeprecationWarning,
+        stacklevel=2,
+    )
+    stop_profiler()
+
+
+def teardown_continuous_profiler() -> None:
+    stop_profiler()
+
+    global _scheduler
+    _scheduler = None
+
+
+def get_profiler_id() -> "Union[str, None]":
+    if _scheduler is None:
+        return None
+    return _scheduler.profiler_id
+
+
+def determine_profile_session_sampling_decision(
+    sample_rate: "Union[float, None]",
+) -> bool:
+    # `None` is treated as `0.0`
+    if not sample_rate:
+        return False
+
+    return random.random() < float(sample_rate)
+
+
+class ContinuousProfile:
+    active: bool = True
+
+    def stop(self) -> None:
+        self.active = False
+
+
+class ContinuousScheduler:
+    mode: "ContinuousProfilerMode" = "unknown"
+
+    def __init__(
+        self,
+        frequency: int,
+        options: "Dict[str, Any]",
+        sdk_info: "SDKInfo",
+        capture_func: "Callable[[Envelope], None]",
+    ) -> None:
+        self.interval = 1.0 / frequency
+        self.options = options
+        self.sdk_info = sdk_info
+        self.capture_func = capture_func
+
+        self.lifecycle = self.options.get("profile_lifecycle")
+        profile_session_sample_rate = self.options.get("profile_session_sample_rate")
+        self.sampled = determine_profile_session_sampling_decision(
+            profile_session_sample_rate
+        )
+
+        self.sampler = self.make_sampler()
+        self.buffer: "Optional[ProfileBuffer]" = None
+        self.pid: "Optional[int]" = None
+
+        self.running = False
+        self.soft_shutdown = False
+
+        self.new_profiles: "Deque[ContinuousProfile]" = deque(maxlen=128)
+        self.active_profiles: "Set[ContinuousProfile]" = set()
+
+    def is_auto_start_enabled(self) -> bool:
+        # Ensure that the scheduler only autostarts once per process.
+        # This is necessary because many web servers use forks to spawn
+        # additional processes. And the profiler is only spawned on the
+        # master process, then it often only profiles the main process
+        # and not the ones where the requests are being handled.
+        if self.pid == os.getpid():
+            return False
+
+        experiments = self.options.get("_experiments")
+        if not experiments:
+            return False
+
+        return experiments.get("continuous_profiling_auto_start")
+
+    def auto_start(self) -> "Union[ContinuousProfile, None]":
+        if not self.sampled:
+            return None
+
+        if self.lifecycle != "trace":
+            return None
+
+        logger.debug("[Profiling] Auto starting profiler")
+
+        profile = ContinuousProfile()
+
+        self.new_profiles.append(profile)
+        self.ensure_running()
+
+        return profile
+
+    def manual_start(self) -> None:
+        if not self.sampled:
+            return
+
+        if self.lifecycle != "manual":
+            return
+
+        self.ensure_running()
+
+    def manual_stop(self) -> None:
+        if self.lifecycle != "manual":
+            return
+
+        self.teardown()
+
+    def ensure_running(self) -> None:
+        raise NotImplementedError
+
+    def teardown(self) -> None:
+        raise NotImplementedError
+
+    def pause(self) -> None:
+        raise NotImplementedError
+
+    def reset_buffer(self) -> None:
+        self.buffer = ProfileBuffer(
+            self.options, self.sdk_info, PROFILE_BUFFER_SECONDS, self.capture_func
+        )
+
+    @property
+    def profiler_id(self) -> "Union[str, None]":
+        if self.buffer is None:
+            return None
+        return self.buffer.profiler_id
+
+    def make_sampler(self) -> "Callable[..., bool]":
+        cwd = os.getcwd()
+
+        cache = LRUCache(max_size=256)
+
+        if self.lifecycle == "trace":
+
+            def _sample_stack(*args: "Any", **kwargs: "Any") -> bool:
+                """
+                Take a sample of the stack on all the threads in the process.
+                This should be called at a regular interval to collect samples.
+                """
+
+                # no profiles taking place, so we can stop early
+                if not self.new_profiles and not self.active_profiles:
+                    return True
+
+                # This is the number of profiles we want to pop off.
+                # It's possible another thread adds a new profile to
+                # the list and we spend longer than we want inside
+                # the loop below.
+                #
+                # Also make sure to set this value before extracting
+                # frames so we do not write to any new profiles that
+                # were started after this point.
+                new_profiles = len(self.new_profiles)
+
+                ts = now()
+
+                try:
+                    sample = [
+                        (str(tid), extract_stack(frame, cache, cwd))
+                        for tid, frame in sys._current_frames().items()
+                    ]
+                except AttributeError:
+                    # For some reason, the frame we get doesn't have certain attributes.
+                    # When this happens, we abandon the current sample as it's bad.
+                    capture_internal_exception(sys.exc_info())
+                    return False
+
+                # Move the new profiles into the active_profiles set.
+                #
+                # We cannot directly add the to active_profiles set
+                # in `start_profiling` because it is called from other
+                # threads which can cause a RuntimeError when it the
+                # set sizes changes during iteration without a lock.
+                #
+                # We also want to avoid using a lock here so threads
+                # that are starting profiles are not blocked until it
+                # can acquire the lock.
+                for _ in range(new_profiles):
+                    self.active_profiles.add(self.new_profiles.popleft())
+                inactive_profiles = []
+
+                for profile in self.active_profiles:
+                    if not profile.active:
+                        # If a profile is marked inactive, we buffer it
+                        # to `inactive_profiles` so it can be removed.
+                        # We cannot remove it here as it would result
+                        # in a RuntimeError.
+                        inactive_profiles.append(profile)
+
+                for profile in inactive_profiles:
+                    self.active_profiles.remove(profile)
+
+                if self.buffer is not None:
+                    self.buffer.write(ts, sample)
+
+                return False
+
+        else:
+
+            def _sample_stack(*args: "Any", **kwargs: "Any") -> bool:
+                """
+                Take a sample of the stack on all the threads in the process.
+                This should be called at a regular interval to collect samples.
+                """
+
+                ts = now()
+
+                try:
+                    sample = [
+                        (str(tid), extract_stack(frame, cache, cwd))
+                        for tid, frame in sys._current_frames().items()
+                    ]
+                except AttributeError:
+                    # For some reason, the frame we get doesn't have certain attributes.
+                    # When this happens, we abandon the current sample as it's bad.
+                    capture_internal_exception(sys.exc_info())
+                    return False
+
+                if self.buffer is not None:
+                    self.buffer.write(ts, sample)
+
+                return False
+
+        return _sample_stack
+
+    def run(self) -> None:
+        last = time.perf_counter()
+
+        while self.running:
+            self.soft_shutdown = self.sampler()
+
+            # some time may have elapsed since the last time
+            # we sampled, so we need to account for that and
+            # not sleep for too long
+            elapsed = time.perf_counter() - last
+            if elapsed < self.interval:
+                thread_sleep(self.interval - elapsed)
+
+            # the soft shutdown happens here to give it a chance
+            # for the profiler to be reused
+            if self.soft_shutdown:
+                self.running = False
+
+                # make sure to explicitly exit the profiler here or there might
+                # be multiple profilers at once
+                break
+
+            # after sleeping, make sure to take the current
+            # timestamp so we can use it next iteration
+            last = time.perf_counter()
+
+        if self.buffer is not None:
+            self.buffer.flush()
+            self.buffer = None
+
+
+class ThreadContinuousScheduler(ContinuousScheduler):
+    """
+    This scheduler is based on running a daemon thread that will call
+    the sampler at a regular interval.
+    """
+
+    mode: "ContinuousProfilerMode" = "thread"
+    name = "sentry.profiler.ThreadContinuousScheduler"
+
+    def __init__(
+        self,
+        frequency: int,
+        options: "Dict[str, Any]",
+        sdk_info: "SDKInfo",
+        capture_func: "Callable[[Envelope], None]",
+    ) -> None:
+        super().__init__(frequency, options, sdk_info, capture_func)
+
+        self.thread: "Optional[threading.Thread]" = None
+        self.lock = threading.Lock()
+
+    def ensure_running(self) -> None:
+        self.soft_shutdown = False
+
+        pid = os.getpid()
+
+        # is running on the right process
+        if self.running and self.pid == pid:
+            return
+
+        with self.lock:
+            # another thread may have tried to acquire the lock
+            # at the same time so it may start another thread
+            # make sure to check again before proceeding
+            if self.running and self.pid == pid:
+                return
+
+            self.pid = pid
+            self.running = True
+
+            # if the profiler thread is changing,
+            # we should create a new buffer along with it
+            self.reset_buffer()
+
+            # make sure the thread is a daemon here otherwise this
+            # can keep the application running after other threads
+            # have exited
+            self.thread = threading.Thread(name=self.name, target=self.run, daemon=True)
+
+            try:
+                self.thread.start()
+            except RuntimeError:
+                # Unfortunately at this point the interpreter is in a state that no
+                # longer allows us to spawn a thread and we have to bail.
+                self.running = False
+                self.thread = None
+
+    def teardown(self) -> None:
+        if self.running:
+            self.running = False
+
+        if self.thread is not None:
+            self.thread.join()
+            self.thread = None
+
+        self.buffer = None
+
+
+class GeventContinuousScheduler(ContinuousScheduler):
+    """
+    This scheduler is based on the thread scheduler but adapted to work with
+    gevent. When using gevent, it may monkey patch the threading modules
+    (`threading` and `_thread`). This results in the use of greenlets instead
+    of native threads.
+
+    This is an issue because the sampler CANNOT run in a greenlet because
+    1. Other greenlets doing sync work will prevent the sampler from running
+    2. The greenlet runs in the same thread as other greenlets so when taking
+       a sample, other greenlets will have been evicted from the thread. This
+       results in a sample containing only the sampler's code.
+    """
+
+    mode: "ContinuousProfilerMode" = "gevent"
+
+    def __init__(
+        self,
+        frequency: int,
+        options: "Dict[str, Any]",
+        sdk_info: "SDKInfo",
+        capture_func: "Callable[[Envelope], None]",
+    ) -> None:
+        if ThreadPool is None:
+            raise ValueError("Profiler mode: {} is not available".format(self.mode))
+
+        super().__init__(frequency, options, sdk_info, capture_func)
+
+        self.thread: "Optional[_ThreadPool]" = None
+        self.lock = threading.Lock()
+
+    def ensure_running(self) -> None:
+        self.soft_shutdown = False
+
+        pid = os.getpid()
+
+        # is running on the right process
+        if self.running and self.pid == pid:
+            return
+
+        with self.lock:
+            # another thread may have tried to acquire the lock
+            # at the same time so it may start another thread
+            # make sure to check again before proceeding
+            if self.running and self.pid == pid:
+                return
+
+            self.pid = pid
+            self.running = True
+
+            # if the profiler thread is changing,
+            # we should create a new buffer along with it
+            self.reset_buffer()
+
+            self.thread = ThreadPool(1)  # type: ignore[misc]
+            try:
+                self.thread.spawn(self.run)
+            except RuntimeError:
+                # Unfortunately at this point the interpreter is in a state that no
+                # longer allows us to spawn a thread and we have to bail.
+                self.running = False
+                self.thread = None
+
+    def teardown(self) -> None:
+        if self.running:
+            self.running = False
+
+        if self.thread is not None:
+            self.thread.join()
+            self.thread = None
+
+        self.buffer = None
+
+
+PROFILE_BUFFER_SECONDS = 60
+
+
+class ProfileBuffer:
+    def __init__(
+        self,
+        options: "Dict[str, Any]",
+        sdk_info: "SDKInfo",
+        buffer_size: int,
+        capture_func: "Callable[[Envelope], None]",
+    ) -> None:
+        self.options = options
+        self.sdk_info = sdk_info
+        self.buffer_size = buffer_size
+        self.capture_func = capture_func
+
+        self.profiler_id = uuid.uuid4().hex
+        self.chunk = ProfileChunk()
+
+        # Make sure to use the same clock to compute a sample's monotonic timestamp
+        # to ensure the timestamps are correctly aligned.
+        self.start_monotonic_time = now()
+
+        # Make sure the start timestamp is defined only once per profiler id.
+        # This prevents issues with clock drift within a single profiler session.
+        #
+        # Subtracting the start_monotonic_time here to find a fixed starting position
+        # for relative monotonic timestamps for each sample.
+        self.start_timestamp = (
+            datetime.now(timezone.utc).timestamp() - self.start_monotonic_time
+        )
+
+    def write(self, monotonic_time: float, sample: "ExtractedSample") -> None:
+        if self.should_flush(monotonic_time):
+            self.flush()
+            self.chunk = ProfileChunk()
+            self.start_monotonic_time = now()
+
+        self.chunk.write(self.start_timestamp + monotonic_time, sample)
+
+    def should_flush(self, monotonic_time: float) -> bool:
+        # If the delta between the new monotonic time and the start monotonic time
+        # exceeds the buffer size, it means we should flush the chunk
+        return monotonic_time - self.start_monotonic_time >= self.buffer_size
+
+    def flush(self) -> None:
+        chunk = self.chunk.to_json(self.profiler_id, self.options, self.sdk_info)
+        envelope = Envelope()
+        envelope.add_profile_chunk(chunk)
+        self.capture_func(envelope)
+
+
+class ProfileChunk:
+    def __init__(self) -> None:
+        self.chunk_id = uuid.uuid4().hex
+
+        self.indexed_frames: "Dict[FrameId, int]" = {}
+        self.indexed_stacks: "Dict[StackId, int]" = {}
+        self.frames: "List[ProcessedFrame]" = []
+        self.stacks: "List[ProcessedStack]" = []
+        self.samples: "List[ProcessedSample]" = []
+
+    def write(self, ts: float, sample: "ExtractedSample") -> None:
+        for tid, (stack_id, frame_ids, frames) in sample:
+            try:
+                # Check if the stack is indexed first, this lets us skip
+                # indexing frames if it's not necessary
+                if stack_id not in self.indexed_stacks:
+                    for i, frame_id in enumerate(frame_ids):
+                        if frame_id not in self.indexed_frames:
+                            self.indexed_frames[frame_id] = len(self.indexed_frames)
+                            self.frames.append(frames[i])
+
+                    self.indexed_stacks[stack_id] = len(self.indexed_stacks)
+                    self.stacks.append(
+                        [self.indexed_frames[frame_id] for frame_id in frame_ids]
+                    )
+
+                self.samples.append(
+                    {
+                        "timestamp": ts,
+                        "thread_id": tid,
+                        "stack_id": self.indexed_stacks[stack_id],
+                    }
+                )
+            except AttributeError:
+                # For some reason, the frame we get doesn't have certain attributes.
+                # When this happens, we abandon the current sample as it's bad.
+                capture_internal_exception(sys.exc_info())
+
+    def to_json(
+        self, profiler_id: str, options: "Dict[str, Any]", sdk_info: "SDKInfo"
+    ) -> "Dict[str, Any]":
+        profile = {
+            "frames": self.frames,
+            "stacks": self.stacks,
+            "samples": self.samples,
+            "thread_metadata": {
+                str(thread.ident): {
+                    "name": str(thread.name),
+                }
+                for thread in threading.enumerate()
+            },
+        }
+
+        set_in_app_in_frames(
+            profile["frames"],
+            options["in_app_exclude"],
+            options["in_app_include"],
+            options["project_root"],
+        )
+
+        payload = {
+            "chunk_id": self.chunk_id,
+            "client_sdk": {
+                "name": sdk_info["name"],
+                "version": VERSION,
+            },
+            "platform": "python",
+            "profile": profile,
+            "profiler_id": profiler_id,
+            "version": "2",
+        }
+
+        for key in "release", "environment", "dist":
+            if options[key] is not None:
+                payload[key] = str(options[key]).strip()
+
+        return payload
diff --git a/lib/python3.12/site-packages/sentry_sdk/profiler/transaction_profiler.py b/lib/python3.12/site-packages/sentry_sdk/profiler/transaction_profiler.py
new file mode 100644
index 0000000000000000000000000000000000000000..822d9cb7422bd2edc8f888f3a7c60516c1a00c21
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/profiler/transaction_profiler.py
@@ -0,0 +1,809 @@
+"""
+This file is originally based on code from https://github.com/nylas/nylas-perftools,
+which is published under the following license:
+
+The MIT License (MIT)
+
+Copyright (c) 2014 Nylas
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+"""
+
+import atexit
+import os
+import platform
+import random
+import sys
+import threading
+import time
+import uuid
+import warnings
+from abc import ABC, abstractmethod
+from collections import deque
+
+import sentry_sdk
+from sentry_sdk._lru_cache import LRUCache
+from sentry_sdk.profiler.utils import (
+    DEFAULT_SAMPLING_FREQUENCY,
+    extract_stack,
+)
+from sentry_sdk.utils import (
+    capture_internal_exception,
+    capture_internal_exceptions,
+    get_current_thread_meta,
+    is_gevent,
+    is_valid_sample_rate,
+    logger,
+    nanosecond_time,
+    set_in_app_in_frames,
+)
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from typing import Any
+    from typing import Callable
+    from typing import Deque
+    from typing import Dict
+    from typing import List
+    from typing import Optional
+    from typing import Set
+    from typing import Type
+    from typing_extensions import TypedDict
+
+    from sentry_sdk.profiler.utils import (
+        ProcessedStack,
+        ProcessedFrame,
+        ProcessedThreadMetadata,
+        FrameId,
+        StackId,
+        ThreadId,
+        ExtractedSample,
+    )
+    from sentry_sdk._types import Event, SamplingContext, ProfilerMode
+
+    ProcessedSample = TypedDict(
+        "ProcessedSample",
+        {
+            "elapsed_since_start_ns": str,
+            "thread_id": ThreadId,
+            "stack_id": int,
+        },
+    )
+
+    ProcessedProfile = TypedDict(
+        "ProcessedProfile",
+        {
+            "frames": List[ProcessedFrame],
+            "stacks": List[ProcessedStack],
+            "samples": List[ProcessedSample],
+            "thread_metadata": Dict[ThreadId, ProcessedThreadMetadata],
+        },
+    )
+
+
+try:
+    from gevent.monkey import get_original
+    from gevent.threadpool import ThreadPool as _ThreadPool
+
+    ThreadPool: "Optional[Type[_ThreadPool]]" = _ThreadPool
+    thread_sleep = get_original("time", "sleep")
+except ImportError:
+    thread_sleep = time.sleep
+
+    ThreadPool = None
+
+
+_scheduler: "Optional[Scheduler]" = None
+
+
+# The minimum number of unique samples that must exist in a profile to be
+# considered valid.
+PROFILE_MINIMUM_SAMPLES = 2
+
+
+def has_profiling_enabled(options: "Dict[str, Any]") -> bool:
+    profiles_sampler = options["profiles_sampler"]
+    if profiles_sampler is not None:
+        return True
+
+    profiles_sample_rate = options["profiles_sample_rate"]
+    if profiles_sample_rate is not None and profiles_sample_rate > 0:
+        return True
+
+    profiles_sample_rate = options["_experiments"].get("profiles_sample_rate")
+    if profiles_sample_rate is not None:
+        logger.warning(
+            "_experiments['profiles_sample_rate'] is deprecated. "
+            "Please use the non-experimental profiles_sample_rate option "
+            "directly."
+        )
+        if profiles_sample_rate > 0:
+            return True
+
+    return False
+
+
+def setup_profiler(options: "Dict[str, Any]") -> bool:
+    global _scheduler
+
+    if _scheduler is not None:
+        logger.debug("[Profiling] Profiler is already setup")
+        return False
+
+    frequency = DEFAULT_SAMPLING_FREQUENCY
+
+    if is_gevent():
+        # If gevent has patched the threading modules then we cannot rely on
+        # them to spawn a native thread for sampling.
+        # Instead we default to the GeventScheduler which is capable of
+        # spawning native threads within gevent.
+        default_profiler_mode = GeventScheduler.mode
+    else:
+        default_profiler_mode = ThreadScheduler.mode
+
+    if options.get("profiler_mode") is not None:
+        profiler_mode = options["profiler_mode"]
+    else:
+        profiler_mode = options.get("_experiments", {}).get("profiler_mode")
+        if profiler_mode is not None:
+            logger.warning(
+                "_experiments['profiler_mode'] is deprecated. Please use the "
+                "non-experimental profiler_mode option directly."
+            )
+        profiler_mode = profiler_mode or default_profiler_mode
+
+    if (
+        profiler_mode == ThreadScheduler.mode
+        # for legacy reasons, we'll keep supporting sleep mode for this scheduler
+        or profiler_mode == "sleep"
+    ):
+        _scheduler = ThreadScheduler(frequency=frequency)
+    elif profiler_mode == GeventScheduler.mode:
+        _scheduler = GeventScheduler(frequency=frequency)
+    else:
+        raise ValueError("Unknown profiler mode: {}".format(profiler_mode))
+
+    logger.debug(
+        "[Profiling] Setting up profiler in {mode} mode".format(mode=_scheduler.mode)
+    )
+    _scheduler.setup()
+
+    atexit.register(teardown_profiler)
+
+    return True
+
+
+def teardown_profiler() -> None:
+    global _scheduler
+
+    if _scheduler is not None:
+        _scheduler.teardown()
+
+    _scheduler = None
+
+
+MAX_PROFILE_DURATION_NS = int(3e10)  # 30 seconds
+
+
+class Profile:
+    def __init__(
+        self,
+        sampled: "Optional[bool]",
+        start_ns: int,
+        hub: "Optional[sentry_sdk.Hub]" = None,
+        scheduler: "Optional[Scheduler]" = None,
+    ) -> None:
+        self.scheduler = _scheduler if scheduler is None else scheduler
+
+        self.event_id: str = uuid.uuid4().hex
+
+        self.sampled: "Optional[bool]" = sampled
+
+        # Various framework integrations are capable of overwriting the active thread id.
+        # If it is set to `None` at the end of the profile, we fall back to the default.
+        self._default_active_thread_id: int = get_current_thread_meta()[0] or 0
+        self.active_thread_id: "Optional[int]" = None
+
+        try:
+            self.start_ns: int = start_ns
+        except AttributeError:
+            self.start_ns = 0
+
+        self.stop_ns: int = 0
+        self.active: bool = False
+
+        self.indexed_frames: "Dict[FrameId, int]" = {}
+        self.indexed_stacks: "Dict[StackId, int]" = {}
+        self.frames: "List[ProcessedFrame]" = []
+        self.stacks: "List[ProcessedStack]" = []
+        self.samples: "List[ProcessedSample]" = []
+
+        self.unique_samples = 0
+
+        # Backwards compatibility with the old hub property
+        self._hub: "Optional[sentry_sdk.Hub]" = None
+        if hub is not None:
+            self._hub = hub
+            warnings.warn(
+                "The `hub` parameter is deprecated. Please do not use it.",
+                DeprecationWarning,
+                stacklevel=2,
+            )
+
+    def update_active_thread_id(self) -> None:
+        self.active_thread_id = get_current_thread_meta()[0]
+        logger.debug(
+            "[Profiling] updating active thread id to {tid}".format(
+                tid=self.active_thread_id
+            )
+        )
+
+    def _set_initial_sampling_decision(
+        self, sampling_context: "SamplingContext"
+    ) -> None:
+        """
+        Sets the profile's sampling decision according to the following
+        precedence rules:
+
+        1. If the transaction to be profiled is not sampled, that decision
+        will be used, regardless of anything else.
+
+        2. Use `profiles_sample_rate` to decide.
+        """
+
+        # The corresponding transaction was not sampled,
+        # so don't generate a profile for it.
+        if not self.sampled:
+            logger.debug(
+                "[Profiling] Discarding profile because transaction is discarded."
+            )
+            self.sampled = False
+            return
+
+        # The profiler hasn't been properly initialized.
+        if self.scheduler is None:
+            logger.debug(
+                "[Profiling] Discarding profile because profiler was not started."
+            )
+            self.sampled = False
+            return
+
+        client = sentry_sdk.get_client()
+        if not client.is_active():
+            self.sampled = False
+            return
+
+        options = client.options
+
+        if callable(options.get("profiles_sampler")):
+            sample_rate = options["profiles_sampler"](sampling_context)
+        elif options["profiles_sample_rate"] is not None:
+            sample_rate = options["profiles_sample_rate"]
+        else:
+            sample_rate = options["_experiments"].get("profiles_sample_rate")
+
+        # The profiles_sample_rate option was not set, so profiling
+        # was never enabled.
+        if sample_rate is None:
+            logger.debug(
+                "[Profiling] Discarding profile because profiling was not enabled."
+            )
+            self.sampled = False
+            return
+
+        if not is_valid_sample_rate(sample_rate, source="Profiling"):
+            logger.warning(
+                "[Profiling] Discarding profile because of invalid sample rate."
+            )
+            self.sampled = False
+            return
+
+        # Now we roll the dice. random.random is inclusive of 0, but not of 1,
+        # so strict < is safe here. In case sample_rate is a boolean, cast it
+        # to a float (True becomes 1.0 and False becomes 0.0)
+        self.sampled = random.random() < float(sample_rate)
+
+        if self.sampled:
+            logger.debug("[Profiling] Initializing profile")
+        else:
+            logger.debug(
+                "[Profiling] Discarding profile because it's not included in the random sample (sample rate = {sample_rate})".format(
+                    sample_rate=float(sample_rate)
+                )
+            )
+
+    def start(self) -> None:
+        if not self.sampled or self.active:
+            return
+
+        assert self.scheduler, "No scheduler specified"
+        logger.debug("[Profiling] Starting profile")
+        self.active = True
+        if not self.start_ns:
+            self.start_ns = nanosecond_time()
+        self.scheduler.start_profiling(self)
+
+    def stop(self) -> None:
+        if not self.sampled or not self.active:
+            return
+
+        assert self.scheduler, "No scheduler specified"
+        logger.debug("[Profiling] Stopping profile")
+        self.active = False
+        self.stop_ns = nanosecond_time()
+
+    def __enter__(self) -> "Profile":
+        scope = sentry_sdk.get_isolation_scope()
+        old_profile = scope.profile
+        scope.profile = self
+
+        self._context_manager_state = (scope, old_profile)
+
+        self.start()
+
+        return self
+
+    def __exit__(
+        self, ty: "Optional[Any]", value: "Optional[Any]", tb: "Optional[Any]"
+    ) -> None:
+        with capture_internal_exceptions():
+            self.stop()
+
+            scope, old_profile = self._context_manager_state
+            del self._context_manager_state
+
+            scope.profile = old_profile
+
+    def write(self, ts: int, sample: "ExtractedSample") -> None:
+        if not self.active:
+            return
+
+        if ts < self.start_ns:
+            return
+
+        offset = ts - self.start_ns
+        if offset > MAX_PROFILE_DURATION_NS:
+            self.stop()
+            return
+
+        self.unique_samples += 1
+
+        elapsed_since_start_ns = str(offset)
+
+        for tid, (stack_id, frame_ids, frames) in sample:
+            try:
+                # Check if the stack is indexed first, this lets us skip
+                # indexing frames if it's not necessary
+                if stack_id not in self.indexed_stacks:
+                    for i, frame_id in enumerate(frame_ids):
+                        if frame_id not in self.indexed_frames:
+                            self.indexed_frames[frame_id] = len(self.indexed_frames)
+                            self.frames.append(frames[i])
+
+                    self.indexed_stacks[stack_id] = len(self.indexed_stacks)
+                    self.stacks.append(
+                        [self.indexed_frames[frame_id] for frame_id in frame_ids]
+                    )
+
+                self.samples.append(
+                    {
+                        "elapsed_since_start_ns": elapsed_since_start_ns,
+                        "thread_id": tid,
+                        "stack_id": self.indexed_stacks[stack_id],
+                    }
+                )
+            except AttributeError:
+                # For some reason, the frame we get doesn't have certain attributes.
+                # When this happens, we abandon the current sample as it's bad.
+                capture_internal_exception(sys.exc_info())
+
+    def process(self) -> "ProcessedProfile":
+        # This collects the thread metadata at the end of a profile. Doing it
+        # this way means that any threads that terminate before the profile ends
+        # will not have any metadata associated with it.
+        thread_metadata: "Dict[str, ProcessedThreadMetadata]" = {
+            str(thread.ident): {
+                "name": str(thread.name),
+            }
+            for thread in threading.enumerate()
+        }
+
+        return {
+            "frames": self.frames,
+            "stacks": self.stacks,
+            "samples": self.samples,
+            "thread_metadata": thread_metadata,
+        }
+
+    def to_json(
+        self, event_opt: "Event", options: "Dict[str, Any]"
+    ) -> "Dict[str, Any]":
+        profile = self.process()
+
+        set_in_app_in_frames(
+            profile["frames"],
+            options["in_app_exclude"],
+            options["in_app_include"],
+            options["project_root"],
+        )
+
+        return {
+            "environment": event_opt.get("environment"),
+            "event_id": self.event_id,
+            "platform": "python",
+            "profile": profile,
+            "release": event_opt.get("release", ""),
+            "timestamp": event_opt["start_timestamp"],
+            "version": "1",
+            "device": {
+                "architecture": platform.machine(),
+            },
+            "os": {
+                "name": platform.system(),
+                "version": platform.release(),
+            },
+            "runtime": {
+                "name": platform.python_implementation(),
+                "version": platform.python_version(),
+            },
+            "transactions": [
+                {
+                    "id": event_opt["event_id"],
+                    "name": event_opt["transaction"],
+                    # we start the transaction before the profile and this is
+                    # the transaction start time relative to the profile, so we
+                    # hardcode it to 0 until we can start the profile before
+                    "relative_start_ns": "0",
+                    # use the duration of the profile instead of the transaction
+                    # because we end the transaction after the profile
+                    "relative_end_ns": str(self.stop_ns - self.start_ns),
+                    "trace_id": event_opt["contexts"]["trace"]["trace_id"],
+                    "active_thread_id": str(
+                        self._default_active_thread_id
+                        if self.active_thread_id is None
+                        else self.active_thread_id
+                    ),
+                }
+            ],
+        }
+
+    def valid(self) -> bool:
+        client = sentry_sdk.get_client()
+        if not client.is_active():
+            return False
+
+        if not has_profiling_enabled(client.options):
+            return False
+
+        if self.sampled is None or not self.sampled:
+            if client.transport:
+                client.transport.record_lost_event(
+                    "sample_rate", data_category="profile"
+                )
+            return False
+
+        if self.unique_samples < PROFILE_MINIMUM_SAMPLES:
+            if client.transport:
+                client.transport.record_lost_event(
+                    "insufficient_data", data_category="profile"
+                )
+            logger.debug("[Profiling] Discarding profile because insufficient samples.")
+            return False
+
+        return True
+
+    @property
+    def hub(self) -> "Optional[sentry_sdk.Hub]":
+        warnings.warn(
+            "The `hub` attribute is deprecated. Please do not access it.",
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        return self._hub
+
+    @hub.setter
+    def hub(self, value: "Optional[sentry_sdk.Hub]") -> None:
+        warnings.warn(
+            "The `hub` attribute is deprecated. Please do not set it.",
+            DeprecationWarning,
+            stacklevel=2,
+        )
+        self._hub = value
+
+
+class Scheduler(ABC):
+    mode: "ProfilerMode" = "unknown"
+
+    def __init__(self, frequency: int) -> None:
+        self.interval = 1.0 / frequency
+
+        self.sampler = self.make_sampler()
+
+        # cap the number of new profiles at any time so it does not grow infinitely
+        self.new_profiles: "Deque[Profile]" = deque(maxlen=128)
+        self.active_profiles: "Set[Profile]" = set()
+
+    def __enter__(self) -> "Scheduler":
+        self.setup()
+        return self
+
+    def __exit__(
+        self, ty: "Optional[Any]", value: "Optional[Any]", tb: "Optional[Any]"
+    ) -> None:
+        self.teardown()
+
+    @abstractmethod
+    def setup(self) -> None:
+        pass
+
+    @abstractmethod
+    def teardown(self) -> None:
+        pass
+
+    def ensure_running(self) -> None:
+        """
+        Ensure the scheduler is running. By default, this method is a no-op.
+        The method should be overridden by any implementation for which it is
+        relevant.
+        """
+        return None
+
+    def start_profiling(self, profile: "Profile") -> None:
+        self.ensure_running()
+        self.new_profiles.append(profile)
+
+    def make_sampler(self) -> "Callable[..., None]":
+        cwd = os.getcwd()
+
+        cache = LRUCache(max_size=256)
+
+        def _sample_stack(*args: "Any", **kwargs: "Any") -> None:
+            """
+            Take a sample of the stack on all the threads in the process.
+            This should be called at a regular interval to collect samples.
+            """
+            # no profiles taking place, so we can stop early
+            if not self.new_profiles and not self.active_profiles:
+                # make sure to clear the cache if we're not profiling so we dont
+                # keep a reference to the last stack of frames around
+                return
+
+            # This is the number of profiles we want to pop off.
+            # It's possible another thread adds a new profile to
+            # the list and we spend longer than we want inside
+            # the loop below.
+            #
+            # Also make sure to set this value before extracting
+            # frames so we do not write to any new profiles that
+            # were started after this point.
+            new_profiles = len(self.new_profiles)
+
+            now = nanosecond_time()
+
+            try:
+                sample = [
+                    (str(tid), extract_stack(frame, cache, cwd))
+                    for tid, frame in sys._current_frames().items()
+                ]
+            except AttributeError:
+                # For some reason, the frame we get doesn't have certain attributes.
+                # When this happens, we abandon the current sample as it's bad.
+                capture_internal_exception(sys.exc_info())
+                return
+
+            # Move the new profiles into the active_profiles set.
+            #
+            # We cannot directly add the to active_profiles set
+            # in `start_profiling` because it is called from other
+            # threads which can cause a RuntimeError when it the
+            # set sizes changes during iteration without a lock.
+            #
+            # We also want to avoid using a lock here so threads
+            # that are starting profiles are not blocked until it
+            # can acquire the lock.
+            for _ in range(new_profiles):
+                self.active_profiles.add(self.new_profiles.popleft())
+
+            inactive_profiles = []
+
+            for profile in self.active_profiles:
+                if profile.active:
+                    profile.write(now, sample)
+                else:
+                    # If a profile is marked inactive, we buffer it
+                    # to `inactive_profiles` so it can be removed.
+                    # We cannot remove it here as it would result
+                    # in a RuntimeError.
+                    inactive_profiles.append(profile)
+
+            for profile in inactive_profiles:
+                self.active_profiles.remove(profile)
+
+        return _sample_stack
+
+
+class ThreadScheduler(Scheduler):
+    """
+    This scheduler is based on running a daemon thread that will call
+    the sampler at a regular interval.
+    """
+
+    mode: "ProfilerMode" = "thread"
+    name = "sentry.profiler.ThreadScheduler"
+
+    def __init__(self, frequency: int) -> None:
+        super().__init__(frequency=frequency)
+
+        # used to signal to the thread that it should stop
+        self.running = False
+        self.thread: "Optional[threading.Thread]" = None
+        self.pid: "Optional[int]" = None
+        self.lock = threading.Lock()
+
+    def setup(self) -> None:
+        pass
+
+    def teardown(self) -> None:
+        if self.running:
+            self.running = False
+            if self.thread is not None:
+                self.thread.join()
+
+    def ensure_running(self) -> None:
+        """
+        Check that the profiler has an active thread to run in, and start one if
+        that's not the case.
+
+        Note that this might fail (e.g. in Python 3.12 it's not possible to
+        spawn new threads at interpreter shutdown). In that case self.running
+        will be False after running this function.
+        """
+        pid = os.getpid()
+
+        # is running on the right process
+        if self.running and self.pid == pid:
+            return
+
+        with self.lock:
+            # another thread may have tried to acquire the lock
+            # at the same time so it may start another thread
+            # make sure to check again before proceeding
+            if self.running and self.pid == pid:
+                return
+
+            self.pid = pid
+            self.running = True
+
+            # make sure the thread is a daemon here otherwise this
+            # can keep the application running after other threads
+            # have exited
+            self.thread = threading.Thread(name=self.name, target=self.run, daemon=True)
+            try:
+                self.thread.start()
+            except RuntimeError:
+                # Unfortunately at this point the interpreter is in a state that no
+                # longer allows us to spawn a thread and we have to bail.
+                self.running = False
+                self.thread = None
+                return
+
+    def run(self) -> None:
+        last = time.perf_counter()
+
+        while self.running:
+            self.sampler()
+
+            # some time may have elapsed since the last time
+            # we sampled, so we need to account for that and
+            # not sleep for too long
+            elapsed = time.perf_counter() - last
+            if elapsed < self.interval:
+                thread_sleep(self.interval - elapsed)
+
+            # after sleeping, make sure to take the current
+            # timestamp so we can use it next iteration
+            last = time.perf_counter()
+
+
+class GeventScheduler(Scheduler):
+    """
+    This scheduler is based on the thread scheduler but adapted to work with
+    gevent. When using gevent, it may monkey patch the threading modules
+    (`threading` and `_thread`). This results in the use of greenlets instead
+    of native threads.
+
+    This is an issue because the sampler CANNOT run in a greenlet because
+    1. Other greenlets doing sync work will prevent the sampler from running
+    2. The greenlet runs in the same thread as other greenlets so when taking
+       a sample, other greenlets will have been evicted from the thread. This
+       results in a sample containing only the sampler's code.
+    """
+
+    mode: "ProfilerMode" = "gevent"
+    name = "sentry.profiler.GeventScheduler"
+
+    def __init__(self, frequency: int) -> None:
+        if ThreadPool is None:
+            raise ValueError("Profiler mode: {} is not available".format(self.mode))
+
+        super().__init__(frequency=frequency)
+
+        # used to signal to the thread that it should stop
+        self.running = False
+        self.thread: "Optional[_ThreadPool]" = None
+        self.pid: "Optional[int]" = None
+
+        # This intentionally uses the gevent patched threading.Lock.
+        # The lock will be required when first trying to start profiles
+        # as we need to spawn the profiler thread from the greenlets.
+        self.lock = threading.Lock()
+
+    def setup(self) -> None:
+        pass
+
+    def teardown(self) -> None:
+        if self.running:
+            self.running = False
+            if self.thread is not None:
+                self.thread.join()
+
+    def ensure_running(self) -> None:
+        pid = os.getpid()
+
+        # is running on the right process
+        if self.running and self.pid == pid:
+            return
+
+        with self.lock:
+            # another thread may have tried to acquire the lock
+            # at the same time so it may start another thread
+            # make sure to check again before proceeding
+            if self.running and self.pid == pid:
+                return
+
+            self.pid = pid
+            self.running = True
+
+            self.thread = ThreadPool(1)  # type: ignore[misc]
+            try:
+                self.thread.spawn(self.run)
+            except RuntimeError:
+                # Unfortunately at this point the interpreter is in a state that no
+                # longer allows us to spawn a thread and we have to bail.
+                self.running = False
+                self.thread = None
+                return
+
+    def run(self) -> None:
+        last = time.perf_counter()
+
+        while self.running:
+            self.sampler()
+
+            # some time may have elapsed since the last time
+            # we sampled, so we need to account for that and
+            # not sleep for too long
+            elapsed = time.perf_counter() - last
+            if elapsed < self.interval:
+                thread_sleep(self.interval - elapsed)
+
+            # after sleeping, make sure to take the current
+            # timestamp so we can use it next iteration
+            last = time.perf_counter()
diff --git a/lib/python3.12/site-packages/sentry_sdk/profiler/utils.py b/lib/python3.12/site-packages/sentry_sdk/profiler/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d122101ad4af9e8ca973a666597fe70d674b923
--- /dev/null
+++ b/lib/python3.12/site-packages/sentry_sdk/profiler/utils.py
@@ -0,0 +1,189 @@
+import os
+from collections import deque
+
+from sentry_sdk._compat import PY311
+from sentry_sdk.utils import filename_for_module
+
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from sentry_sdk._lru_cache import LRUCache
+    from types import FrameType
+    from typing import Deque
+    from typing import List
+    from typing import Optional
+    from typing import Sequence
+    from typing import Tuple
+    from typing_extensions import TypedDict
+
+    ThreadId = str
+
+    ProcessedStack = List[int]
+
+    ProcessedFrame = TypedDict(
+        "ProcessedFrame",
+        {
+            "abs_path": str,
+            "filename": Optional[str],
+            "function": str,
+            "lineno": int,
+            "module": Optional[str],
+        },
+    )
+
+    ProcessedThreadMetadata = TypedDict(
+        "ProcessedThreadMetadata",
+        {"name": str},
+    )
+
+    FrameId = Tuple[
+        str,  # abs_path
+        int,  # lineno
+        str,  # function
+    ]
+    FrameIds = Tuple[FrameId, ...]
+
+    # The exact value of this id is not very meaningful. The purpose
+    # of this id is to give us a compact and unique identifier for a
+    # raw stack that can be used as a key to a dictionary so that it
+    # can be used during the sampled format generation.
+    StackId = Tuple[int, int]
+
+    ExtractedStack = Tuple[StackId, FrameIds, List[ProcessedFrame]]
+    ExtractedSample = Sequence[Tuple[ThreadId, ExtractedStack]]
+
+# The default sampling frequency to use. This is set at 101 in order to
+# mitigate the effects of lockstep sampling.
+DEFAULT_SAMPLING_FREQUENCY = 101
+
+
+# We want to impose a stack depth limit so that samples aren't too large.
+MAX_STACK_DEPTH = 128
+
+
+if PY311:
+
+    def get_frame_name(frame: "FrameType") -> str:
+        return frame.f_code.co_qualname
+
+else:
+
+    def get_frame_name(frame: "FrameType") -> str:
+        f_code = frame.f_code
+        co_varnames = f_code.co_varnames
+
+        # co_name only contains the frame name.  If the frame was a method,
+        # the class name will NOT be included.
+        name = f_code.co_name
+
+        # if it was a method, we can get the class name by inspecting
+        # the f_locals for the `self` argument
+        try:
+            if (
+                # the co_varnames start with the frame's positional arguments
+                # and we expect the first to be `self` if its an instance method
+                co_varnames and co_varnames[0] == "self" and "self" in frame.f_locals
+            ):
+                for cls in type(frame.f_locals["self"]).__mro__:
+                    if name in cls.__dict__:
+                        return "{}.{}".format(cls.__name__, name)
+        except (AttributeError, ValueError):
+            pass
+
+        # if it was a class method, (decorated with `@classmethod`)
+        # we can get the class name by inspecting the f_locals for the `cls` argument
+        try:
+            if (
+                # the co_varnames start with the frame's positional arguments
+                # and we expect the first to be `cls` if its a class method
+                co_varnames and co_varnames[0] == "cls" and "cls" in frame.f_locals
+            ):
+                for cls in frame.f_locals["cls"].__mro__:
+                    if name in cls.__dict__:
+                        return "{}.{}".format(cls.__name__, name)
+        except (AttributeError, ValueError):
+            pass
+
+        # nothing we can do if it is a staticmethod (decorated with @staticmethod)
+
+        # we've done all we can, time to give up and return what we have
+        return name
+
+
+def frame_id(raw_frame: "FrameType") -> "FrameId":
+    return (raw_frame.f_code.co_filename, raw_frame.f_lineno, get_frame_name(raw_frame))
+
+
+def extract_frame(fid: "FrameId", raw_frame: "FrameType", cwd: str) -> "ProcessedFrame":
+    abs_path = raw_frame.f_code.co_filename
+
+    try:
+        module = raw_frame.f_globals["__name__"]
+    except Exception:
+        module = None
+
+    # namedtuples can be many times slower when initialing
+    # and accessing attribute so we opt to use a tuple here instead
+    return {
+        # This originally was `os.path.abspath(abs_path)` but that had
+        # a large performance overhead.
+        #
+        # According to docs, this is equivalent to
+        # `os.path.normpath(os.path.join(os.getcwd(), path))`.
+        # The `os.getcwd()` call is slow here, so we precompute it.
+        #
+        # Additionally, since we are using normalized path already,
+        # we skip calling `os.path.normpath` entirely.
+        "abs_path": os.path.join(cwd, abs_path),
+        "module": module,
+        "filename": filename_for_module(module, abs_path) or None,
+        "function": fid[2],
+        "lineno": raw_frame.f_lineno,
+    }
+
+
+def extract_stack(
+    raw_frame: "Optional[FrameType]",
+    cache: "LRUCache",
+    cwd: str,
+    max_stack_depth: int = MAX_STACK_DEPTH,
+) -> "ExtractedStack":
+    """
+    Extracts the stack starting the specified frame. The extracted stack
+    assumes the specified frame is the top of the stack, and works back
+    to the bottom of the stack.
+
+    In the event that the stack is more than `MAX_STACK_DEPTH` frames deep,
+    only the first `MAX_STACK_DEPTH` frames will be returned.
+    """
+
+    raw_frames: "Deque[FrameType]" = deque(maxlen=max_stack_depth)
+
+    while raw_frame is not None:
+        f_back = raw_frame.f_back
+        raw_frames.append(raw_frame)
+        raw_frame = f_back
+
+    frame_ids = tuple(frame_id(raw_frame) for raw_frame in raw_frames)
+    frames = []
+    for i, fid in enumerate(frame_ids):
+        frame = cache.get(fid)
+        if frame is None:
+            frame = extract_frame(fid, raw_frames[i], cwd)
+            cache.set(fid, frame)
+        frames.append(frame)
+
+    # Instead of mapping the stack into frame ids and hashing
+    # that as a tuple, we can directly hash the stack.
+    # This saves us from having to generate yet another list.
+    # Additionally, using the stack as the key directly is
+    # costly because the stack can be large, so we pre-hash
+    # the stack, and use the hash as the key as this will be
+    # needed a few times to improve performance.
+    #
+    # To Reduce the likelihood of hash collisions, we include
+    # the stack depth. This means that only stacks of the same
+    # depth can suffer from hash collisions.
+    stack_id = len(raw_frames), hash(frame_ids)
+
+    return stack_id, frame_ids, frames
diff --git a/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/INSTALLER b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/INSTALLER
new file mode 100644
index 0000000000000000000000000000000000000000..a1b589e38a32041e49332e5e81c2d363dc418d68
--- /dev/null
+++ b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/LICENSE.txt b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..473e36e246edd5800325e9fa1eaa7697c95be1ef
--- /dev/null
+++ b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Alex Hall
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/METADATA b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/METADATA
new file mode 100644
index 0000000000000000000000000000000000000000..e7c52daf19194c965745a656bec78f137a060614
--- /dev/null
+++ b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/METADATA
@@ -0,0 +1,443 @@
+Metadata-Version: 2.1
+Name: stack-data
+Version: 0.6.3
+Summary: Extract data from python stack frames and tracebacks for informative displays
+Home-page: http://github.com/alexmojaki/stack_data
+Author: Alex Hall
+Author-email: alex.mojaki@gmail.com
+License: MIT
+Classifier: Intended Audience :: Developers
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Topic :: Software Development :: Debuggers
+Description-Content-Type: text/markdown
+License-File: LICENSE.txt
+Requires-Dist: executing >=1.2.0
+Requires-Dist: asttokens >=2.1.0
+Requires-Dist: pure-eval
+Provides-Extra: tests
+Requires-Dist: pytest ; extra == 'tests'
+Requires-Dist: typeguard ; extra == 'tests'
+Requires-Dist: pygments ; extra == 'tests'
+Requires-Dist: littleutils ; extra == 'tests'
+Requires-Dist: cython ; extra == 'tests'
+
+# stack_data
+
+[![Tests](https://github.com/alexmojaki/stack_data/actions/workflows/pytest.yml/badge.svg)](https://github.com/alexmojaki/stack_data/actions/workflows/pytest.yml) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/stack_data/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/stack_data?branch=master) [![Supports Python versions 3.5+](https://img.shields.io/pypi/pyversions/stack_data.svg)](https://pypi.python.org/pypi/stack_data)
+
+This is a library that extracts data from stack frames and tracebacks, particularly to display more useful tracebacks than the default. It powers the tracebacks in IPython and [futurecoder](https://futurecoder.io/):
+
+![futurecoder example](https://futurecoder.io/static/img/features/traceback.png)
+
+You can install it from PyPI:
+
+    pip install stack_data
+    
+## Basic usage
+
+Here's some code we'd like to inspect:
+
+```python
+def foo():
+    result = []
+    for i in range(5):
+        row = []
+        result.append(row)
+        print_stack()
+        for j in range(5):
+            row.append(i * j)
+    return result
+```
+
+Note that `foo` calls a function `print_stack()`. In reality we can imagine that an exception was raised at this line, or a debugger stopped there, but this is easy to play with directly. Here's a basic implementation:
+
+```python
+import inspect
+import stack_data
+
+
+def print_stack():
+    frame = inspect.currentframe().f_back
+    frame_info = stack_data.FrameInfo(frame)
+    print(f"{frame_info.code.co_name} at line {frame_info.lineno}")
+    print("-----------")
+    for line in frame_info.lines:
+        print(f"{'-->' if line.is_current else '   '} {line.lineno:4} | {line.render()}")
+```
+
+(Beware that this has a major bug - it doesn't account for line gaps, which we'll learn about later)
+
+The output of one call to `print_stack()` looks like:
+
+```
+foo at line 9
+-----------
+       6 | for i in range(5):
+       7 |     row = []
+       8 |     result.append(row)
+-->    9 |     print_stack()
+      10 |     for j in range(5):
+```
+
+The code for `print_stack()` is fairly self-explanatory. If you want to learn more details about a particular class or method I suggest looking through some docstrings. `FrameInfo` is a class that accepts either a frame or a traceback object and provides a bunch of nice attributes and properties (which are cached so you don't need to worry about performance). In particular `frame_info.lines` is a list of `Line` objects. `line.render()` returns the source code of that line suitable for display. Without any arguments it simply strips any common leading indentation. Later on we'll see a more powerful use for it.
+
+You can see that `frame_info.lines` includes some lines of surrounding context. By default it includes 3 pieces of context before the main line and 1 piece after. We can configure the amount of context by passing options:
+
+```python
+options = stack_data.Options(before=1, after=0)
+frame_info = stack_data.FrameInfo(frame, options)
+```
+
+Then the output looks like:
+
+```
+foo at line 9
+-----------
+       8 | result.append(row)
+-->    9 | print_stack()
+```
+
+Note that these parameters are not the number of *lines* before and after to include, but the number of *pieces*. A piece is a range of one or more lines in a file that should logically be grouped together. A piece contains either a single simple statement or a part of a compound statement (loops, if, try/except, etc) that doesn't contain any other statements. Most pieces are a single line, but a multi-line statement or `if` condition is a single piece. In the example above, all pieces are one line, because nothing is spread across multiple lines. If we change our code to include some multiline bits:
+
+
+```python
+def foo():
+    result = []
+    for i in range(5):
+        row = []
+        result.append(
+            row
+        )
+        print_stack()
+        for j in range(
+                5
+        ):
+            row.append(i * j)
+    return result
+```
+
+and then run the original code with the default options, then the output is:
+
+```
+foo at line 11
+-----------
+       6 | for i in range(5):
+       7 |     row = []
+       8 |     result.append(
+       9 |         row
+      10 |     )
+-->   11 |     print_stack()
+      12 |     for j in range(
+      13 |             5
+      14 |     ):
+```
+
+Now lines 8-10 and lines 12-14 are each a single piece. Note that the output is essentially the same as the original in terms of the amount of code. The division of files into pieces means that the edge of the context is intuitive and doesn't crop out parts of statements or expressions. For example, if context was measured in lines instead of pieces, the last line of the above would be `for j in range(` which is much less useful.
+
+However, if a piece is very long, including all of it could be cumbersome. For this, `Options` has a parameter `max_lines_per_piece`, which is 6 by default. Suppose we have a piece in our code that's longer than that:
+
+```python
+        row = [
+            1,
+            2,
+            3,
+            4,
+            5,
+        ]
+```
+
+`frame_info.lines` will truncate this piece so that instead of 7 `Line` objects it will produce 5 `Line` objects and one `LINE_GAP` in the middle, making 6 objects in total for the piece. Our code doesn't currently handle gaps, so it will raise an exception. We can modify it like so:
+
+```python
+    for line in frame_info.lines:
+        if line is stack_data.LINE_GAP:
+            print("       (...)")
+        else:
+            print(f"{'-->' if line.is_current else '   '} {line.lineno:4} | {line.render()}")
+```
+
+Now the output looks like:
+
+```
+foo at line 15
+-----------
+       6 | for i in range(5):
+       7 |     row = [
+       8 |         1,
+       9 |         2,
+       (...)
+      12 |         5,
+      13 |     ]
+      14 |     result.append(row)
+-->   15 |     print_stack()
+      16 |     for j in range(5):
+```
+
+Alternatively, you can flip the condition around and check `if isinstance(line, stack_data.Line):`. Either way, you should always check for line gaps, or your code may appear to work at first but fail when it encounters a long piece.
+
+Note that the executing piece, i.e. the piece containing the current line being executed (line 15 in this case) is never truncated, no matter how long it is.
+
+The lines of context never stray outside `frame_info.scope`, which is the innermost function or class definition containing the current line. For example, this is the output for a short function which has neither 3 lines before nor 1 line after the current line:
+
+```
+bar at line 6
+-----------
+       4 | def bar():
+       5 |     foo()
+-->    6 |     print_stack()
+```
+
+Sometimes it's nice to ensure that the function signature is always showing. This can be done with `Options(include_signature=True)`. The result looks like this:
+
+```
+foo at line 14
+-----------
+       9 | def foo():
+       (...)
+      11 |     for i in range(5):
+      12 |         row = []
+      13 |         result.append(row)
+-->   14 |         print_stack()
+      15 |         for j in range(5):
+```
+
+To avoid wasting space, pieces never start or end with a blank line, and blank lines between pieces are excluded. So if our code looks like this:
+
+
+```python
+    for i in range(5):
+        row = []
+
+        result.append(row)
+        print_stack()
+
+        for j in range(5):
+```
+
+The output doesn't change much, except you can see jumps in the line numbers:
+
+```
+      11 |     for i in range(5):
+      12 |         row = []
+      14 |         result.append(row)
+-->   15 |         print_stack()
+      17 |         for j in range(5):
+```
+
+## Variables
+
+You can also inspect variables and other expressions in a frame, e.g:
+
+```python
+    for var in frame_info.variables:
+        print(f"{var.name} = {repr(var.value)}")
+```
+
+which may output:
+
+```python
+result = [[0, 0, 0, 0, 0], [0, 1, 2, 3, 4], [0, 2, 4, 6, 8], [0, 3, 6, 9, 12], []]
+i = 4
+row = []
+j = 4
+```
+
+`frame_info.variables` returns a list of `Variable` objects, which have attributes `name`, `value`, and `nodes`, which is a list of all AST representing that expression.
+
+A `Variable` may refer to an expression other than a simple variable name. It can be any expression evaluated by the library [`pure_eval`](https://github.com/alexmojaki/pure_eval) which it deems 'interesting' (see those docs for more info). This includes expressions like `foo.bar` or `foo[bar]`. In these cases `name` is the source code of that expression. `pure_eval` ensures that it only evaluates expressions that won't have any side effects, e.g. where `foo.bar` is a normal attribute rather than a descriptor such as a property.
+
+`frame_info.variables` is a list of all the interesting expressions found in `frame_info.scope`, e.g. the current function, which may include expressions not visible in `frame_info.lines`. You can restrict the list by using `frame_info.variables_in_lines` or even `frame_info.variables_in_executing_piece`. For more control you can use `frame_info.variables_by_lineno`. See the docstrings for more information.
+
+## Rendering lines with ranges and markers
+
+Sometimes you may want to insert special characters into the text for display purposes, e.g. HTML or ANSI color codes. `stack_data` provides a few tools to make this easier.
+
+Let's say we have a `Line` object where `line.text` (the original raw source code of that line) is `"foo = bar"`, so `line.text[6:9]` is `"bar"`, and we want to emphasise that part by inserting HTML at positions 6 and 9 in the text. Here's how we can do that directly:
+
+```python
+markers = [
+    stack_data.MarkerInLine(position=6, is_start=True, string=""),
+    stack_data.MarkerInLine(position=9, is_start=False, string=""),
+]
+line.render(markers)  # returns "foo = bar"
+```
+
+Here `is_start=True` indicates that the marker is the first of a pair. This helps `line.render()` sort and insert the markers correctly so you don't end up with malformed HTML like `foo.bar` where tags overlap.
+
+Since we're inserting HTML, we should actually use `line.render(markers, escape_html=True)` which will escape special HTML characters in the Python source (but not the markers) so for example `foo = bar < spam` would be rendered as `foo = bar < spam`.
+
+Usually though you wouldn't create markers directly yourself. Instead you would start with one or more ranges and then convert them, like so:
+
+```python
+ranges = [
+    stack_data.RangeInLine(start=0, end=3, data="foo"),
+    stack_data.RangeInLine(start=6, end=9, data="bar"),
+]
+
+def convert_ranges(r):
+    if r.data == "bar":
+        return "", ""        
+
+# This results in `markers` being the same as in the above example.
+markers = stack_data.markers_from_ranges(ranges, convert_ranges)
+```
+
+`RangeInLine` has a `data` attribute which can be any object. `markers_from_ranges` accepts a converter function to which it passes all the `RangeInLine` objects. If the converter function returns a pair of strings, it creates two markers from them. Otherwise it should return `None` to indicate that the range should be ignored, as with the first range containing `"foo"` in this example.
+
+The reason this is useful is because there are built in tools to create these ranges for you. For example, if we change our `print_stack()` function to contain this:
+
+```python
+def convert_variable_ranges(r):
+    variable, _node = r.data
+    return f'', ''
+
+markers = stack_data.markers_from_ranges(line.variable_ranges, convert_variable_ranges)
+print(f"{'-->' if line.is_current else '   '} {line.lineno:4} | {line.render(markers, escape_html=True)}")
+```
+
+Then the output becomes:
+
+```
+foo at line 15
+-----------
+       9 | def foo():
+       (...)
+      11 |     for i in range(5):
+      12 |         row = []
+      14 |         result.append(row)
+-->   15 |         print_stack()
+      17 |         for j in range(5):
+```
+
+`line.variable_ranges` is a list of RangeInLines for each Variable that appears at least partially in this line. The data attribute of the range is a pair `(variable, node)` where node is the particular AST node from the list `variable.nodes` that corresponds to this range.
+
+You can also use `line.token_ranges` (e.g. if you want to do your own syntax highlighting) or `line.executing_node_ranges` if you want to highlight the currently executing node identified by the [`executing`](https://github.com/alexmojaki/executing) library. Or if you want to make your own range from an AST node, use `line.range_from_node(node, data)`. See the docstrings for more info.
+
+### Syntax highlighting with Pygments
+
+If you'd like pretty colored text without the work, you can let [Pygments](https://pygments.org/) do it for you. Just follow these steps:
+
+1. `pip install pygments` separately as it's not a dependency of `stack_data`.
+2. Create a pygments formatter object such as `HtmlFormatter` or `Terminal256Formatter`.
+3. Pass the formatter to `Options` in the argument `pygments_formatter`.
+4. Use `line.render(pygmented=True)` to get your formatted text. In this case you can't pass any markers to `render`.
+
+If you want, you can also highlight the executing node in the frame in combination with the pygments syntax highlighting. For this you will need:
+
+1. A pygments style - either a style class or a string that names it. See the [documentation on styles](https://pygments.org/docs/styles/) and the [styles gallery](https://blog.yjl.im/2015/08/pygments-styles-gallery.html).
+2. A modification to make to the style for the executing node, which is a string such as `"bold"` or `"bg:#ffff00"` (yellow background). See the [documentation on style rules](https://pygments.org/docs/styles/#style-rules).
+3. Pass these two things to `stack_data.style_with_executing_node(style, modifier)` to get a new style class.
+4. Pass the new style to your formatter when you create it.
+
+Note that this doesn't work with `TerminalFormatter` which just uses the basic ANSI colors and doesn't use the style passed to it in general.
+
+## Getting the full stack
+
+Currently `print_stack()` doesn't actually print the stack, it just prints one frame. Instead of `frame_info = FrameInfo(frame, options)`, let's do this:
+
+```python
+for frame_info in FrameInfo.stack_data(frame, options):
+```
+
+Now the output looks something like this:
+
+```
+ at line 18
+-----------
+      14 |         for j in range(5):
+      15 |             row.append(i * j)
+      16 |     return result
+-->   18 | bar()
+
+bar at line 5
+-----------
+       4 | def bar():
+-->    5 |     foo()
+
+foo at line 13
+-----------
+      10 | for i in range(5):
+      11 |     row = []
+      12 |     result.append(row)
+-->   13 |     print_stack()
+      14 |     for j in range(5):
+```
+
+However, just as `frame_info.lines` doesn't always yield `Line` objects, `FrameInfo.stack_data` doesn't always yield `FrameInfo` objects, and we must modify our code to handle that. Let's look at some different sample code:
+
+```python
+def factorial(x):
+    return x * factorial(x - 1)
+
+
+try:
+    print(factorial(5))
+except:
+    print_stack()
+```
+
+In this code we've forgotten to include a base case in our `factorial` function so it will fail with a `RecursionError` and there'll be many frames with similar information. Similar to the built in Python traceback, `stack_data` avoids showing all of these frames. Instead you will get a `RepeatedFrames` object which summarises the information. See its docstring for more details.
+
+Here is our updated implementation:
+
+```python
+def print_stack():
+    for frame_info in FrameInfo.stack_data(sys.exc_info()[2]):
+        if isinstance(frame_info, FrameInfo):
+            print(f"{frame_info.code.co_name} at line {frame_info.lineno}")
+            print("-----------")
+            for line in frame_info.lines:
+                print(f"{'-->' if line.is_current else '   '} {line.lineno:4} | {line.render()}")
+
+            for var in frame_info.variables:
+                print(f"{var.name} = {repr(var.value)}")
+
+            print()
+        else:
+            print(f"... {frame_info.description} ...\n")
+```
+
+And the output:
+
+```
+ at line 9
+-----------
+       4 | def factorial(x):
+       5 |     return x * factorial(x - 1)
+       8 | try:
+-->    9 |     print(factorial(5))
+      10 | except:
+
+factorial at line 5
+-----------
+       4 | def factorial(x):
+-->    5 |     return x * factorial(x - 1)
+x = 5
+
+factorial at line 5
+-----------
+       4 | def factorial(x):
+-->    5 |     return x * factorial(x - 1)
+x = 4
+
+... factorial at line 5 (996 times) ...
+
+factorial at line 5
+-----------
+       4 | def factorial(x):
+-->    5 |     return x * factorial(x - 1)
+x = -993
+```
+
+In addition to handling repeated frames, we've passed a traceback object to `FrameInfo.stack_data` instead of a frame.
+
+If you want, you can pass `collapse_repeated_frames=False` to `FrameInfo.stack_data` (not to `Options`) and it will just yield `FrameInfo` objects for the full stack.
diff --git a/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/RECORD b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/RECORD
new file mode 100644
index 0000000000000000000000000000000000000000..c5ba617fe19c3b265a59e9e14f7fe6ebc51f72b9
--- /dev/null
+++ b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/RECORD
@@ -0,0 +1,19 @@
+stack_data-0.6.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+stack_data-0.6.3.dist-info/LICENSE.txt,sha256=pHaiyw70xBRQNApXeii5GsTH9mkTay7hSAR_q9X8QYE,1066
+stack_data-0.6.3.dist-info/METADATA,sha256=8opm8q3eVOcDE1XgmhZuQ3vA0COjHBDJc6xJQojKTG8,18440
+stack_data-0.6.3.dist-info/RECORD,,
+stack_data-0.6.3.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
+stack_data-0.6.3.dist-info/top_level.txt,sha256=IarPBYYY9efJkAgUnuykMUPznQR-ebWQYYsQcqYGxCo,11
+stack_data/__init__.py,sha256=oC0PI_cmh6R2evHFLgUFbrMZEgF_YvCh6pHXbPuoPSw,419
+stack_data/__pycache__/__init__.cpython-312.pyc,,
+stack_data/__pycache__/core.cpython-312.pyc,,
+stack_data/__pycache__/formatting.cpython-312.pyc,,
+stack_data/__pycache__/serializing.cpython-312.pyc,,
+stack_data/__pycache__/utils.cpython-312.pyc,,
+stack_data/__pycache__/version.cpython-312.pyc,,
+stack_data/core.py,sha256=Er8EfeM7scNIl5G6pmRSGaJspZvHyMGLgd70qXDnBl4,33355
+stack_data/formatting.py,sha256=dIiaw47H4PLsXZRseC0jEnij5RFs98lAql8r7DV4Sl0,8508
+stack_data/py.typed,sha256=5k8BacvFEvRONDNQm6FTsj5DwT8pMZnyCk7FIHcLkv8,73
+stack_data/serializing.py,sha256=tAJpXKcYOAGdA-0k8QAmJXZzcT2UKJmeHCAC_eZytO0,6468
+stack_data/utils.py,sha256=nHk5zd3jz_lts6nf_xmmbVKTIM5cwRK65FipX3X-gyM,5898
+stack_data/version.py,sha256=0ICX8PeSmWoiPyIEViMxRYkvCjQE1KvQPJp9o52KRjw,22
diff --git a/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/WHEEL b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/WHEEL
new file mode 100644
index 0000000000000000000000000000000000000000..7e688737d490be3643d705bc16b5a77f7bd567b7
--- /dev/null
+++ b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.41.2)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/top_level.txt b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/top_level.txt
new file mode 100644
index 0000000000000000000000000000000000000000..09e7428c13d54975b17407e7fc15de93234e9d75
--- /dev/null
+++ b/lib/python3.12/site-packages/stack_data-0.6.3.dist-info/top_level.txt
@@ -0,0 +1 @@
+stack_data
diff --git a/lib/python3.12/site-packages/torchao/__init__.py b/lib/python3.12/site-packages/torchao/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..752aa94a4f253984a694efffdf22cfe0f41dad70
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/__init__.py
@@ -0,0 +1,55 @@
+import logging
+
+# torch/nested/_internal/nested_tensor.py:417: UserWarning: Failed to initialize NumPy: No module named 'numpy'
+import warnings
+
+import torch
+
+warnings.filterwarnings(
+    "ignore", message="Failed to initialize NumPy: No module named 'numpy'"
+)
+
+# We use this "hack" to set torchao.__version__ correctly
+# the version of ao is dependent on environment variables for multiple architectures
+# For local development this will default to whatever is version.txt
+# For release builds this will be set the version+architecture_postfix
+from importlib.metadata import PackageNotFoundError, version
+
+try:
+    __version__ = version("torchao")
+except PackageNotFoundError:
+    __version__ = "unknown"  # In case this logic breaks don't break the build
+
+try:
+    from pathlib import Path
+
+    so_files = list(Path(__file__).parent.glob("_C*.so"))
+    if len(so_files) > 0:
+        assert len(so_files) == 1, f"Expected one _C*.so file, found {len(so_files)}"
+        torch.ops.load_library(str(so_files[0]))
+        from . import ops
+
+    # The following library contains CPU kernels from torchao/experimental
+    # They are built automatically by ao/setup.py if on an ARM machine.
+    # They can also be built outside of the torchao install process by
+    # running the script `torchao/experimental/build_torchao_ops.sh `
+    # For more information, see https://github.com/pytorch/ao/blob/main/torchao/experimental/docs/readme.md
+    from torchao.experimental.op_lib import *  # noqa: F403
+except Exception as e:
+    logging.debug(f"Skipping import of cpp extensions: {e}")
+
+from torchao.quantization import (
+    autoquant,
+    quantize_,
+)
+
+from . import dtypes, optim, testing
+
+__all__ = [
+    "dtypes",
+    "autoquant",
+    "optim",
+    "quantize_",
+    "testing",
+    "ops",
+]
diff --git a/lib/python3.12/site-packages/torchao/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c5f4a5418d5153ddcf21c62f3d73b7bdbdd5636e
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/__pycache__/_executorch_ops.cpython-312.pyc b/lib/python3.12/site-packages/torchao/__pycache__/_executorch_ops.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6e57c048f55146a1150e635151ed81ea80caa462
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/__pycache__/_executorch_ops.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/__pycache__/ops.cpython-312.pyc b/lib/python3.12/site-packages/torchao/__pycache__/ops.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..25328bdb95787785d34b98acadf0cdbb22f38257
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/__pycache__/ops.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/torchao/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8547160c079a071986827980759f518dec94f1a8
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/__pycache__/utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/_executorch_ops.py b/lib/python3.12/site-packages/torchao/_executorch_ops.py
new file mode 100644
index 0000000000000000000000000000000000000000..4b761ad725cd6ae33d69cd5aa50cacebda034f87
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_executorch_ops.py
@@ -0,0 +1,99 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import torch
+
+# TODO: delete these ops
+
+
+def _quantized_decomposed_quantize_per_channel_group_wrapper(*args, **kwargs):
+    """
+    Wrapper around torch.ops.quantized_decomposed.quantize_per_channel_group to mitigate
+    availability issue until it can be supplanted by new quantize_affine function.
+
+    torch.ops.quantized_decomposed.quantize_per_channel_group is only available
+    in PyTorch 2.3+ and recently changed signatures.
+    """
+    from torchao.utils import TORCH_VERSION_AT_LEAST_2_3
+
+    if TORCH_VERSION_AT_LEAST_2_3:
+        return torch.ops.quantized_decomposed.quantize_per_channel_group(
+            *args, **kwargs
+        )
+    raise ImportError(
+        "Need torch.ops.quantized_decomposed.quantize_per_channel_group, which is only available with PyTorch 2.3 or later."
+    )
+
+
+def _quantized_decomposed_choose_qparams_per_token_asymmetric_wrapper(*args, **kwargs):
+    """
+    Wrapper around torch.ops.quantized_decomposed.choose_qparams_per_token_asymmetric to mitigate
+    availability issue until it can be supplanted by new choose_qparams_affine function.
+
+    torch.ops.quantized_decomposed.choose_qparams_per_token_asymmetric is only available
+    in PyTorch 2.3+ and recently changed signatures.
+    """
+    from torchao.utils import TORCH_VERSION_AT_LEAST_2_3
+
+    if TORCH_VERSION_AT_LEAST_2_3:
+        return torch.ops.quantized_decomposed.choose_qparams_per_token_asymmetric(
+            *args, **kwargs
+        )
+    raise ImportError(
+        "Need torch.ops.quantized_decomposed.choose_qparams_per_token_asymmetric, which is only available with PyTorch 2.3 or later."
+    )
+
+
+def _quantized_decomposed_dequantize_per_channel_group_wrapper(*args, **kwargs):
+    """
+    Wrapper around torch.ops.quantized_decomposed.dequantize_per_channel_group to mitigate
+    availability issue until it can be supplanted by new choose_qparams_affine function.
+
+    torch.ops.quantized_decomposed.dequantize_per_channel_group is only available
+    in PyTorch 2.3+ and recently changed signatures.
+    """
+    from torchao.utils import TORCH_VERSION_AT_LEAST_2_3
+
+    if TORCH_VERSION_AT_LEAST_2_3:
+        return torch.ops.quantized_decomposed.dequantize_per_channel_group(
+            *args, **kwargs
+        )
+    raise ImportError(
+        "Need torch.ops.quantized_decomposed.dequantize_per_channel_group, which is only available with PyTorch 2.3 or later."
+    )
+
+
+def _quantized_decomposed_quantize_per_token_wrapper(*args, **kwargs):
+    """
+    Wrapper around torch.ops.quantized_decomposed.quantize_per_token to mitigate
+    availability issue until it can be supplanted by new choose_qparams_affine function.
+
+    torch.ops.quantized_decomposed.quantize_per_token is only available
+    in PyTorch 2.3+ and recently changed signatures.
+    """
+    from torchao.utils import TORCH_VERSION_AT_LEAST_2_3
+
+    if TORCH_VERSION_AT_LEAST_2_3:
+        return torch.ops.quantized_decomposed.quantize_per_token(*args, **kwargs)
+    raise ImportError(
+        "Need torch.ops.quantized_decomposed.quantize_per_token, which is only available with PyTorch 2.3 or later."
+    )
+
+
+def _quantized_decomposed_dequantize_per_token_wrapper(*args, **kwargs):
+    """
+    Wrapper around torch.ops.quantized_decomposed.dequantize_per_token to mitigate
+    availability issue until it can be supplanted by new choose_qparams_affine function.
+
+    torch.ops.quantized_decomposed.dequantize_per_token is only available
+    in PyTorch 2.3+ and recently changed signatures.
+    """
+    from torchao.utils import TORCH_VERSION_AT_LEAST_2_3
+
+    if TORCH_VERSION_AT_LEAST_2_3:
+        return torch.ops.quantized_decomposed.dequantize_per_token(*args, **kwargs)
+    raise ImportError(
+        "Need torch.ops.quantized_decomposed.dequantize_per_token, which is only available with PyTorch 2.3 or later."
+    )
diff --git a/lib/python3.12/site-packages/torchao/_models/__init__.py b/lib/python3.12/site-packages/torchao/_models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/torchao/_models/_eval.py b/lib/python3.12/site-packages/torchao/_models/_eval.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f429278e3c73ef75b6067e003e85703be5237d5
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/_eval.py
@@ -0,0 +1,362 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree.
+
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import lm_eval
+import torch
+import torch.nn.functional as F
+
+from torchao.quantization.GPTQ_MT import MultiTensor
+from torchao.quantization.utils import _MultiInput
+
+try:  # lm_eval version 0.4
+    from lm_eval.evaluator import evaluate  # pyre-ignore[21]
+    from lm_eval.models.huggingface import HFLM as eval_wrapper  # pyre-ignore[21]
+    from lm_eval.tasks import get_task_dict  # pyre-ignore[21]
+except:  # lm_eval version 0.3
+    from lm_eval import base, evaluator, tasks
+
+    eval_wrapper = base.BaseLM
+    get_task_dict = tasks.get_task_dict
+    evaluate = evaluator.evaluate
+
+
+class MultiTensorInputRecorder(eval_wrapper):
+    def __init__(
+        self,
+        tokenizer,
+        calibration_seq_length,
+        input_prep_func=None,
+        pad_calibration_inputs=False,
+        vocab_size=32000,
+        pad_token=0,
+        device="cpu",
+    ):
+        try:
+            super().__init__()
+        except TypeError:
+            # lm_eval 0.4.2 removed the default init
+            super().__init__("gpt2", device="cpu")
+
+        self.tokenizer = tokenizer
+        self._device = torch.device(device)
+        self.vocab_size = vocab_size
+        self._max_seq_length = calibration_seq_length
+        self.calibration_seq_length = calibration_seq_length
+
+        self.input_prep_func = (
+            input_prep_func if input_prep_func is not None else lambda x: (x,)
+        )
+
+        self.pad_calibration_inputs = pad_calibration_inputs
+        self.pad_token = pad_token
+
+        # Initialize inputs as a list of two empty lists for input tensors and indices
+        self.inputs = [[], []]
+
+    @property
+    def eot_token_id(self):
+        try:
+            return self.tokenizer.eos_id()
+        except:
+            return self.tokenizer.eos_id
+
+    @property
+    def max_length(self):
+        return self._max_seq_length
+
+    @property
+    def max_gen_toks(self):
+        return 50
+
+    @property
+    def batch_size(self):
+        return 1
+
+    @property
+    def device(self):
+        return self._device
+
+    def tok_encode(self, string: str, **kwargs):
+        tokens = self.tokenizer.encode(string)
+        if hasattr(self.tokenizer, "bos_id"):
+            try:
+                tokens = [self.tokenizer.bos_id()] + tokens
+            except:
+                tokens = [self.tokenizer.bos_id] + tokens
+        return tokens
+
+    def tok_decode(self, tokens):
+        decoded = self.tokenizer.decode(tokens)
+        return decoded
+
+    def add_input(self, args):
+        # Ensure that inputs are added correctly as pairs
+        self.inputs[0].append(args[0])
+        self.inputs[1].append(args[1])
+
+    def record_inputs(self, calibration_tasks, calibration_limit):
+        try:
+            lm_eval.tasks.initialize_tasks()
+        except:
+            pass
+
+        task_dict = get_task_dict(calibration_tasks)
+        print("Obtaining GPTQ calibration inputs on: ", calibration_tasks)
+
+        evaluate(
+            self,
+            task_dict,
+            limit=calibration_limit,
+        )
+        return self
+
+    def get_inputs(self):
+        # Return MultiTensor instances for both inputs and indices
+        return [MultiTensor(self.inputs[0]), MultiTensor(self.inputs[1])]
+
+    def _model_call(self, inps):
+        inps = inps.squeeze(0)
+        T = len(inps)
+        if (
+            # Can't use inputs that are too short when padding is disabled
+            (T < self.calibration_seq_length and not self.pad_calibration_inputs)
+            or
+            # Can't use inputs that actually use the token we use for padding
+            (self.pad_calibration_inputs and self.pad_token in inps)
+        ):
+            # Give random output
+            return torch.randn(
+                (1, T, self.vocab_size), dtype=torch.bfloat16, device=self._device
+            )
+
+        # Pad or truncate to the correct size
+        if T >= self.calibration_seq_length:
+            inps = inps[: self.calibration_seq_length]
+        else:
+            inps = F.pad(
+                inps, (0, self.calibration_seq_length - T), value=self.pad_token
+            )
+
+        inps = inps.unsqueeze(0)
+        model_in = self.input_prep_func(inps)
+
+        self.add_input(model_in)
+
+        # Output `something` with the correct shape to keep eval going
+        return torch.randn(
+            (1, T, self.vocab_size), dtype=torch.bfloat16, device=self._device
+        )
+
+    def _model_generate(self, context, max_length, eos_token_id):
+        raise Exception("unimplemented")
+
+
+class InputRecorder(eval_wrapper):
+    """
+    This is a fake evaluation wrapper from the lm_eval library that just records the inputs
+    so that they can be used in calibration.
+
+    If pad_calibration_inputs is enabled, the input recorder will take
+    each input and pad/truncate it down to the calibration_seq_length.
+    (if using padding you should set the embeddings for the pad_token to 0
+    in the model)
+
+    Note: after padding/truncation, input_prep_function is called to bring
+    it to the proper form to be inserted into a given model.
+
+    If not, it will only truncate inputs to the desired length.
+    """
+
+    def __init__(
+        self,
+        tokenizer,
+        calibration_seq_length,
+        input_prep_func=None,
+        pad_calibration_inputs=False,
+        vocab_size=32000,
+        pad_token=0,
+        device="cpu",
+    ):
+        try:
+            super().__init__()
+        except TypeError:
+            # lm_eval 0.4.2 removed the default init
+            super().__init__("gpt2", device="cpu")
+
+        self.tokenizer = tokenizer
+        self._device = torch.device(device)
+        self.vocab_size = vocab_size
+        self._max_seq_length = calibration_seq_length
+        self.calibration_seq_length = calibration_seq_length
+
+        # need to take inps and convert to corrent input
+        # for model
+        self.input_prep_func = (
+            input_prep_func if input_prep_func is not None else lambda x: (x,)
+        )
+
+        self.pad_calibration_inputs = pad_calibration_inputs
+        self.pad_token = pad_token
+
+        self.inputs = None
+
+    @property
+    def eot_token_id(self):
+        try:
+            return self.tokenizer.eos_id()
+        except:
+            return self.tokenizer.eos_id
+
+    @property
+    def max_length(self):
+        return self._max_seq_length
+
+    @property
+    def max_gen_toks(self):
+        return 50
+
+    @property
+    def batch_size(self):
+        return 1
+
+    @property
+    def device(self):
+        return self._device
+
+    def tok_encode(self, string: str, **kwargs):
+        # TODO: verify this for multi-batch as well
+        tokens = self.tokenizer.encode(string)
+        if hasattr(self.tokenizer, "bos_id"):
+            try:
+                tokens = [self.tokenizer.bos_id()] + tokens
+            except:
+                tokens = [self.tokenizer.bos_id] + tokens
+        return tokens
+
+    def tok_decode(self, tokens):
+        decoded = self.tokenizer.decode(tokens)
+        return decoded
+
+    def add_input(self, args):
+        if self.inputs is None:
+            self.inputs = [_MultiInput([arg]) for arg in args]
+        else:
+            self.inputs = [
+                multi.add_input(arg) for (multi, arg) in zip(self.inputs, args)
+            ]
+
+    def record_inputs(
+        self,
+        calibration_tasks,
+        calibration_limit,
+    ):
+        try:
+            lm_eval.tasks.initialize_tasks()
+        except:
+            pass
+
+        task_dict = get_task_dict(calibration_tasks)
+        print("Obtaining GPTQ calibration inputs on: ", calibration_tasks)
+
+        evaluate(
+            self,
+            task_dict,
+            limit=calibration_limit,
+        )
+        return self
+
+    def get_inputs(self):
+        return self.inputs
+
+    def _model_call(self, inps):
+        inps = inps.squeeze(0)
+        T = len(inps)
+        if (
+            # can't use inputs that are too short when padding disabled
+            (T < self.calibration_seq_length and not self.pad_calibration_inputs)
+            or
+            # can't use inputs that actually use token we use for padding
+            (self.pad_calibration_inputs and self.pad_token in inps)
+        ):
+            # give random output
+            return torch.randn(
+                (1, T, self.vocab_size), dtype=torch.bfloat16, device=self._device
+            )
+
+        # pad or truncate to the right size
+        if T >= self.calibration_seq_length:
+            inps = inps[: self.calibration_seq_length]
+        else:
+            inps = F.pad(inps, (self.pad_token, self.calibration_seq_length - T))
+
+        inps = inps.unsqueeze(0)
+        model_in = self.input_prep_func(inps)
+
+        self.add_input(model_in)
+
+        # output `something` with correct shape to keep eval going
+        return torch.randn(
+            (1, T, self.vocab_size), dtype=torch.bfloat16, device=self._device
+        )
+
+    def _model_generate(self, context, max_length, eos_token_id):
+        raise Exception("unimplemented")
+
+
+class TransformerEvalWrapper(InputRecorder):
+    """
+    A wrapper class for GPTFast, providing integration with the lm-evaluation-harness library.
+    """
+
+    def __init__(
+        self, model, tokenizer, max_seq_length, input_prep_func=None, device="cuda"
+    ):
+        super().__init__(tokenizer, None)
+        self._model = model
+        # self.tokenizer = tokenizer
+        self._device = torch.device(device)
+        self._max_seq_length = max_seq_length
+
+        # need to take inps and convert to corrent input
+        # for model
+        self.input_prep_func = (
+            input_prep_func if input_prep_func is not None else lambda x: (x,)
+        )
+
+    def _model_call(self, inps):
+        # TODO: make batches work
+        input = self.input_prep_func(inps)
+
+        max_seq_length = min(max(inps.size()), self.max_length)
+        with torch.device(self._device):
+            self._model.setup_caches(self.batch_size, max_seq_length)
+        logits = self._model(*input)
+        return logits
+
+    def _model_generate(self, context, max_length, eos_token_id):
+        raise Exception("unimplemented")
+
+    def run_eval(self, tasks, limit):
+        try:
+            lm_eval.tasks.initialize_tasks()
+        except:
+            pass
+
+        task_dict = get_task_dict(tasks)
+        print("Evaluating Model On: ", task_dict)
+        with torch.no_grad():
+            result = evaluate(
+                self,
+                task_dict,
+                limit=limit,
+            )
+        for task, res in result["results"].items():
+            print(f"{task}: {res}")
+        return result
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/__init__.py b/lib/python3.12/site-packages/torchao/_models/sam2/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0dc11c2fdec08a17b72087dd50195c899b9d42ff
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/__init__.py
@@ -0,0 +1,11 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+from hydra import initialize_config_module
+from hydra.core.global_hydra import GlobalHydra
+
+if not GlobalHydra.instance().is_initialized():
+    initialize_config_module("torchao._models.sam2", version_base="1.2")
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/automatic_mask_generator.py b/lib/python3.12/site-packages/torchao/_models/sam2/automatic_mask_generator.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3b72318ba963004ea9fd8f936ce4b8852ba6226
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/automatic_mask_generator.py
@@ -0,0 +1,759 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+# Adapted from https://github.com/facebookresearch/segment-anything/blob/main/segment_anything/automatic_mask_generator.py
+from typing import Any, Dict, List, Optional, Tuple, Union
+
+import numpy as np
+import torch
+from torchvision.ops.boxes import batched_nms, box_area  # type: ignore
+
+from torchao._models.sam2.modeling.sam2_base import SAM2Base
+from torchao._models.sam2.sam2_image_predictor import SAM2ImagePredictor
+from torchao._models.sam2.utils.amg import (
+    MaskData,
+    _mask_to_rle_pytorch_2_0,
+    _mask_to_rle_pytorch_2_1,
+    area_from_rle,
+    batch_iterator,
+    batched_mask_to_box,
+    box_xyxy_to_xywh,
+    build_all_layer_point_grids,
+    calculate_stability_score,
+    coco_encode_rle,
+    generate_crop_boxes,
+    is_box_near_crop_edge_torch,
+    mask_to_rle_pytorch,
+    remove_small_regions,
+    rle_to_mask,
+    uncrop_boxes_xyxy,
+    uncrop_masks,
+    uncrop_points,
+)
+from torchao._models.sam2.utils.misc import (
+    crop_image,
+    get_image_size,
+)
+
+
+class SAM2AutomaticMaskGenerator(torch.nn.Module):
+    def __init__(
+        self,
+        model: SAM2Base,
+        points_per_side: Optional[int] = 32,
+        points_per_batch: int = 64,
+        pred_iou_thresh: float = 0.8,
+        stability_score_thresh: float = 0.95,
+        stability_score_offset: float = 1.0,
+        mask_threshold: float = 0.0,
+        box_nms_thresh: float = 0.7,
+        crop_n_layers: int = 0,
+        crop_nms_thresh: float = 0.7,
+        crop_overlap_ratio: float = 512 / 1500,
+        crop_n_points_downscale_factor: int = 1,
+        point_grids: Optional[List[np.ndarray]] = None,
+        min_mask_region_area: int = 0,
+        output_mode: str = "binary_mask",
+        use_m2m: bool = False,
+        multimask_output: bool = True,
+        **kwargs,
+    ) -> None:
+        """
+        Using a SAM 2 model, generates masks for the entire image.
+        Generates a grid of point prompts over the image, then filters
+        low quality and duplicate masks. The default settings are chosen
+        for SAM 2 with a HieraL backbone.
+
+        Arguments:
+          model (Sam): The SAM 2 model to use for mask prediction.
+          points_per_side (int or None): The number of points to be sampled
+            along one side of the image. The total number of points is
+            points_per_side**2. If None, 'point_grids' must provide explicit
+            point sampling.
+          points_per_batch (int): Sets the number of points run simultaneously
+            by the model. Higher numbers may be faster but use more GPU memory.
+          pred_iou_thresh (float): A filtering threshold in [0,1], using the
+            model's predicted mask quality.
+          stability_score_thresh (float): A filtering threshold in [0,1], using
+            the stability of the mask under changes to the cutoff used to binarize
+            the model's mask predictions.
+          stability_score_offset (float): The amount to shift the cutoff when
+            calculated the stability score.
+          mask_threshold (float): Threshold for binarizing the mask logits
+          box_nms_thresh (float): The box IoU cutoff used by non-maximal
+            suppression to filter duplicate masks.
+          crop_n_layers (int): If >0, mask prediction will be run again on
+            crops of the image. Sets the number of layers to run, where each
+            layer has 2**i_layer number of image crops.
+          crop_nms_thresh (float): The box IoU cutoff used by non-maximal
+            suppression to filter duplicate masks between different crops.
+          crop_overlap_ratio (float): Sets the degree to which crops overlap.
+            In the first crop layer, crops will overlap by this fraction of
+            the image length. Later layers with more crops scale down this overlap.
+          crop_n_points_downscale_factor (int): The number of points-per-side
+            sampled in layer n is scaled down by crop_n_points_downscale_factor**n.
+          point_grids (list(np.ndarray) or None): A list over explicit grids
+            of points used for sampling, normalized to [0,1]. The nth grid in the
+            list is used in the nth crop layer. Exclusive with points_per_side.
+          min_mask_region_area (int): If >0, postprocessing will be applied
+            to remove disconnected regions and holes in masks with area smaller
+            than min_mask_region_area. Requires opencv.
+          output_mode (str): The form masks are returned in. Can be 'binary_mask',
+            'uncompressed_rle', or 'coco_rle'. 'coco_rle' requires pycocotools.
+            For large resolutions, 'binary_mask' may consume large amounts of
+            memory.
+          use_m2m (bool): Whether to add a one step refinement using previous mask predictions.
+          multimask_output (bool): Whether to output multimask at each point of the grid.
+        """
+        super().__init__()
+        assert (points_per_side is None) != (point_grids is None), (
+            "Exactly one of points_per_side or point_grid must be provided."
+        )
+        if points_per_side is not None:
+            self.point_grids = build_all_layer_point_grids(
+                points_per_side,
+                crop_n_layers,
+                crop_n_points_downscale_factor,
+            )
+        elif point_grids is not None:
+            self.point_grids = point_grids
+        else:
+            raise ValueError("Can't have both points_per_side and point_grid be None.")
+
+        assert output_mode in [
+            "binary_mask",
+            "uncompressed_rle",
+            "coco_rle",
+        ], f"Unknown output_mode {output_mode}."
+        if output_mode == "coco_rle":
+            try:
+                from pycocotools import mask as mask_utils  # type: ignore  # noqa: F401
+            except ImportError as e:
+                print("Please install pycocotools")
+                raise e
+
+        self.predictor = SAM2ImagePredictor(
+            model,
+            max_hole_area=min_mask_region_area,
+            max_sprinkle_area=min_mask_region_area,
+        )
+        self.points_per_batch = points_per_batch
+        self.pred_iou_thresh = pred_iou_thresh
+        self.stability_score_thresh = stability_score_thresh
+        self.stability_score_offset = stability_score_offset
+        self.mask_threshold = mask_threshold
+        self.box_nms_thresh = box_nms_thresh
+        self.crop_n_layers = crop_n_layers
+        self.crop_nms_thresh = crop_nms_thresh
+        self.crop_overlap_ratio = crop_overlap_ratio
+        self.crop_n_points_downscale_factor = crop_n_points_downscale_factor
+        self.min_mask_region_area = min_mask_region_area
+        self.output_mode = output_mode
+        self.use_m2m = use_m2m
+        self.multimask_output = multimask_output
+
+        # Store a reference to these on the model so I can overwrite them
+        # with compile annotation if desired
+
+        self.calculate_stability_score = calculate_stability_score
+        self.batched_mask_to_box = batched_mask_to_box
+
+    @classmethod
+    def from_pretrained(cls, model_id: str, **kwargs) -> "SAM2AutomaticMaskGenerator":
+        """
+        Load a pretrained model from the Hugging Face hub.
+
+        Arguments:
+          model_id (str): The Hugging Face repository ID.
+          **kwargs: Additional arguments to pass to the model constructor.
+
+        Returns:
+          (SAM2AutomaticMaskGenerator): The loaded model.
+        """
+        from sam2.build_sam import build_sam2_hf
+
+        sam_model = build_sam2_hf(model_id, **kwargs)
+        return cls(sam_model, **kwargs)
+
+    @torch.no_grad()
+    def generate(self, image: np.ndarray) -> List[Dict[str, Any]]:
+        """
+        Generates masks for the given image.
+
+        Arguments:
+          image (np.ndarray): The image to generate masks for, in HWC uint8 format.
+
+        Returns:
+           list(dict(str, any)): A list over records for masks. Each record is
+             a dict containing the following keys:
+               segmentation (dict(str, any) or np.ndarray): The mask. If
+                 output_mode='binary_mask', is an array of shape HW. Otherwise,
+                 is a dictionary containing the RLE.
+               bbox (list(float)): The box around the mask, in XYWH format.
+               area (int): The area in pixels of the mask.
+               predicted_iou (float): The model's own prediction of the mask's
+                 quality. This is filtered by the pred_iou_thresh parameter.
+               point_coords (list(list(float))): The point coordinates input
+                 to the model to generate this mask.
+               stability_score (float): A measure of the mask's quality. This
+                 is filtered on using the stability_score_thresh parameter.
+               crop_box (list(float)): The crop of the image used to generate
+                 the mask, given in XYWH format.
+        """
+
+        # Generate masks
+        mask_data = self._generate_masks(image)
+
+        return self._encode_masks(mask_data)
+
+    def _encode_masks(self, mask_data):
+        mask_data["rles"] = _mask_to_rle_pytorch_2_1(mask_data["rles"])
+        # Encode masks
+        if self.output_mode == "coco_rle":
+            mask_data["segmentations"] = [
+                coco_encode_rle(rle) for rle in mask_data["rles"]
+            ]
+        elif self.output_mode == "binary_mask":
+            mask_data["segmentations"] = [rle_to_mask(rle) for rle in mask_data["rles"]]
+        else:
+            mask_data["segmentations"] = mask_data["rles"]
+
+        # Write mask records
+        curr_anns = []
+        for idx in range(len(mask_data["segmentations"])):
+            ann = {
+                "segmentation": mask_data["segmentations"][idx],
+                "area": area_from_rle(mask_data["rles"][idx]),
+                "bbox": box_xyxy_to_xywh(mask_data["boxes"][idx]).tolist(),
+                "predicted_iou": mask_data["iou_preds"][idx].item(),
+                "point_coords": [mask_data["points"][idx].tolist()],
+                "stability_score": mask_data["stability_score"][idx].item(),
+                "crop_box": box_xyxy_to_xywh(mask_data["crop_boxes"][idx]).tolist(),
+            }
+            curr_anns.append(ann)
+
+        return curr_anns
+
+    @torch.no_grad()
+    def generate_batch(self, images: List[np.ndarray]) -> List[List[Dict[str, Any]]]:
+        data = self._generate_masks_batch(images)
+        return [self._encode_masks(d) for d in data]
+
+    def _generate_masks(self, image: Union[np.ndarray, torch.Tensor]) -> MaskData:
+        orig_size = get_image_size(image)
+        crop_boxes, layer_idxs = generate_crop_boxes(
+            orig_size, self.crop_n_layers, self.crop_overlap_ratio
+        )
+
+        # Iterate over image crops
+        data = None
+        for crop_box, layer_idx in zip(crop_boxes, layer_idxs):
+            crop_data = self._process_crop(image, crop_box, layer_idx, orig_size)
+            if data is None:
+                data = crop_data
+            else:
+                data.cat(crop_data)
+
+        return self._deduplicate_masks(crop_boxes, data)
+
+    def _deduplicate_masks(self, crop_boxes, data):
+        # Remove duplicate masks between crops
+        if len(crop_boxes) > 1:
+            # Prefer masks from smaller crops
+            scores = 1 / box_area(data["crop_boxes"])
+            scores = scores.to(data["boxes"].device)
+            keep_by_nms = batched_nms(
+                data["boxes"].float(),
+                scores,
+                torch.zeros_like(data["boxes"][:, 0]),  # categories
+                iou_threshold=self.crop_nms_thresh,
+            )
+            data.filter(keep_by_nms)
+        data.to_numpy()
+        return data
+
+    def _generate_masks_batch(self, images: List[np.ndarray]) -> List[MaskData]:
+        all_orig_size = []
+        all_crop_boxes = []
+        all_layer_idxs = []
+        for image in images:
+            orig_size = get_image_size(image)
+            all_orig_size.append(orig_size)
+            crop_boxes, layer_idxs = generate_crop_boxes(
+                orig_size, self.crop_n_layers, self.crop_overlap_ratio
+            )
+            all_crop_boxes.append(crop_boxes)
+            all_layer_idxs.append(layer_idxs)
+
+        all_data = self._process_crop_batch(
+            images, all_crop_boxes, all_layer_idxs, all_orig_size
+        )
+
+        return [
+            self._deduplicate_masks(crop_boxes, data)
+            for (crop_boxes, data) in zip(all_crop_boxes, all_data)
+        ]
+
+    def _process_crop(
+        self,
+        image: np.ndarray,
+        crop_box: List[int],
+        crop_layer_idx: int,
+        orig_size: Tuple[int, ...],
+    ) -> MaskData:
+        # Crop the image and calculate embeddings
+        cropped_im = crop_image(image, crop_box)
+        cropped_im_size = get_image_size(cropped_im)
+        with torch.autograd.profiler.record_function("set_image"):
+            self.predictor.set_image(cropped_im)
+
+        return self._process_crop_points(
+            cropped_im_size, crop_layer_idx, crop_box, orig_size
+        )
+
+    def _process_crop_points(
+        self, cropped_im_size, crop_layer_idx, crop_box, orig_size
+    ):
+        # Get points for this crop
+        points_scale = np.array(cropped_im_size)[None, ::-1]
+        points_for_image = self.point_grids[crop_layer_idx] * points_scale
+
+        # Generate masks for this crop in batches
+        # data = MaskData()
+        data = None
+        points_per_batch = self.points_per_batch
+        if self.points_per_batch is None:
+            points_per_batch = len(points_for_image)
+        for (points,) in batch_iterator(points_per_batch, points_for_image):
+            batch_data = self._process_batch(
+                points, cropped_im_size, crop_box, orig_size, normalize=True
+            )
+            with torch.autograd.profiler.record_function("data.cat"):
+                if data is None:
+                    data = batch_data
+                else:
+                    data.cat(batch_data)
+                    del batch_data
+        self.predictor.reset_predictor()
+        return self._process_crop_points_dedup(data, crop_box)
+
+    def _process_crop_points_dedup(self, data, crop_box):
+        with torch.autograd.profiler.record_function("batched_nms"):
+            # Remove duplicates within this crop.
+            keep_by_nms = batched_nms(
+                data["boxes"].float(),
+                data["iou_preds"],
+                torch.zeros_like(data["boxes"][:, 0]),  # categories
+                iou_threshold=self.box_nms_thresh,
+            )
+
+        with torch.autograd.profiler.record_function("filter"):
+            data.filter(keep_by_nms)
+
+        with torch.autograd.profiler.record_function("uncrop_boxes_xyxy"):
+            # Return to the original image frame
+            data["boxes"] = uncrop_boxes_xyxy(data["boxes"], crop_box)
+        with torch.autograd.profiler.record_function("uncrop_points"):
+            data["points"] = uncrop_points(data["points"], crop_box)
+        with torch.autograd.profiler.record_function("crop_boxes"):
+            data["crop_boxes"] = torch.tensor(
+                [crop_box for _ in range(len(data["rles"]))]
+            )
+
+        return data
+
+    def _process_crop_batch(
+        self,
+        images: List[np.ndarray],
+        all_crop_boxes: List[List[int]],
+        all_layer_idxs: List[int],
+        all_orig_size_compact: List[Tuple[int, ...]],
+    ) -> List[MaskData]:
+        all_image = []
+        all_crop_box = []
+        all_layer_idx = []
+        all_orig_size = []
+        for image, orig_size, crop_boxes, layer_idxs in zip(
+            images, all_orig_size_compact, all_crop_boxes, all_layer_idxs
+        ):
+            # Iterate over image crops
+            for crop_box, layer_idx in zip(crop_boxes, layer_idxs):
+                all_image.append(image)
+                all_crop_box.append(crop_box)
+                all_layer_idx.append(layer_idx)
+                all_orig_size.append(orig_size)
+
+        # # TODO: NOTE: Calling process_crop in a loop like this might be an issue, because the predictor is stateful
+
+        all_cropped_im = [
+            crop_image(image, crop_box)
+            for image, crop_box in zip(all_image, all_crop_box)
+        ]
+
+        with torch.autograd.profiler.record_function("set_batch_image"):
+            self.predictor.set_image_batch(all_cropped_im)
+
+        i = 0
+        batch_features = self.predictor._features
+        all_crop_data = []
+        for cropped_im, crop_box, layer_idx, orig_size in zip(
+            all_cropped_im, all_crop_box, all_layer_idx, all_orig_size
+        ):
+            cropped_im_size = get_image_size(cropped_im)
+            self.predictor._orig_hw = [get_image_size(cropped_im)]
+            self.predictor._features = {
+                "image_embed": batch_features["image_embed"][i].unsqueeze(0),
+                "high_res_feats": [
+                    b[i].unsqueeze(0) for b in batch_features["high_res_feats"]
+                ],
+            }
+            i += 1
+            self.predictor._is_image_set = True
+
+            # TODO: Batch mask_to_rle_pytorch_2 calls
+            # TODO: Specialize for rle-only return (specify which keys you want in data)
+
+            # all_crop_data.append(self._process_crop_points(cropped_im_size, layer_idx, crop_box, orig_size))
+
+            crop_layer_idx = layer_idx
+
+            # Get points for this crop
+            points_scale = np.array(cropped_im_size)[None, ::-1]
+            points_for_image = self.point_grids[crop_layer_idx] * points_scale
+
+            # Generate masks for this crop in batches
+            points_per_batch = self.points_per_batch
+            if self.points_per_batch is None:
+                points_per_batch = len(points_for_image)
+
+            all_batch_iterator_data = []
+            with torch.autograd.profiler.record_function("all _process_batch"):
+                for (points,) in batch_iterator(points_per_batch, points_for_image):
+                    # batch_data = self._process_batch(
+                    #     points, cropped_im_size, crop_box, orig_size, normalize=True
+                    # )
+
+                    im_size = cropped_im_size
+                    normalize = True
+
+                    orig_h, orig_w = orig_size
+
+                    orig_box = [0, 0, orig_w, orig_h]
+                    orig_box_torch = torch.as_tensor(
+                        orig_box, dtype=torch.float, device=self.predictor.device
+                    )
+                    crop_box_torch = torch.as_tensor(
+                        crop_box, dtype=torch.float, device=self.predictor.device
+                    )
+                    data = self._process_batch_fullgraph(
+                        points,
+                        im_size,
+                        crop_box,
+                        crop_box_torch,
+                        orig_size,
+                        normalize,
+                        orig_box_torch,
+                    )
+                    all_batch_iterator_data.append(data)
+                self.predictor.reset_predictor()
+
+            result_data = None
+            with torch.autograd.profiler.record_function("all mask_to_rle_pytorch_2"):
+                for data in all_batch_iterator_data:
+                    # Compress to RLE
+                    data["masks"] = uncrop_masks(
+                        data["masks"], crop_box, orig_h, orig_w
+                    )
+                    # TODO: Capture all these masks in a single NT for mask_to_rle_pytorch_2
+                    # or at a minimum create a mask_to_rle_pytorch_2_list and use loops
+                    # to cause a single DtoH sync
+                    data["rles"] = _mask_to_rle_pytorch_2_0(data["masks"])
+                    del data["masks"]
+
+                    batch_data = data
+                    with torch.autograd.profiler.record_function("data.cat"):
+                        if result_data is None:
+                            result_data = batch_data
+                        else:
+                            result_data.cat(batch_data)
+                            del batch_data
+                self.predictor.reset_predictor()
+
+            all_crop_data.append(self._process_crop_points_dedup(result_data, crop_box))
+
+        i = 0
+        all_data = []
+        for _, _, crop_boxes, layer_idxs in zip(
+            images, all_orig_size, all_crop_boxes, all_layer_idxs
+        ):
+            data = None
+            for _, _ in zip(crop_boxes, layer_idxs):
+                if data is None:
+                    data = all_crop_data[i]
+                else:
+                    data.cat(all_crop_data[i])
+                i += 1
+            all_data.append(data)
+        return all_data
+
+    def _process_batch_fullgraph(
+        self,
+        points: np.ndarray,
+        im_size: Tuple[int, ...],
+        crop_box: List[int],
+        crop_box_torch: torch.Tensor,
+        orig_size: Tuple[int, ...],
+        normalize: bool,
+        orig_box_torch: torch.Tensor,
+    ) -> MaskData:
+        orig_h, orig_w = orig_size
+
+        # Run model on this batch
+        points = torch.as_tensor(points, dtype=torch.float32).pin_memory()
+        points = points.to(device=self.predictor.device, non_blocking=True)
+        in_points = self.predictor._transforms.transform_coords(
+            points, normalize=normalize, orig_hw=im_size
+        )
+        in_labels = torch.ones(
+            in_points.shape[0], dtype=torch.int, device=in_points.device
+        )
+        with torch.autograd.profiler.record_function("_predict"):
+            # NOTE: Just leaving this for reference. predict was split to
+            # allow earlier filtering by predicted iou
+            # masks, iou_preds, low_res_masks = self.predictor._predict(
+            masks = None
+            high_res_feats = self.predictor._features["high_res_feats"]
+            image_embed = self.predictor._features["image_embed"]
+            image_pe = self.predictor.model.sam_prompt_encoder.get_dense_pe().clone()
+            assert self.multimask_output, (
+                "Currently require multimask_output set to True"
+            )
+            high_res_feats_input = [
+                feat_level[-1].unsqueeze(0).clone()
+                # for feat_level in self._features["high_res_feats"]
+                for feat_level in high_res_feats
+            ]
+            image_embed_input = image_embed[-1].unsqueeze(0).clone()
+            low_res_masks, iou_preds = self.predictor._predict_masks(
+                [t.contiguous() for t in high_res_feats_input],
+                image_embed_input.contiguous(),
+                image_pe.contiguous(),
+                in_points[:, None, :].contiguous(),
+                in_labels[:, None].contiguous(),
+                boxes=None,
+                mask_input=None,
+                multimask_output=self.multimask_output,
+                # img_idx=-1,
+            )
+
+        x0, y0, _, _ = crop_box
+        points = points.repeat_interleave(3 if masks is None else masks.shape[1], dim=0)
+
+        if not self.use_m2m:
+            with torch.autograd.profiler.record_function("thresh and filter"):
+                # Filter by predicted IoU
+                if self.pred_iou_thresh > 0.0:
+                    keep_mask = iou_preds.flatten(0, 1) > self.pred_iou_thresh
+                    keep_index = keep_mask.nonzero(as_tuple=True)[0]
+                    low_res_masks = low_res_masks.flatten(0, 1).unsqueeze(1)
+                    low_res_masks = low_res_masks[keep_index]
+                    iou_preds = iou_preds.flatten(0, 1).unsqueeze(1)[keep_index]
+                    points = points[keep_index]
+        if masks is None:
+            masks, low_res_mask = self.predictor._predict_masks_postprocess(
+                low_res_masks, -1, True, channel_1=low_res_masks.size(1) == 1
+            )
+
+        # Serialize predictions and store in MaskData
+        with torch.autograd.profiler.record_function("MaskData"):
+            data = MaskData(
+                masks=masks.flatten(0, 1),
+                iou_preds=iou_preds.flatten(0, 1),
+                points=points,
+                low_res_masks=low_res_masks.flatten(0, 1),
+            )
+        del masks
+
+        keep_mask = None
+
+        if not self.use_m2m:
+            # NOTE: This is left just for reference. We filter earlier for this case to save
+            # on compute within the expensive _predict_masks_postprocess
+            # with torch.autograd.profiler.record_function("thresh and filter"):
+            #     # Filter by predicted IoU
+            #     if self.pred_iou_thresh > 0.0:
+            #         keep_mask = data["iou_preds"] > self.pred_iou_thresh
+            #         # TODO: Might need this for correctness due to calculate_stability_score IoU?
+            #         data.filter(keep_mask)
+
+            with torch.autograd.profiler.record_function("calculate_stability_score"):
+                # Calculate and filter by stability score
+                data["stability_score"] = self.calculate_stability_score(
+                    data["masks"], self.mask_threshold, self.stability_score_offset
+                )
+            with torch.autograd.profiler.record_function("stability_score_thresh"):
+                if self.stability_score_thresh > 0.0:
+                    keep_mask = data["stability_score"] >= self.stability_score_thresh
+                    keep_index = keep_mask.nonzero(as_tuple=True)[0]
+                    data.filter(keep_index)
+        else:
+            # One step refinement using previous mask predictions
+            in_points = self.predictor._transforms.transform_coords(
+                data["points"], normalize=normalize, orig_hw=im_size
+            )
+            labels = torch.ones(
+                in_points.shape[0], dtype=torch.int, device=in_points.device
+            )
+            masks, ious = self.refine_with_m2m(
+                in_points, labels, data["low_res_masks"], self.points_per_batch
+            )
+            data["masks"] = masks.squeeze(1)
+            data["iou_preds"] = ious.squeeze(1)
+
+            if self.pred_iou_thresh > 0.0:
+                keep_mask = data["iou_preds"] > self.pred_iou_thresh
+                data.filter(keep_mask)
+
+            data["stability_score"] = self.calculate_stability_score(
+                data["masks"], self.mask_threshold, self.stability_score_offset
+            )
+            if self.stability_score_thresh > 0.0:
+                keep_mask = data["stability_score"] >= self.stability_score_thresh
+                data.filter(keep_mask)
+
+        with torch.autograd.profiler.record_function(
+            "Threshold masks and calculate boxes"
+        ):
+            # Threshold masks and calculate boxes
+            data["masks"] = data["masks"] > self.mask_threshold
+            data["boxes"] = self.batched_mask_to_box(data["masks"])
+
+        with torch.autograd.profiler.record_function("is_box_near_crop_edge"):
+            # Filter boxes that touch crop boundaries
+            keep_mask = ~is_box_near_crop_edge_torch(
+                data["boxes"],
+                crop_box,
+                crop_box_torch,
+                orig_box_torch,
+            )
+
+        with torch.autograd.profiler.record_function("filter(keep_mask)"):
+            keep_index = keep_mask.nonzero(as_tuple=True)[0]
+            data.filter(keep_index)
+
+        return data
+
+    def _process_batch(
+        self,
+        points: np.ndarray,
+        im_size: Tuple[int, ...],
+        crop_box: List[int],
+        orig_size: Tuple[int, ...],
+        normalize=False,
+    ) -> MaskData:
+        orig_h, orig_w = orig_size
+
+        orig_box = [0, 0, orig_w, orig_h]
+        orig_box_torch = torch.as_tensor(orig_box, dtype=torch.float)
+        orig_box_torch = orig_box_torch.pin_memory()
+        orig_box_torch = orig_box_torch.to(
+            device=self.predictor.device, non_blocking=True
+        )
+
+        crop_box_torch = torch.as_tensor(crop_box, dtype=torch.float)
+        crop_box_torch = crop_box_torch.pin_memory()
+        crop_box_torch = crop_box_torch.to(
+            device=self.predictor.device, non_blocking=True
+        )
+
+        data = self._process_batch_fullgraph(
+            points,
+            im_size,
+            crop_box,
+            crop_box_torch,
+            orig_size,
+            normalize,
+            orig_box_torch,
+        )
+
+        with torch.autograd.profiler.record_function("uncrop_masks"):
+            # Compress to RLE
+            data["masks"] = uncrop_masks(data["masks"], crop_box, orig_h, orig_w)
+            data["rles"] = _mask_to_rle_pytorch_2_0(data["masks"])
+            del data["masks"]
+
+        return data
+
+    @staticmethod
+    def postprocess_small_regions(
+        mask_data: MaskData, min_area: int, nms_thresh: float
+    ) -> MaskData:
+        """
+        Removes small disconnected regions and holes in masks, then reruns
+        box NMS to remove any new duplicates.
+
+        Edits mask_data in place.
+
+        Requires open-cv as a dependency.
+        """
+        if len(mask_data["rles"]) == 0:
+            return mask_data
+
+        # Filter small disconnected regions and holes
+        new_masks = []
+        scores = []
+        for rle in mask_data["rles"]:
+            mask = rle_to_mask(rle)
+
+            mask, changed = remove_small_regions(mask, min_area, mode="holes")
+            unchanged = not changed
+            mask, changed = remove_small_regions(mask, min_area, mode="islands")
+            unchanged = unchanged and not changed
+
+            new_masks.append(torch.as_tensor(mask).unsqueeze(0))
+            # Give score=0 to changed masks and score=1 to unchanged masks
+            # so NMS will prefer ones that didn't need postprocessing
+            scores.append(float(unchanged))
+
+        # Recalculate boxes and remove any new duplicates
+        masks = torch.cat(new_masks, dim=0)
+        # TODO: This doesn't use the possibly compiled self.batched_mask_to_box
+        boxes = batched_mask_to_box(masks)
+        keep_by_nms = batched_nms(
+            boxes.float(),
+            torch.as_tensor(scores),
+            torch.zeros_like(boxes[:, 0]),  # categories
+            iou_threshold=nms_thresh,
+        )
+
+        # Only recalculate RLEs for masks that have changed
+        for i_mask in keep_by_nms:
+            if scores[i_mask] == 0.0:
+                mask_torch = masks[i_mask].unsqueeze(0)
+                mask_data["rles"][i_mask] = mask_to_rle_pytorch(mask_torch)[0]
+                mask_data["boxes"][i_mask] = boxes[i_mask]  # update res directly
+        mask_data.filter(keep_by_nms)
+
+        return mask_data
+
+    def refine_with_m2m(self, points, point_labels, low_res_masks, points_per_batch):
+        new_masks = []
+        new_iou_preds = []
+
+        for cur_points, cur_point_labels, low_res_mask in batch_iterator(
+            points_per_batch, points, point_labels, low_res_masks
+        ):
+            best_masks, best_iou_preds, _ = self.predictor._predict(
+                cur_points[:, None, :],
+                cur_point_labels[:, None],
+                mask_input=low_res_mask[:, None, :],
+                multimask_output=False,
+                return_logits=True,
+            )
+            new_masks.append(best_masks)
+            new_iou_preds.append(best_iou_preds)
+        masks = torch.cat(new_masks, dim=0)
+        return masks, torch.cat(new_iou_preds, dim=0)
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/build_sam.py b/lib/python3.12/site-packages/torchao/_models/sam2/build_sam.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad0d1fe41cf58a905e69ea19b8f6e21f0933c4cd
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/build_sam.py
@@ -0,0 +1,166 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import logging
+import os
+
+import torch
+from hydra import compose
+from hydra.utils import instantiate
+from omegaconf import OmegaConf
+
+from torchao._models import sam2
+
+# Check if the user is running Python from the parent directory of the sam2 repo
+# (i.e. the directory where this repo is cloned into) -- this is not supported since
+# it could shadow the sam2 package and cause issues.
+if os.path.isdir(os.path.join(sam2.__path__[0], "sam2")):
+    # If the user has "sam2/sam2" in their path, they are likey importing the repo itself
+    # as "sam2" rather than importing the "sam2" python package (i.e. "sam2/sam2" directory).
+    # This typically happens because the user is running Python from the parent directory
+    # that contains the sam2 repo they cloned.
+    raise RuntimeError(
+        "You're likely running Python from the parent directory of the sam2 repository "
+        "(i.e. the directory where https://github.com/facebookresearch/sam2 is cloned into). "
+        "This is not supported since the `sam2` Python package could be shadowed by the "
+        "repository name (the repository is also named `sam2` and contains the Python package "
+        "in `sam2/sam2`). Please run Python from another directory (e.g. from the repo dir "
+        "rather than its parent dir, or from your home directory) after installing SAM 2."
+    )
+
+
+HF_MODEL_ID_TO_FILENAMES = {
+    "facebook/sam2-hiera-tiny": (
+        "configs/sam2/sam2_hiera_t.yaml",
+        "sam2_hiera_tiny.pt",
+    ),
+    "facebook/sam2-hiera-small": (
+        "configs/sam2/sam2_hiera_s.yaml",
+        "sam2_hiera_small.pt",
+    ),
+    "facebook/sam2-hiera-base-plus": (
+        "configs/sam2/sam2_hiera_b+.yaml",
+        "sam2_hiera_base_plus.pt",
+    ),
+    "facebook/sam2-hiera-large": (
+        "configs/sam2/sam2_hiera_l.yaml",
+        "sam2_hiera_large.pt",
+    ),
+    "facebook/sam2.1-hiera-tiny": (
+        "configs/sam2.1/sam2.1_hiera_t.yaml",
+        "sam2.1_hiera_tiny.pt",
+    ),
+    "facebook/sam2.1-hiera-small": (
+        "configs/sam2.1/sam2.1_hiera_s.yaml",
+        "sam2.1_hiera_small.pt",
+    ),
+    "facebook/sam2.1-hiera-base-plus": (
+        "configs/sam2.1/sam2.1_hiera_b+.yaml",
+        "sam2.1_hiera_base_plus.pt",
+    ),
+    "facebook/sam2.1-hiera-large": (
+        "configs/sam2.1/sam2.1_hiera_l.yaml",
+        "sam2.1_hiera_large.pt",
+    ),
+}
+
+
+def build_sam2(
+    config_file,
+    ckpt_path=None,
+    device="cuda",
+    mode="eval",
+    hydra_overrides_extra=[],
+    apply_postprocessing=True,
+    **kwargs,
+):
+    if apply_postprocessing:
+        hydra_overrides_extra = hydra_overrides_extra.copy()
+        hydra_overrides_extra += [
+            # dynamically fall back to multi-mask if the single mask is not stable
+            "++model.sam_mask_decoder_extra_args.dynamic_multimask_via_stability=true",
+            "++model.sam_mask_decoder_extra_args.dynamic_multimask_stability_delta=0.05",
+            "++model.sam_mask_decoder_extra_args.dynamic_multimask_stability_thresh=0.98",
+        ]
+    # Read config and init model
+    cfg = compose(config_name=config_file, overrides=hydra_overrides_extra)
+    OmegaConf.resolve(cfg)
+    model = instantiate(cfg.model, _recursive_=True)
+    _load_checkpoint(model, ckpt_path)
+    model = model.to(device)
+    if mode == "eval":
+        model.eval()
+    return model
+
+
+def build_sam2_video_predictor(
+    config_file,
+    ckpt_path=None,
+    device="cuda",
+    mode="eval",
+    hydra_overrides_extra=[],
+    apply_postprocessing=True,
+    **kwargs,
+):
+    hydra_overrides = [
+        "++model._target_=torchao._models.sam2.sam2_video_predictor.SAM2VideoPredictor",
+    ]
+    if apply_postprocessing:
+        hydra_overrides_extra = hydra_overrides_extra.copy()
+        hydra_overrides_extra += [
+            # dynamically fall back to multi-mask if the single mask is not stable
+            "++model.sam_mask_decoder_extra_args.dynamic_multimask_via_stability=true",
+            "++model.sam_mask_decoder_extra_args.dynamic_multimask_stability_delta=0.05",
+            "++model.sam_mask_decoder_extra_args.dynamic_multimask_stability_thresh=0.98",
+            # the sigmoid mask logits on interacted frames with clicks in the memory encoder so that the encoded masks are exactly as what users see from clicking
+            "++model.binarize_mask_from_pts_for_mem_enc=true",
+            # fill small holes in the low-res masks up to `fill_hole_area` (before resizing them to the original video resolution)
+            "++model.fill_hole_area=8",
+        ]
+    hydra_overrides.extend(hydra_overrides_extra)
+
+    # Read config and init model
+    cfg = compose(config_name=config_file, overrides=hydra_overrides)
+    OmegaConf.resolve(cfg)
+    model = instantiate(cfg.model, _recursive_=True)
+    _load_checkpoint(model, ckpt_path)
+    model = model.to(device)
+    if mode == "eval":
+        model.eval()
+    return model
+
+
+def _hf_download(model_id):
+    from huggingface_hub import hf_hub_download
+
+    config_name, checkpoint_name = HF_MODEL_ID_TO_FILENAMES[model_id]
+    ckpt_path = hf_hub_download(repo_id=model_id, filename=checkpoint_name)
+    return config_name, ckpt_path
+
+
+def build_sam2_hf(model_id, **kwargs):
+    config_name, ckpt_path = _hf_download(model_id)
+    return build_sam2(config_file=config_name, ckpt_path=ckpt_path, **kwargs)
+
+
+def build_sam2_video_predictor_hf(model_id, **kwargs):
+    config_name, ckpt_path = _hf_download(model_id)
+    return build_sam2_video_predictor(
+        config_file=config_name, ckpt_path=ckpt_path, **kwargs
+    )
+
+
+def _load_checkpoint(model, ckpt_path):
+    if ckpt_path is not None:
+        sd = torch.load(ckpt_path, map_location="cpu", weights_only=True)["model"]
+        missing_keys, unexpected_keys = model.load_state_dict(sd)
+        if missing_keys:
+            logging.error(missing_keys)
+            raise RuntimeError()
+        if unexpected_keys:
+            logging.error(unexpected_keys)
+            raise RuntimeError()
+        logging.info("Loaded checkpoint sucessfully")
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/map_tensor.py b/lib/python3.12/site-packages/torchao/_models/sam2/map_tensor.py
new file mode 100644
index 0000000000000000000000000000000000000000..0310e7f8b64bf7122f6a6e9b92d71f2bf1906d81
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/map_tensor.py
@@ -0,0 +1,781 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import contextlib
+import functools
+from typing import Dict
+
+import torch
+from torch.nested._internal.nested_tensor import nested_view_from_values_offsets
+from torch.utils._pytree import tree_map
+
+MAP_TENSOR_ATEN_OP_TABLE = {}
+
+
+def implements(aten_ops_or_torch_fns):
+    if not isinstance(aten_ops_or_torch_fns, (list, tuple)):
+        aten_ops_or_torch_fns = [aten_ops_or_torch_fns]
+
+    def decorator(func):
+        for op in aten_ops_or_torch_fns:
+
+            @functools.wraps(op)
+            def wrapper(f, types, args, kwargs):
+                return func(f, types, args, kwargs)
+
+            MAP_TENSOR_ATEN_OP_TABLE[op] = wrapper
+        return func
+
+    return decorator
+
+
+@contextlib.contextmanager
+def no_dispatch():
+    guard = torch._C._DisableTorchDispatch()
+    try:
+        yield
+    finally:
+        del guard
+
+
+def wrap_dim(i, dim):
+    if i < 0:
+        return dim + i
+    return i
+
+
+def unwrap(t):
+    if isinstance(t, MapTensor):
+        with no_dispatch():
+            return t.elems
+    else:
+        return t
+
+
+def unwrap_i(t, i):
+    if isinstance(t, MapTensor):
+        with no_dispatch():
+            return t.elems[i]
+    else:
+        return t
+
+
+def unwrap_fn(t, fn):
+    if isinstance(t, MapTensor):
+        with no_dispatch():
+            return fn(t.elems)
+    else:
+        return None
+
+
+def wrap(t):
+    if isinstance(t, torch.Tensor):
+        return MapTensor(t)
+    else:
+        return t
+
+
+@implements(torch.ops.aten.native_layer_norm.default)
+def layer_norm_impl(func, types, args, kwargs=None):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 5, f"args: {unwrapped_args}"
+    norm_res = func(*unwrapped_args)
+    assert len(norm_res) == 3
+    return tuple(wrap(a) for a in norm_res)
+
+
+@implements(torch.ops.aten.add.Tensor)
+def add_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 2, f"args: {unwrapped_args}"
+    if not isinstance(args[0], MapTensor) and isinstance(args[1], MapTensor):
+        if args[0].dim() == (args[1].dim() + 1):
+            return NotImplemented
+        return NotImplemented
+    return wrap(func(*unwrapped_args, **unwrapped_kwargs))
+
+
+@implements([torch.ops.aten.cat.default, torch.ops.aten.stack.default])
+def cat_ops_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) <= 2, f"args: {unwrapped_args}"
+    # TODO: Use MapTensor type for filter
+    # First argument's dim
+    dim = unwrapped_args[0][0].dim()
+    size = unwrapped_args[0][0].size()
+    for a in unwrapped_args[0]:
+        if a.dim() > dim:
+            dim = a.dim()
+            size = a.size()
+    new_args = []
+    for a in unwrapped_args[0]:
+        if a.dim() == dim:
+            new_args.append(a)
+        else:
+            assert a.dim() + 1 == dim
+            new_args.append(a.unsqueeze(0).expand((size[0],) + a.size()))
+    orig_dim = unwrapped_args[1] if len(unwrapped_args) == 2 else 0
+    return wrap(func(new_args, wrap_dim(orig_dim, dim - 1) + 1))
+
+
+@implements(torch.ops.aten.select.int)
+def select_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 3, f"args: {unwrapped_args}"
+    return wrap(func(unwrapped_args[0], unwrapped_args[1] + 1, unwrapped_args[2]))
+
+
+@implements(torch.ops.aten.slice.Tensor)
+def slice_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 4, f"args: {unwrapped_args}"
+    dim = unwrapped_args[0].dim()
+    return wrap(
+        func(
+            unwrapped_args[0],
+            wrap_dim(unwrapped_args[1], dim - 1) + 1,
+            unwrapped_args[2],
+            unwrapped_args[3],
+        )
+    )
+
+
+@implements(
+    [
+        torch.ops.aten.mean.dim,
+        torch.ops.aten.max.dim,
+        torch.ops.aten.argmax.default,
+        torch.ops.aten.min.dim,
+        torch.ops.aten.any.dim,
+        torch.ops.aten.amax.default,
+        torch.ops.aten.amin.default,
+        torch.ops.aten.all.default,
+        torch.ops.aten.sum.dim_IntList,
+    ]
+)
+def reductions_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    # TODO: THIS MIGHT BE WRONG
+    if len(unwrapped_args) == 3 and len(unwrapped_kwargs) == 0:
+        assert len(unwrapped_args[1]) == 1
+        dim = unwrapped_args[0].dim()
+        return wrap(
+            func(
+                unwrapped_args[0],
+                [wrap_dim(u, dim - 1) + 1 for u in unwrapped_args[1]],
+                unwrapped_args[2],
+            )
+        )
+    if len(unwrapped_args) == 2 and len(unwrapped_kwargs) == 1:
+        assert len(unwrapped_args[1]) == 1
+        dim = unwrapped_args[0].dim()
+        return wrap(
+            func(
+                unwrapped_args[0],
+                [wrap_dim(u, dim - 1) + 1 for u in unwrapped_args[1]],
+                **unwrapped_kwargs,
+            )
+        )
+    if (
+        len(unwrapped_args) == 2
+        and len(unwrapped_kwargs) == 0
+        and type(unwrapped_args[1]) == list
+    ):
+        assert len(unwrapped_args[1]) == 1
+        dim = unwrapped_args[0].dim()
+        return wrap(
+            func(
+                unwrapped_args[0], [wrap_dim(u, dim - 1) + 1 for u in unwrapped_args[1]]
+            )
+        )
+    if (
+        len(unwrapped_args) == 2
+        and len(unwrapped_kwargs) == 0
+        and type(unwrapped_args[1]) == int
+    ):
+        dim = unwrapped_args[0].dim()
+        return wrap(func(unwrapped_args[0], wrap_dim(unwrapped_args[1], dim - 1) + 1))
+    if len(args) == 1 and len(kwargs) == 0:
+        return wrap(func(unwrapped_args[0]))
+    return NotImplemented
+
+
+@implements([torch.ops.aten._unsafe_view.default, torch.ops.aten.expand.default])
+def view_ops_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 2, f"args: {unwrapped_args}"
+    input_size = unwrapped_args[0].size()
+    bigger_size = list(input_size[:1]) + unwrapped_args[1]
+    return wrap(func(unwrapped_args[0], bigger_size))
+
+
+@implements(torch.ops.aten.view.default)
+def view_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 2, f"args: {unwrapped_args}"
+    input_size = unwrapped_args[0].size()
+    bigger_size = list(input_size[:1]) + unwrapped_args[1]
+    if unwrapped_args[0].size() == tuple(bigger_size):
+        return wrap(args[0].elems)
+    return wrap(unwrapped_args[0].reshape(bigger_size))
+
+
+@implements([torch.ops.aten.mm.default, torch.ops.aten.bmm.default])
+def mm_ops_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 2, f"args: {unwrapped_args}"
+    return wrap(torch.matmul(*unwrapped_args))
+
+
+@implements(torch.ops.aten.unsqueeze.default)
+def unsqueeze_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 2, f"args: {unwrapped_args}"
+    new_i = unwrapped_args[1]
+    if new_i >= 0:
+        new_i += 1
+    return wrap(func(unwrapped_args[0], new_i))
+
+
+@implements(torch.ops.aten.squeeze.dim)
+def squeeze_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 2, f"args: {unwrapped_args}"
+    new_i = unwrapped_args[1]
+    if new_i >= 0:
+        new_i += 1
+    return wrap(func(unwrapped_args[0], new_i))
+
+
+@implements(torch.ops.aten.addmm.default)
+def addmm_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 3, f"args: {unwrapped_args}"
+    return wrap(torch.matmul(unwrapped_args[1], unwrapped_args[2]) + unwrapped_args[0])
+
+
+@implements(torch.ops.aten.convolution.default)
+def convolution_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 9, f"args: {unwrapped_args}"
+    a = unwrapped_args[0]
+    a = unwrapped_args[0].flatten(0, 1)
+    # TODO: It's scary that this .contiguous seems necessary, but I we're below composite conv
+    # which might expected contiguous output
+    resa = func(*((a,) + unwrapped_args[1:])).contiguous()
+    resb = resa.view(
+        (unwrapped_args[0].size(0), unwrapped_args[0].size(1)) + resa.size()[1:]
+    )
+    return wrap(resb)
+
+
+@implements(torch.ops.aten.upsample_bilinear2d.default)
+def upsample_bilinear2d_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 3, f"args: {unwrapped_args}"
+    a = unwrapped_args[0]
+    a = unwrapped_args[0].flatten(0, 1)
+    # NOTE: It's scary that this .contiguous seems necessary, but we're below composite upsample
+    # which might expected contiguous output
+    resa = func(*((a,) + unwrapped_args[1:])).contiguous()
+    resb = resa.view(
+        (unwrapped_args[0].size(0), unwrapped_args[0].size(1)) + resa.size()[1:]
+    )
+    return wrap(resb)
+
+
+@implements(torch.ops.aten.transpose.int)
+def transpose_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 3, f"args: {unwrapped_args}"
+    dim = unwrapped_args[0].dim()
+    return wrap(
+        func(
+            unwrapped_args[0],
+            wrap_dim(unwrapped_args[1], dim - 1) + 1,
+            wrap_dim(unwrapped_args[2], dim - 1) + 1,
+        )
+    )
+
+
+@implements(torch.ops.aten.unbind.int)
+def unbind_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 2, f"args: {unwrapped_args}"
+    dim = unwrapped_args[0].dim()
+    return wrap(func(unwrapped_args[0], wrap_dim(unwrapped_args[1], dim - 1) + 1))
+
+
+@implements(torch.ops.aten.permute.default)
+def permute_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 2, f"args: {unwrapped_args}"
+    dim = unwrapped_args[0].dim()
+    return wrap(
+        func(
+            unwrapped_args[0],
+            ([0] + [wrap_dim(u, dim - 1) + 1 for u in unwrapped_args[1]]),
+        )
+    )
+
+
+@implements(torch.ops.aten._scaled_dot_product_efficient_attention.default)
+def _scaled_dot_product_efficient_attention_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(args) == 5
+    if all(isinstance(a, MapTensor) for a in args[:3]):
+        # assert len(unwrapped_kwargs) == 0
+        assert len(unwrapped_args) == 5, f"args: {unwrapped_args}"
+        assert unwrapped_args[0].dim() == 5
+        assert unwrapped_args[1].dim() == 5
+        assert unwrapped_args[2].dim() == 5
+        sdpa_res = wrap(
+            func(
+                unwrapped_args[0].flatten(0, 1),
+                unwrapped_args[1].flatten(0, 1),
+                unwrapped_args[2].flatten(0, 1),
+                unwrapped_args[3],
+                unwrapped_args[4],
+                **unwrapped_kwargs,
+            )
+        )
+        return (wrap(sdpa_res[0].view(unwrapped_args[0].size())),) + sdpa_res[1:]
+    if isinstance(args[0], MapTensor) and not any(
+        isinstance(a, MapTensor) for a in args[1:]
+    ):
+        # assert len(unwrapped_kwargs) == 0
+        assert len(unwrapped_args) == 5, f"args: {unwrapped_args}"
+        assert unwrapped_args[0].dim() == 5
+        assert unwrapped_args[1].dim() == 4
+        assert unwrapped_args[2].dim() == 4
+        a0 = unwrapped_args[0]
+        a1_size = unwrapped_args[1].size()
+        a1 = unwrapped_args[1].unsqueeze(0).expand((a0.size(0),) + a1_size)
+        a2 = unwrapped_args[2].unsqueeze(0).expand((a0.size(0),) + a1_size)
+        sdpa_res = wrap(
+            func(
+                a0.flatten(0, 1),
+                a1.flatten(0, 1),
+                a2.flatten(0, 1),
+                unwrapped_args[3],
+                unwrapped_args[4],
+                **unwrapped_kwargs,
+            )
+        )
+        return (wrap(sdpa_res[0].view(unwrapped_args[0].size())),) + sdpa_res[1:]
+    if (
+        (not isinstance(args[0], MapTensor))
+        and isinstance(args[1], MapTensor)
+        and (not isinstance(args[2], MapTensor))
+    ):
+        assert len(unwrapped_kwargs) == 0
+        assert len(unwrapped_args) == 5, f"args: {unwrapped_args}"
+        assert unwrapped_args[0].dim() == 4
+        assert unwrapped_args[1].dim() == 5
+        assert unwrapped_args[2].dim() == 4
+        a1_size = unwrapped_args[1].size()
+        a0 = (
+            unwrapped_args[0]
+            .unsqueeze(0)
+            .expand((a1_size[0],) + unwrapped_args[0].size()[1:])
+        )
+        a2 = (
+            unwrapped_args[2]
+            .unsqueeze(0)
+            .expand((a1_size[0],) + unwrapped_args[2].size()[1:])
+        )
+        sdpa_res = wrap(
+            func(
+                a0.flatten(0, 1),
+                a1.flatten(0, 1),
+                a2.flatten(0, 1),
+                unwrapped_args[3],
+                unwrapped_args[4],
+            )
+        )
+        return (wrap(sdpa_res[0].view(unwrapped_args[0].size())),) + sdpa_res[1:]
+    if (
+        (not isinstance(args[0], MapTensor))
+        and isinstance(args[1], MapTensor)
+        and isinstance(args[2], MapTensor)
+    ):
+        # assert len(unwrapped_kwargs) == 0
+        assert len(unwrapped_args) == 5, f"args: {unwrapped_args}"
+        assert unwrapped_args[0].dim() == 4
+        assert unwrapped_args[1].dim() == 5
+        assert unwrapped_args[2].dim() == 5
+        a0_size = unwrapped_args[0].size()
+        a1_size = unwrapped_args[1].size()
+        a0 = unwrapped_args[0].unsqueeze(0).expand((a1_size[0],) + a0_size)
+        a1 = unwrapped_args[1]
+        a2 = unwrapped_args[2]
+        sdpa_res = wrap(
+            func(
+                a0.flatten(0, 1),
+                a1.flatten(0, 1),
+                a2.flatten(0, 1),
+                unwrapped_args[3],
+                unwrapped_args[4],
+                **unwrapped_kwargs,
+            )
+        )
+        return (wrap(sdpa_res[0].view((a1_size[0],) + a0_size)),) + sdpa_res[1:]
+    return NotImplemented
+
+
+@implements(torch.ops.aten._scaled_dot_product_flash_attention.default)
+def _scaled_dot_product_flash_attention_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(args) == 3
+    assert len(unwrapped_kwargs) == 1
+    assert len(unwrapped_args) == 3, f"args: {unwrapped_args}"
+    if all(isinstance(a, MapTensor) for a in args[:3]):
+        assert unwrapped_args[0].dim() == 5
+        assert unwrapped_args[1].dim() == 5
+        assert unwrapped_args[2].dim() == 5
+        sdpa_res = wrap(
+            func(
+                unwrapped_args[0].flatten(0, 1),
+                unwrapped_args[1].flatten(0, 1),
+                unwrapped_args[2].flatten(0, 1),
+                **unwrapped_kwargs,
+            )
+        )
+        return (wrap(sdpa_res[0].view(unwrapped_args[0].size())),) + sdpa_res[1:]
+    if isinstance(args[0], MapTensor) and not any(
+        isinstance(a, MapTensor) for a in args[1:]
+    ):
+        assert unwrapped_args[0].dim() == 5
+        assert unwrapped_args[1].dim() == 4
+        assert unwrapped_args[2].dim() == 4
+        a0 = unwrapped_args[0]
+        a1_size = unwrapped_args[1].size()
+        a1 = unwrapped_args[1].unsqueeze(0).expand((a0.size(0),) + a1_size)
+        a2 = unwrapped_args[2].unsqueeze(0).expand((a0.size(0),) + a1_size)
+        sdpa_res = wrap(
+            func(
+                a0.flatten(0, 1), a1.flatten(0, 1), a2.flatten(0, 1), **unwrapped_kwargs
+            )
+        )
+        return (wrap(sdpa_res[0].view(unwrapped_args[0].size())),) + sdpa_res[1:]
+    if (
+        (not isinstance(args[0], MapTensor))
+        and isinstance(args[1], MapTensor)
+        and (not isinstance(args[2], MapTensor))
+    ):
+        assert unwrapped_args[0].dim() == 4
+        assert unwrapped_args[1].dim() == 5
+        assert unwrapped_args[2].dim() == 4
+        a1_size = unwrapped_args[1].size()
+        a0 = (
+            unwrapped_args[0]
+            .unsqueeze(0)
+            .expand((a1_size[0],) + unwrapped_args[0].size()[1:])
+        )
+        a2 = (
+            unwrapped_args[2]
+            .unsqueeze(0)
+            .expand((a1_size[0],) + unwrapped_args[2].size()[1:])
+        )
+        sdpa_res = wrap(
+            func(
+                a0.flatten(0, 1), a1.flatten(0, 1), a2.flatten(0, 1), **unwrapped_kwargs
+            )
+        )
+        return (wrap(sdpa_res[0].view(unwrapped_args[0].size())),) + sdpa_res[1:]
+    if (
+        (not isinstance(args[0], MapTensor))
+        and isinstance(args[1], MapTensor)
+        and isinstance(args[2], MapTensor)
+    ):
+        assert unwrapped_args[0].dim() == 4
+        assert unwrapped_args[1].dim() == 5
+        assert unwrapped_args[2].dim() == 5
+        a0_size = unwrapped_args[0].size()
+        a1_size = unwrapped_args[1].size()
+        a0 = unwrapped_args[0].unsqueeze(0).expand((a1_size[0],) + a0_size)
+        a1 = unwrapped_args[1]
+        a2 = unwrapped_args[2]
+        sdpa_res = wrap(
+            func(
+                a0.flatten(0, 1), a1.flatten(0, 1), a2.flatten(0, 1), **unwrapped_kwargs
+            )
+        )
+        return (wrap(sdpa_res[0].view((a1_size[0],) + a0_size)),) + sdpa_res[1:]
+    return NotImplemented
+
+
+# torch.ops.aten._unsafe_index.Tensor is only needed by inductor for compile
+@implements([torch.ops.aten._unsafe_index.Tensor, torch.ops.aten.index.Tensor])
+def index_ops_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    assert len(unwrapped_kwargs) == 0
+    assert len(unwrapped_args) == 2, f"args: {unwrapped_args}"
+    # if len(args[1]) == 1 and isinstance(args[1][0], MapTensor) and isinstance(args[0], MapTensor):
+    #     return wrap(func(*unwrapped_args))
+    if (
+        len(args[1]) == 1
+        and isinstance(args[1][0], MapTensor)
+        and not isinstance(args[0], MapTensor)
+    ):
+        tensors = [
+            func(args[0], [args[1][0].elems[i]]) for i in range(len(args[1][0].elems))
+        ]
+        values = torch.cat(tensors)
+        lengths = torch.tensor([0] + [t.size(0) for t in tensors], pin_memory=True).to(
+            values.device, non_blocking=True
+        )
+        offsets = torch.cumsum(lengths, dim=0)
+        nt = nested_view_from_values_offsets(values, offsets)
+        assert nt.layout == torch.jagged
+        return wrap(nt)
+    if (
+        isinstance(args[0], MapTensor)
+        and not isinstance(args[1][0], MapTensor)
+        and len(args[1]) == 1
+    ):
+        return wrap(func(args[0].elems, [args[1][0].unsqueeze(0)]))
+    if (
+        isinstance(args[0], MapTensor)
+        and not isinstance(args[1][0], MapTensor)
+        and isinstance(args[1][1], MapTensor)
+        and len(args[1]) == 2
+    ):
+        res = []
+        for a0, a11 in zip(args[0].elems.unbind(), args[1][1].elems.unbind()):
+            res.append(func(a0, [args[1][0], a11]))
+        return wrap(torch.stack(res))
+    if (
+        isinstance(args[0], MapTensor)
+        and isinstance(args[1][0], MapTensor)
+        and len(args[1]) == 1
+    ):
+        tensors = [
+            func(args[0].elems[i], [args[1][0].elems[i]])
+            for i in range(len(args[0].elems))
+        ]
+        values = torch.cat(tensors)
+        lengths = torch.tensor([0] + [t.size(0) for t in tensors], pin_memory=True).to(
+            values.device, non_blocking=True
+        )
+        offsets = torch.cumsum(lengths, dim=0)
+        nt = nested_view_from_values_offsets(values, offsets)
+        assert nt.layout == torch.jagged
+        return wrap(nt)
+    a = unwrapped_args[0]
+    a = unwrapped_args[0].flatten(0, 1)
+    resa = func(a, args[1])
+    resb = resa.view(
+        (unwrapped_args[0].size(0), unwrapped_args[0].size(1)) + resa.size()[1:]
+    )
+    return wrap(resb)
+
+
+# Prims
+@implements(torch.ops.aten.dim.default)
+def dim_impl(func, types, args, kwargs):
+    assert len(args) == 1
+    assert len(kwargs) == 0
+    ret_dim = func(args[0].elems) - 1
+    assert ret_dim >= 0
+    return ret_dim
+
+
+@implements(torch.ops.aten.sym_size.default)
+def sym_impl(func, types, args, kwargs):
+    assert len(args) == 1
+    assert len(kwargs) == 0
+    elems_size = func(args[0].elems)
+    assert len(elems_size) > 0
+    return elems_size[1:]
+
+
+@implements(torch.ops.aten.is_contiguous.default)
+def is_contiguous_impl(func, types, args, kwargs):
+    assert len(args) == 1
+    assert len(kwargs) == 0
+    return func(args[0].elems)
+
+
+@implements(
+    [
+        torch.ops.aten.clamp.default,
+        torch.ops.aten.clone.default,
+        torch.ops.aten.cos.default,
+        torch.ops.aten.div.Tensor,
+        torch.ops.aten.eq.Scalar,
+        torch.ops.aten.gelu.default,
+        torch.ops.aten.mul.Tensor,
+        torch.ops.aten.pow.Tensor_Scalar,
+        torch.ops.aten.relu.default,
+        torch.ops.aten.sigmoid.default,
+        torch.ops.aten.sin.default,
+        torch.ops.aten.sqrt.default,
+        torch.ops.aten.sub.Tensor,
+        torch.ops.aten.unbind.int,
+        torch.ops.aten.where.self,
+        torch.ops.aten.zeros_like.default,
+        torch.ops.aten._to_copy.default,
+        torch.ops.aten.gt.Scalar,
+        torch.ops.aten.ge.Scalar,
+        torch.ops.aten.bitwise_not.default,
+        torch.ops.aten.lt.Tensor,
+        torch.ops.aten.bitwise_or.Tensor,
+        torch.ops.aten.eq.Tensor,
+        torch.ops.aten.abs.default,
+        torch.ops.aten.ne.Scalar,
+        torch.ops.aten.le.Tensor,
+        torch.ops.aten.view_as_complex.default,
+        torch.ops.aten.view_as_real.default,
+        torch.ops.aten.neg.default,
+        torch.ops.aten.le.Scalar,
+        torch.ops.aten.rsub.Scalar,
+        # Sketchy new in place ops
+        torch.ops.aten.bitwise_and_.Tensor,
+        torch.ops.aten.bitwise_or_.Tensor,
+        torch.ops.aten.le.Tensor,
+        torch.ops.aten.logical_and.default,
+        # in place ops
+        torch.ops.aten.add_.Tensor,
+        torch.ops.aten.copy_.default,
+        # Prims
+        torch.ops.prim.layout.default,
+    ]
+)
+def forwardables_impl(func, types, args, kwargs):
+    unwrapped_args = tree_map(unwrap, args)
+    unwrapped_kwargs = tree_map(unwrap, kwargs)
+    return wrap(func(*unwrapped_args, **unwrapped_kwargs))
+
+
+def run_invariant_test(res, func, args, kwargs):
+    # Compares 0th element of list of results with
+    # func applied to 0th arg and kwarg.
+    # Rough test to maintain per-op accuracy.
+    if isinstance(res, torch.Tensor):
+        unwrapped_args_0 = tree_map(lambda x: unwrap_i(x, 0), args)
+        unwrapped_kwargs_0 = tree_map(lambda x: unwrap_i(x, 0), kwargs)
+        if func == torch.ops.aten.view.default:
+            res_0 = torch.ops.aten.reshape.default(
+                *unwrapped_args_0, **unwrapped_kwargs_0
+            )
+        else:
+            res_0 = func(*unwrapped_args_0, **unwrapped_kwargs_0)
+        # TODO: Extend this all elems not just elems[0]
+        if res.elems[0].size() != res_0.size():
+            import pdb
+
+            pdb.set_trace()
+        if not torch.allclose(res.elems[0], res_0, atol=1e-3, rtol=1e-3):
+            import pdb
+
+            pdb.set_trace()
+    else:
+        pass
+        # print("res got type: ", type(res))
+        # import pdb; pdb.set_trace()
+    return res
+
+
+class MapTensor(torch.Tensor):
+    @staticmethod
+    def __new__(cls, elems):
+        # print("elems.layout: ", elems.layout)
+        return torch.Tensor._make_wrapper_subclass(
+            cls,
+            elems.shape[1:],
+            dtype=elems.dtype,
+            device=elems.device,
+            layout=elems.layout,
+            dispatch_layout=True,
+            dispatch_sizes_strides_policy=(
+                "sizes" if elems.layout == torch.jagged else None
+            ),
+            storage_size=(
+                elems._values.untyped_storage().size()
+                if elems.layout == torch.jagged
+                else None
+            ),
+        )
+
+    def __init__(self, elems):
+        self.elems = elems
+
+    @classmethod
+    def __torch_dispatch__(cls, func, types, args, kwargs=None):
+        if func in MAP_TENSOR_ATEN_OP_TABLE:
+            res = MAP_TENSOR_ATEN_OP_TABLE[func](func, types, args, kwargs)
+            # run_invariant_test(res, func, args, kwargs)
+            return res
+        return NotImplemented
+
+    @classmethod
+    def __torch_function__(cls, func, types, args=(), kwargs=None):
+        if kwargs is None:
+            kwargs = {}
+        with torch._C.DisableTorchFunctionSubclass():
+            return func(*args, **kwargs)
+
+    # flatten/unflatten is needed for compile
+    def __tensor_flatten__(self):
+        ctx = {}
+        inner_tensors = ["elems"]
+        return inner_tensors, ctx
+
+    @staticmethod
+    def __tensor_unflatten__(inner_tensors: Dict, meta, outer_size, outer_stride):
+        # inner tensors: _values, _offsets, [_lengths], [_min_seqlen], [_max_seqlen]
+        assert len(inner_tensors) == 1, f"{inner_tensors}"
+        elems = inner_tensors["elems"]
+
+        return MapTensor(elems)
+
+    def __repr__(self):
+        return f"MapTensor({self.elems.size()})"
+
+    def pin_memory(self):
+        elems = self.elems.pin_memory()
+        return wrap(elems)
+
+
+# ts is a higher dim Tensor
+def to_map_tensor(ts: torch.Tensor):
+    return MapTensor(ts)
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/modeling/sam2_base.py b/lib/python3.12/site-packages/torchao/_models/sam2/modeling/sam2_base.py
new file mode 100644
index 0000000000000000000000000000000000000000..a16fe8dd616c227544577e9c2ebbc65d592d5af2
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/modeling/sam2_base.py
@@ -0,0 +1,929 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import torch
+import torch.distributed
+import torch.nn.functional as F
+from torch.nn.init import trunc_normal_
+
+from torchao._models.sam2.modeling.sam.mask_decoder import MaskDecoder
+from torchao._models.sam2.modeling.sam.prompt_encoder import PromptEncoder
+from torchao._models.sam2.modeling.sam.transformer import TwoWayTransformer
+from torchao._models.sam2.modeling.sam2_utils import (
+    MLP,
+    get_1d_sine_pe,
+    select_closest_cond_frames,
+)
+
+# a large negative value as a placeholder score for missing objects
+NO_OBJ_SCORE = -1024.0
+
+
+class SAM2Base(torch.nn.Module):
+    def __init__(
+        self,
+        image_encoder,
+        memory_attention,
+        memory_encoder,
+        num_maskmem=7,  # default 1 input frame + 6 previous frames
+        image_size=512,
+        backbone_stride=16,  # stride of the image backbone output
+        sigmoid_scale_for_mem_enc=1.0,  # scale factor for mask sigmoid prob
+        sigmoid_bias_for_mem_enc=0.0,  # bias factor for mask sigmoid prob
+        # During evaluation, whether to binarize the sigmoid mask logits on interacted frames with clicks
+        binarize_mask_from_pts_for_mem_enc=False,
+        use_mask_input_as_output_without_sam=False,  # on frames with mask input, whether to directly output the input mask without using a SAM prompt encoder + mask decoder
+        # The maximum number of conditioning frames to participate in the memory attention (-1 means no limit; if there are more conditioning frames than this limit,
+        # we only cross-attend to the temporally closest `max_cond_frames_in_attn` conditioning frames in the encoder when tracking each frame). This gives the model
+        # a temporal locality when handling a large number of annotated frames (since closer frames should be more important) and also avoids GPU OOM.
+        max_cond_frames_in_attn=-1,
+        # on the first frame, whether to directly add the no-memory embedding to the image feature
+        # (instead of using the transformer encoder)
+        directly_add_no_mem_embed=False,
+        # whether to use high-resolution feature maps in the SAM mask decoder
+        use_high_res_features_in_sam=False,
+        # whether to output multiple (3) masks for the first click on initial conditioning frames
+        multimask_output_in_sam=False,
+        # the minimum and maximum number of clicks to use multimask_output_in_sam (only relevant when `multimask_output_in_sam=True`;
+        # default is 1 for both, meaning that only the first click gives multimask output; also note that a box counts as two points)
+        multimask_min_pt_num=1,
+        multimask_max_pt_num=1,
+        # whether to also use multimask output for tracking (not just for the first click on initial conditioning frames; only relevant when `multimask_output_in_sam=True`)
+        multimask_output_for_tracking=False,
+        # Whether to use multimask tokens for obj ptr; Only relevant when both
+        # use_obj_ptrs_in_encoder=True and multimask_output_for_tracking=True
+        use_multimask_token_for_obj_ptr: bool = False,
+        # whether to use sigmoid to restrict ious prediction to [0-1]
+        iou_prediction_use_sigmoid=False,
+        # The memory bank's temporal stride during evaluation (i.e. the `r` parameter in XMem and Cutie; XMem and Cutie use r=5).
+        # For r>1, the (self.num_maskmem - 1) non-conditioning memory frames consist of
+        # (self.num_maskmem - 2) nearest frames from every r-th frames, plus the last frame.
+        memory_temporal_stride_for_eval=1,
+        # whether to apply non-overlapping constraints on the object masks in the memory encoder during evaluation (to avoid/alleviate superposing masks)
+        non_overlap_masks_for_mem_enc=False,
+        # whether to cross-attend to object pointers from other frames (based on SAM output tokens) in the encoder
+        use_obj_ptrs_in_encoder=False,
+        # the maximum number of object pointers from other frames in encoder cross attention (only relevant when `use_obj_ptrs_in_encoder=True`)
+        max_obj_ptrs_in_encoder=16,
+        # whether to add temporal positional encoding to the object pointers in the encoder (only relevant when `use_obj_ptrs_in_encoder=True`)
+        add_tpos_enc_to_obj_ptrs=True,
+        # whether to add an extra linear projection layer for the temporal positional encoding in the object pointers to avoid potential interference
+        # with spatial positional encoding (only relevant when both `use_obj_ptrs_in_encoder=True` and `add_tpos_enc_to_obj_ptrs=True`)
+        proj_tpos_enc_in_obj_ptrs=False,
+        # whether to use signed distance (instead of unsigned absolute distance) in the temporal positional encoding in the object pointers
+        # (only relevant when both `use_obj_ptrs_in_encoder=True` and `add_tpos_enc_to_obj_ptrs=True`)
+        use_signed_tpos_enc_to_obj_ptrs=False,
+        # whether to only attend to object pointers in the past (before the current frame) in the encoder during evaluation
+        # (only relevant when `use_obj_ptrs_in_encoder=True`; this might avoid pointer information too far in the future to distract the initial tracking)
+        only_obj_ptrs_in_the_past_for_eval=False,
+        # Whether to predict if there is an object in the frame
+        pred_obj_scores: bool = False,
+        # Whether to use an MLP to predict object scores
+        pred_obj_scores_mlp: bool = False,
+        # Only relevant if pred_obj_scores=True and use_obj_ptrs_in_encoder=True;
+        # Whether to have a fixed no obj pointer when there is no object present
+        # or to use it as an additive embedding with obj_ptr produced by decoder
+        fixed_no_obj_ptr: bool = False,
+        # Soft no object, i.e. mix in no_obj_ptr softly,
+        # hope to make recovery easier if there is a mistake and mitigate accumulation of errors
+        soft_no_obj_ptr: bool = False,
+        use_mlp_for_obj_ptr_proj: bool = False,
+        # add no obj embedding to spatial frames
+        no_obj_embed_spatial: bool = False,
+        # extra arguments used to construct the SAM mask decoder; if not None, it should be a dict of kwargs to be passed into `MaskDecoder` class.
+        sam_mask_decoder_extra_args=None,
+        compile_image_encoder: bool = False,
+    ):
+        super().__init__()
+
+        # Part 1: the image backbone
+        self.image_encoder = image_encoder
+        # Use level 0, 1, 2 for high-res setting, or just level 2 for the default setting
+        self.use_high_res_features_in_sam = use_high_res_features_in_sam
+        self.num_feature_levels = 3 if use_high_res_features_in_sam else 1
+        self.use_obj_ptrs_in_encoder = use_obj_ptrs_in_encoder
+        self.max_obj_ptrs_in_encoder = max_obj_ptrs_in_encoder
+        if use_obj_ptrs_in_encoder:
+            # A conv layer to downsample the mask prompt to stride 4 (the same stride as
+            # low-res SAM mask logits) and to change its scales from 0~1 to SAM logit scale,
+            # so that it can be fed into the SAM mask decoder to generate a pointer.
+            self.mask_downsample = torch.nn.Conv2d(1, 1, kernel_size=4, stride=4)
+        self.add_tpos_enc_to_obj_ptrs = add_tpos_enc_to_obj_ptrs
+        if proj_tpos_enc_in_obj_ptrs:
+            assert add_tpos_enc_to_obj_ptrs  # these options need to be used together
+        self.proj_tpos_enc_in_obj_ptrs = proj_tpos_enc_in_obj_ptrs
+        self.use_signed_tpos_enc_to_obj_ptrs = use_signed_tpos_enc_to_obj_ptrs
+        self.only_obj_ptrs_in_the_past_for_eval = only_obj_ptrs_in_the_past_for_eval
+
+        # Part 2: memory attention to condition current frame's visual features
+        # with memories (and obj ptrs) from past frames
+        self.memory_attention = memory_attention
+        self.hidden_dim = image_encoder.neck.d_model
+
+        # Part 3: memory encoder for the previous frame's outputs
+        self.memory_encoder = memory_encoder
+        self.mem_dim = self.hidden_dim
+        if hasattr(self.memory_encoder, "out_proj") and hasattr(
+            self.memory_encoder.out_proj, "weight"
+        ):
+            # if there is compression of memories along channel dim
+            self.mem_dim = self.memory_encoder.out_proj.weight.shape[0]
+        self.num_maskmem = num_maskmem  # Number of memories accessible
+        # Temporal encoding of the memories
+        self.maskmem_tpos_enc = torch.nn.Parameter(
+            torch.zeros(num_maskmem, 1, 1, self.mem_dim)
+        )
+        trunc_normal_(self.maskmem_tpos_enc, std=0.02)
+        # a single token to indicate no memory embedding from previous frames
+        self.no_mem_embed = torch.nn.Parameter(torch.zeros(1, 1, self.hidden_dim))
+        self.no_mem_pos_enc = torch.nn.Parameter(torch.zeros(1, 1, self.hidden_dim))
+        trunc_normal_(self.no_mem_embed, std=0.02)
+        trunc_normal_(self.no_mem_pos_enc, std=0.02)
+        self.directly_add_no_mem_embed = directly_add_no_mem_embed
+        # Apply sigmoid to the output raw mask logits (to turn them from
+        # range (-inf, +inf) to range (0, 1)) before feeding them into the memory encoder
+        self.sigmoid_scale_for_mem_enc = sigmoid_scale_for_mem_enc
+        self.sigmoid_bias_for_mem_enc = sigmoid_bias_for_mem_enc
+        self.binarize_mask_from_pts_for_mem_enc = binarize_mask_from_pts_for_mem_enc
+        self.non_overlap_masks_for_mem_enc = non_overlap_masks_for_mem_enc
+        self.memory_temporal_stride_for_eval = memory_temporal_stride_for_eval
+        # On frames with mask input, whether to directly output the input mask without
+        # using a SAM prompt encoder + mask decoder
+        self.use_mask_input_as_output_without_sam = use_mask_input_as_output_without_sam
+        self.multimask_output_in_sam = multimask_output_in_sam
+        self.multimask_min_pt_num = multimask_min_pt_num
+        self.multimask_max_pt_num = multimask_max_pt_num
+        self.multimask_output_for_tracking = multimask_output_for_tracking
+        self.use_multimask_token_for_obj_ptr = use_multimask_token_for_obj_ptr
+        self.iou_prediction_use_sigmoid = iou_prediction_use_sigmoid
+
+        # Part 4: SAM-style prompt encoder (for both mask and point inputs)
+        # and SAM-style mask decoder for the final mask output
+        self.image_size = image_size
+        self.backbone_stride = backbone_stride
+        self.sam_mask_decoder_extra_args = sam_mask_decoder_extra_args
+        self.pred_obj_scores = pred_obj_scores
+        self.pred_obj_scores_mlp = pred_obj_scores_mlp
+        self.fixed_no_obj_ptr = fixed_no_obj_ptr
+        self.soft_no_obj_ptr = soft_no_obj_ptr
+        if self.fixed_no_obj_ptr:
+            assert self.pred_obj_scores
+            assert self.use_obj_ptrs_in_encoder
+        if self.pred_obj_scores and self.use_obj_ptrs_in_encoder:
+            self.no_obj_ptr = torch.nn.Parameter(torch.zeros(1, self.hidden_dim))
+            trunc_normal_(self.no_obj_ptr, std=0.02)
+        self.use_mlp_for_obj_ptr_proj = use_mlp_for_obj_ptr_proj
+        self.no_obj_embed_spatial = None
+        if no_obj_embed_spatial:
+            self.no_obj_embed_spatial = torch.nn.Parameter(torch.zeros(1, self.mem_dim))
+            trunc_normal_(self.no_obj_embed_spatial, std=0.02)
+
+        self._build_sam_heads()
+        self.max_cond_frames_in_attn = max_cond_frames_in_attn
+
+        # Model compilation
+        if compile_image_encoder:
+            # Compile the forward function (not the full module) to allow loading checkpoints.
+            print(
+                "Image encoder compilation is enabled. First forward pass will be slow."
+            )
+            self.image_encoder.forward = torch.compile(
+                self.image_encoder.forward,
+                mode="max-autotune",
+                fullgraph=True,
+                dynamic=False,
+            )
+
+    @property
+    def device(self):
+        return next(self.parameters()).device
+
+    def forward(self, *args, **kwargs):
+        raise NotImplementedError(
+            "Please use the corresponding methods in SAM2VideoPredictor for inference or SAM2Train for training/fine-tuning"
+            "See notebooks/video_predictor_example.ipynb for an inference example."
+        )
+
+    def _build_sam_heads(self):
+        """Build SAM-style prompt encoder and mask decoder."""
+        self.sam_prompt_embed_dim = self.hidden_dim
+        self.sam_image_embedding_size = self.image_size // self.backbone_stride
+
+        # build PromptEncoder and MaskDecoder from SAM
+        # (their hyperparameters like `mask_in_chans=16` are from SAM code)
+        self.sam_prompt_encoder = PromptEncoder(
+            embed_dim=self.sam_prompt_embed_dim,
+            image_embedding_size=(
+                self.sam_image_embedding_size,
+                self.sam_image_embedding_size,
+            ),
+            input_image_size=(self.image_size, self.image_size),
+            mask_in_chans=16,
+        )
+        self.sam_mask_decoder = MaskDecoder(
+            num_multimask_outputs=3,
+            transformer=TwoWayTransformer(
+                depth=2,
+                embedding_dim=self.sam_prompt_embed_dim,
+                mlp_dim=2048,
+                num_heads=8,
+            ),
+            transformer_dim=self.sam_prompt_embed_dim,
+            iou_head_depth=3,
+            iou_head_hidden_dim=256,
+            use_high_res_features=self.use_high_res_features_in_sam,
+            iou_prediction_use_sigmoid=self.iou_prediction_use_sigmoid,
+            pred_obj_scores=self.pred_obj_scores,
+            pred_obj_scores_mlp=self.pred_obj_scores_mlp,
+            use_multimask_token_for_obj_ptr=self.use_multimask_token_for_obj_ptr,
+            **(self.sam_mask_decoder_extra_args or {}),
+        )
+        if self.use_obj_ptrs_in_encoder:
+            # a linear projection on SAM output tokens to turn them into object pointers
+            self.obj_ptr_proj = torch.nn.Linear(self.hidden_dim, self.hidden_dim)
+            if self.use_mlp_for_obj_ptr_proj:
+                self.obj_ptr_proj = MLP(
+                    self.hidden_dim, self.hidden_dim, self.hidden_dim, 3
+                )
+        else:
+            self.obj_ptr_proj = torch.nn.Identity()
+        if self.proj_tpos_enc_in_obj_ptrs:
+            # a linear projection on temporal positional encoding in object pointers to
+            # avoid potential interference with spatial positional encoding
+            self.obj_ptr_tpos_proj = torch.nn.Linear(self.hidden_dim, self.mem_dim)
+        else:
+            self.obj_ptr_tpos_proj = torch.nn.Identity()
+
+    def _forward_sam_heads(
+        self,
+        backbone_features,
+        point_inputs=None,
+        mask_inputs=None,
+        high_res_features=None,
+        multimask_output=False,
+    ):
+        """
+        Forward SAM prompt encoders and mask heads.
+
+        Inputs:
+        - backbone_features: image features of [B, C, H, W] shape
+        - point_inputs: a dictionary with "point_coords" and "point_labels", where
+          1) "point_coords" has [B, P, 2] shape and float32 dtype and contains the
+             absolute pixel-unit coordinate in (x, y) format of the P input points
+          2) "point_labels" has shape [B, P] and int32 dtype, where 1 means
+             positive clicks, 0 means negative clicks, and -1 means padding
+        - mask_inputs: a mask of [B, 1, H*16, W*16] shape, float or bool, with the
+          same spatial size as the image.
+        - high_res_features: either 1) None or 2) or a list of length 2 containing
+          two feature maps of [B, C, 4*H, 4*W] and [B, C, 2*H, 2*W] shapes respectively,
+          which will be used as high-resolution feature maps for SAM decoder.
+        - multimask_output: if it's True, we output 3 candidate masks and their 3
+          corresponding IoU estimates, and if it's False, we output only 1 mask and
+          its corresponding IoU estimate.
+
+        Outputs:
+        - low_res_multimasks: [B, M, H*4, W*4] shape (where M = 3 if
+          `multimask_output=True` and M = 1 if `multimask_output=False`), the SAM
+          output mask logits (before sigmoid) for the low-resolution masks, with 4x
+          the resolution (1/4 stride) of the input backbone_features.
+        - high_res_multimasks: [B, M, H*16, W*16] shape (where M = 3
+          if `multimask_output=True` and M = 1 if `multimask_output=False`),
+          upsampled from the low-resolution masks, with shape size as the image
+          (stride is 1 pixel).
+        - ious, [B, M] shape, where (where M = 3 if `multimask_output=True` and M = 1
+          if `multimask_output=False`), the estimated IoU of each output mask.
+        - low_res_masks: [B, 1, H*4, W*4] shape, the best mask in `low_res_multimasks`.
+          If `multimask_output=True`, it's the mask with the highest IoU estimate.
+          If `multimask_output=False`, it's the same as `low_res_multimasks`.
+        - high_res_masks: [B, 1, H*16, W*16] shape, the best mask in `high_res_multimasks`.
+          If `multimask_output=True`, it's the mask with the highest IoU estimate.
+          If `multimask_output=False`, it's the same as `high_res_multimasks`.
+        - obj_ptr: [B, C] shape, the object pointer vector for the output mask, extracted
+          based on the output token from the SAM mask decoder.
+        """
+        B = backbone_features.size(0)
+        device = backbone_features.device
+        assert backbone_features.size(1) == self.sam_prompt_embed_dim
+        assert backbone_features.size(2) == self.sam_image_embedding_size
+        assert backbone_features.size(3) == self.sam_image_embedding_size
+
+        # a) Handle point prompts
+        if point_inputs is not None:
+            sam_point_coords = point_inputs["point_coords"]
+            sam_point_labels = point_inputs["point_labels"]
+            assert sam_point_coords.size(0) == B and sam_point_labels.size(0) == B
+        else:
+            # If no points are provide, pad with an empty point (with label -1)
+            sam_point_coords = torch.zeros(B, 1, 2, device=device)
+            sam_point_labels = -torch.ones(B, 1, dtype=torch.int32, device=device)
+
+        # b) Handle mask prompts
+        if mask_inputs is not None:
+            # If mask_inputs is provided, downsize it into low-res mask input if needed
+            # and feed it as a dense mask prompt into the SAM mask encoder
+            assert len(mask_inputs.shape) == 4 and mask_inputs.shape[:2] == (B, 1)
+            if mask_inputs.shape[-2:] != self.sam_prompt_encoder.mask_input_size:
+                sam_mask_prompt = F.interpolate(
+                    mask_inputs.float(),
+                    size=self.sam_prompt_encoder.mask_input_size,
+                    align_corners=False,
+                    mode="bilinear",
+                    antialias=True,  # use antialias for downsampling
+                )
+            else:
+                sam_mask_prompt = mask_inputs
+        else:
+            # Otherwise, simply feed None (and SAM's prompt encoder will add
+            # a learned `no_mask_embed` to indicate no mask input in this case).
+            sam_mask_prompt = None
+
+        sparse_embeddings, dense_embeddings = self.sam_prompt_encoder(
+            points=(sam_point_coords, sam_point_labels),
+            boxes=None,
+            masks=sam_mask_prompt,
+        )
+        (
+            low_res_multimasks,
+            ious,
+            sam_output_tokens,
+            object_score_logits,
+        ) = self.sam_mask_decoder(
+            image_embeddings=backbone_features,
+            image_pe=self.sam_prompt_encoder.get_dense_pe(),
+            sparse_prompt_embeddings=sparse_embeddings,
+            dense_prompt_embeddings=dense_embeddings,
+            multimask_output=multimask_output,
+            repeat_image=False,  # the image is already batched
+            high_res_features=high_res_features,
+        )
+        if self.pred_obj_scores:
+            is_obj_appearing = object_score_logits > 0
+
+            # Mask used for spatial memories is always a *hard* choice between obj and no obj,
+            # consistent with the actual mask prediction
+            low_res_multimasks = torch.where(
+                is_obj_appearing[:, None, None],
+                low_res_multimasks,
+                NO_OBJ_SCORE,
+            )
+
+        # convert masks from possibly bfloat16 (or float16) to float32
+        # (older PyTorch versions before 2.1 don't support `interpolate` on bf16)
+        low_res_multimasks = low_res_multimasks.float()
+        high_res_multimasks = F.interpolate(
+            low_res_multimasks,
+            size=(self.image_size, self.image_size),
+            mode="bilinear",
+            align_corners=False,
+        )
+
+        sam_output_token = sam_output_tokens[:, 0]
+        if multimask_output:
+            # take the best mask prediction (with the highest IoU estimation)
+            best_iou_inds = torch.argmax(ious, dim=-1)
+            batch_inds = torch.arange(B, device=device)
+            low_res_masks = low_res_multimasks[batch_inds, best_iou_inds].unsqueeze(1)
+            high_res_masks = high_res_multimasks[batch_inds, best_iou_inds].unsqueeze(1)
+            if sam_output_tokens.size(1) > 1:
+                sam_output_token = sam_output_tokens[batch_inds, best_iou_inds]
+        else:
+            low_res_masks, high_res_masks = low_res_multimasks, high_res_multimasks
+
+        # Extract object pointer from the SAM output token (with occlusion handling)
+        obj_ptr = self.obj_ptr_proj(sam_output_token)
+        if self.pred_obj_scores:
+            # Allow *soft* no obj ptr, unlike for masks
+            if self.soft_no_obj_ptr:
+                lambda_is_obj_appearing = object_score_logits.sigmoid()
+            else:
+                lambda_is_obj_appearing = is_obj_appearing.float()
+
+            if self.fixed_no_obj_ptr:
+                obj_ptr = lambda_is_obj_appearing * obj_ptr
+            obj_ptr = obj_ptr + (1 - lambda_is_obj_appearing) * self.no_obj_ptr
+
+        return (
+            low_res_multimasks,
+            high_res_multimasks,
+            ious,
+            low_res_masks,
+            high_res_masks,
+            obj_ptr,
+            object_score_logits,
+        )
+
+    def _use_mask_as_output(self, backbone_features, high_res_features, mask_inputs):
+        """
+        Directly turn binary `mask_inputs` into a output mask logits without using SAM.
+        (same input and output shapes as in _forward_sam_heads above).
+        """
+        # Use -10/+10 as logits for neg/pos pixels (very close to 0/1 in prob after sigmoid).
+        out_scale, out_bias = 20.0, -10.0  # sigmoid(-10.0)=4.5398e-05
+        mask_inputs_float = mask_inputs.float()
+        high_res_masks = mask_inputs_float * out_scale + out_bias
+        low_res_masks = F.interpolate(
+            high_res_masks,
+            size=(high_res_masks.size(-2) // 4, high_res_masks.size(-1) // 4),
+            align_corners=False,
+            mode="bilinear",
+            antialias=True,  # use antialias for downsampling
+        )
+        # a dummy IoU prediction of all 1's under mask input
+        ious = mask_inputs.new_ones(mask_inputs.size(0), 1).float()
+        if not self.use_obj_ptrs_in_encoder:
+            # all zeros as a dummy object pointer (of shape [B, C])
+            obj_ptr = torch.zeros(
+                mask_inputs.size(0), self.hidden_dim, device=mask_inputs.device
+            )
+        else:
+            # produce an object pointer using the SAM decoder from the mask input
+            _, _, _, _, _, obj_ptr, _ = self._forward_sam_heads(
+                backbone_features=backbone_features,
+                mask_inputs=self.mask_downsample(mask_inputs_float),
+                high_res_features=high_res_features,
+            )
+        # In this method, we are treating mask_input as output, e.g. using it directly to create spatial mem;
+        # Below, we follow the same design axiom to use mask_input to decide if obj appears or not instead of relying
+        # on the object_scores from the SAM decoder.
+        is_obj_appearing = torch.any(mask_inputs.flatten(1).float() > 0.0, dim=1)
+        is_obj_appearing = is_obj_appearing[..., None]
+        lambda_is_obj_appearing = is_obj_appearing.float()
+        object_score_logits = out_scale * lambda_is_obj_appearing + out_bias
+        if self.pred_obj_scores:
+            if self.fixed_no_obj_ptr:
+                obj_ptr = lambda_is_obj_appearing * obj_ptr
+            obj_ptr = obj_ptr + (1 - lambda_is_obj_appearing) * self.no_obj_ptr
+
+        return (
+            low_res_masks,
+            high_res_masks,
+            ious,
+            low_res_masks,
+            high_res_masks,
+            obj_ptr,
+            object_score_logits,
+        )
+
+    def forward_image(self, img_batch: torch.Tensor):
+        """Get the image feature on the input batch."""
+        backbone_out = self.image_encoder(img_batch)
+        if self.use_high_res_features_in_sam:
+            # precompute projected level 0 and level 1 features in SAM decoder
+            # to avoid running it again on every SAM click
+            # NOTE: These are 1x1 convolutions
+            backbone_out["backbone_fpn"][0] = self.sam_mask_decoder.conv_s0(
+                backbone_out["backbone_fpn"][0]
+            )
+            backbone_out["backbone_fpn"][1] = self.sam_mask_decoder.conv_s1(
+                backbone_out["backbone_fpn"][1]
+            )
+        return backbone_out
+
+    def _prepare_backbone_features(self, backbone_out):
+        """Prepare and flatten visual features."""
+        backbone_out = backbone_out.copy()
+        assert len(backbone_out["backbone_fpn"]) == len(backbone_out["vision_pos_enc"])
+        assert len(backbone_out["backbone_fpn"]) >= self.num_feature_levels
+
+        feature_maps = backbone_out["backbone_fpn"][-self.num_feature_levels :]
+        vision_pos_embeds = backbone_out["vision_pos_enc"][-self.num_feature_levels :]
+
+        feat_sizes = [(x.shape[-2], x.shape[-1]) for x in vision_pos_embeds]
+        # flatten NxCxHxW to HWxNxC
+        vision_feats = [x.flatten(2).permute(2, 0, 1) for x in feature_maps]
+        vision_pos_embeds = [x.flatten(2).permute(2, 0, 1) for x in vision_pos_embeds]
+
+        return backbone_out, vision_feats, vision_pos_embeds, feat_sizes
+
+    def _prepare_memory_conditioned_features(
+        self,
+        frame_idx,
+        is_init_cond_frame,
+        current_vision_feats,
+        current_vision_pos_embeds,
+        feat_sizes,
+        output_dict,
+        num_frames,
+        track_in_reverse=False,  # tracking in reverse time order (for demo usage)
+    ):
+        """Fuse the current frame's visual feature map with previous memory."""
+        B = current_vision_feats[-1].size(1)  # batch size on this frame
+        C = self.hidden_dim
+        H, W = feat_sizes[-1]  # top-level (lowest-resolution) feature size
+        device = current_vision_feats[-1].device
+        # The case of `self.num_maskmem == 0` below is primarily used for reproducing SAM on images.
+        # In this case, we skip the fusion with any memory.
+        if self.num_maskmem == 0:  # Disable memory and skip fusion
+            pix_feat = current_vision_feats[-1].permute(1, 2, 0).view(B, C, H, W)
+            return pix_feat
+
+        num_obj_ptr_tokens = 0
+        tpos_sign_mul = -1 if track_in_reverse else 1
+        # Step 1: condition the visual features of the current frame on previous memories
+        if not is_init_cond_frame:
+            # Retrieve the memories encoded with the maskmem backbone
+            to_cat_memory, to_cat_memory_pos_embed = [], []
+            # Add conditioning frames's output first (all cond frames have t_pos=0 for
+            # when getting temporal positional embedding below)
+            assert len(output_dict["cond_frame_outputs"]) > 0
+            # Select a maximum number of temporally closest cond frames for cross attention
+            cond_outputs = output_dict["cond_frame_outputs"]
+            selected_cond_outputs, unselected_cond_outputs = select_closest_cond_frames(
+                frame_idx, cond_outputs, self.max_cond_frames_in_attn
+            )
+            t_pos_and_prevs = [(0, out) for out in selected_cond_outputs.values()]
+            # Add last (self.num_maskmem - 1) frames before current frame for non-conditioning memory
+            # the earliest one has t_pos=1 and the latest one has t_pos=self.num_maskmem-1
+            # We also allow taking the memory frame non-consecutively (with stride>1), in which case
+            # we take (self.num_maskmem - 2) frames among every stride-th frames plus the last frame.
+            stride = 1 if self.training else self.memory_temporal_stride_for_eval
+            for t_pos in range(1, self.num_maskmem):
+                t_rel = self.num_maskmem - t_pos  # how many frames before current frame
+                if t_rel == 1:
+                    # for t_rel == 1, we take the last frame (regardless of r)
+                    if not track_in_reverse:
+                        # the frame immediately before this frame (i.e. frame_idx - 1)
+                        prev_frame_idx = frame_idx - t_rel
+                    else:
+                        # the frame immediately after this frame (i.e. frame_idx + 1)
+                        prev_frame_idx = frame_idx + t_rel
+                else:
+                    # for t_rel >= 2, we take the memory frame from every r-th frames
+                    if not track_in_reverse:
+                        # first find the nearest frame among every r-th frames before this frame
+                        # for r=1, this would be (frame_idx - 2)
+                        prev_frame_idx = ((frame_idx - 2) // stride) * stride
+                        # then seek further among every r-th frames
+                        prev_frame_idx = prev_frame_idx - (t_rel - 2) * stride
+                    else:
+                        # first find the nearest frame among every r-th frames after this frame
+                        # for r=1, this would be (frame_idx + 2)
+                        prev_frame_idx = -(-(frame_idx + 2) // stride) * stride
+                        # then seek further among every r-th frames
+                        prev_frame_idx = prev_frame_idx + (t_rel - 2) * stride
+                out = output_dict["non_cond_frame_outputs"].get(prev_frame_idx, None)
+                if out is None:
+                    # If an unselected conditioning frame is among the last (self.num_maskmem - 1)
+                    # frames, we still attend to it as if it's a non-conditioning frame.
+                    out = unselected_cond_outputs.get(prev_frame_idx, None)
+                t_pos_and_prevs.append((t_pos, out))
+
+            for t_pos, prev in t_pos_and_prevs:
+                if prev is None:
+                    continue  # skip padding frames
+                # "maskmem_features" might have been offloaded to CPU in demo use cases,
+                # so we load it back to GPU (it's a no-op if it's already on GPU).
+                feats = prev["maskmem_features"].to(device, non_blocking=True)
+                to_cat_memory.append(feats.flatten(2).permute(2, 0, 1))
+                # Spatial positional encoding (it might have been offloaded to CPU in eval)
+                maskmem_enc = prev["maskmem_pos_enc"][-1].to(device)
+                maskmem_enc = maskmem_enc.flatten(2).permute(2, 0, 1)
+                # Temporal positional encoding
+                maskmem_enc = (
+                    maskmem_enc + self.maskmem_tpos_enc[self.num_maskmem - t_pos - 1]
+                )
+                to_cat_memory_pos_embed.append(maskmem_enc)
+
+            # Construct the list of past object pointers
+            if self.use_obj_ptrs_in_encoder:
+                max_obj_ptrs_in_encoder = min(num_frames, self.max_obj_ptrs_in_encoder)
+                # First add those object pointers from selected conditioning frames
+                # (optionally, only include object pointers in the past during evaluation)
+                if not self.training and self.only_obj_ptrs_in_the_past_for_eval:
+                    ptr_cond_outputs = {
+                        t: out
+                        for t, out in selected_cond_outputs.items()
+                        if (t >= frame_idx if track_in_reverse else t <= frame_idx)
+                    }
+                else:
+                    ptr_cond_outputs = selected_cond_outputs
+                pos_and_ptrs = [
+                    # Temporal pos encoding contains how far away each pointer is from current frame
+                    (
+                        (
+                            (frame_idx - t) * tpos_sign_mul
+                            if self.use_signed_tpos_enc_to_obj_ptrs
+                            else abs(frame_idx - t)
+                        ),
+                        out["obj_ptr"],
+                    )
+                    for t, out in ptr_cond_outputs.items()
+                ]
+                # Add up to (max_obj_ptrs_in_encoder - 1) non-conditioning frames before current frame
+                for t_diff in range(1, max_obj_ptrs_in_encoder):
+                    t = frame_idx + t_diff if track_in_reverse else frame_idx - t_diff
+                    if t < 0 or (num_frames is not None and t >= num_frames):
+                        break
+                    out = output_dict["non_cond_frame_outputs"].get(
+                        t, unselected_cond_outputs.get(t, None)
+                    )
+                    if out is not None:
+                        pos_and_ptrs.append((t_diff, out["obj_ptr"]))
+                # If we have at least one object pointer, add them to the across attention
+                if len(pos_and_ptrs) > 0:
+                    pos_list, ptrs_list = zip(*pos_and_ptrs)
+                    # stack object pointers along dim=0 into [ptr_seq_len, B, C] shape
+                    obj_ptrs = torch.stack(ptrs_list, dim=0)
+                    # a temporal positional embedding based on how far each object pointer is from
+                    # the current frame (sine embedding normalized by the max pointer num).
+                    if self.add_tpos_enc_to_obj_ptrs:
+                        t_diff_max = max_obj_ptrs_in_encoder - 1
+                        tpos_dim = C if self.proj_tpos_enc_in_obj_ptrs else self.mem_dim
+                        obj_pos = (
+                            torch.tensor(pos_list)
+                            .pin_memory()
+                            .to(device=device, non_blocking=True)
+                        )
+                        obj_pos = get_1d_sine_pe(obj_pos / t_diff_max, dim=tpos_dim)
+                        obj_pos = self.obj_ptr_tpos_proj(obj_pos)
+                        obj_pos = obj_pos.unsqueeze(1).expand(-1, B, self.mem_dim)
+                    else:
+                        obj_pos = obj_ptrs.new_zeros(len(pos_list), B, self.mem_dim)
+                    if self.mem_dim < C:
+                        # split a pointer into (C // self.mem_dim) tokens for self.mem_dim < C
+                        obj_ptrs = obj_ptrs.reshape(
+                            -1, B, C // self.mem_dim, self.mem_dim
+                        )
+                        obj_ptrs = obj_ptrs.permute(0, 2, 1, 3).flatten(0, 1)
+                        obj_pos = obj_pos.repeat_interleave(C // self.mem_dim, dim=0)
+                    to_cat_memory.append(obj_ptrs)
+                    to_cat_memory_pos_embed.append(obj_pos)
+                    num_obj_ptr_tokens = obj_ptrs.shape[0]
+                else:
+                    num_obj_ptr_tokens = 0
+        else:
+            # for initial conditioning frames, encode them without using any previous memory
+            if self.directly_add_no_mem_embed:
+                # directly add no-mem embedding (instead of using the transformer encoder)
+                pix_feat_with_mem = current_vision_feats[-1] + self.no_mem_embed
+                pix_feat_with_mem = pix_feat_with_mem.permute(1, 2, 0).view(B, C, H, W)
+                return pix_feat_with_mem
+
+            # Use a dummy token on the first frame (to avoid empty memory input to tranformer encoder)
+            to_cat_memory = [self.no_mem_embed.expand(1, B, self.mem_dim)]
+            to_cat_memory_pos_embed = [self.no_mem_pos_enc.expand(1, B, self.mem_dim)]
+
+        # Step 2: Concatenate the memories and forward through the transformer encoder
+        memory = torch.cat(to_cat_memory, dim=0)
+        memory_pos_embed = torch.cat(to_cat_memory_pos_embed, dim=0)
+
+        current_vision_feats = [c.clone() for c in current_vision_feats]
+        current_vision_pos_embeds = [c.clone() for c in current_vision_pos_embeds]
+        memory = memory.clone()
+        memory_pos_embed = memory_pos_embed.clone()
+        pix_feat_with_mem = self.memory_attention(
+            curr=current_vision_feats,
+            curr_pos=current_vision_pos_embeds,
+            memory=memory,
+            memory_pos=memory_pos_embed,
+            num_obj_ptr_tokens=num_obj_ptr_tokens,
+        )
+        pix_feat_with_mem = pix_feat_with_mem.clone()
+        # reshape the output (HW)BC => BCHW
+        pix_feat_with_mem = pix_feat_with_mem.permute(1, 2, 0).view(B, C, H, W)
+        return pix_feat_with_mem
+
+    def _encode_new_memory(
+        self,
+        current_vision_feats,
+        feat_sizes,
+        pred_masks_high_res,
+        object_score_logits,
+        is_mask_from_pts,
+    ):
+        """Encode the current image and its prediction into a memory feature."""
+        B = current_vision_feats[-1].size(1)  # batch size on this frame
+        C = self.hidden_dim
+        H, W = feat_sizes[-1]  # top-level (lowest-resolution) feature size
+        # top-level feature, (HW)BC => BCHW
+        pix_feat = current_vision_feats[-1].permute(1, 2, 0).view(B, C, H, W)
+        if self.non_overlap_masks_for_mem_enc and not self.training:
+            # optionally, apply non-overlapping constraints to the masks (it's applied
+            # in the batch dimension and should only be used during eval, where all
+            # the objects come from the same video under batch size 1).
+            pred_masks_high_res = self._apply_non_overlapping_constraints(
+                pred_masks_high_res
+            )
+        # scale the raw mask logits with a temperature before applying sigmoid
+        binarize = self.binarize_mask_from_pts_for_mem_enc and is_mask_from_pts
+        if binarize and not self.training:
+            mask_for_mem = (pred_masks_high_res > 0).float()
+        else:
+            # apply sigmoid on the raw mask logits to turn them into range (0, 1)
+            mask_for_mem = torch.sigmoid(pred_masks_high_res)
+        # apply scale and bias terms to the sigmoid probabilities
+        if self.sigmoid_scale_for_mem_enc != 1.0:
+            mask_for_mem = mask_for_mem * self.sigmoid_scale_for_mem_enc
+        if self.sigmoid_bias_for_mem_enc != 0.0:
+            mask_for_mem = mask_for_mem + self.sigmoid_bias_for_mem_enc
+        maskmem_out = self.memory_encoder(
+            pix_feat,
+            mask_for_mem,
+            skip_mask_sigmoid=True,  # sigmoid already applied
+        )
+        maskmem_features = maskmem_out["vision_features"].clone()
+        maskmem_pos_enc = [m.clone() for m in maskmem_out["vision_pos_enc"]]
+        # add a no-object embedding to the spatial memory to indicate that the frame
+        # is predicted to be occluded (i.e. no object is appearing in the frame)
+        if self.no_obj_embed_spatial is not None:
+            is_obj_appearing = (object_score_logits > 0).float()
+            maskmem_features += (
+                1 - is_obj_appearing[..., None, None]
+            ) * self.no_obj_embed_spatial[..., None, None].expand(
+                *maskmem_features.shape
+            )
+
+        return maskmem_features, maskmem_pos_enc
+
+    def _track_step(
+        self,
+        frame_idx,
+        is_init_cond_frame,
+        current_vision_feats,
+        current_vision_pos_embeds,
+        feat_sizes,
+        point_inputs,
+        mask_inputs,
+        output_dict,
+        num_frames,
+        track_in_reverse,
+        prev_sam_mask_logits,
+    ):
+        current_out = {"point_inputs": point_inputs, "mask_inputs": mask_inputs}
+        # High-resolution feature maps for the SAM head, reshape (HW)BC => BCHW
+        if len(current_vision_feats) > 1:
+            high_res_features = [
+                x.permute(1, 2, 0).view(x.size(1), x.size(2), *s)
+                for x, s in zip(current_vision_feats[:-1], feat_sizes[:-1])
+            ]
+        else:
+            high_res_features = None
+        if mask_inputs is not None and self.use_mask_input_as_output_without_sam:
+            # When use_mask_input_as_output_without_sam=True, we directly output the mask input
+            # (see it as a GT mask) without using a SAM prompt encoder + mask decoder.
+            pix_feat = current_vision_feats[-1].permute(1, 2, 0)
+            pix_feat = pix_feat.view(-1, self.hidden_dim, *feat_sizes[-1])
+            sam_outputs = self._use_mask_as_output(
+                pix_feat, high_res_features, mask_inputs
+            )
+        else:
+            # fused the visual feature with previous memory features in the memory bank
+            pix_feat = self._prepare_memory_conditioned_features(
+                frame_idx=frame_idx,
+                is_init_cond_frame=is_init_cond_frame,
+                current_vision_feats=current_vision_feats[-1:],
+                current_vision_pos_embeds=current_vision_pos_embeds[-1:],
+                feat_sizes=feat_sizes[-1:],
+                output_dict=output_dict,
+                num_frames=num_frames,
+                track_in_reverse=track_in_reverse,
+            )
+            # apply SAM-style segmentation head
+            # here we might feed previously predicted low-res SAM mask logits into the SAM mask decoder,
+            # e.g. in demo where such logits come from earlier interaction instead of correction sampling
+            # (in this case, any `mask_inputs` shouldn't reach here as they are sent to _use_mask_as_output instead)
+            if prev_sam_mask_logits is not None:
+                assert point_inputs is not None and mask_inputs is None
+                mask_inputs = prev_sam_mask_logits
+            else:
+                assert mask_inputs is None
+            multimask_output = self._use_multimask(is_init_cond_frame, point_inputs)
+
+            assert multimask_output
+            if point_inputs is not None:
+                point_inputs = {k: point_inputs[k].contiguous() for k in point_inputs}
+            sam_outputs = self._forward_sam_heads(
+                backbone_features=pix_feat.contiguous(),
+                point_inputs=point_inputs,
+                mask_inputs=mask_inputs,
+                high_res_features=[h.contiguous() for h in high_res_features],
+                multimask_output=multimask_output,
+            )
+
+        return current_out, sam_outputs, high_res_features, pix_feat
+
+    def _encode_memory_in_output(
+        self,
+        current_vision_feats,
+        feat_sizes,
+        point_inputs,
+        run_mem_encoder,
+        high_res_masks,
+        object_score_logits,
+        current_out,
+    ):
+        if run_mem_encoder and self.num_maskmem > 0:
+            high_res_masks_for_mem_enc = high_res_masks
+            maskmem_features, maskmem_pos_enc = self._encode_new_memory(
+                current_vision_feats=current_vision_feats,
+                feat_sizes=feat_sizes,
+                pred_masks_high_res=high_res_masks_for_mem_enc,
+                object_score_logits=object_score_logits,
+                is_mask_from_pts=(point_inputs is not None),
+            )
+            current_out["maskmem_features"] = maskmem_features
+            current_out["maskmem_pos_enc"] = maskmem_pos_enc
+        else:
+            current_out["maskmem_features"] = None
+            current_out["maskmem_pos_enc"] = None
+
+    @torch.autograd.profiler.record_function("track_step")
+    def track_step(
+        self,
+        frame_idx,
+        is_init_cond_frame,
+        current_vision_feats,
+        current_vision_pos_embeds,
+        feat_sizes,
+        point_inputs,
+        mask_inputs,
+        output_dict,
+        num_frames,
+        track_in_reverse=False,  # tracking in reverse time order (for demo usage)
+        # Whether to run the memory encoder on the predicted masks. Sometimes we might want
+        # to skip the memory encoder with `run_mem_encoder=False`. For example,
+        # in demo we might call `track_step` multiple times for each user click,
+        # and only encode the memory when the user finalizes their clicks. And in ablation
+        # settings like SAM training on static images, we don't need the memory encoder.
+        run_mem_encoder=True,
+        # The previously predicted SAM mask logits (which can be fed together with new clicks in demo).
+        prev_sam_mask_logits=None,
+    ):
+        current_out, sam_outputs, _, _ = self._track_step(
+            frame_idx,
+            is_init_cond_frame,
+            current_vision_feats,
+            current_vision_pos_embeds,
+            feat_sizes,
+            point_inputs,
+            mask_inputs,
+            output_dict,
+            num_frames,
+            track_in_reverse,
+            prev_sam_mask_logits,
+        )
+
+        (
+            _,
+            _,
+            _,
+            low_res_masks,
+            high_res_masks,
+            obj_ptr,
+            object_score_logits,
+        ) = sam_outputs
+
+        current_out["pred_masks"] = low_res_masks.clone()
+        current_out["pred_masks_high_res"] = high_res_masks.clone()
+        current_out["obj_ptr"] = obj_ptr.clone()
+        if not self.training:
+            # Only add this in inference (to avoid unused param in activation checkpointing;
+            # it's mainly used in the demo to encode spatial memories w/ consolidated masks)
+            current_out["object_score_logits"] = object_score_logits.clone()
+
+        # Finally run the memory encoder on the predicted mask to encode
+        # it into a new memory feature (that can be used in future frames)
+        self._encode_memory_in_output(
+            current_vision_feats,
+            feat_sizes,
+            point_inputs,
+            run_mem_encoder,
+            high_res_masks,
+            object_score_logits.clone(),
+            current_out,
+        )
+
+        return current_out
+
+    def _use_multimask(self, is_init_cond_frame, point_inputs):
+        """Whether to use multimask output in the SAM head."""
+        num_pts = 0 if point_inputs is None else point_inputs["point_labels"].size(1)
+        multimask_output = (
+            self.multimask_output_in_sam
+            and (is_init_cond_frame or self.multimask_output_for_tracking)
+            and (self.multimask_min_pt_num <= num_pts <= self.multimask_max_pt_num)
+        )
+        return multimask_output
+
+    def _apply_non_overlapping_constraints(self, pred_masks):
+        """
+        Apply non-overlapping constraints to the object scores in pred_masks. Here we
+        keep only the highest scoring object at each spatial location in pred_masks.
+        """
+        batch_size = pred_masks.size(0)
+        if batch_size == 1:
+            return pred_masks
+
+        device = pred_masks.device
+        # "max_obj_inds": object index of the object with the highest score at each location
+        max_obj_inds = torch.argmax(pred_masks, dim=0, keepdim=True)
+        # "batch_obj_inds": object index of each object slice (along dim 0) in `pred_masks`
+        batch_obj_inds = torch.arange(batch_size, device=device)[:, None, None, None]
+        keep = max_obj_inds == batch_obj_inds
+        # suppress overlapping regions' scores below -10.0 so that the foreground regions
+        # don't overlap (here sigmoid(-10.0)=4.5398e-05)
+        pred_masks = torch.where(keep, pred_masks, torch.clamp(pred_masks, max=-10.0))
+        return pred_masks
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/sam2_image_predictor.py b/lib/python3.12/site-packages/torchao/_models/sam2/sam2_image_predictor.py
new file mode 100644
index 0000000000000000000000000000000000000000..189e26b25caad4c09862c0abf20773899a9c6502
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/sam2_image_predictor.py
@@ -0,0 +1,571 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import logging
+from typing import List, Optional, Tuple, Union
+
+import numpy as np
+import torch
+from PIL.Image import Image
+
+from torchao._models.sam2.modeling.sam2_base import SAM2Base
+from torchao._models.sam2.utils.misc import get_image_size
+from torchao._models.sam2.utils.transforms import SAM2Transforms
+
+
+class SAM2ImagePredictor(torch.nn.Module):
+    def __init__(
+        self,
+        sam_model: SAM2Base,
+        mask_threshold=0.0,
+        max_hole_area=0.0,
+        max_sprinkle_area=0.0,
+        **kwargs,
+    ) -> None:
+        """
+        Uses SAM-2 to calculate the image embedding for an image, and then
+        allow repeated, efficient mask prediction given prompts.
+
+        Arguments:
+          sam_model (Sam-2): The model to use for mask prediction.
+          mask_threshold (float): The threshold to use when converting mask logits
+            to binary masks. Masks are thresholded at 0 by default.
+          max_hole_area (int): If max_hole_area > 0, we fill small holes in up to
+            the maximum area of max_hole_area in low_res_masks.
+          max_sprinkle_area (int): If max_sprinkle_area > 0, we remove small sprinkles up to
+            the maximum area of max_sprinkle_area in low_res_masks.
+        """
+        super().__init__()
+        self.model = sam_model
+        self._transforms = SAM2Transforms(
+            resolution=self.model.image_size,
+            mask_threshold=mask_threshold,
+            max_hole_area=max_hole_area,
+            max_sprinkle_area=max_sprinkle_area,
+        )
+
+        # Predictor state
+        self._is_image_set = False
+        self._features = None
+        self._orig_hw = None
+        # Whether the predictor is set for single image or a batch of images
+        self._is_batch = False
+
+        # Predictor config
+        self.mask_threshold = mask_threshold
+
+        # Spatial dim for backbone feature maps
+        self._bb_feat_sizes = [
+            (256, 256),
+            (128, 128),
+            (64, 64),
+        ]
+
+        self._image_dtype = torch.float32
+        self._transforms_device = "cpu"
+
+    @classmethod
+    def from_pretrained(cls, model_id: str, **kwargs) -> "SAM2ImagePredictor":
+        """
+        Load a pretrained model from the Hugging Face hub.
+
+        Arguments:
+          model_id (str): The Hugging Face repository ID.
+          **kwargs: Additional arguments to pass to the model constructor.
+
+        Returns:
+          (SAM2ImagePredictor): The loaded model.
+        """
+        from sam2.build_sam import build_sam2_hf
+
+        sam_model = build_sam2_hf(model_id, **kwargs)
+        return cls(sam_model, **kwargs)
+
+    @torch.no_grad()
+    def set_image(
+        self,
+        image: Union[np.ndarray, Image, torch.Tensor],
+    ) -> None:
+        """
+        Calculates the image embeddings for the provided image, allowing
+        masks to be predicted with the 'predict' method.
+
+        Arguments:
+          image (np.ndarray or PIL Image): The input image to embed in RGB format. The image should be in HWC format if np.ndarray, or WHC format if PIL Image
+          with pixel values in [0, 255].
+          image_format (str): The color format of the image, in ['RGB', 'BGR'].
+        """
+        self.reset_predictor()
+        # Transform the image to the form expected by the model
+        self._orig_hw = [get_image_size(image)]
+
+        if isinstance(image, torch.Tensor):
+            # from torchvision.transforms.v2 import functional as F
+            # input_image = F.to_dtype(image, torch.float32, scale=True)
+            input_image = image
+        else:
+            input_image = self._transforms.to_tensor(image)
+
+        # NOTE: Doing these transforms on the GPU changes the numerics
+        input_image = input_image.to(device=self._transforms_device)
+        input_image = self._transforms.transforms(input_image)
+        input_image = input_image.to(device=self.device)
+        # input_image = self._transforms.transforms(input_image)
+        input_image = input_image[None, ...].to(dtype=self._image_dtype)
+
+        assert len(input_image.shape) == 4 and input_image.shape[1] == 3, (
+            f"input_image must be of size 1x3xHxW, got {input_image.shape}"
+        )
+        logging.info("Computing image embeddings for the provided image...")
+        with torch.autograd.profiler.record_function("forward_image"):
+            backbone_out = self.model.forward_image(input_image)
+        _, vision_feats, _, _ = self.model._prepare_backbone_features(backbone_out)
+        # Add no_mem_embed, which is added to the lowest rest feat. map during training on videos
+        if self.model.directly_add_no_mem_embed:
+            vision_feats[-1] = vision_feats[-1] + self.model.no_mem_embed
+
+        feats = [
+            feat.permute(1, 2, 0).view(1, -1, *feat_size)
+            for feat, feat_size in zip(vision_feats[::-1], self._bb_feat_sizes[::-1])
+        ][::-1]
+        self._features = {"image_embed": feats[-1], "high_res_feats": feats[:-1]}
+        self._is_image_set = True
+        logging.info("Image embeddings computed.")
+
+    @torch.no_grad()
+    def set_image_batch(
+        self,
+        image_list: List[Union[np.ndarray, torch.Tensor]],
+    ) -> None:
+        """
+        Calculates the image embeddings for the provided image batch, allowing
+        masks to be predicted with the 'predict_batch' method.
+
+        Arguments:
+          image_list (List[np.ndarray]): The input images to embed in RGB format. The image should be in HWC format if np.ndarray
+          with pixel values in [0, 255].
+        """
+        self.reset_predictor()
+        assert isinstance(image_list, list)
+        self._orig_hw = list(map(get_image_size, image_list))
+        with torch.autograd.profiler.record_function("forward_batch"):
+            # Transform the image to the form expected by the model
+            # img_batch = self._transforms.forward_batch(image_list)
+            image_list = [
+                self._transforms.to_tensor(img) if isinstance(img, np.ndarray) else img
+                for img in image_list
+            ]
+            image_list = [self._transforms.transforms(img) for img in image_list]
+            img_batch = torch.stack(image_list, dim=0)
+            img_batch = img_batch.to(self.device)
+            img_batch = img_batch.to(self._image_dtype)
+        batch_size = img_batch.shape[0]
+        assert len(img_batch.shape) == 4 and img_batch.shape[1] == 3, (
+            f"img_batch must be of size Bx3xHxW, got {img_batch.shape}"
+        )
+        logging.info("Computing image embeddings for the provided images...")
+        with torch.autograd.profiler.record_function("forward_image"):
+            backbone_out = self.model.forward_image(img_batch)
+        with torch.autograd.profiler.record_function("_prepare_backbone_features"):
+            _, vision_feats, _, _ = self.model._prepare_backbone_features(backbone_out)
+        # Add no_mem_embed, which is added to the lowest rest feat. map during training on videos
+        if self.model.directly_add_no_mem_embed:
+            vision_feats[-1] = vision_feats[-1] + self.model.no_mem_embed
+
+        feats = [
+            feat.permute(1, 2, 0).view(batch_size, -1, *feat_size)
+            for feat, feat_size in zip(vision_feats[::-1], self._bb_feat_sizes[::-1])
+        ][::-1]
+        self._features = {"image_embed": feats[-1], "high_res_feats": feats[:-1]}
+        self._is_image_set = True
+        self._is_batch = True
+        logging.info("Image embeddings computed.")
+
+    def predict_batch(
+        self,
+        point_coords_batch: List[np.ndarray] = None,
+        point_labels_batch: List[np.ndarray] = None,
+        box_batch: List[np.ndarray] = None,
+        mask_input_batch: List[np.ndarray] = None,
+        multimask_output: bool = True,
+        return_logits: bool = False,
+        normalize_coords=True,
+        return_type: str = "numpy",
+    ) -> Tuple[List[np.ndarray], List[np.ndarray], List[np.ndarray]]:
+        """This function is very similar to predict(...), however it is used for batched mode, when the model is expected to generate predictions on multiple images.
+        It returns a tuple of lists of masks, ious, and low_res_masks_logits.
+        """
+        if return_type not in ["numpy", "torch"]:
+            raise ValueError(
+                f"Expected return_type to be either numpy or torch, but got {return_type}"
+            )
+        assert self._is_batch, "This function should only be used when in batched mode"
+        if not self._is_image_set:
+            raise RuntimeError(
+                "An image must be set with .set_image_batch(...) before mask prediction."
+            )
+        num_images = len(self._features["image_embed"])
+        all_masks = []
+        all_ious = []
+        all_low_res_masks = []
+        for img_idx in range(num_images):
+            # Transform input prompts
+            point_coords = (
+                point_coords_batch[img_idx] if point_coords_batch is not None else None
+            )
+            point_labels = (
+                point_labels_batch[img_idx] if point_labels_batch is not None else None
+            )
+            box = box_batch[img_idx] if box_batch is not None else None
+            mask_input = (
+                mask_input_batch[img_idx] if mask_input_batch is not None else None
+            )
+            mask_input, unnorm_coords, labels, unnorm_box = self._prep_prompts(
+                point_coords,
+                point_labels,
+                box,
+                mask_input,
+                normalize_coords,
+                img_idx=img_idx,
+            )
+            masks, iou_predictions, low_res_masks = self._predict(
+                unnorm_coords,
+                labels,
+                unnorm_box,
+                mask_input,
+                multimask_output,
+                return_logits=return_logits,
+                img_idx=img_idx,
+            )
+            if return_type == "numpy":
+                masks = masks.squeeze(0).float().detach().cpu().numpy()
+                iou_predictions = (
+                    iou_predictions.squeeze(0).float().detach().cpu().numpy()
+                )
+                low_res_masks = low_res_masks.squeeze(0).float().detach().cpu().numpy()
+            # NOTE: Need these additional clones to prevent overwriting tensor output of CUDAGraph
+            all_masks.append(masks.clone())
+            all_ious.append(iou_predictions.clone())
+            all_low_res_masks.append(low_res_masks.clone())
+
+        return all_masks, all_ious, all_low_res_masks
+
+    def predict(
+        self,
+        point_coords: Optional[np.ndarray] = None,
+        point_labels: Optional[np.ndarray] = None,
+        box: Optional[np.ndarray] = None,
+        mask_input: Optional[np.ndarray] = None,
+        multimask_output: bool = True,
+        return_logits: bool = False,
+        normalize_coords=True,
+        return_type: str = "numpy",
+    ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
+        """
+        Predict masks for the given input prompts, using the currently set image.
+
+        Arguments:
+          point_coords (np.ndarray or None): A Nx2 array of point prompts to the
+            model. Each point is in (X,Y) in pixels.
+          point_labels (np.ndarray or None): A length N array of labels for the
+            point prompts. 1 indicates a foreground point and 0 indicates a
+            background point.
+          box (np.ndarray or None): A length 4 array given a box prompt to the
+            model, in XYXY format.
+          mask_input (np.ndarray): A low resolution mask input to the model, typically
+            coming from a previous prediction iteration. Has form 1xHxW, where
+            for SAM, H=W=256.
+          multimask_output (bool): If true, the model will return three masks.
+            For ambiguous input prompts (such as a single click), this will often
+            produce better masks than a single prediction. If only a single
+            mask is needed, the model's predicted quality score can be used
+            to select the best mask. For non-ambiguous prompts, such as multiple
+            input prompts, multimask_output=False can give better results.
+          return_logits (bool): If true, returns un-thresholded masks logits
+            instead of a binary mask.
+          normalize_coords (bool): If true, the point coordinates will be normalized to the range [0,1] and point_coords is expected to be wrt. image dimensions.
+
+        Returns:
+          (np.ndarray): The output masks in CxHxW format, where C is the
+            number of masks, and (H, W) is the original image size.
+          (np.ndarray): An array of length C containing the model's
+            predictions for the quality of each mask.
+          (np.ndarray): An array of shape CxHxW, where C is the number
+            of masks and H=W=256. These low resolution logits can be passed to
+            a subsequent iteration as mask input.
+        """
+        if return_type not in ["numpy", "torch"]:
+            raise ValueError(
+                f"Expected return_type to be either numpy or torch, but got {return_type}"
+            )
+        if not self._is_image_set:
+            raise RuntimeError(
+                "An image must be set with .set_image(...) before mask prediction."
+            )
+
+        # Transform input prompts
+
+        mask_input, unnorm_coords, labels, unnorm_box = self._prep_prompts(
+            point_coords, point_labels, box, mask_input, normalize_coords
+        )
+
+        masks, iou_predictions, low_res_masks = self._predict(
+            unnorm_coords,
+            labels,
+            unnorm_box,
+            mask_input,
+            multimask_output,
+            return_logits=return_logits,
+        )
+
+        if return_type == "torch":
+            return (
+                masks.squeeze(0),
+                iou_predictions.squeeze(0),
+                low_res_masks.squeeze(0),
+            )
+
+        masks_np = masks.squeeze(0).float().detach().cpu().numpy()
+        iou_predictions_np = iou_predictions.squeeze(0).float().detach().cpu().numpy()
+        low_res_masks_np = low_res_masks.squeeze(0).float().detach().cpu().numpy()
+        return masks_np, iou_predictions_np, low_res_masks_np
+
+    def _prep_prompts(
+        self, point_coords, point_labels, box, mask_logits, normalize_coords, img_idx=-1
+    ):
+        unnorm_coords, labels, unnorm_box, mask_input = None, None, None, None
+        if point_coords is not None:
+            assert point_labels is not None, (
+                "point_labels must be supplied if point_coords is supplied."
+            )
+            point_coords = (
+                torch.as_tensor(point_coords, dtype=torch.float)
+                .pin_memory()
+                .to(self.device, non_blocking=True)
+            )
+            unnorm_coords = self._transforms.transform_coords(
+                point_coords, normalize=normalize_coords, orig_hw=self._orig_hw[img_idx]
+            )
+            labels = (
+                torch.as_tensor(point_labels, dtype=torch.int)
+                .pin_memory()
+                .to(self.device, non_blocking=True)
+            )
+            if len(unnorm_coords.shape) == 2:
+                unnorm_coords, labels = unnorm_coords[None, ...], labels[None, ...]
+        if box is not None:
+            box = torch.as_tensor(box, dtype=torch.float, device=self.device)
+            unnorm_box = self._transforms.transform_boxes(
+                box, normalize=normalize_coords, orig_hw=self._orig_hw[img_idx]
+            )  # Bx2x2
+        if mask_logits is not None:
+            mask_input = torch.as_tensor(
+                mask_logits, dtype=torch.float, device=self.device
+            )
+            if len(mask_input.shape) == 3:
+                mask_input = mask_input[None, :, :, :]
+        return mask_input, unnorm_coords, labels, unnorm_box
+
+    @torch.no_grad()
+    def _predict(
+        self,
+        point_coords: Optional[torch.Tensor],
+        point_labels: Optional[torch.Tensor],
+        boxes: Optional[torch.Tensor] = None,
+        mask_input: Optional[torch.Tensor] = None,
+        multimask_output: bool = True,
+        return_logits: bool = False,
+        img_idx: int = -1,
+    ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
+        """
+        Predict masks for the given input prompts, using the currently set image.
+        Input prompts are batched torch tensors and are expected to already be
+        transformed to the input frame using SAM2Transforms.
+
+        Arguments:
+          point_coords (torch.Tensor or None): A BxNx2 array of point prompts to the
+            model. Each point is in (X,Y) in pixels.
+          point_labels (torch.Tensor or None): A BxN array of labels for the
+            point prompts. 1 indicates a foreground point and 0 indicates a
+            background point.
+          boxes (np.ndarray or None): A Bx4 array given a box prompt to the
+            model, in XYXY format.
+          mask_input (np.ndarray): A low resolution mask input to the model, typically
+            coming from a previous prediction iteration. Has form Bx1xHxW, where
+            for SAM, H=W=256. Masks returned by a previous iteration of the
+            predict method do not need further transformation.
+          multimask_output (bool): If true, the model will return three masks.
+            For ambiguous input prompts (such as a single click), this will often
+            produce better masks than a single prediction. If only a single
+            mask is needed, the model's predicted quality score can be used
+            to select the best mask. For non-ambiguous prompts, such as multiple
+            input prompts, multimask_output=False can give better results.
+          return_logits (bool): If true, returns un-thresholded masks logits
+            instead of a binary mask.
+
+        Returns:
+          (torch.Tensor): The output masks in BxCxHxW format, where C is the
+            number of masks, and (H, W) is the original image size.
+          (torch.Tensor): An array of shape BxC containing the model's
+            predictions for the quality of each mask.
+          (torch.Tensor): An array of shape BxCxHxW, where C is the number
+            of masks and H=W=256. These low res logits can be passed to
+            a subsequent iteration as mask input.
+        """
+        if not self._is_image_set:
+            raise RuntimeError(
+                "An image must be set with .set_image(...) before mask prediction."
+            )
+
+        with torch.autograd.profiler.record_function("_predict_masks"):
+            high_res_feats = self._features["high_res_feats"]
+            image_embed = self._features["image_embed"]
+            image_pe = self.model.sam_prompt_encoder.get_dense_pe().clone()
+            high_res_feats_input = [
+                feat_level[img_idx].unsqueeze(0).clone()
+                # for feat_level in self._features["high_res_feats"]
+                for feat_level in high_res_feats
+            ]
+            image_embed_input = image_embed[img_idx].unsqueeze(0).clone()
+            assert boxes is None
+            assert mask_input is None
+            assert multimask_output is True
+            low_res_masks, iou_predictions = self._predict_masks(
+                [t.contiguous() for t in high_res_feats_input],
+                image_embed_input.contiguous(),
+                image_pe.contiguous(),
+                point_coords.contiguous(),
+                point_labels.contiguous(),
+                boxes=boxes,
+                mask_input=mask_input,
+                multimask_output=multimask_output,
+            )
+            # img_idx=img_idx)
+        with torch.autograd.profiler.record_function("_predict_masks_postprocess"):
+            masks, low_res_masks = self._predict_masks_postprocess(
+                low_res_masks, img_idx, return_logits
+            )
+            return masks, iou_predictions, low_res_masks
+
+    def _predict_masks(
+        self,
+        high_res_feats_input,
+        image_embed,
+        image_pe,
+        point_coords,
+        point_labels,
+        boxes: Optional[torch.Tensor] = None,
+        mask_input: Optional[torch.Tensor] = None,
+        multimask_output: bool = True,
+    ):
+        # NOTE: img_idx causes unnecessary recompilations, because
+        # the int guard will fail otherwise.
+        #   img_idx: int = -1):
+        if point_coords is not None:
+            concat_points = (point_coords, point_labels)
+        else:
+            concat_points = None
+
+        # Embed prompts
+        if boxes is not None:
+            box_coords = boxes.reshape(-1, 2, 2)
+            box_labels = torch.tensor([[2, 3]], dtype=torch.int, device=boxes.device)
+            box_labels = box_labels.repeat(boxes.size(0), 1)
+            # we merge "boxes" and "points" into a single "concat_points" input (where
+            # boxes are added at the beginning) to sam_prompt_encoder
+            if concat_points is not None:
+                concat_coords = torch.cat([box_coords, concat_points[0]], dim=1)
+                concat_labels = torch.cat([box_labels, concat_points[1]], dim=1)
+                concat_points = (concat_coords, concat_labels)
+            else:
+                concat_points = (box_coords, box_labels)
+
+        with torch.autograd.profiler.record_function("self.model.sam_prompt_encoder"):
+            sparse_embeddings, dense_embeddings = self.model.sam_prompt_encoder(
+                points=concat_points,
+                boxes=None,
+                masks=mask_input,
+            )
+
+        # Predict masks
+        batched_mode = (
+            concat_points is not None and concat_points[0].shape[0] > 1
+        )  # multi object prediction
+        # high_res_features = [
+        #     feat_level[img_idx].unsqueeze(0).clone()
+        #     # for feat_level in self._features["high_res_feats"]
+        #     for feat_level in high_res_feats_input
+        # ]
+        high_res_features = high_res_feats_input
+        with torch.autograd.profiler.record_function("self.model.sam_mask_decoder"):
+            # if not multimask_output:
+            #     raise ValueError("Expected multimask_output.")
+            # if batched_mode:
+            #     raise ValueError("Did not expected repeat_image.")
+            low_res_masks, iou_predictions, _, _ = self.model.sam_mask_decoder(
+                # image_embeddings=self._features["image_embed"][img_idx].unsqueeze(0).clone(),
+                # image_embeddings=image_embed[img_idx].unsqueeze(0).clone(),
+                image_embeddings=image_embed,
+                # image_pe=self.model.sam_prompt_encoder.get_dense_pe().clone(),
+                image_pe=image_pe,
+                sparse_prompt_embeddings=sparse_embeddings.clone(),
+                dense_prompt_embeddings=dense_embeddings.clone(),
+                multimask_output=multimask_output,
+                repeat_image=batched_mode,
+                high_res_features=high_res_features,
+            )
+
+        return low_res_masks, iou_predictions
+
+    def _predict_masks_postprocess(
+        self, low_res_masks, img_idx, return_logits, channel_1=False
+    ):
+        # TODO: Might want to defer this until after data["iou_preds"] > self.pred_iou_thresh
+        with torch.autograd.profiler.record_function(
+            "self._transforms.postprocess_masks"
+        ):
+            # Upscale the masks to the original image resolution
+            if channel_1:
+                masks = self._transforms.postprocess_masks_1_channel(
+                    low_res_masks, self._orig_hw[img_idx], self._image_dtype
+                )
+            else:
+                masks = self._transforms.postprocess_masks(
+                    low_res_masks, self._orig_hw[img_idx], self._image_dtype
+                )
+        low_res_masks = torch.clamp(low_res_masks, -32.0, 32.0)
+        if not return_logits:
+            masks = masks > self.mask_threshold
+
+        return masks, low_res_masks
+
+    def get_image_embedding(self) -> torch.Tensor:
+        """
+        Returns the image embeddings for the currently set image, with
+        shape 1xCxHxW, where C is the embedding dimension and (H,W) are
+        the embedding spatial dimension of SAM (typically C=256, H=W=64).
+        """
+        if not self._is_image_set:
+            raise RuntimeError(
+                "An image must be set with .set_image(...) to generate an embedding."
+            )
+        assert self._features is not None, (
+            "Features must exist if an image has been set."
+        )
+        return self._features["image_embed"]
+
+    @property
+    def device(self) -> torch.device:
+        return self.model.device
+
+    def reset_predictor(self) -> None:
+        """
+        Resets the image embeddings and other state variables.
+        """
+        self._is_image_set = False
+        self._features = None
+        self._orig_hw = None
+        self._is_batch = False
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/sam2_video_predictor.py b/lib/python3.12/site-packages/torchao/_models/sam2/sam2_video_predictor.py
new file mode 100644
index 0000000000000000000000000000000000000000..53b0a11d7c7c3d9f2040af0f2debb5ce7ce17eda
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/sam2_video_predictor.py
@@ -0,0 +1,1192 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import warnings
+from collections import OrderedDict
+
+import torch
+from tqdm import tqdm
+
+from torchao._models.sam2.modeling.sam2_base import NO_OBJ_SCORE, SAM2Base
+from torchao._models.sam2.utils.misc import (
+    concat_points,
+    fill_holes_in_mask_scores,
+    load_video_frames,
+)
+
+
+class SAM2VideoPredictor(SAM2Base):
+    """The predictor class to handle user interactions and manage inference states."""
+
+    def __init__(
+        self,
+        fill_hole_area=0,
+        # whether to apply non-overlapping constraints on the output object masks
+        non_overlap_masks=False,
+        # whether to clear non-conditioning memory of the surrounding frames (which may contain outdated information) after adding correction clicks;
+        # note that this would only apply to *single-object tracking* unless `clear_non_cond_mem_for_multi_obj` is also set to True)
+        clear_non_cond_mem_around_input=False,
+        # whether to also clear non-conditioning memory of the surrounding frames (only effective when `clear_non_cond_mem_around_input` is True).
+        clear_non_cond_mem_for_multi_obj=False,
+        # if `add_all_frames_to_correct_as_cond` is True, we also append to the conditioning frame list any frame that receives a later correction click
+        # if `add_all_frames_to_correct_as_cond` is False, we conditioning frame list to only use those initial conditioning frames
+        add_all_frames_to_correct_as_cond=False,
+        **kwargs,
+    ):
+        super().__init__(**kwargs)
+        self.fill_hole_area = fill_hole_area
+        self.non_overlap_masks = non_overlap_masks
+        self.clear_non_cond_mem_around_input = clear_non_cond_mem_around_input
+        self.clear_non_cond_mem_for_multi_obj = clear_non_cond_mem_for_multi_obj
+        self.add_all_frames_to_correct_as_cond = add_all_frames_to_correct_as_cond
+
+    @staticmethod
+    def batch_inference_states(inference_states: list):
+        assert all(dict == type(state) for state in inference_states)
+        num_states = len(inference_states)
+        assert num_states > 0
+        import copy
+
+        batched_inference_state = copy.copy(inference_states[0])
+
+        from torchao._models.sam2.map_tensor import to_map_tensor
+
+        # NOTE: Making a build assumption only images differ
+        all_images = torch.stack([state["images"] for state in inference_states])
+        batched_inference_state["images"] = to_map_tensor(all_images)
+        return batched_inference_state
+
+    @torch.no_grad()
+    def init_state(
+        self,
+        video_path,
+        offload_video_to_cpu=False,
+        offload_state_to_cpu=False,
+        async_loading_frames=False,
+    ):
+        """Initialize an inference state."""
+        compute_device = self.device  # device of the model
+        images, video_height, video_width = load_video_frames(
+            video_path=video_path,
+            image_size=self.image_size,
+            offload_video_to_cpu=offload_video_to_cpu,
+            async_loading_frames=async_loading_frames,
+            compute_device=compute_device,
+        )
+        inference_state = {}
+        inference_state["images"] = images
+        inference_state["num_frames"] = len(images)
+        # whether to offload the video frames to CPU memory
+        # turning on this option saves the GPU memory with only a very small overhead
+        inference_state["offload_video_to_cpu"] = offload_video_to_cpu
+        # whether to offload the inference state to CPU memory
+        # turning on this option saves the GPU memory at the cost of a lower tracking fps
+        # (e.g. in a test case of 768x768 model, fps dropped from 27 to 24 when tracking one object
+        # and from 24 to 21 when tracking two objects)
+        inference_state["offload_state_to_cpu"] = offload_state_to_cpu
+        # the original video height and width, used for resizing final output scores
+        inference_state["video_height"] = video_height
+        inference_state["video_width"] = video_width
+        inference_state["device"] = compute_device
+        if offload_state_to_cpu:
+            inference_state["storage_device"] = torch.device("cpu")
+        else:
+            inference_state["storage_device"] = compute_device
+        # inputs on each frame
+        inference_state["point_inputs_per_obj"] = {}
+        inference_state["mask_inputs_per_obj"] = {}
+        # visual features on a small number of recently visited frames for quick interactions
+        inference_state["cached_features"] = {}
+        # values that don't change across frames (so we only need to hold one copy of them)
+        inference_state["constants"] = {}
+        # mapping between client-side object id and model-side object index
+        inference_state["obj_id_to_idx"] = OrderedDict()
+        inference_state["obj_idx_to_id"] = OrderedDict()
+        inference_state["obj_ids"] = []
+        # A storage to hold the model's tracking results and states on each frame
+        inference_state["output_dict"] = {
+            "cond_frame_outputs": {},  # dict containing {frame_idx: }
+            "non_cond_frame_outputs": {},  # dict containing {frame_idx: }
+        }
+        # Slice (view) of each object tracking results, sharing the same memory with "output_dict"
+        inference_state["output_dict_per_obj"] = {}
+        # A temporary storage to hold new outputs when user interact with a frame
+        # to add clicks or mask (it's merged into "output_dict" before propagation starts)
+        inference_state["temp_output_dict_per_obj"] = {}
+        # Frames that already holds consolidated outputs from click or mask inputs
+        # (we directly use their consolidated outputs during tracking)
+        inference_state["consolidated_frame_inds"] = {
+            "cond_frame_outputs": set(),  # set containing frame indices
+            "non_cond_frame_outputs": set(),  # set containing frame indices
+        }
+        # metadata for each tracking frame (e.g. which direction it's tracked)
+        inference_state["tracking_has_started"] = False
+        inference_state["frames_already_tracked"] = {}
+        # Warm up the visual backbone and cache the image feature on frame 0
+        self._get_image_feature(inference_state, frame_idx=0, batch_size=1)
+        return inference_state
+
+    @classmethod
+    def from_pretrained(cls, model_id: str, **kwargs) -> "SAM2VideoPredictor":
+        """
+        Load a pretrained model from the Hugging Face hub.
+
+        Arguments:
+          model_id (str): The Hugging Face repository ID.
+          **kwargs: Additional arguments to pass to the model constructor.
+
+        Returns:
+          (SAM2VideoPredictor): The loaded model.
+        """
+        from sam2.build_sam import build_sam2_video_predictor_hf
+
+        sam_model = build_sam2_video_predictor_hf(model_id, **kwargs)
+        return sam_model
+
+    def _obj_id_to_idx(self, inference_state, obj_id):
+        """Map client-side object id to model-side object index."""
+        obj_idx = inference_state["obj_id_to_idx"].get(obj_id, None)
+        if obj_idx is not None:
+            return obj_idx
+
+        # This is a new object id not sent to the server before. We only allow adding
+        # new objects *before* the tracking starts.
+        allow_new_object = not inference_state["tracking_has_started"]
+        if allow_new_object:
+            # get the next object slot
+            obj_idx = len(inference_state["obj_id_to_idx"])
+            inference_state["obj_id_to_idx"][obj_id] = obj_idx
+            inference_state["obj_idx_to_id"][obj_idx] = obj_id
+            inference_state["obj_ids"] = list(inference_state["obj_id_to_idx"])
+            # set up input and output structures for this object
+            inference_state["point_inputs_per_obj"][obj_idx] = {}
+            inference_state["mask_inputs_per_obj"][obj_idx] = {}
+            inference_state["output_dict_per_obj"][obj_idx] = {
+                "cond_frame_outputs": {},  # dict containing {frame_idx: }
+                "non_cond_frame_outputs": {},  # dict containing {frame_idx: }
+            }
+            inference_state["temp_output_dict_per_obj"][obj_idx] = {
+                "cond_frame_outputs": {},  # dict containing {frame_idx: }
+                "non_cond_frame_outputs": {},  # dict containing {frame_idx: }
+            }
+            return obj_idx
+        else:
+            raise RuntimeError(
+                f"Cannot add new object id {obj_id} after tracking starts. "
+                f"All existing object ids: {inference_state['obj_ids']}. "
+                f"Please call 'reset_state' to restart from scratch."
+            )
+
+    def _obj_idx_to_id(self, inference_state, obj_idx):
+        """Map model-side object index to client-side object id."""
+        return inference_state["obj_idx_to_id"][obj_idx]
+
+    def _get_obj_num(self, inference_state):
+        """Get the total number of unique object ids received so far in this session."""
+        return len(inference_state["obj_idx_to_id"])
+
+    @torch.no_grad()
+    def add_new_points_or_box(
+        self,
+        inference_state,
+        frame_idx,
+        obj_id,
+        points=None,
+        labels=None,
+        clear_old_points=True,
+        normalize_coords=True,
+        box=None,
+    ):
+        """Add new points to a frame."""
+        obj_idx = self._obj_id_to_idx(inference_state, obj_id)
+        point_inputs_per_frame = inference_state["point_inputs_per_obj"][obj_idx]
+        mask_inputs_per_frame = inference_state["mask_inputs_per_obj"][obj_idx]
+
+        if (points is not None) != (labels is not None):
+            raise ValueError("points and labels must be provided together")
+        if points is None and box is None:
+            raise ValueError("at least one of points or box must be provided as input")
+
+        if points is None:
+            points = torch.zeros(0, 2, dtype=torch.float32)
+        elif not isinstance(points, torch.Tensor):
+            points = torch.tensor(points, dtype=torch.float32)
+        if labels is None:
+            labels = torch.zeros(0, dtype=torch.int32)
+        elif not isinstance(labels, torch.Tensor):
+            labels = torch.tensor(labels, dtype=torch.int32)
+        if points.dim() == 2:
+            points = points.unsqueeze(0)  # add batch dimension
+        if labels.dim() == 1:
+            labels = labels.unsqueeze(0)  # add batch dimension
+
+        # If `box` is provided, we add it as the first two points with labels 2 and 3
+        # along with the user-provided points (consistent with how SAM 2 is trained).
+        if box is not None:
+            if not clear_old_points:
+                raise ValueError(
+                    "cannot add box without clearing old points, since "
+                    "box prompt must be provided before any point prompt "
+                    "(please use clear_old_points=True instead)"
+                )
+            if inference_state["tracking_has_started"]:
+                warnings.warn(
+                    "You are adding a box after tracking starts. SAM 2 may not always be "
+                    "able to incorporate a box prompt for *refinement*. If you intend to "
+                    "use box prompt as an *initial* input before tracking, please call "
+                    "'reset_state' on the inference state to restart from scratch.",
+                    category=UserWarning,
+                    stacklevel=2,
+                )
+            if not isinstance(box, torch.Tensor):
+                box = torch.tensor(box, dtype=torch.float32, device=points.device)
+            box_coords = box.reshape(1, 2, 2)
+            box_labels = torch.tensor([2, 3], dtype=torch.int32, device=labels.device)
+            box_labels = box_labels.reshape(1, 2)
+            points = torch.cat([box_coords, points], dim=1)
+            labels = torch.cat([box_labels, labels], dim=1)
+
+        if normalize_coords:
+            video_H = inference_state["video_height"]
+            video_W = inference_state["video_width"]
+            points = points / torch.tensor([video_W, video_H]).to(points.device)
+        # scale the (normalized) coordinates by the model's internal image size
+        points = points * self.image_size
+        points = points.to(inference_state["device"])
+        labels = labels.to(inference_state["device"])
+
+        if not clear_old_points:
+            point_inputs = point_inputs_per_frame.get(frame_idx, None)
+        else:
+            point_inputs = None
+        point_inputs = concat_points(point_inputs, points, labels)
+
+        point_inputs_per_frame[frame_idx] = point_inputs
+        mask_inputs_per_frame.pop(frame_idx, None)
+        # If this frame hasn't been tracked before, we treat it as an initial conditioning
+        # frame, meaning that the inputs points are to generate segments on this frame without
+        # using any memory from other frames, like in SAM. Otherwise (if it has been tracked),
+        # the input points will be used to correct the already tracked masks.
+        is_init_cond_frame = frame_idx not in inference_state["frames_already_tracked"]
+        # whether to track in reverse time order
+        if is_init_cond_frame:
+            reverse = False
+        else:
+            reverse = inference_state["frames_already_tracked"][frame_idx]["reverse"]
+        obj_output_dict = inference_state["output_dict_per_obj"][obj_idx]
+        obj_temp_output_dict = inference_state["temp_output_dict_per_obj"][obj_idx]
+        # Add a frame to conditioning output if it's an initial conditioning frame or
+        # if the model sees all frames receiving clicks/mask as conditioning frames.
+        is_cond = is_init_cond_frame or self.add_all_frames_to_correct_as_cond
+        storage_key = "cond_frame_outputs" if is_cond else "non_cond_frame_outputs"
+
+        # Get any previously predicted mask logits on this object and feed it along with
+        # the new clicks into the SAM mask decoder.
+        prev_sam_mask_logits = None
+        # lookup temporary output dict first, which contains the most recent output
+        # (if not found, then lookup conditioning and non-conditioning frame output)
+        prev_out = obj_temp_output_dict[storage_key].get(frame_idx)
+        if prev_out is None:
+            prev_out = obj_output_dict["cond_frame_outputs"].get(frame_idx)
+            if prev_out is None:
+                prev_out = obj_output_dict["non_cond_frame_outputs"].get(frame_idx)
+
+        if prev_out is not None and prev_out["pred_masks"] is not None:
+            device = inference_state["device"]
+            prev_sam_mask_logits = prev_out["pred_masks"].to(device, non_blocking=True)
+            # Clamp the scale of prev_sam_mask_logits to avoid rare numerical issues.
+            prev_sam_mask_logits = torch.clamp(prev_sam_mask_logits, -32.0, 32.0)
+        current_out, _ = self._run_single_frame_inference(
+            inference_state=inference_state,
+            output_dict=obj_output_dict,  # run on the slice of a single object
+            frame_idx=frame_idx,
+            batch_size=1,  # run on the slice of a single object
+            is_init_cond_frame=is_init_cond_frame,
+            point_inputs=point_inputs,
+            mask_inputs=None,
+            reverse=reverse,
+            # Skip the memory encoder when adding clicks or mask. We execute the memory encoder
+            # at the beginning of `propagate_in_video` (after user finalize their clicks). This
+            # allows us to enforce non-overlapping constraints on all objects before encoding
+            # them into memory.
+            run_mem_encoder=False,
+            prev_sam_mask_logits=prev_sam_mask_logits,
+        )
+        # Add the output to the output dict (to be used as future memory)
+        obj_temp_output_dict[storage_key][frame_idx] = current_out
+
+        # Resize the output mask to the original video resolution
+        obj_ids = inference_state["obj_ids"]
+        consolidated_out = self._consolidate_temp_output_across_obj(
+            inference_state,
+            frame_idx,
+            is_cond=is_cond,
+            run_mem_encoder=False,
+            consolidate_at_video_res=True,
+        )
+        _, video_res_masks = self._get_orig_video_res_output(
+            inference_state, consolidated_out["pred_masks_video_res"]
+        )
+        return frame_idx, obj_ids, video_res_masks
+
+    def add_new_points(self, *args, **kwargs):
+        """Deprecated method. Please use `add_new_points_or_box` instead."""
+        return self.add_new_points_or_box(*args, **kwargs)
+
+    @torch.no_grad()
+    def add_new_mask(
+        self,
+        inference_state,
+        frame_idx,
+        obj_id,
+        mask,
+    ):
+        """Add new mask to a frame."""
+        obj_idx = self._obj_id_to_idx(inference_state, obj_id)
+        point_inputs_per_frame = inference_state["point_inputs_per_obj"][obj_idx]
+        mask_inputs_per_frame = inference_state["mask_inputs_per_obj"][obj_idx]
+
+        if not isinstance(mask, torch.Tensor):
+            mask = torch.tensor(mask, dtype=torch.bool)
+        assert mask.dim() == 2
+        mask_H, mask_W = mask.shape
+        mask_inputs_orig = mask[None, None]  # add batch and channel dimension
+        mask_inputs_orig = mask_inputs_orig.float().to(inference_state["device"])
+
+        # resize the mask if it doesn't match the model's image size
+        if mask_H != self.image_size or mask_W != self.image_size:
+            mask_inputs = torch.nn.functional.interpolate(
+                mask_inputs_orig,
+                size=(self.image_size, self.image_size),
+                align_corners=False,
+                mode="bilinear",
+                antialias=True,  # use antialias for downsampling
+            )
+            mask_inputs = (mask_inputs >= 0.5).float()
+        else:
+            mask_inputs = mask_inputs_orig
+
+        mask_inputs_per_frame[frame_idx] = mask_inputs
+        point_inputs_per_frame.pop(frame_idx, None)
+        # If this frame hasn't been tracked before, we treat it as an initial conditioning
+        # frame, meaning that the inputs points are to generate segments on this frame without
+        # using any memory from other frames, like in SAM. Otherwise (if it has been tracked),
+        # the input points will be used to correct the already tracked masks.
+        is_init_cond_frame = frame_idx not in inference_state["frames_already_tracked"]
+        # whether to track in reverse time order
+        if is_init_cond_frame:
+            reverse = False
+        else:
+            reverse = inference_state["frames_already_tracked"][frame_idx]["reverse"]
+        obj_output_dict = inference_state["output_dict_per_obj"][obj_idx]
+        obj_temp_output_dict = inference_state["temp_output_dict_per_obj"][obj_idx]
+        # Add a frame to conditioning output if it's an initial conditioning frame or
+        # if the model sees all frames receiving clicks/mask as conditioning frames.
+        is_cond = is_init_cond_frame or self.add_all_frames_to_correct_as_cond
+        storage_key = "cond_frame_outputs" if is_cond else "non_cond_frame_outputs"
+
+        current_out, _ = self._run_single_frame_inference(
+            inference_state=inference_state,
+            output_dict=obj_output_dict,  # run on the slice of a single object
+            frame_idx=frame_idx,
+            batch_size=1,  # run on the slice of a single object
+            is_init_cond_frame=is_init_cond_frame,
+            point_inputs=None,
+            mask_inputs=mask_inputs,
+            reverse=reverse,
+            # Skip the memory encoder when adding clicks or mask. We execute the memory encoder
+            # at the beginning of `propagate_in_video` (after user finalize their clicks). This
+            # allows us to enforce non-overlapping constraints on all objects before encoding
+            # them into memory.
+            run_mem_encoder=False,
+        )
+        # Add the output to the output dict (to be used as future memory)
+        obj_temp_output_dict[storage_key][frame_idx] = current_out
+
+        # Resize the output mask to the original video resolution
+        obj_ids = inference_state["obj_ids"]
+        consolidated_out = self._consolidate_temp_output_across_obj(
+            inference_state,
+            frame_idx,
+            is_cond=is_cond,
+            run_mem_encoder=False,
+            consolidate_at_video_res=True,
+        )
+        _, video_res_masks = self._get_orig_video_res_output(
+            inference_state, consolidated_out["pred_masks_video_res"]
+        )
+        return frame_idx, obj_ids, video_res_masks
+
+    def _get_orig_video_res_output(self, inference_state, any_res_masks):
+        """
+        Resize the object scores to the original video resolution (video_res_masks)
+        and apply non-overlapping constraints for final output.
+        """
+        device = inference_state["device"]
+        video_H = inference_state["video_height"]
+        video_W = inference_state["video_width"]
+        any_res_masks = any_res_masks.to(device, non_blocking=True)
+        if any_res_masks.shape[-2:] == (video_H, video_W):
+            video_res_masks = any_res_masks
+        else:
+            video_res_masks = torch.nn.functional.interpolate(
+                any_res_masks,
+                size=(video_H, video_W),
+                mode="bilinear",
+                align_corners=False,
+            )
+        if self.non_overlap_masks:
+            video_res_masks = self._apply_non_overlapping_constraints(video_res_masks)
+        return any_res_masks, video_res_masks
+
+    def _consolidate_temp_output_across_obj(
+        self,
+        inference_state,
+        frame_idx,
+        is_cond,
+        run_mem_encoder,
+        consolidate_at_video_res=False,
+    ):
+        """
+        Consolidate the per-object temporary outputs in `temp_output_dict_per_obj` on
+        a frame into a single output for all objects, including
+        1) fill any missing objects either from `output_dict_per_obj` (if they exist in
+           `output_dict_per_obj` for this frame) or leave them as placeholder values
+           (if they don't exist in `output_dict_per_obj` for this frame);
+        2) if specified, rerun memory encoder after apply non-overlapping constraints
+           on the object scores.
+        """
+        batch_size = self._get_obj_num(inference_state)
+        storage_key = "cond_frame_outputs" if is_cond else "non_cond_frame_outputs"
+        # Optionally, we allow consolidating the temporary outputs at the original
+        # video resolution (to provide a better editing experience for mask prompts).
+        if consolidate_at_video_res:
+            assert not run_mem_encoder, "memory encoder cannot run at video resolution"
+            consolidated_H = inference_state["video_height"]
+            consolidated_W = inference_state["video_width"]
+            consolidated_mask_key = "pred_masks_video_res"
+        else:
+            consolidated_H = consolidated_W = self.image_size // 4
+            consolidated_mask_key = "pred_masks"
+
+        # Initialize `consolidated_out`. Its "maskmem_features" and "maskmem_pos_enc"
+        # will be added when rerunning the memory encoder after applying non-overlapping
+        # constraints to object scores. Its "pred_masks" are prefilled with a large
+        # negative value (NO_OBJ_SCORE) to represent missing objects.
+        consolidated_out = {
+            "maskmem_features": None,
+            "maskmem_pos_enc": None,
+            consolidated_mask_key: torch.full(
+                size=(batch_size, 1, consolidated_H, consolidated_W),
+                fill_value=NO_OBJ_SCORE,
+                dtype=torch.float32,
+                device=inference_state["storage_device"],
+            ),
+            "obj_ptr": torch.full(
+                size=(batch_size, self.hidden_dim),
+                fill_value=NO_OBJ_SCORE,
+                dtype=torch.float32,
+                device=inference_state["device"],
+            ),
+            "object_score_logits": torch.full(
+                size=(batch_size, 1),
+                # default to 10.0 for object_score_logits, i.e. assuming the object is
+                # present as sigmoid(10)=1, same as in `predict_masks` of `MaskDecoder`
+                fill_value=10.0,
+                dtype=torch.float32,
+                device=inference_state["device"],
+            ),
+        }
+        empty_mask_ptr = None
+        for obj_idx in range(batch_size):
+            obj_temp_output_dict = inference_state["temp_output_dict_per_obj"][obj_idx]
+            obj_output_dict = inference_state["output_dict_per_obj"][obj_idx]
+            out = obj_temp_output_dict[storage_key].get(frame_idx, None)
+            # If the object doesn't appear in "temp_output_dict_per_obj" on this frame,
+            # we fall back and look up its previous output in "output_dict_per_obj".
+            # We look up both "cond_frame_outputs" and "non_cond_frame_outputs" in
+            # "output_dict_per_obj" to find a previous output for this object.
+            if out is None:
+                out = obj_output_dict["cond_frame_outputs"].get(frame_idx, None)
+            if out is None:
+                out = obj_output_dict["non_cond_frame_outputs"].get(frame_idx, None)
+            # If the object doesn't appear in "output_dict_per_obj" either, we skip it
+            # and leave its mask scores to the default scores (i.e. the NO_OBJ_SCORE
+            # placeholder above) and set its object pointer to be a dummy pointer.
+            if out is None:
+                # Fill in dummy object pointers for those objects without any inputs or
+                # tracking outcomes on this frame (only do it under `run_mem_encoder=True`,
+                # i.e. when we need to build the memory for tracking).
+                if run_mem_encoder:
+                    if empty_mask_ptr is None:
+                        empty_mask_ptr = self._get_empty_mask_ptr(
+                            inference_state, frame_idx
+                        )
+                    # fill object pointer with a dummy pointer (based on an empty mask)
+                    consolidated_out["obj_ptr"][obj_idx : obj_idx + 1] = empty_mask_ptr
+                continue
+            # Add the temporary object output mask to consolidated output mask
+            obj_mask = out["pred_masks"]
+            consolidated_pred_masks = consolidated_out[consolidated_mask_key]
+            if obj_mask.shape[-2:] == consolidated_pred_masks.shape[-2:]:
+                consolidated_pred_masks[obj_idx : obj_idx + 1] = obj_mask
+            else:
+                # Resize first if temporary object mask has a different resolution
+                resized_obj_mask = torch.nn.functional.interpolate(
+                    obj_mask,
+                    size=consolidated_pred_masks.shape[-2:],
+                    mode="bilinear",
+                    align_corners=False,
+                )
+                consolidated_pred_masks[obj_idx : obj_idx + 1] = resized_obj_mask
+            consolidated_out["obj_ptr"][obj_idx : obj_idx + 1] = out["obj_ptr"]
+            consolidated_out["object_score_logits"][obj_idx : obj_idx + 1] = out[
+                "object_score_logits"
+            ]
+
+        # Optionally, apply non-overlapping constraints on the consolidated scores
+        # and rerun the memory encoder
+        if run_mem_encoder:
+            device = inference_state["device"]
+            high_res_masks = torch.nn.functional.interpolate(
+                consolidated_out["pred_masks"].to(device, non_blocking=True),
+                size=(self.image_size, self.image_size),
+                mode="bilinear",
+                align_corners=False,
+            )
+            if self.non_overlap_masks_for_mem_enc:
+                high_res_masks = self._apply_non_overlapping_constraints(high_res_masks)
+            maskmem_features, maskmem_pos_enc = self._run_memory_encoder(
+                inference_state=inference_state,
+                frame_idx=frame_idx,
+                batch_size=batch_size,
+                high_res_masks=high_res_masks,
+                object_score_logits=consolidated_out["object_score_logits"],
+                is_mask_from_pts=True,  # these frames are what the user interacted with
+            )
+            consolidated_out["maskmem_features"] = maskmem_features
+            consolidated_out["maskmem_pos_enc"] = maskmem_pos_enc
+
+        return consolidated_out
+
+    def _get_empty_mask_ptr(self, inference_state, frame_idx):
+        """Get a dummy object pointer based on an empty mask on the current frame."""
+        # A dummy (empty) mask with a single object
+        batch_size = 1
+        mask_inputs = torch.zeros(
+            (batch_size, 1, self.image_size, self.image_size),
+            dtype=torch.float32,
+            device=inference_state["device"],
+        )
+
+        # Retrieve correct image features
+        (
+            _,
+            _,
+            current_vision_feats,
+            current_vision_pos_embeds,
+            feat_sizes,
+        ) = self._get_image_feature(inference_state, frame_idx, batch_size)
+
+        # Feed the empty mask and image feature above to get a dummy object pointer
+        current_out = self.track_step(
+            frame_idx=frame_idx,
+            is_init_cond_frame=True,
+            current_vision_feats=current_vision_feats,
+            current_vision_pos_embeds=current_vision_pos_embeds,
+            feat_sizes=feat_sizes,
+            point_inputs=None,
+            mask_inputs=mask_inputs,
+            output_dict={},
+            num_frames=inference_state["num_frames"],
+            track_in_reverse=False,
+            run_mem_encoder=False,
+            prev_sam_mask_logits=None,
+        )
+        return current_out["obj_ptr"]
+
+    @torch.no_grad()
+    def propagate_in_video_preflight(self, inference_state):
+        """Prepare inference_state and consolidate temporary outputs before tracking."""
+        # Tracking has started and we don't allow adding new objects until session is reset.
+        inference_state["tracking_has_started"] = True
+        batch_size = self._get_obj_num(inference_state)
+
+        # Consolidate per-object temporary outputs in "temp_output_dict_per_obj" and
+        # add them into "output_dict".
+        temp_output_dict_per_obj = inference_state["temp_output_dict_per_obj"]
+        output_dict = inference_state["output_dict"]
+        # "consolidated_frame_inds" contains indices of those frames where consolidated
+        # temporary outputs have been added (either in this call or any previous calls
+        # to `propagate_in_video_preflight`).
+        consolidated_frame_inds = inference_state["consolidated_frame_inds"]
+        for is_cond in [False, True]:
+            # Separately consolidate conditioning and non-conditioning temp outputs
+            storage_key = "cond_frame_outputs" if is_cond else "non_cond_frame_outputs"
+            # Find all the frames that contain temporary outputs for any objects
+            # (these should be the frames that have just received clicks for mask inputs
+            # via `add_new_points_or_box` or `add_new_mask`)
+            temp_frame_inds = set()
+            for obj_temp_output_dict in temp_output_dict_per_obj.values():
+                temp_frame_inds.update(obj_temp_output_dict[storage_key].keys())
+            consolidated_frame_inds[storage_key].update(temp_frame_inds)
+            # consolidate the temporary output across all objects on this frame
+            for frame_idx in temp_frame_inds:
+                consolidated_out = self._consolidate_temp_output_across_obj(
+                    inference_state, frame_idx, is_cond=is_cond, run_mem_encoder=True
+                )
+                # merge them into "output_dict" and also create per-object slices
+                output_dict[storage_key][frame_idx] = consolidated_out
+                self._add_output_per_object(
+                    inference_state, frame_idx, consolidated_out, storage_key
+                )
+                clear_non_cond_mem = self.clear_non_cond_mem_around_input and (
+                    self.clear_non_cond_mem_for_multi_obj or batch_size <= 1
+                )
+                if clear_non_cond_mem:
+                    # clear non-conditioning memory of the surrounding frames
+                    self._clear_non_cond_mem_around_input(inference_state, frame_idx)
+
+            # clear temporary outputs in `temp_output_dict_per_obj`
+            for obj_temp_output_dict in temp_output_dict_per_obj.values():
+                obj_temp_output_dict[storage_key].clear()
+
+        # edge case: if an output is added to "cond_frame_outputs", we remove any prior
+        # output on the same frame in "non_cond_frame_outputs"
+        for frame_idx in output_dict["cond_frame_outputs"]:
+            output_dict["non_cond_frame_outputs"].pop(frame_idx, None)
+        for obj_output_dict in inference_state["output_dict_per_obj"].values():
+            for frame_idx in obj_output_dict["cond_frame_outputs"]:
+                obj_output_dict["non_cond_frame_outputs"].pop(frame_idx, None)
+        for frame_idx in consolidated_frame_inds["cond_frame_outputs"]:
+            assert frame_idx in output_dict["cond_frame_outputs"]
+            consolidated_frame_inds["non_cond_frame_outputs"].discard(frame_idx)
+
+        # Make sure that the frame indices in "consolidated_frame_inds" are exactly those frames
+        # with either points or mask inputs (which should be true under a correct workflow).
+        all_consolidated_frame_inds = (
+            consolidated_frame_inds["cond_frame_outputs"]
+            | consolidated_frame_inds["non_cond_frame_outputs"]
+        )
+        input_frames_inds = set()
+        for point_inputs_per_frame in inference_state["point_inputs_per_obj"].values():
+            input_frames_inds.update(point_inputs_per_frame.keys())
+        for mask_inputs_per_frame in inference_state["mask_inputs_per_obj"].values():
+            input_frames_inds.update(mask_inputs_per_frame.keys())
+        assert all_consolidated_frame_inds == input_frames_inds
+
+    @torch.no_grad()
+    def propagate_in_video(
+        self,
+        inference_state,
+        start_frame_idx=None,
+        max_frame_num_to_track=None,
+        reverse=False,
+    ):
+        """Propagate the input points across frames to track in the entire video."""
+        self.propagate_in_video_preflight(inference_state)
+
+        output_dict = inference_state["output_dict"]
+        consolidated_frame_inds = inference_state["consolidated_frame_inds"]
+        obj_ids = inference_state["obj_ids"]
+        num_frames = inference_state["num_frames"]
+        batch_size = self._get_obj_num(inference_state)
+        if len(output_dict["cond_frame_outputs"]) == 0:
+            raise RuntimeError("No points are provided; please add points first")
+        clear_non_cond_mem = self.clear_non_cond_mem_around_input and (
+            self.clear_non_cond_mem_for_multi_obj or batch_size <= 1
+        )
+
+        # set start index, end index, and processing order
+        if start_frame_idx is None:
+            # default: start from the earliest frame with input points
+            start_frame_idx = min(output_dict["cond_frame_outputs"])
+        if max_frame_num_to_track is None:
+            # default: track all the frames in the video
+            max_frame_num_to_track = num_frames
+        if reverse:
+            end_frame_idx = max(start_frame_idx - max_frame_num_to_track, 0)
+            if start_frame_idx > 0:
+                processing_order = range(start_frame_idx, end_frame_idx - 1, -1)
+            else:
+                processing_order = []  # skip reverse tracking if starting from frame 0
+        else:
+            end_frame_idx = min(
+                start_frame_idx + max_frame_num_to_track, num_frames - 1
+            )
+            processing_order = range(start_frame_idx, end_frame_idx + 1)
+
+        for frame_idx in tqdm(processing_order, desc="propagate in video"):
+            # We skip those frames already in consolidated outputs (these are frames
+            # that received input clicks or mask). Note that we cannot directly run
+            # batched forward on them via `_run_single_frame_inference` because the
+            # number of clicks on each object might be different.
+            if frame_idx in consolidated_frame_inds["cond_frame_outputs"]:
+                storage_key = "cond_frame_outputs"
+                current_out = output_dict[storage_key][frame_idx]
+                pred_masks = current_out["pred_masks"]
+                if clear_non_cond_mem:
+                    # clear non-conditioning memory of the surrounding frames
+                    self._clear_non_cond_mem_around_input(inference_state, frame_idx)
+            elif frame_idx in consolidated_frame_inds["non_cond_frame_outputs"]:
+                storage_key = "non_cond_frame_outputs"
+                current_out = output_dict[storage_key][frame_idx]
+                pred_masks = current_out["pred_masks"]
+            else:
+                storage_key = "non_cond_frame_outputs"
+                current_out, pred_masks = self._run_single_frame_inference(
+                    inference_state=inference_state,
+                    output_dict=output_dict,
+                    frame_idx=frame_idx,
+                    batch_size=batch_size,
+                    is_init_cond_frame=False,
+                    point_inputs=None,
+                    mask_inputs=None,
+                    reverse=reverse,
+                    run_mem_encoder=True,
+                )
+                output_dict[storage_key][frame_idx] = current_out
+            # Create slices of per-object outputs for subsequent interaction with each
+            # individual object after tracking.
+            self._add_output_per_object(
+                inference_state, frame_idx, current_out, storage_key
+            )
+            inference_state["frames_already_tracked"][frame_idx] = {"reverse": reverse}
+
+            # Resize the output mask to the original video resolution (we directly use
+            # the mask scores on GPU for output to avoid any CPU conversion in between)
+            _, video_res_masks = self._get_orig_video_res_output(
+                inference_state, pred_masks
+            )
+            yield frame_idx, obj_ids, video_res_masks
+
+    def _add_output_per_object(
+        self, inference_state, frame_idx, current_out, storage_key
+    ):
+        """
+        Split a multi-object output into per-object output slices and add them into
+        `output_dict_per_obj`. The resulting slices share the same tensor storage.
+        """
+        maskmem_features = current_out["maskmem_features"]
+        assert maskmem_features is None or isinstance(maskmem_features, torch.Tensor)
+
+        maskmem_pos_enc = current_out["maskmem_pos_enc"]
+        assert maskmem_pos_enc is None or isinstance(maskmem_pos_enc, list)
+
+        output_dict_per_obj = inference_state["output_dict_per_obj"]
+        for obj_idx, obj_output_dict in output_dict_per_obj.items():
+            obj_slice = slice(obj_idx, obj_idx + 1)
+            obj_out = {
+                "maskmem_features": None,
+                "maskmem_pos_enc": None,
+                "pred_masks": current_out["pred_masks"][obj_slice],
+                "obj_ptr": current_out["obj_ptr"][obj_slice],
+                "object_score_logits": current_out["object_score_logits"][obj_slice],
+            }
+            if maskmem_features is not None:
+                obj_out["maskmem_features"] = maskmem_features[obj_slice]
+            if maskmem_pos_enc is not None:
+                obj_out["maskmem_pos_enc"] = [x[obj_slice] for x in maskmem_pos_enc]
+            obj_output_dict[storage_key][frame_idx] = obj_out
+
+    @torch.no_grad()
+    def clear_all_prompts_in_frame(
+        self, inference_state, frame_idx, obj_id, need_output=True
+    ):
+        """Remove all input points or mask in a specific frame for a given object."""
+        obj_idx = self._obj_id_to_idx(inference_state, obj_id)
+
+        # Clear the conditioning information on the given frame
+        inference_state["point_inputs_per_obj"][obj_idx].pop(frame_idx, None)
+        inference_state["mask_inputs_per_obj"][obj_idx].pop(frame_idx, None)
+
+        temp_output_dict_per_obj = inference_state["temp_output_dict_per_obj"]
+        temp_output_dict_per_obj[obj_idx]["cond_frame_outputs"].pop(frame_idx, None)
+        temp_output_dict_per_obj[obj_idx]["non_cond_frame_outputs"].pop(frame_idx, None)
+
+        # Check and see if there are still any inputs left on this frame
+        batch_size = self._get_obj_num(inference_state)
+        frame_has_input = False
+        for obj_idx2 in range(batch_size):
+            if frame_idx in inference_state["point_inputs_per_obj"][obj_idx2]:
+                frame_has_input = True
+                break
+            if frame_idx in inference_state["mask_inputs_per_obj"][obj_idx2]:
+                frame_has_input = True
+                break
+
+        # If this frame has no remaining inputs for any objects, we further clear its
+        # conditioning frame status
+        if not frame_has_input:
+            output_dict = inference_state["output_dict"]
+            consolidated_frame_inds = inference_state["consolidated_frame_inds"]
+            consolidated_frame_inds["cond_frame_outputs"].discard(frame_idx)
+            consolidated_frame_inds["non_cond_frame_outputs"].discard(frame_idx)
+            # Remove the frame's conditioning output (possibly downgrading it to non-conditioning)
+            out = output_dict["cond_frame_outputs"].pop(frame_idx, None)
+            if out is not None:
+                # The frame is not a conditioning frame anymore since it's not receiving inputs,
+                # so we "downgrade" its output (if exists) to a non-conditioning frame output.
+                output_dict["non_cond_frame_outputs"][frame_idx] = out
+                inference_state["frames_already_tracked"].pop(frame_idx, None)
+            # Similarly, do it for the sliced output on each object.
+            for obj_idx2 in range(batch_size):
+                obj_output_dict = inference_state["output_dict_per_obj"][obj_idx2]
+                obj_out = obj_output_dict["cond_frame_outputs"].pop(frame_idx, None)
+                if obj_out is not None:
+                    obj_output_dict["non_cond_frame_outputs"][frame_idx] = obj_out
+
+            # If all the conditioning frames have been removed, we also clear the tracking outputs
+            if len(output_dict["cond_frame_outputs"]) == 0:
+                self._reset_tracking_results(inference_state)
+
+        if not need_output:
+            return
+        # Finally, output updated masks per object (after removing the inputs above)
+        obj_ids = inference_state["obj_ids"]
+        is_cond = any(
+            frame_idx in obj_temp_output_dict["cond_frame_outputs"]
+            for obj_temp_output_dict in temp_output_dict_per_obj.values()
+        )
+        consolidated_out = self._consolidate_temp_output_across_obj(
+            inference_state,
+            frame_idx,
+            is_cond=is_cond,
+            run_mem_encoder=False,
+            consolidate_at_video_res=True,
+        )
+        _, video_res_masks = self._get_orig_video_res_output(
+            inference_state, consolidated_out["pred_masks_video_res"]
+        )
+        return frame_idx, obj_ids, video_res_masks
+
+    @torch.no_grad()
+    def reset_state(self, inference_state):
+        """Remove all input points or mask in all frames throughout the video."""
+        self._reset_tracking_results(inference_state)
+        # Remove all object ids
+        inference_state["obj_id_to_idx"].clear()
+        inference_state["obj_idx_to_id"].clear()
+        inference_state["obj_ids"].clear()
+        inference_state["point_inputs_per_obj"].clear()
+        inference_state["mask_inputs_per_obj"].clear()
+        inference_state["output_dict_per_obj"].clear()
+        inference_state["temp_output_dict_per_obj"].clear()
+
+    def _reset_tracking_results(self, inference_state):
+        """Reset all tracking inputs and results across the videos."""
+        for v in inference_state["point_inputs_per_obj"].values():
+            v.clear()
+        for v in inference_state["mask_inputs_per_obj"].values():
+            v.clear()
+        for v in inference_state["output_dict_per_obj"].values():
+            v["cond_frame_outputs"].clear()
+            v["non_cond_frame_outputs"].clear()
+        for v in inference_state["temp_output_dict_per_obj"].values():
+            v["cond_frame_outputs"].clear()
+            v["non_cond_frame_outputs"].clear()
+        inference_state["output_dict"]["cond_frame_outputs"].clear()
+        inference_state["output_dict"]["non_cond_frame_outputs"].clear()
+        inference_state["consolidated_frame_inds"]["cond_frame_outputs"].clear()
+        inference_state["consolidated_frame_inds"]["non_cond_frame_outputs"].clear()
+        inference_state["tracking_has_started"] = False
+        inference_state["frames_already_tracked"].clear()
+
+    def _get_image_feature(self, inference_state, frame_idx, batch_size):
+        """Compute the image features on a given frame."""
+        # Look up in the cache first
+        image, backbone_out = inference_state["cached_features"].get(
+            frame_idx, (None, None)
+        )
+        if backbone_out is None:
+            # Cache miss -- we will run inference on a single image
+            device = inference_state["device"]
+            image = inference_state["images"][frame_idx].to(device).float().unsqueeze(0)
+            backbone_out = self.forward_image(image)
+            # Cache the most recent frame's feature (for repeated interactions with
+            # a frame; we can use an LRU cache for more frames in the future).
+            inference_state["cached_features"] = {frame_idx: (image, backbone_out)}
+
+        # expand the features to have the same dimension as the number of objects
+        expanded_image = image.expand(batch_size, -1, -1, -1)
+        expanded_backbone_out = {
+            "backbone_fpn": backbone_out["backbone_fpn"].copy(),
+            "vision_pos_enc": backbone_out["vision_pos_enc"].copy(),
+        }
+        for i, feat in enumerate(expanded_backbone_out["backbone_fpn"]):
+            expanded_backbone_out["backbone_fpn"][i] = feat.expand(
+                batch_size, -1, -1, -1
+            )
+        for i, pos in enumerate(expanded_backbone_out["vision_pos_enc"]):
+            pos = pos.expand(batch_size, -1, -1, -1)
+            expanded_backbone_out["vision_pos_enc"][i] = pos
+
+        features = self._prepare_backbone_features(expanded_backbone_out)
+        features = (expanded_image,) + features
+        return features
+
+    @torch.autograd.profiler.record_function("_run_single_frame_inference")
+    def _run_single_frame_inference(
+        self,
+        inference_state,
+        output_dict,
+        frame_idx,
+        batch_size,
+        is_init_cond_frame,
+        point_inputs,
+        mask_inputs,
+        reverse,
+        run_mem_encoder,
+        prev_sam_mask_logits=None,
+    ):
+        """Run tracking on a single frame based on current inputs and previous memory."""
+        # Retrieve correct image features
+        (
+            _,
+            _,
+            current_vision_feats,
+            current_vision_pos_embeds,
+            feat_sizes,
+        ) = self._get_image_feature(inference_state, frame_idx, batch_size)
+
+        # point and mask should not appear as input simultaneously on the same frame
+        assert point_inputs is None or mask_inputs is None
+        current_out = self.track_step(
+            frame_idx=frame_idx,
+            is_init_cond_frame=is_init_cond_frame,
+            current_vision_feats=current_vision_feats,
+            current_vision_pos_embeds=current_vision_pos_embeds,
+            feat_sizes=feat_sizes,
+            point_inputs=point_inputs,
+            mask_inputs=mask_inputs,
+            output_dict=output_dict,
+            num_frames=inference_state["num_frames"],
+            track_in_reverse=reverse,
+            run_mem_encoder=run_mem_encoder,
+            prev_sam_mask_logits=prev_sam_mask_logits,
+        )
+
+        # optionally offload the output to CPU memory to save GPU space
+        storage_device = inference_state["storage_device"]
+        maskmem_features = current_out["maskmem_features"]
+        if maskmem_features is not None:
+            maskmem_features = maskmem_features.to(torch.bfloat16)
+            maskmem_features = maskmem_features.to(storage_device, non_blocking=True)
+        pred_masks_gpu = current_out["pred_masks"]
+        # potentially fill holes in the predicted masks
+        if self.fill_hole_area > 0:
+            pred_masks_gpu = fill_holes_in_mask_scores(
+                pred_masks_gpu, self.fill_hole_area
+            )
+        pred_masks = pred_masks_gpu.to(storage_device, non_blocking=True)
+        # "maskmem_pos_enc" is the same across frames, so we only need to store one copy of it
+        maskmem_pos_enc = self._get_maskmem_pos_enc(inference_state, current_out)
+        # object pointer is a small tensor, so we always keep it on GPU memory for fast access
+        obj_ptr = current_out["obj_ptr"]
+        object_score_logits = current_out["object_score_logits"]
+        # make a compact version of this frame's output to reduce the state size
+        compact_current_out = {
+            "maskmem_features": maskmem_features,
+            "maskmem_pos_enc": maskmem_pos_enc,
+            "pred_masks": pred_masks,
+            "obj_ptr": obj_ptr,
+            "object_score_logits": object_score_logits,
+        }
+        return compact_current_out, pred_masks_gpu
+
+    def _run_memory_encoder(
+        self,
+        inference_state,
+        frame_idx,
+        batch_size,
+        high_res_masks,
+        object_score_logits,
+        is_mask_from_pts,
+    ):
+        """
+        Run the memory encoder on `high_res_masks`. This is usually after applying
+        non-overlapping constraints to object scores. Since their scores changed, their
+        memory also need to be computed again with the memory encoder.
+        """
+        # Retrieve correct image features
+        _, _, current_vision_feats, _, feat_sizes = self._get_image_feature(
+            inference_state, frame_idx, batch_size
+        )
+        maskmem_features, maskmem_pos_enc = self._encode_new_memory(
+            current_vision_feats=current_vision_feats,
+            feat_sizes=feat_sizes,
+            pred_masks_high_res=high_res_masks,
+            object_score_logits=object_score_logits,
+            is_mask_from_pts=is_mask_from_pts,
+        )
+
+        # optionally offload the output to CPU memory to save GPU space
+        storage_device = inference_state["storage_device"]
+        maskmem_features = maskmem_features.to(torch.bfloat16)
+        maskmem_features = maskmem_features.to(storage_device, non_blocking=True)
+        # "maskmem_pos_enc" is the same across frames, so we only need to store one copy of it
+        maskmem_pos_enc = self._get_maskmem_pos_enc(
+            inference_state, {"maskmem_pos_enc": maskmem_pos_enc}
+        )
+        return maskmem_features, maskmem_pos_enc
+
+    def _get_maskmem_pos_enc(self, inference_state, current_out):
+        """
+        `maskmem_pos_enc` is the same across frames and objects, so we cache it as
+        a constant in the inference session to reduce session storage size.
+        """
+        model_constants = inference_state["constants"]
+        # "out_maskmem_pos_enc" should be either a list of tensors or None
+        out_maskmem_pos_enc = current_out["maskmem_pos_enc"]
+        if out_maskmem_pos_enc is not None:
+            if "maskmem_pos_enc" not in model_constants:
+                assert isinstance(out_maskmem_pos_enc, list)
+                # only take the slice for one object, since it's same across objects
+                maskmem_pos_enc = [x[0:1].clone() for x in out_maskmem_pos_enc]
+                model_constants["maskmem_pos_enc"] = maskmem_pos_enc
+            else:
+                maskmem_pos_enc = model_constants["maskmem_pos_enc"]
+            # expand the cached maskmem_pos_enc to the actual batch size
+            batch_size = out_maskmem_pos_enc[0].size(0)
+            expanded_maskmem_pos_enc = [
+                x.expand(batch_size, -1, -1, -1) for x in maskmem_pos_enc
+            ]
+        else:
+            expanded_maskmem_pos_enc = None
+        return expanded_maskmem_pos_enc
+
+    @torch.no_grad()
+    def remove_object(self, inference_state, obj_id, strict=False, need_output=True):
+        """
+        Remove an object id from the tracking state. If strict is True, we check whether
+        the object id actually exists and raise an error if it doesn't exist.
+        """
+        old_obj_idx_to_rm = inference_state["obj_id_to_idx"].get(obj_id, None)
+        updated_frames = []
+        # Check whether this object_id to remove actually exists and possibly raise an error.
+        if old_obj_idx_to_rm is None:
+            if not strict:
+                return inference_state["obj_ids"], updated_frames
+            raise RuntimeError(
+                f"Cannot remove object id {obj_id} as it doesn't exist. "
+                f"All existing object ids: {inference_state['obj_ids']}."
+            )
+
+        # If this is the only remaining object id, we simply reset the state.
+        if len(inference_state["obj_id_to_idx"]) == 1:
+            self.reset_state(inference_state)
+            return inference_state["obj_ids"], updated_frames
+
+        # There are still remaining objects after removing this object id. In this case,
+        # we need to delete the object storage from inference state tensors.
+        # Step 0: clear the input on those frames where this object id has point or mask input
+        # (note that this step is required as it might downgrade conditioning frames to
+        # non-conditioning ones)
+        obj_input_frames_inds = set()
+        obj_input_frames_inds.update(
+            inference_state["point_inputs_per_obj"][old_obj_idx_to_rm]
+        )
+        obj_input_frames_inds.update(
+            inference_state["mask_inputs_per_obj"][old_obj_idx_to_rm]
+        )
+        for frame_idx in obj_input_frames_inds:
+            self.clear_all_prompts_in_frame(
+                inference_state, frame_idx, obj_id, need_output=False
+            )
+
+        # Step 1: Update the object id mapping (note that it must be done after Step 0,
+        # since Step 0 still requires the old object id mappings in inference_state)
+        old_obj_ids = inference_state["obj_ids"]
+        old_obj_inds = list(range(len(old_obj_ids)))
+        remain_old_obj_inds = old_obj_inds.copy()
+        remain_old_obj_inds.remove(old_obj_idx_to_rm)
+        new_obj_ids = [old_obj_ids[old_idx] for old_idx in remain_old_obj_inds]
+        new_obj_inds = list(range(len(new_obj_ids)))
+        # build new mappings
+        old_idx_to_new_idx = dict(zip(remain_old_obj_inds, new_obj_inds))
+        inference_state["obj_id_to_idx"] = dict(zip(new_obj_ids, new_obj_inds))
+        inference_state["obj_idx_to_id"] = dict(zip(new_obj_inds, new_obj_ids))
+        inference_state["obj_ids"] = new_obj_ids
+
+        # Step 2: For per-object tensor storage, we shift their obj_idx in the dict keys.
+        # (note that "consolidated_frame_inds" doesn't need to be updated in this step as
+        # it's already handled in Step 0)
+        def _map_keys(container):
+            new_kvs = []
+            for k in old_obj_inds:
+                v = container.pop(k)
+                if k in old_idx_to_new_idx:
+                    new_kvs.append((old_idx_to_new_idx[k], v))
+            container.update(new_kvs)
+
+        _map_keys(inference_state["point_inputs_per_obj"])
+        _map_keys(inference_state["mask_inputs_per_obj"])
+        _map_keys(inference_state["output_dict_per_obj"])
+        _map_keys(inference_state["temp_output_dict_per_obj"])
+
+        # Step 3: For packed tensor storage, we index the remaining ids and rebuild the per-object slices.
+        def _slice_state(output_dict, storage_key):
+            for frame_idx, out in output_dict[storage_key].items():
+                out["maskmem_features"] = out["maskmem_features"][remain_old_obj_inds]
+                out["maskmem_pos_enc"] = [
+                    x[remain_old_obj_inds] for x in out["maskmem_pos_enc"]
+                ]
+                # "maskmem_pos_enc" is the same across frames, so we only need to store one copy of it
+                out["maskmem_pos_enc"] = self._get_maskmem_pos_enc(inference_state, out)
+                out["pred_masks"] = out["pred_masks"][remain_old_obj_inds]
+                out["obj_ptr"] = out["obj_ptr"][remain_old_obj_inds]
+                out["object_score_logits"] = out["object_score_logits"][
+                    remain_old_obj_inds
+                ]
+                # also update the per-object slices
+                self._add_output_per_object(
+                    inference_state, frame_idx, out, storage_key
+                )
+
+        _slice_state(inference_state["output_dict"], "cond_frame_outputs")
+        _slice_state(inference_state["output_dict"], "non_cond_frame_outputs")
+
+        # Step 4: Further collect the outputs on those frames in `obj_input_frames_inds`, which
+        # could show an updated mask for objects previously occluded by the object being removed
+        if need_output:
+            temp_output_dict_per_obj = inference_state["temp_output_dict_per_obj"]
+            for frame_idx in obj_input_frames_inds:
+                is_cond = any(
+                    frame_idx in obj_temp_output_dict["cond_frame_outputs"]
+                    for obj_temp_output_dict in temp_output_dict_per_obj.values()
+                )
+                consolidated_out = self._consolidate_temp_output_across_obj(
+                    inference_state,
+                    frame_idx,
+                    is_cond=is_cond,
+                    run_mem_encoder=False,
+                    consolidate_at_video_res=True,
+                )
+                _, video_res_masks = self._get_orig_video_res_output(
+                    inference_state, consolidated_out["pred_masks_video_res"]
+                )
+                updated_frames.append((frame_idx, video_res_masks))
+
+        return inference_state["obj_ids"], updated_frames
+
+    def _clear_non_cond_mem_around_input(self, inference_state, frame_idx):
+        """
+        Remove the non-conditioning memory around the input frame. When users provide
+        correction clicks, the surrounding frames' non-conditioning memories can still
+        contain outdated object appearance information and could confuse the model.
+
+        This method clears those non-conditioning memories surrounding the interacted
+        frame to avoid giving the model both old and new information about the object.
+        """
+        r = self.memory_temporal_stride_for_eval
+        frame_idx_begin = frame_idx - r * self.num_maskmem
+        frame_idx_end = frame_idx + r * self.num_maskmem
+        output_dict = inference_state["output_dict"]
+        non_cond_frame_outputs = output_dict["non_cond_frame_outputs"]
+        for t in range(frame_idx_begin, frame_idx_end + 1):
+            non_cond_frame_outputs.pop(t, None)
+            for obj_output_dict in inference_state["output_dict_per_obj"].values():
+                obj_output_dict["non_cond_frame_outputs"].pop(t, None)
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/utils/__init__.py b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..5277f46157403e47fd830fc519144b97ef69d4ae
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__init__.py
@@ -0,0 +1,5 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3ef2f65b35fb92d4db6d91266e50e2a9d19996c7
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/amg.cpython-312.pyc b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/amg.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ceef66a772bda4c7bf5c26f95ebf247251d78a82
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/amg.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/misc.cpython-312.pyc b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/misc.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..04bddd3def4f1e93acc3fb71f138e79ba5b07321
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/misc.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/transforms.cpython-312.pyc b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/transforms.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..032d26ec9dbb2f5d8b195862ce2d706d0eb71933
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/_models/sam2/utils/__pycache__/transforms.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/utils/amg.py b/lib/python3.12/site-packages/torchao/_models/sam2/utils/amg.py
new file mode 100644
index 0000000000000000000000000000000000000000..66f8fa15ebed0e60ab5441d1790ba30de8c11db4
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/utils/amg.py
@@ -0,0 +1,523 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import math
+from copy import deepcopy
+from dataclasses import dataclass
+from itertools import product
+from typing import Any, Dict, Generator, ItemsView, List, Tuple
+
+import numpy as np
+import torch
+
+
+@dataclass
+class RLEData:
+    alt_lens_nt: torch.Tensor
+    counts_init: torch.Tensor
+    b: int
+    h: int
+    w: int
+
+    def __len__(self):
+        return self.b
+
+
+def nt_index_select_dim_0(nt, index):
+    values = nt.values()
+    offsets = nt.offsets()
+    lengths = offsets.diff()
+    offsets_index = offsets[index].cpu()
+    lengths_index = lengths[index].cpu()
+    indices = [o + torch.arange(l) for (o, l) in zip(offsets_index, lengths_index)]
+    indices = torch.cat(indices).to(values.device)
+    values_index = torch.index_select(values, 0, indices)
+    lengths_index = lengths_index.to(values.device)
+    return torch.nested.nested_tensor_from_jagged(values_index, lengths=lengths_index)
+
+
+def nt_cat_dim_0(nts: List[torch.Tensor]):
+    all_values = []
+    all_lengths = []
+    for nt in nts:
+        all_values.append(nt.values())
+        all_lengths.append(nt.offsets().diff())
+    new_values = torch.cat(all_values)
+    new_lengths = torch.cat(all_lengths)
+    return torch.nested.nested_tensor_from_jagged(new_values, lengths=new_lengths)
+
+
+# Very lightly adapted from https://github.com/facebookresearch/segment-anything/blob/main/segment_anything/utils/amg.py
+class MaskData:
+    """
+    A structure for storing masks and their related data in batched format.
+    Implements basic filtering and concatenation.
+    """
+
+    def __init__(self, **kwargs) -> None:
+        for v in kwargs.values():
+            assert isinstance(v, (list, np.ndarray, torch.Tensor, RLEData)), (
+                "MaskData only supports list, numpy arrays, and torch tensors."
+            )
+        self._stats = dict(**kwargs)
+
+    def __setitem__(self, key: str, item: Any) -> None:
+        assert isinstance(item, (list, np.ndarray, torch.Tensor, RLEData)), (
+            "MaskData only supports list, numpy arrays, and torch tensors."
+        )
+        self._stats[key] = item
+
+    def __delitem__(self, key: str) -> None:
+        del self._stats[key]
+
+    def __getitem__(self, key: str) -> Any:
+        return self._stats[key]
+
+    def items(self) -> ItemsView[str, Any]:
+        return self._stats.items()
+
+    def filter(self, keep: torch.Tensor) -> None:
+        for k, v in self._stats.items():
+            if v is None:
+                self._stats[k] = None
+            elif isinstance(v, torch.Tensor):
+                # self._stats[k] = v[torch.as_tensor(keep, device=v.device)]
+                self._stats[k] = v[keep]
+            elif isinstance(v, np.ndarray):
+                self._stats[k] = v[keep.detach().cpu().numpy()]
+            elif isinstance(v, list) and keep.dtype == torch.bool:
+                self._stats[k] = [a for i, a in enumerate(v) if keep[i]]
+            elif isinstance(v, list):
+                self._stats[k] = [v[i] for i in keep]
+            elif isinstance(v, RLEData):
+                new_alt_lens_nt = nt_index_select_dim_0(v.alt_lens_nt, keep)
+                self._stats[k] = RLEData(
+                    alt_lens_nt=new_alt_lens_nt,
+                    counts_init=v.counts_init[keep],
+                    b=new_alt_lens_nt.size(0),
+                    h=v.h,
+                    w=v.w,
+                )
+            else:
+                raise TypeError(f"MaskData key {k} has an unsupported type {type(v)}.")
+
+    def cat(self, new_stats: "MaskData") -> None:
+        for k, v in new_stats.items():
+            if k not in self._stats or self._stats[k] is None:
+                self._stats[k] = deepcopy(v)
+            elif isinstance(v, torch.Tensor):
+                self._stats[k] = torch.cat([self._stats[k], v], dim=0)
+            elif isinstance(v, np.ndarray):
+                self._stats[k] = np.concatenate([self._stats[k], v], axis=0)
+            elif isinstance(v, list):
+                self._stats[k] = self._stats[k] + deepcopy(v)
+            elif isinstance(v, RLEData):
+                assert self._stats[k].h == v.h
+                assert self._stats[k].w == v.w
+                self._stats[k] = RLEData(
+                    alt_lens_nt=nt_cat_dim_0(
+                        [self._stats[k].alt_lens_nt, v.alt_lens_nt]
+                    ),
+                    counts_init=torch.cat([self._stats[k].counts_init, v.counts_init]),
+                    b=self._stats[k].b + v.b,
+                    h=v.h,
+                    w=v.w,
+                )
+            else:
+                raise TypeError(f"MaskData key {k} has an unsupported type {type(v)}.")
+
+    def to_numpy(self) -> None:
+        for k, v in self._stats.items():
+            if isinstance(v, torch.Tensor):
+                self._stats[k] = v.float().detach().cpu().numpy()
+
+
+def is_box_near_crop_edge_torch(
+    boxes: torch.Tensor,
+    crop_box: List[int],
+    crop_box_torch: torch.Tensor,
+    orig_box_torch: torch.Tensor,
+    atol: float = 20.0,
+) -> torch.Tensor:
+    """Filter masks at the edge of a crop, but not at the edge of the original image."""
+    boxes = uncrop_boxes_xyxy(boxes, crop_box).float()
+    near_crop_edge = torch.isclose(boxes, crop_box_torch[None, :], atol=atol, rtol=0)
+    near_image_edge = torch.isclose(boxes, orig_box_torch[None, :], atol=atol, rtol=0)
+    near_crop_edge = torch.logical_and(near_crop_edge, ~near_image_edge)
+    return torch.any(near_crop_edge, dim=1)
+
+
+def is_box_near_crop_edge(
+    boxes: torch.Tensor, crop_box: List[int], orig_box: List[int], atol: float = 20.0
+) -> torch.Tensor:
+    crop_box_torch = torch.as_tensor(crop_box, dtype=torch.float, device=boxes.device)
+    orig_box_torch = torch.as_tensor(orig_box, dtype=torch.float, device=boxes.device)
+    return is_box_near_crop_edge_torch(
+        boxes, crop_box, crop_box_torch, orig_box_torch, atol
+    )
+
+
+def box_xyxy_to_xywh(box_xyxy: torch.Tensor) -> torch.Tensor:
+    box_xywh = deepcopy(box_xyxy)
+    box_xywh[2] = box_xywh[2] - box_xywh[0]
+    box_xywh[3] = box_xywh[3] - box_xywh[1]
+    return box_xywh
+
+
+def batch_iterator(batch_size: int, *args) -> Generator[List[Any], None, None]:
+    assert len(args) > 0 and all(len(a) == len(args[0]) for a in args), (
+        "Batched iteration must have inputs of all the same size."
+    )
+    n_batches = len(args[0]) // batch_size + int(len(args[0]) % batch_size != 0)
+    for b in range(n_batches):
+        yield [arg[b * batch_size : (b + 1) * batch_size] for arg in args]
+
+
+def mask_to_rle_pytorch(tensor: torch.Tensor) -> List[Dict[str, Any]]:
+    """
+    Encodes masks to an uncompressed RLE, in the format expected by
+    pycoco tools.
+    """
+    # Put in fortran order and flatten h,w
+    b, h, w = tensor.shape
+    tensor = tensor.permute(0, 2, 1).flatten(1)
+
+    # Compute change indices
+    diff = tensor[:, 1:] ^ tensor[:, :-1]
+    change_indices = diff.nonzero()
+
+    # Encode run length
+    out = []
+    for i in range(b):
+        cur_idxs = change_indices[change_indices[:, 0] == i, 1]
+        cur_idxs = torch.cat(
+            [
+                torch.tensor([0], dtype=cur_idxs.dtype, device=cur_idxs.device),
+                cur_idxs + 1,
+                torch.tensor([h * w], dtype=cur_idxs.dtype, device=cur_idxs.device),
+            ]
+        )
+        btw_idxs = cur_idxs[1:] - cur_idxs[:-1]
+        counts = [] if tensor[i, 0] == 0 else [0]
+        counts.extend(btw_idxs.detach().cpu().tolist())
+        out.append({"size": [h, w], "counts": counts})
+    return out
+
+
+def rle_to_mask(rle: Dict[str, Any]) -> np.ndarray:
+    """Compute a binary mask from an uncompressed RLE."""
+    h, w = rle["size"]
+    mask = np.empty(h * w, dtype=bool)
+    idx = 0
+    parity = False
+    for count in rle["counts"]:
+        mask[idx : idx + count] = parity
+        idx += count
+        parity ^= True
+    mask = mask.reshape(w, h)
+    return mask.transpose()  # Put in C order
+
+
+# @torch.compile(fullgraph=True, dynamic=True)
+def _mask_to_rle_pytorch_2_0_0(tensor: torch.Tensor) -> (torch.Tensor, torch.Tensor):
+    """
+    Encodes masks to an uncompressed RLE, in the format expected by
+    pycoco tools.
+    """
+    # Put in fortran order and flatten h,w
+    b, h, w = tensor.shape
+    tensor = tensor.permute(0, 2, 1).flatten(1)
+
+    # Compute change indices
+    diff = tensor[:, 1:] ^ tensor[:, :-1]
+    # a = torch.tensor([[True]])
+    a = torch.ones((1, 1), dtype=bool, device=diff.device)
+    # if diff.is_cuda:
+    #     a = a.pin_memory().cuda()
+    #     # a = a.to(diff.device)
+    a = a.expand_as(diff.narrow(1, 0, 1))
+    diff = torch.cat([a, diff, a], dim=1)
+    return diff
+
+
+# @torch.compile(fullgraph=True, dynamic=True)
+def _mask_to_rle_pytorch_2_0_1(
+    tensor: torch.Tensor, diff: torch.Tensor, change_indices: torch.Tensor
+) -> (torch.Tensor, torch.Tensor):
+    tensor = tensor.permute(0, 2, 1).flatten(1)
+
+    alt_lens = diff.sum(dim=1)
+
+    all_cur_idx = change_indices[:, 1]
+    if all_cur_idx.numel() == 0:
+        all_cur_idx_0 = all_cur_idx
+        all_cur_idx_1 = all_cur_idx
+    else:
+        all_cur_idx_0 = all_cur_idx.narrow(0, 1, all_cur_idx.size(0) - 1)
+        all_cur_idx_1 = all_cur_idx.narrow(0, 0, 1)
+    all_btw_idx = torch.cat([all_cur_idx_0, all_cur_idx_1])
+    all_btw_idx = all_btw_idx - all_cur_idx
+
+    alt_lens_nt = torch.nested.nested_tensor_from_jagged(all_btw_idx, lengths=alt_lens)
+    # Encode run length
+    counts_init = tensor[:, 0] == 0
+    return alt_lens_nt, counts_init
+
+
+def _mask_to_rle_pytorch_2_0(tensor: torch.Tensor) -> RLEData:
+    b, h, w = tensor.shape
+    with torch.autograd.profiler.record_function(
+        "mask_to_rle_pytorch_2: _mask_to_rle_pytorch_2_0_0"
+    ):
+        diff = _mask_to_rle_pytorch_2_0_0(tensor)
+    with torch.autograd.profiler.record_function("mask_to_rle_pytorch_2: nonzero"):
+        # NOTE: While we could operate on less chunks, a set number of chunks prevents recompilations
+        # if diff.numel() > 2147483646:
+        #     num_chunks = (diff.numel() + 2147483646) // 2147483646
+        #     change_indices = torch.cat([d.nonzero() for d in diff.chunk(num_chunks)])
+        # else:
+        #     change_indices = diff.nonzero()
+        num_chunks = 8
+        assert num_chunks >= ((diff.numel() + 2147483646) // 2147483646), (
+            "Needed more chunks than expected."
+        )
+        change_indices = torch.cat([d.nonzero() for d in diff.chunk(num_chunks)])
+    with torch.autograd.profiler.record_function(
+        "mask_to_rle_pytorch_2: _mask_to_rle_pytorch_2_0_1"
+    ):
+        alt_lens_nt, counts_init = _mask_to_rle_pytorch_2_0_1(
+            tensor, diff, change_indices
+        )
+    return RLEData(alt_lens_nt=alt_lens_nt, counts_init=counts_init, b=b, h=h, w=w)
+
+
+def _mask_to_rle_pytorch_2_1(rle_data: RLEData):
+    with torch.autograd.profiler.record_function(
+        "mask_to_rle_pytorch_2: Encode run length"
+    ):
+        out = []
+        alt_lens = rle_data.alt_lens_nt.offsets().diff()
+        all_btw_idx = rle_data.alt_lens_nt.values()
+        alt_lens = alt_lens.tolist()
+        all_btw_idx = all_btw_idx.tolist()
+        counts_init = rle_data.counts_init.tolist()
+        offset = 0
+        for i, ci in zip(range(rle_data.b), counts_init):
+            btw_idxs = all_btw_idx[offset : offset + alt_lens[i]][:-1]
+            offset += alt_lens[i]
+            counts = [] if ci else [0]
+            counts.extend(btw_idxs)
+            out.append({"size": [rle_data.h, rle_data.w], "counts": counts})
+
+    return out
+
+
+def mask_to_rle_pytorch_2(tensor: torch.Tensor) -> List[Dict[str, Any]]:
+    with torch.autograd.profiler.record_function("mask_to_rle_pytorch_2"):
+        return _mask_to_rle_pytorch_2_1(_mask_to_rle_pytorch_2_0(tensor))
+
+
+def area_from_rle(rle: Dict[str, Any]) -> int:
+    return sum(rle["counts"][1::2])
+
+
+# TODO: Turn this on if you can mitigate recompiles!
+# @torch.compile(fullgraph=True, dynamic=True)
+def calculate_stability_score(
+    masks: torch.Tensor, mask_threshold: float, threshold_offset: float
+) -> torch.Tensor:
+    """
+    Computes the stability score for a batch of masks. The stability
+    score is the IoU between the binary masks obtained by thresholding
+    the predicted mask logits at high and low values.
+    """
+    # One mask is always contained inside the other.
+    # Save memory by preventing unnecessary cast to torch.int64
+    intersections = (
+        (masks > (mask_threshold + threshold_offset))
+        .sum(-1, dtype=torch.int16)
+        .sum(-1, dtype=torch.int32)
+    )
+    unions = (
+        (masks > (mask_threshold - threshold_offset))
+        .sum(-1, dtype=torch.int16)
+        .sum(-1, dtype=torch.int32)
+    )
+    return intersections / unions
+
+
+def build_point_grid(n_per_side: int) -> np.ndarray:
+    """Generates a 2D grid of points evenly spaced in [0,1]x[0,1]."""
+    offset = 1 / (2 * n_per_side)
+    points_one_side = np.linspace(offset, 1 - offset, n_per_side)
+    points_x = np.tile(points_one_side[None, :], (n_per_side, 1))
+    points_y = np.tile(points_one_side[:, None], (1, n_per_side))
+    points = np.stack([points_x, points_y], axis=-1).reshape(-1, 2)
+    return points
+
+
+def build_all_layer_point_grids(
+    n_per_side: int, n_layers: int, scale_per_layer: int
+) -> List[np.ndarray]:
+    """Generates point grids for all crop layers."""
+    points_by_layer = []
+    for i in range(n_layers + 1):
+        n_points = int(n_per_side / (scale_per_layer**i))
+        points_by_layer.append(build_point_grid(n_points))
+    return points_by_layer
+
+
+def generate_crop_boxes(
+    im_size: Tuple[int, ...], n_layers: int, overlap_ratio: float
+) -> Tuple[List[List[int]], List[int]]:
+    """
+    Generates a list of crop boxes of different sizes. Each layer
+    has (2**i)**2 boxes for the ith layer.
+    """
+    crop_boxes, layer_idxs = [], []
+    im_h, im_w = im_size
+    short_side = min(im_h, im_w)
+
+    # Original image
+    crop_boxes.append([0, 0, im_w, im_h])
+    layer_idxs.append(0)
+
+    def crop_len(orig_len, n_crops, overlap):
+        return int(math.ceil((overlap * (n_crops - 1) + orig_len) / n_crops))
+
+    for i_layer in range(n_layers):
+        n_crops_per_side = 2 ** (i_layer + 1)
+        overlap = int(overlap_ratio * short_side * (2 / n_crops_per_side))
+
+        crop_w = crop_len(im_w, n_crops_per_side, overlap)
+        crop_h = crop_len(im_h, n_crops_per_side, overlap)
+
+        crop_box_x0 = [int((crop_w - overlap) * i) for i in range(n_crops_per_side)]
+        crop_box_y0 = [int((crop_h - overlap) * i) for i in range(n_crops_per_side)]
+
+        # Crops in XYWH format
+        for x0, y0 in product(crop_box_x0, crop_box_y0):
+            box = [x0, y0, min(x0 + crop_w, im_w), min(y0 + crop_h, im_h)]
+            crop_boxes.append(box)
+            layer_idxs.append(i_layer + 1)
+
+    return crop_boxes, layer_idxs
+
+
+def uncrop_boxes_xyxy(boxes: torch.Tensor, crop_box: List[int]) -> torch.Tensor:
+    x0, y0, _, _ = crop_box
+    offset = torch.tensor([[x0, y0, x0, y0]]).pin_memory()
+    offset = offset.to(device=boxes.device, non_blocking=True)
+    # Check if boxes has a channel dimension
+    if len(boxes.shape) == 3:
+        offset = offset.unsqueeze(1)
+    return boxes + offset
+
+
+def uncrop_points(points: torch.Tensor, crop_box: List[int]) -> torch.Tensor:
+    x0, y0, _, _ = crop_box
+    offset = torch.tensor([[x0, y0]]).pin_memory()
+    offset = offset.to(device=points.device, non_blocking=True)
+    # Check if points has a channel dimension
+    if len(points.shape) == 3:
+        offset = offset.unsqueeze(1)
+    return points + offset
+
+
+def uncrop_masks(
+    masks: torch.Tensor, crop_box: List[int], orig_h: int, orig_w: int
+) -> torch.Tensor:
+    x0, y0, x1, y1 = crop_box
+    if x0 == 0 and y0 == 0 and x1 == orig_w and y1 == orig_h:
+        return masks
+    # Coordinate transform masks
+    pad_x, pad_y = orig_w - (x1 - x0), orig_h - (y1 - y0)
+    pad = (x0, pad_x - x0, y0, pad_y - y0)
+    return torch.nn.functional.pad(masks, pad, value=0)
+
+
+def remove_small_regions(
+    mask: np.ndarray, area_thresh: float, mode: str
+) -> Tuple[np.ndarray, bool]:
+    """
+    Removes small disconnected regions and holes in a mask. Returns the
+    mask and an indicator of if the mask has been modified.
+    """
+    import cv2  # type: ignore
+
+    assert mode in ["holes", "islands"]
+    correct_holes = mode == "holes"
+    working_mask = (correct_holes ^ mask).astype(np.uint8)
+    n_labels, regions, stats, _ = cv2.connectedComponentsWithStats(working_mask, 8)
+    sizes = stats[:, -1][1:]  # Row 0 is background label
+    small_regions = [i + 1 for i, s in enumerate(sizes) if s < area_thresh]
+    if len(small_regions) == 0:
+        return mask, False
+    fill_labels = [0] + small_regions
+    if not correct_holes:
+        fill_labels = [i for i in range(n_labels) if i not in fill_labels]
+        # If every region is below threshold, keep largest
+        if len(fill_labels) == 0:
+            fill_labels = [int(np.argmax(sizes)) + 1]
+    mask = np.isin(regions, fill_labels)
+    return mask, True
+
+
+def coco_encode_rle(uncompressed_rle: Dict[str, Any]) -> Dict[str, Any]:
+    from pycocotools import mask as mask_utils  # type: ignore
+
+    h, w = uncompressed_rle["size"]
+    rle = mask_utils.frPyObjects(uncompressed_rle, h, w)
+    rle["counts"] = rle["counts"].decode("utf-8")  # Necessary to serialize with json
+    return rle
+
+
+# TODO: Turn this on if you can mitigate recompiles!
+# @torch.compile(fullgraph=True, dynamic=True)
+def batched_mask_to_box(masks: torch.Tensor) -> torch.Tensor:
+    """
+    Calculates boxes in XYXY format around masks. Return [0,0,0,0] for
+    an empty mask. For input shape C1xC2x...xHxW, the output shape is C1xC2x...x4.
+    """
+    # # torch.max below raises an error on empty inputs, just skip in this case
+    # if torch.numel(masks) == 0:
+    #     return torch.zeros(*masks.shape[:-2], 4, device=masks.device)
+
+    # Normalize shape to CxHxW
+    shape = masks.shape
+    h, w = shape[-2:]
+    if len(shape) > 2:
+        masks = masks.flatten(0, -3)
+    else:
+        masks = masks.unsqueeze(0)
+
+    # Get top and bottom edges
+    in_height, _ = torch.max(masks, dim=-1)
+    in_height_coords = in_height * torch.arange(h, device=in_height.device)[None, :]
+    bottom_edges, _ = torch.max(in_height_coords, dim=-1)
+    in_height_coords = in_height_coords + h * (~in_height)
+    top_edges, _ = torch.min(in_height_coords, dim=-1)
+
+    # Get left and right edges
+    in_width, _ = torch.max(masks, dim=-2)
+    in_width_coords = in_width * torch.arange(w, device=in_width.device)[None, :]
+    right_edges, _ = torch.max(in_width_coords, dim=-1)
+    in_width_coords = in_width_coords + w * (~in_width)
+    left_edges, _ = torch.min(in_width_coords, dim=-1)
+
+    # If the mask is empty the right edge will be to the left of the left edge.
+    # Replace these boxes with [0, 0, 0, 0]
+    empty_filter = (right_edges < left_edges) | (bottom_edges < top_edges)
+    out = torch.stack([left_edges, top_edges, right_edges, bottom_edges], dim=-1)
+    out = out * (~empty_filter).unsqueeze(-1)
+
+    # Return to original shape
+    if len(shape) > 2:
+        out = out.reshape(*shape[:-2], 4)
+    else:
+        out = out[0]
+
+    return out
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/utils/misc.py b/lib/python3.12/site-packages/torchao/_models/sam2/utils/misc.py
new file mode 100644
index 0000000000000000000000000000000000000000..b98fbcdae461ec191a6f0d68260d795bc672f4bf
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/utils/misc.py
@@ -0,0 +1,382 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import os
+import warnings
+from threading import Thread
+from typing import Tuple, Union
+
+import numpy as np
+import torch
+from PIL import Image
+from tqdm import tqdm
+
+
+def get_sdpa_settings():
+    if torch.cuda.is_available():
+        old_gpu = torch.cuda.get_device_properties(0).major < 7
+        # only use Flash Attention on Ampere (8.0) or newer GPUs
+        use_flash_attn = torch.cuda.get_device_properties(0).major >= 8
+        if not use_flash_attn:
+            warnings.warn(
+                "Flash Attention is disabled as it requires a GPU with Ampere (8.0) CUDA capability.",
+                category=UserWarning,
+                stacklevel=2,
+            )
+        # keep math kernel for PyTorch versions before 2.2 (Flash Attention v2 is only
+        # available on PyTorch 2.2+, while Flash Attention v1 cannot handle all cases)
+        pytorch_version = tuple(int(v) for v in torch.__version__.split(".")[:2])
+        if pytorch_version < (2, 2):
+            warnings.warn(
+                f"You are using PyTorch {torch.__version__} without Flash Attention v2 support. "
+                "Consider upgrading to PyTorch 2.2+ for Flash Attention v2 (which could be faster).",
+                category=UserWarning,
+                stacklevel=2,
+            )
+        math_kernel_on = pytorch_version < (2, 2) or not use_flash_attn
+    else:
+        old_gpu = True
+        use_flash_attn = False
+        math_kernel_on = True
+
+    return old_gpu, use_flash_attn, math_kernel_on
+
+
+def get_connected_components(mask):
+    """
+    Get the connected components (8-connectivity) of binary masks of shape (N, 1, H, W).
+
+    Inputs:
+    - mask: A binary mask tensor of shape (N, 1, H, W), where 1 is foreground and 0 is
+            background.
+
+    Outputs:
+    - labels: A tensor of shape (N, 1, H, W) containing the connected component labels
+              for foreground pixels and 0 for background pixels.
+    - counts: A tensor of shape (N, 1, H, W) containing the area of the connected
+              components for foreground pixels and 0 for background pixels.
+    """
+    from sam2 import _C
+
+    return _C.get_connected_componnets(mask.to(torch.uint8).contiguous())
+
+
+def mask_to_box(masks: torch.Tensor):
+    """
+    compute bounding box given an input mask
+
+    Inputs:
+    - masks: [B, 1, H, W] masks, dtype=torch.Tensor
+
+    Returns:
+    - box_coords: [B, 1, 4], contains (x, y) coordinates of top left and bottom right box corners, dtype=torch.Tensor
+    """
+    B, _, h, w = masks.shape
+    device = masks.device
+    xs = torch.arange(w, device=device, dtype=torch.int32)
+    ys = torch.arange(h, device=device, dtype=torch.int32)
+    grid_xs, grid_ys = torch.meshgrid(xs, ys, indexing="xy")
+    grid_xs = grid_xs[None, None, ...].expand(B, 1, h, w)
+    grid_ys = grid_ys[None, None, ...].expand(B, 1, h, w)
+    min_xs, _ = torch.min(torch.where(masks, grid_xs, w).flatten(-2), dim=-1)
+    max_xs, _ = torch.max(torch.where(masks, grid_xs, -1).flatten(-2), dim=-1)
+    min_ys, _ = torch.min(torch.where(masks, grid_ys, h).flatten(-2), dim=-1)
+    max_ys, _ = torch.max(torch.where(masks, grid_ys, -1).flatten(-2), dim=-1)
+    bbox_coords = torch.stack((min_xs, min_ys, max_xs, max_ys), dim=-1)
+
+    return bbox_coords
+
+
+def _load_img_as_tensor(img_path, image_size):
+    img_pil = Image.open(img_path)
+    img_np = np.array(img_pil.convert("RGB").resize((image_size, image_size)))
+    if img_np.dtype == np.uint8:  # np.uint8 is expected for JPEG images
+        img_np = img_np / 255.0
+    else:
+        raise RuntimeError(f"Unknown image dtype: {img_np.dtype} on {img_path}")
+    img = torch.from_numpy(img_np).permute(2, 0, 1)
+    video_width, video_height = img_pil.size  # the original video size
+    return img, video_height, video_width
+
+
+class AsyncVideoFrameLoader:
+    """
+    A list of video frames to be load asynchronously without blocking session start.
+    """
+
+    def __init__(
+        self,
+        img_paths,
+        image_size,
+        offload_video_to_cpu,
+        img_mean,
+        img_std,
+        compute_device,
+    ):
+        self.img_paths = img_paths
+        self.image_size = image_size
+        self.offload_video_to_cpu = offload_video_to_cpu
+        self.img_mean = img_mean
+        self.img_std = img_std
+        # items in `self.images` will be loaded asynchronously
+        self.images = [None] * len(img_paths)
+        # catch and raise any exceptions in the async loading thread
+        self.exception = None
+        # video_height and video_width be filled when loading the first image
+        self.video_height = None
+        self.video_width = None
+        self.compute_device = compute_device
+
+        # load the first frame to fill video_height and video_width and also
+        # to cache it (since it's most likely where the user will click)
+        self.__getitem__(0)
+
+        # load the rest of frames asynchronously without blocking the session start
+        def _load_frames():
+            try:
+                for n in tqdm(range(len(self.images)), desc="frame loading (JPEG)"):
+                    self.__getitem__(n)
+            except Exception as e:
+                self.exception = e
+
+        self.thread = Thread(target=_load_frames, daemon=True)
+        self.thread.start()
+
+    def __getitem__(self, index):
+        if self.exception is not None:
+            raise RuntimeError("Failure in frame loading thread") from self.exception
+
+        img = self.images[index]
+        if img is not None:
+            return img
+
+        img, video_height, video_width = _load_img_as_tensor(
+            self.img_paths[index], self.image_size
+        )
+        self.video_height = video_height
+        self.video_width = video_width
+        # normalize by mean and std
+        img -= self.img_mean
+        img /= self.img_std
+        if not self.offload_video_to_cpu:
+            img = img.to(self.compute_device, non_blocking=True)
+        self.images[index] = img
+        return img
+
+    def __len__(self):
+        return len(self.images)
+
+
+def load_video_frames(
+    video_path,
+    image_size,
+    offload_video_to_cpu,
+    img_mean=(0.485, 0.456, 0.406),
+    img_std=(0.229, 0.224, 0.225),
+    async_loading_frames=False,
+    compute_device=torch.device("cuda"),
+):
+    """
+    Load the video frames from video_path. The frames are resized to image_size as in
+    the model and are loaded to GPU if offload_video_to_cpu=False. This is used by the demo.
+    """
+    is_bytes = isinstance(video_path, bytes)
+    is_str = isinstance(video_path, str)
+    is_mp4_path = is_str and os.path.splitext(video_path)[-1] in [".mp4", ".MP4"]
+    if is_bytes or is_mp4_path:
+        return load_video_frames_from_video_file(
+            video_path=video_path,
+            image_size=image_size,
+            offload_video_to_cpu=offload_video_to_cpu,
+            img_mean=img_mean,
+            img_std=img_std,
+            compute_device=compute_device,
+        )
+    elif is_str and os.path.isdir(video_path):
+        return load_video_frames_from_jpg_images(
+            video_path=video_path,
+            image_size=image_size,
+            offload_video_to_cpu=offload_video_to_cpu,
+            img_mean=img_mean,
+            img_std=img_std,
+            async_loading_frames=async_loading_frames,
+            compute_device=compute_device,
+        )
+    else:
+        raise NotImplementedError(
+            "Only MP4 video and JPEG folder are supported at this moment"
+        )
+
+
+def load_video_frames_from_jpg_images(
+    video_path,
+    image_size,
+    offload_video_to_cpu,
+    img_mean=(0.485, 0.456, 0.406),
+    img_std=(0.229, 0.224, 0.225),
+    async_loading_frames=False,
+    compute_device=torch.device("cuda"),
+):
+    """
+    Load the video frames from a directory of JPEG files (".jpg" format).
+
+    The frames are resized to image_size x image_size and are loaded to GPU if
+    `offload_video_to_cpu` is `False` and to CPU if `offload_video_to_cpu` is `True`.
+
+    You can load a frame asynchronously by setting `async_loading_frames` to `True`.
+    """
+    if isinstance(video_path, str) and os.path.isdir(video_path):
+        jpg_folder = video_path
+    else:
+        raise NotImplementedError(
+            "Only JPEG frames are supported at this moment. For video files, you may use "
+            "ffmpeg (https://ffmpeg.org/) to extract frames into a folder of JPEG files, such as \n"
+            "```\n"
+            "ffmpeg -i .mp4 -q:v 2 -start_number 0 /'%05d.jpg'\n"
+            "```\n"
+            "where `-q:v` generates high-quality JPEG frames and `-start_number 0` asks "
+            "ffmpeg to start the JPEG file from 00000.jpg."
+        )
+
+    frame_names = [
+        p
+        for p in os.listdir(jpg_folder)
+        if os.path.splitext(p)[-1] in [".jpg", ".jpeg", ".JPG", ".JPEG"]
+    ]
+    frame_names.sort(key=lambda p: int(os.path.splitext(p)[0]))
+    num_frames = len(frame_names)
+    if num_frames == 0:
+        raise RuntimeError(f"no images found in {jpg_folder}")
+    img_paths = [os.path.join(jpg_folder, frame_name) for frame_name in frame_names]
+    img_mean = torch.tensor(img_mean, dtype=torch.float32)[:, None, None]
+    img_std = torch.tensor(img_std, dtype=torch.float32)[:, None, None]
+
+    if async_loading_frames:
+        lazy_images = AsyncVideoFrameLoader(
+            img_paths,
+            image_size,
+            offload_video_to_cpu,
+            img_mean,
+            img_std,
+            compute_device,
+        )
+        return lazy_images, lazy_images.video_height, lazy_images.video_width
+
+    images = torch.zeros(num_frames, 3, image_size, image_size, dtype=torch.float32)
+    for n, img_path in enumerate(tqdm(img_paths, desc="frame loading (JPEG)")):
+        images[n], video_height, video_width = _load_img_as_tensor(img_path, image_size)
+    if not offload_video_to_cpu:
+        images = images.to(compute_device)
+        img_mean = img_mean.to(compute_device)
+        img_std = img_std.to(compute_device)
+    # normalize by mean and std
+    images -= img_mean
+    images /= img_std
+    return images, video_height, video_width
+
+
+def load_video_frames_from_video_file(
+    video_path,
+    image_size,
+    offload_video_to_cpu,
+    img_mean=(0.485, 0.456, 0.406),
+    img_std=(0.229, 0.224, 0.225),
+    compute_device=torch.device("cuda"),
+):
+    """Load the video frames from a video file."""
+    import decord
+
+    img_mean = torch.tensor(img_mean, dtype=torch.float32)[:, None, None]
+    img_std = torch.tensor(img_std, dtype=torch.float32)[:, None, None]
+    # Get the original video height and width
+    decord.bridge.set_bridge("torch")
+    video_height, video_width, _ = decord.VideoReader(video_path).next().shape
+    # Iterate over all frames in the video
+    images = []
+    for frame in decord.VideoReader(video_path, width=image_size, height=image_size):
+        images.append(frame.permute(2, 0, 1))
+
+    images = torch.stack(images, dim=0).float() / 255.0
+    if not offload_video_to_cpu:
+        images = images.to(compute_device)
+        img_mean = img_mean.to(compute_device)
+        img_std = img_std.to(compute_device)
+    # normalize by mean and std
+    images -= img_mean
+    images /= img_std
+    return images, video_height, video_width
+
+
+def fill_holes_in_mask_scores(mask, max_area):
+    """
+    A post processor to fill small holes in mask scores with area under `max_area`.
+    """
+    # Holes are those connected components in background with area <= self.max_area
+    # (background regions are those with mask scores <= 0)
+    assert max_area > 0, "max_area must be positive"
+
+    input_mask = mask
+    try:
+        labels, areas = get_connected_components(mask <= 0)
+        is_hole = (labels > 0) & (areas <= max_area)
+        # We fill holes with a small positive mask score (0.1) to change them to foreground.
+        mask = torch.where(is_hole, 0.1, mask)
+    except Exception as e:
+        # Skip the post-processing step on removing small holes if the CUDA kernel fails
+        warnings.warn(
+            f"{e}\n\nSkipping the post-processing step due to the error above. You can "
+            "still use SAM 2 and it's OK to ignore the error above, although some post-processing "
+            "functionality may be limited (which doesn't affect the results in most cases; see "
+            "https://github.com/facebookresearch/sam2/blob/main/INSTALL.md).",
+            category=UserWarning,
+            stacklevel=2,
+        )
+        mask = input_mask
+
+    return mask
+
+
+def concat_points(old_point_inputs, new_points, new_labels):
+    """Add new points and labels to previous point inputs (add at the end)."""
+    if old_point_inputs is None:
+        points, labels = new_points, new_labels
+    else:
+        points = torch.cat([old_point_inputs["point_coords"], new_points], dim=1)
+        labels = torch.cat([old_point_inputs["point_labels"], new_labels], dim=1)
+
+    return {"point_coords": points, "point_labels": labels}
+
+
+def get_image_size(image: Union[np.ndarray, torch.Tensor]):
+    if isinstance(image, np.ndarray):
+        return image.shape[:2]
+    elif isinstance(image, torch.Tensor):
+        _, h, w = image.shape
+        return (h, w)
+    elif isinstance(image, Image):
+        w, h = image.size
+        return (h, w)
+    else:
+        raise NotImplementedError(
+            f"Only support np.ndarray, torch.Tensoror PIL Image, but got {type(image)}"
+        )
+
+
+def crop_image(
+    image: Union[np.ndarray, torch.Tensor], crop_box: Tuple[int, int, int, int]
+):
+    x0, y0, x1, y1 = crop_box
+    if isinstance(image, np.ndarray):
+        # HxWxC
+        return image[y0:y1, x0:x1, :]
+    elif isinstance(image, torch.Tensor):
+        # CxHxW
+        return image[:, y0:y1, x0:x1]
+    else:
+        raise ValueError(
+            "Expected image to be of type np.ndarray or "
+            f"torch.Tensor, but got {type(image)}"
+        )
diff --git a/lib/python3.12/site-packages/torchao/_models/sam2/utils/transforms.py b/lib/python3.12/site-packages/torchao/_models/sam2/utils/transforms.py
new file mode 100644
index 0000000000000000000000000000000000000000..c616233050bd5b2ab8d1ea873163f8253f68d20a
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/sam2/utils/transforms.py
@@ -0,0 +1,170 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import warnings
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+from torchvision.transforms import Normalize, Resize, ToTensor
+
+
+class SAM2Transforms(nn.Module):
+    def __init__(
+        self, resolution, mask_threshold, max_hole_area=0.0, max_sprinkle_area=0.0
+    ):
+        """
+        Transforms for SAM2.
+        """
+        super().__init__()
+        self.resolution = resolution
+        self.mask_threshold = mask_threshold
+        self.max_hole_area = max_hole_area
+        self.max_sprinkle_area = max_sprinkle_area
+        self.mean = [0.485, 0.456, 0.406]
+        self.std = [0.229, 0.224, 0.225]
+        self.to_tensor = ToTensor()
+        # self.transforms = torch.jit.script(
+        self.transforms = nn.Sequential(
+            Resize((self.resolution, self.resolution)),
+            Normalize(self.mean, self.std),
+        )
+
+    def __call__(self, x):
+        x = self.to_tensor(x)
+        return self.transforms(x)
+
+    def forward_batch(self, img_list):
+        img_batch = [self.transforms(self.to_tensor(img)) for img in img_list]
+        img_batch = torch.stack(img_batch, dim=0)
+        return img_batch
+
+    def transform_coords(
+        self, coords: torch.Tensor, normalize=False, orig_hw=None
+    ) -> torch.Tensor:
+        """
+        Expects a torch tensor with length 2 in the last dimension. The coordinates can be in absolute image or normalized coordinates,
+        If the coords are in absolute image coordinates, normalize should be set to True and original image size is required.
+
+        Returns
+            Un-normalized coordinates in the range of [0, 1] which is expected by the SAM2 model.
+        """
+        if normalize:
+            assert orig_hw is not None
+            h, w = orig_hw
+            coords = coords.clone()
+            coords[..., 0] = coords[..., 0] / w
+            coords[..., 1] = coords[..., 1] / h
+
+        coords = coords * self.resolution  # unnormalize coords
+        return coords
+
+    def transform_boxes(
+        self, boxes: torch.Tensor, normalize=False, orig_hw=None
+    ) -> torch.Tensor:
+        """
+        Expects a tensor of shape Bx4. The coordinates can be in absolute image or normalized coordinates,
+        if the coords are in absolute image coordinates, normalize should be set to True and original image size is required.
+        """
+        boxes = self.transform_coords(boxes.reshape(-1, 2, 2), normalize, orig_hw)
+        return boxes
+
+    def postprocess_masks(
+        self, masks: torch.Tensor, orig_hw, output_dtype
+    ) -> torch.Tensor:
+        """
+        Perform PostProcessing on output masks.
+        """
+        from torchao._models.sam2.utils.misc import get_connected_components
+
+        masks = masks.float()
+        input_masks = masks
+        mask_flat = masks.flatten(0, 1).unsqueeze(1)  # flatten as 1-channel image
+        try:
+            if self.max_hole_area > 0:
+                # Holes are those connected components in background with area <= self.fill_hole_area
+                # (background regions are those with mask scores <= self.mask_threshold)
+                labels, areas = get_connected_components(
+                    mask_flat <= self.mask_threshold
+                )
+                is_hole = (labels > 0) & (areas <= self.max_hole_area)
+                is_hole = is_hole.reshape_as(masks)
+                # We fill holes with a small positive mask score (10.0) to change them to foreground.
+                masks = torch.where(is_hole, self.mask_threshold + 10.0, masks)
+
+            if self.max_sprinkle_area > 0:
+                labels, areas = get_connected_components(
+                    mask_flat > self.mask_threshold
+                )
+                is_hole = (labels > 0) & (areas <= self.max_sprinkle_area)
+                is_hole = is_hole.reshape_as(masks)
+                # We fill holes with negative mask score (-10.0) to change them to background.
+                masks = torch.where(is_hole, self.mask_threshold - 10.0, masks)
+        except Exception as e:
+            # Skip the post-processing step if the CUDA kernel fails
+            warnings.warn(
+                f"{e}\n\nSkipping the post-processing step due to the error above. You can "
+                "still use SAM 2 and it's OK to ignore the error above, although some post-processing "
+                "functionality may be limited (which doesn't affect the results in most cases; see "
+                "https://github.com/facebookresearch/sam2/blob/main/INSTALL.md).",
+                category=UserWarning,
+                stacklevel=2,
+            )
+            masks = input_masks
+
+        masks = masks.to(output_dtype)
+        masks = F.interpolate(masks, orig_hw, mode="bilinear", align_corners=False)
+        return masks
+
+    def postprocess_masks_1_channel(
+        self, masks: torch.Tensor, orig_hw, output_dtype
+    ) -> torch.Tensor:
+        """
+        Perform PostProcessing on output masks.
+        """
+        from torchao._models.sam2.utils.misc import get_connected_components
+
+        assert masks.dim() == 4
+        assert masks.size(1) == 1
+        masks = masks.float()
+        input_masks = masks
+        # mask_flat = masks.flatten(0, 1).unsqueeze(1)  # flatten as 1-channel image
+        mask_flat = masks
+        try:
+            if self.max_hole_area > 0:
+                # Holes are those connected components in background with area <= self.fill_hole_area
+                # (background regions are those with mask scores <= self.mask_threshold)
+                labels, areas = get_connected_components(
+                    mask_flat <= self.mask_threshold
+                )
+                is_hole = (labels > 0) & (areas <= self.max_hole_area)
+                # is_hole = is_hole.reshape_as(masks)
+                # We fill holes with a small positive mask score (10.0) to change them to foreground.
+                masks = torch.where(is_hole, self.mask_threshold + 10.0, masks)
+
+            if self.max_sprinkle_area > 0:
+                labels, areas = get_connected_components(
+                    mask_flat > self.mask_threshold
+                )
+                is_hole = (labels > 0) & (areas <= self.max_sprinkle_area)
+                # is_hole = is_hole.reshape_as(masks)
+                # We fill holes with negative mask score (-10.0) to change them to background.
+                masks = torch.where(is_hole, self.mask_threshold - 10.0, masks)
+        except Exception as e:
+            # Skip the post-processing step if the CUDA kernel fails
+            warnings.warn(
+                f"{e}\n\nSkipping the post-processing step due to the error above. You can "
+                "still use SAM 2 and it's OK to ignore the error above, although some post-processing "
+                "functionality may be limited (which doesn't affect the results in most cases; see "
+                "https://github.com/facebookresearch/sam2/blob/main/INSTALL.md).",
+                category=UserWarning,
+                stacklevel=2,
+            )
+            masks = input_masks
+
+        masks = masks.to(output_dtype)
+        masks = F.interpolate(masks, orig_hw, mode="bilinear", align_corners=False)
+        return masks
diff --git a/lib/python3.12/site-packages/torchao/_models/utils.py b/lib/python3.12/site-packages/torchao/_models/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b46f06aa732211e92b25e8add24df22150752c5
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/_models/utils.py
@@ -0,0 +1,111 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import datetime
+import hashlib
+import json
+import os
+import platform
+import time
+
+import torch
+
+
+def get_arch_name() -> str:
+    if torch.cuda.is_available():
+        return torch.cuda.get_device_name()
+    else:
+        # This returns x86_64 or arm64 (for aarch64)
+        return platform.machine()
+
+
+def write_json_result_ossci(output_json_path, headers, row):
+    """
+    Write the result into JSON format, so that it can be uploaded to the benchmark database
+    to be displayed on OSS dashboard. The JSON format is defined at
+    https://github.com/pytorch/pytorch/wiki/How-to-integrate-with-PyTorch-OSS-benchmark-database
+
+    OSS CI version, that will leave many fields to be filled in by CI
+    """
+    mapping_headers = {headers[i]: v for i, v in enumerate(row)}
+    record = {
+        "benchmark": {
+            "name": "TorchAO benchmark",
+            "mode": "inference",
+            "dtype": mapping_headers["dtype"],
+            "extra_info": {
+                "device": mapping_headers["device"],
+                "arch": mapping_headers["arch"],
+                "min_sqnr": mapping_headers["min_sqnr"],
+                # True means compile is enabled, False means eager mode
+                "compile": mapping_headers["compile"],
+            },
+        },
+        "model": {
+            "name": mapping_headers["name"],
+            "type": "model",
+            "origins": ["torchao"],
+        },
+        "metric": {
+            "name": mapping_headers["metric"],
+            "benchmark_values": [mapping_headers["actual"]],
+            "target_value": mapping_headers["target"],
+        },
+    }
+
+    with open(f"{os.path.splitext(output_json_path)[0]}.json", "a") as f:
+        print(json.dumps(record), file=f)
+
+
+def write_json_result_local(output_json_path, headers, row):
+    """
+    Write the result into JSON format, so that it can be uploaded to the benchmark database
+    to be displayed on OSS dashboard. The JSON format is defined at
+    https://github.com/pytorch/pytorch/wiki/How-to-integrate-with-PyTorch-OSS-benchmark-database
+
+    Local version (filling in dummy values for fields that should be populated by CI)
+    """
+    mapping_headers = {headers[i]: v for i, v in enumerate(row)}
+    today = datetime.date.today()
+    sha_hash = hashlib.sha256(str(today).encode("utf-8")).hexdigest()
+    first_second = datetime.datetime.combine(today, datetime.time.min)
+    workflow_id = int(first_second.timestamp())
+    job_id = workflow_id + 1
+    record = {
+        "timestamp": int(time.time()),
+        "schema_version": "v3",
+        "name": "devvm local benchmark",
+        "repo": "pytorch/ao",
+        "head_branch": "main",
+        "head_sha": sha_hash,
+        "workflow_id": workflow_id,
+        "run_attempt": 1,
+        "job_id": job_id,
+        "benchmark": {
+            "name": "TorchAO benchmark",
+            "mode": "inference",
+            "dtype": mapping_headers["dtype"],
+            "extra_info": {
+                "device": mapping_headers["device"],
+                "arch": mapping_headers["arch"],
+                "min_sqnr": mapping_headers["min_sqnr"],
+                # True means compile is enabled, False means eager mode
+                "compile": mapping_headers["compile"],
+            },
+        },
+        "model": {
+            "name": mapping_headers["name"],
+            "type": "model",
+            "origins": ["torchao"],
+        },
+        "metric": {
+            "name": mapping_headers["metric"],
+            "benchmark_values": [mapping_headers["actual"]],
+            "target_value": mapping_headers["target"],
+        },
+    }
+
+    with open(f"{os.path.splitext(output_json_path)[0]}.json", "a") as f:
+        print(json.dumps(record), file=f)
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/fp6_llm/fp6_linear.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/fp6_llm/fp6_linear.cu
new file mode 100644
index 0000000000000000000000000000000000000000..26f649422045097c1238f49fd780ffa8ca7788f1
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/fp6_llm/fp6_linear.cu
@@ -0,0 +1,293 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+//    Copyright 2024 FP6-LLM authors
+//
+//    Licensed under the Apache License, Version 2.0 (the "License");
+//    you may not use this file except in compliance with the License.
+//    You may obtain a copy of the License at
+//
+//        http://www.apache.org/licenses/LICENSE-2.0
+//
+//    Unless required by applicable law or agreed to in writing, software
+//    distributed under the License is distributed on an "AS IS" BASIS,
+//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//    See the License for the specific language governing permissions and
+//    limitations under the License.
+//
+// This file is adapted from https://github.com/usyd-fsalab/fp6_llm/blob/5df6737cca32f604e957e3f63f03ccc2e4d1df0d/fp6_llm/csrc/fp6_linear.cu
+//
+// MODIFICATION NOTE (2024-09-25): added SM75 support (https://github.com/pytorch/ao/pull/942):
+// - Modified the TilingConfig parameters for SM75 to deal with smaller shared memory
+// - Added proper architecture check at both host and device level
+//
+
+
+#include "kernel_matmul.cuh"
+#include "kernel_reduction.cuh"
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+
+// https://github.com/Dao-AILab/flash-attention/blob/478ee666cccbd1b8f63648633003059a8dc6827d/hopper/utils.h#L25
+#define CHECK_CUDA(call)                                                                                  \
+    do {                                                                                                  \
+        cudaError_t status_ = call;                                                                       \
+        if (status_ != cudaSuccess) {                                                                     \
+            fprintf(stderr, "CUDA error (%s:%d): %s\n", __FILE__, __LINE__, cudaGetErrorString(status_)); \
+            exit(1);                                                                                      \
+        }                                                                                                 \
+    } while(0)
+
+#define CHECK_CUDA_KERNEL_LAUNCH() CHECK_CUDA(cudaGetLastError())
+
+
+template
+static void Kernel_Ex(cudaStream_t    stream,
+                      const uint4     *Weight,
+                      const half      *Scales,
+                      const half      *B,
+                      OutputDataType  *C,
+                      const size_t    M_Global,
+                      const size_t    N_Global,
+                      const size_t    K_Global,
+                      int             Split_K)
+{
+    #ifdef DEBUG_MODE
+        printf("\n");
+        printf("Launcher.cu->Kernel_Ex():\n");
+        printf("M: %d, N: %d, K: %d, SplitK: %d\n", M_Global, N_Global, K_Global, Split_K);
+        printf("TILE_M: %d, TILE_K: %d, TILE_N: %d\n", TilingConfig::TILE_M, TilingConfig::TILE_K, TilingConfig::TILE_N);
+    #endif
+    static size_t SHMEM_SZ = max(TilingConfig::SMEM_SIZE_B_TILE+SMEM_SIZE_PER_TB_A_TILE, TilingConfig::SMEM_SIZE_C_TILE);
+    cudaFuncSetAttribute(QUANT_GEMM_Kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, SHMEM_SZ);
+    size_t  dimN = (N_Global-1) / TilingConfig::TILE_N + 1;
+    size_t  dimM = M_Global * Split_K / TilingConfig::TILE_M;
+    dim3    GridDim(dimN, dimM, 1);
+    dim3    BlockDim(WARP_SIZE * TilingConfig::BLOCK_WARPS, 1, 1);
+    //
+    #ifdef DEBUG_MODE
+        printf("GridDim.x: %d, GridDim.y: %d, GridDim.z: %d, BlockDim.x: %d, BlockDim.y: %d, BlockDim.z: %d SHMEM_SZ: %d\n",
+                GridDim.x, GridDim.y, GridDim.z, BlockDim.x, BlockDim.y, BlockDim.z, SHMEM_SZ);
+        printf("\n");
+    #endif
+    QUANT_GEMM_Kernel<<>>
+                    (Weight, Scales, B, C, M_Global, N_Global, K_Global, Split_K);
+    CHECK_CUDA_KERNEL_LAUNCH();
+}
+
+template
+void        fpx_linear_kernel(cudaStream_t    stream,
+                              const uint4     *Weight,
+                              const half      *Scales,
+                              const half      *B,
+                              InputDataType   *C,
+                              const size_t    M_Global,
+                              const size_t    N_Global,
+                              const size_t    K_Global,
+                              float           *Reduction_Workspace,  // Reduction_Workspace_Size = Split_K * M_Global * N_Global * sizeof(fp32)
+                              int             Split_K)
+{
+    static_assert(std::is_same::value || std::is_same::value, "Type must be 'half' or '__nv_bfloat16'");
+    assert(M_Global % 256 == 0);
+    assert(K_Global % 64 == 0);
+    assert(N_Global > 0);
+
+    // Check GPU Compute Capability before proceeding
+    int device, major, minor;
+    CHECK_CUDA(cudaGetDevice(&device));
+    CHECK_CUDA(cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, device));
+    CHECK_CUDA(cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, device));
+
+    // Early exit with error for unsupported architectures
+    if ((major < 7) || (major == 7 && minor < 5)) {
+        TORCH_CHECK(false, "Quant-LLM Error: This kernel requires GPU with SM75 (Turing) or higher architecture. "
+                         "Your current device has SM", major, minor, " which is not supported.");
+    }
+
+    const bool is_sm75_gpu = (major == 7) && (minor == 5);
+    if (is_sm75_gpu && std::is_same::value) {
+        TORCH_CHECK(false, "Quant-LLM Error: BFloat16 inputs are not supported on SM75 (Turing) GPUs.");
+    }
+
+    // Work around to support more N shapes:
+    size_t N_PowerOf2;
+    if(N_Global>0 &&  N_Global<=8)      N_PowerOf2 = 8;
+    if(N_Global>8 &&  N_Global<=16)     N_PowerOf2 = 16;
+    if(N_Global>16 && N_Global<=32)     N_PowerOf2 = 32;
+    if(N_Global>32 && N_Global<=64)     N_PowerOf2 = 64;
+    if(N_Global>64 && N_Global<=128)    N_PowerOf2 = 128;
+    if(N_Global>128)                    N_PowerOf2 = ((N_Global-1)/128+1) * 128;
+
+    if (is_sm75_gpu && (N_PowerOf2 == 64 || N_PowerOf2 == 128 || N_PowerOf2 % 128 == 0)) {
+        // For SM75 and N >= 64, we use a different TilingConfig to deal with smaller shared memory.
+        if (Split_K == 1) {
+            Kernel_Ex, InputDataType, InputDataType, EXPONENT, MANTISSA>(stream, Weight, Scales, B, C, M_Global, N_Global, K_Global, Split_K);
+        } else {
+            Kernel_Ex, InputDataType, float, EXPONENT, MANTISSA>(stream, Weight, Scales, B, Reduction_Workspace, M_Global, N_Global, K_Global, Split_K);
+        }
+    } else {
+        if (Split_K == 1) {
+            switch (N_PowerOf2) {
+                case 8:     Kernel_Ex, InputDataType, InputDataType, EXPONENT, MANTISSA>(stream, Weight, Scales, B, C, M_Global, N_Global, K_Global, Split_K);  break;
+                case 16:    Kernel_Ex, InputDataType, InputDataType, EXPONENT, MANTISSA>(stream, Weight, Scales, B, C, M_Global, N_Global, K_Global, Split_K);  break;
+                case 32:    Kernel_Ex, InputDataType, InputDataType, EXPONENT, MANTISSA>(stream, Weight, Scales, B, C, M_Global, N_Global, K_Global, Split_K);  break;
+                case 64:    Kernel_Ex, InputDataType, InputDataType, EXPONENT, MANTISSA>(stream, Weight, Scales, B, C, M_Global, N_Global, K_Global, Split_K);  break;
+                case 128:   Kernel_Ex, InputDataType, InputDataType, EXPONENT, MANTISSA>(stream, Weight, Scales, B, C, M_Global, N_Global, K_Global, Split_K);  break;
+                default:    if (N_PowerOf2 % 128 != 0) {
+                                TORCH_CHECK(false, "Quant-LLM Error: Unsupported N dimension ", N_PowerOf2);
+                            }
+                            Kernel_Ex, InputDataType, InputDataType, EXPONENT, MANTISSA>(stream, Weight, Scales, B, C, M_Global, N_Global, K_Global, Split_K);  break;
+            }
+        }
+        else {
+            switch (N_PowerOf2) {
+                case 8:     Kernel_Ex, InputDataType, float, EXPONENT, MANTISSA>(stream, Weight, Scales, B, Reduction_Workspace, M_Global, N_Global, K_Global, Split_K);  break;
+                case 16:    Kernel_Ex, InputDataType, float, EXPONENT, MANTISSA>(stream, Weight, Scales, B, Reduction_Workspace, M_Global, N_Global, K_Global, Split_K);  break;
+                case 32:    Kernel_Ex, InputDataType, float, EXPONENT, MANTISSA>(stream, Weight, Scales, B, Reduction_Workspace, M_Global, N_Global, K_Global, Split_K);  break;
+                case 64:    Kernel_Ex, InputDataType, float, EXPONENT, MANTISSA>(stream, Weight, Scales, B, Reduction_Workspace, M_Global, N_Global, K_Global, Split_K);  break;
+                case 128:   Kernel_Ex, InputDataType, float, EXPONENT, MANTISSA>(stream, Weight, Scales, B, Reduction_Workspace, M_Global, N_Global, K_Global, Split_K);  break;
+                default:    if (N_PowerOf2 % 128 != 0) {
+                                TORCH_CHECK(false, "Quant-LLM Error: Unsupported N dimension ", N_PowerOf2);
+                            }
+                            Kernel_Ex, InputDataType, float, EXPONENT, MANTISSA>(stream, Weight, Scales, B, Reduction_Workspace, M_Global, N_Global, K_Global, Split_K);  break;
+            }
+        }
+    }
+
+    if (Split_K != 1) {
+        // Reduction for SplitK
+        dim3 GridDim((M_Global * N_Global) / REDUCTION_ELEMENT_PER_THREADBLOCK, 1, 1);
+        dim3 BlockDim(WARP_SIZE, 1, 1);
+        SplitK_Reduction<<>>(C, Reduction_Workspace, M_Global, N_Global, Split_K);
+        CHECK_CUDA_KERNEL_LAUNCH();
+    }
+}
+
+
+// https://github.com/NVIDIA/apex/blob/master/csrc/type_shim.h
+#define DISPATCH_HALF_AND_BF16(TYPE, NAME, ...)                                \
+  switch (TYPE) {                                                              \
+  case at::ScalarType::Half: {                                                 \
+    using torch_t = at::Half;                                                  \
+    using nv_t = half;                                                         \
+    __VA_ARGS__();                                                             \
+    break;                                                                     \
+  }                                                                            \
+  case at::ScalarType::BFloat16: {                                             \
+    using torch_t = at::BFloat16;                                              \
+    using nv_t = __nv_bfloat16;                                                \
+    __VA_ARGS__();                                                             \
+    break;                                                                     \
+  }                                                                            \
+  default:                                                                     \
+    AT_ERROR(#NAME, " not implemented for '", toString(TYPE), "'");            \
+  }
+
+namespace torchao {
+// MODIFICATION NOTE: dtype of _weights is changed to uint8
+/*
+Computes FPx-FP16 GEMM (PyTorch interface).
+
+[Mathmatical Formula]
+Standard definition of linear layer:    Out = In * trans(W), where In, Out, and W are stored in row-major.
+After Equivalent transformation    :    trans(Out) = W * trans(In). Note that we do not perform "transpose" during runtime, we instead interpret the In/Out as column-major matrices when calling our CUDA kernel.
+
+[Inputs]
+  _in_feats:  tensor of shape [B, IC];                  // half or bf16
+  _weights:   int tensor of shape [OC, IC // 8 * x];    // x UINT8 words contains 8 FPx weights.
+  _scales:    tensor of shape [OC];                     // half or bf16
+  splitK:     spliting the MatMul problem along K dimension for higher GPU utilization, default 1.
+[Outputs]
+  _out_feats: tensor of shape [B, OC];                  // half or bf16
+*/
+torch::Tensor fp_eXmY_linear_forward_cuda(
+    int64_t         EXPONENT,
+    int64_t         MANTISSA,
+    torch::Tensor   _in_feats,
+    torch::Tensor   _weights,
+    torch::Tensor   _scales,
+    int64_t         splitK=1)
+{
+    // Check GPU Compute Capability before proceeding
+    int device, major, minor;
+    CHECK_CUDA(cudaGetDevice(&device));
+    CHECK_CUDA(cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, device));
+    CHECK_CUDA(cudaDeviceGetAttribute(&minor, cudaDevAttrComputeCapabilityMinor, device));
+
+    // Early exit with error for unsupported architectures
+    if ((major < 7) || (major == 7 && minor < 5)) {
+        TORCH_CHECK(false, "Quant-LLM Error: This kernel requires GPU with SM75 (Turing) or higher architecture. "
+                         "Your current device has SM", major, minor, " which is not supported.");
+    }
+
+    const bool is_sm75_gpu = (major == 7) && (minor == 5);
+    if (is_sm75_gpu && _in_feats.scalar_type() == at::ScalarType::BFloat16) {
+        TORCH_CHECK(false, "Quant-LLM Error: BFloat16 inputs are not supported on SM75 (Turing) GPUs.");
+    }
+
+    const int64_t NBITS   = 1 + EXPONENT + MANTISSA;
+    int num_in_feats      = _in_feats.size(0);
+    int num_in_channels   = _in_feats.size(1);
+    int num_out_channels  = _weights.size(0);
+    TORCH_CHECK(num_in_channels % 64 == 0, "Expected in_features to be a multiple of 64, but received ", num_in_channels);
+    TORCH_CHECK((num_in_channels / 8 * NBITS) == _weights.size(1));    // Making sure the K dimension is matched.
+    //
+    int M = num_out_channels;
+    int K = num_in_channels;
+    int N = num_in_feats;
+    auto options = torch::TensorOptions().dtype(_in_feats.dtype()).device(_in_feats.device());
+    at::Tensor _out_feats = torch::empty({num_in_feats, num_out_channels}, options);
+
+    options = torch::TensorOptions().dtype(torch::kFloat32).device(_in_feats.device());
+    at::Tensor _workspace = torch::empty({splitK, num_in_feats, num_out_channels}, options);
+    auto Reduction_Workspace = reinterpret_cast(_workspace.data_ptr());  // Reduction_Workspace_Size = Split_K * M_Global * N_Global * sizeof(fp32)
+
+    // MODIFICATION NOTE: use at::cuda::getCurrentCUDAStream() instead of default stream (0)
+    // this fixes problem with CUDA graphs when used with torch.compile()
+    auto stream = at::cuda::getCurrentCUDAStream();
+
+    DISPATCH_HALF_AND_BF16(_in_feats.scalar_type(), "fpx_linear_kernel", [&] {
+        auto weight = reinterpret_cast(_weights.data_ptr());  // weights is [OC, IC] but in FP6.
+        auto in_feats = reinterpret_cast(_in_feats.data_ptr());
+        auto scales = reinterpret_cast(_scales.data_ptr());
+        auto out_feats = reinterpret_cast(_out_feats.data_ptr());
+
+        // officially supported in Quant-LLM
+        if (EXPONENT == 3 && MANTISSA == 2)
+            fpx_linear_kernel(stream, weight, scales, in_feats, out_feats, M, N, K, Reduction_Workspace, splitK);
+        else if (EXPONENT == 2 && MANTISSA == 2)
+            fpx_linear_kernel(stream, weight, scales, in_feats, out_feats, M, N, K, Reduction_Workspace, splitK);
+
+        // experimental
+        else if (EXPONENT == 2 && MANTISSA == 3)
+            fpx_linear_kernel(stream, weight, scales, in_feats, out_feats, M, N, K, Reduction_Workspace, splitK);
+        else if (EXPONENT == 3 && MANTISSA == 1)
+            fpx_linear_kernel(stream, weight, scales, in_feats, out_feats, M, N, K, Reduction_Workspace, splitK);
+        // else if (EXPONENT == 2 && MANTISSA == 1)
+        //     fpx_linear_kernel(stream, weight, scales, in_feats, out_feats, M, N, K, Reduction_Workspace, splitK);
+        // else if (EXPONENT == 3 && MANTISSA == 0)
+        //     fpx_linear_kernel(stream, weight, scales, in_feats, out_feats, M, N, K, Reduction_Workspace, splitK);
+        // else if (EXPONENT == 2 && MANTISSA == 0)
+        //     fpx_linear_kernel(stream, weight, scales, in_feats, out_feats, M, N, K, Reduction_Workspace, splitK);
+
+        else
+            TORCH_CHECK(false, "FP", NBITS, " E", EXPONENT, "M", MANTISSA, " is not supported.");
+    });
+
+    return _out_feats;
+}
+
+TORCH_LIBRARY_IMPL(torchao, CUDA, m) {
+  m.impl("torchao::quant_llm_linear", &fp_eXmY_linear_forward_cuda);
+}
+
+} // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/marlin_qqq/marlin_qqq_kernel.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/marlin_qqq/marlin_qqq_kernel.cu
new file mode 100644
index 0000000000000000000000000000000000000000..bd24af7a2c7c14c3665aeef1d7c963d8f2b3494b
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/marlin_qqq/marlin_qqq_kernel.cu
@@ -0,0 +1,1218 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+/*
+ * Adapted from
+ * https://github.com/IST-DASLab/marlin/blob/master/marlin/marlin_cuda_kernel.cu
+ * https://github.com/IST-DASLab/marlin/blob/master/marlin/marlin_cuda.cpp
+ * Modified by HandH1998
+ * Copyright (C) 2024 HandH1998
+ * Copyright (C) Marlin.2024 Elias Frantar
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include "base.h"
+#include "mem.h"
+
+template 
+inline std::string str(T x) {
+  return std::to_string(x);
+}
+
+namespace torchao {
+
+using I4 = Vec;
+// Matrix fragments for tensor core instructions; their precise layout is
+// documented here:
+// https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#matrix-fragments-for-mma-m16n8k16-with-integer-type
+using FragA = Vec;
+using FragB = Vec;
+using FragC = Vec;
+using FragS_GROUP = Vec;  // weight per-group quantization scales
+using FragS_CHANNEL =
+    Vec;  // weight per-channel quantization scales or activaton
+                    // per-token quantization scales
+
+// NOTE(HandH1998): cp.async.cg only support BYTES = 16, however,
+// cp.async.ca can support BYTES = 4, 8, 16;
+// as s_tok's shape is equal to prob_m, we need set s_tok to float type,
+// and cp_size = 1 float, i.e., 4 BYTES
+// Asynchronous global->shared copy for activation quantizaton scales s_tok
+__device__ inline void cp_async1(void* smem_ptr, const void* glob_ptr) {
+  const int BYTES = 4;
+  uint32_t smem = static_cast(__cvta_generic_to_shared(smem_ptr));
+  asm volatile(
+      "{\n"
+      "   cp.async.ca.shared.global [%0], [%1], %2;\n"
+      "}\n" ::"r"(smem),
+      "l"(glob_ptr), "n"(BYTES));
+}
+
+// m16n8k16 tensor core mma instruction with int8 inputs and int32
+// output/accumulation.
+__device__ inline void mma(const FragA& a_frag, const FragB& frag_b,
+                           FragC& frag_c) {
+  const uint32_t* a = reinterpret_cast(&a_frag);
+  const uint32_t* b = reinterpret_cast(&frag_b);
+  int* c = reinterpret_cast(&frag_c);
+  asm volatile(
+      "mma.sync.aligned.m16n8k16.row.col.satfinite.s32.s8.s8.s32 "
+      "{%0,%1,%2,%3}, {%4,%5}, {%6}, {%7,%8,%9,%10};\n"
+      : "=r"(c[0]), "=r"(c[1]), "=r"(c[2]), "=r"(c[3])
+      : "r"(a[0]), "r"(a[1]), "r"(b[0]), "r"(c[0]), "r"(c[1]), "r"(c[2]),
+        "r"(c[3]));
+}
+
+// Instruction for loading a full 16x16 matrix fragment of operand A from shared
+// memory, directly in int8 tensor core layout.
+__device__ inline void ldsm4(FragA& frag_a, const void* smem_ptr) {
+  uint32_t* a = reinterpret_cast(&frag_a);
+  uint32_t smem = static_cast(__cvta_generic_to_shared(smem_ptr));
+  asm volatile("ldmatrix.sync.aligned.m8n8.x2.shared.b16 {%0,%1}, [%2];\n"
+               : "=r"(a[0]), "=r"(a[1])
+               : "r"(smem));
+}
+
+inline __device__ half2 float2_to_half2(float2 f) {
+  uint32_t res;
+  // NOTE(HandH1998): h0,h1 should be uint16_t, not half
+  uint16_t h0, h1;
+  asm volatile("cvt.rn.f16.f32 %0, %1;\n" : "=h"(h0) : "f"(f.x));
+  asm volatile("cvt.rn.f16.f32 %0, %1;\n" : "=h"(h1) : "f"(f.y));
+  asm volatile("mov.b32 %0, {%1, %2};\n" : "=r"(res) : "h"(h0), "h"(h1));
+  return reinterpret_cast(res);
+}
+
+inline __device__ float int32_to_float(int h) {
+  float res;
+  asm volatile("cvt.rn.f32.s32 %0, %1;\n" : "=f"(res) : "r"(h));
+  return res;
+}
+
+// Lookup-table based 3-input logical operation; explicitly used for
+// dequantization as the compiler does not seem to automatically recognize it in
+// all cases.
+template 
+__device__ inline int lop3(int a, int b, int c) {
+  int res;
+  asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
+               : "=r"(res)
+               : "r"(a), "r"(b), "r"(c), "n"(lut));
+  return res;
+}
+
+// Efficiently dequantize an int32 value into a full B-fragment of 4 int8 values
+// for weight per channel dequant.
+__device__ inline FragB dequant_per_channel(int q) {
+  static constexpr int MASK = 0xf0f0f0f0;
+  FragB frag_b;
+  frag_b[0] = (q & MASK);
+  return frag_b;
+}
+
+// Efficiently dequantize an int32 value into a full B-fragment of 4 int8 values
+// for weight per group dequant.
+__device__ inline FragB dequant_per_group(int q, FragS_GROUP& frag_s, int i) {
+  static constexpr uint32_t LO = 0x000f000f;
+  static constexpr uint32_t HI = 0x00f000f0;
+  static constexpr uint32_t EX = 0x64006400;
+  // Guarantee that the `(a & b) | c` operations are LOP3s.
+  uint32_t t0 = lop3<(0xf0 & 0xcc) | 0xaa>(q, LO, EX);
+  uint32_t t1 = lop3<(0xf0 & 0xcc) | 0xaa>(q, HI, EX);
+  // We want signed int4 outputs, hence we fuse the `-8` symmetric zero point
+  // directly into `SUB` and `ADD`.
+  static constexpr uint32_t SUB = 0x64086408;
+  static constexpr uint32_t MUL = 0x2c002c00;
+  static constexpr uint32_t ADD = 0xd480d480;
+  *reinterpret_cast(&t0) = __hsub2(
+      *reinterpret_cast(&t0), *reinterpret_cast(&SUB));
+  *reinterpret_cast(&t1) = __hfma2(
+      *reinterpret_cast(&t1), *reinterpret_cast(&MUL),
+      *reinterpret_cast(&ADD));
+
+  uint16_t s = reinterpret_cast(&frag_s)[i];
+  uint32_t double_s;
+  // pack 2xfp16 to half2
+  asm volatile("mov.b32 %0, {%1, %2};\n" : "=r"(double_s) : "h"(s), "h"(s));
+  // dequant and convert 4 half to 4 uint8 (be placed at the low 8 bits of 4
+  // half, respectively)
+  static constexpr uint32_t MAGIC_NUM = 0x64806480;
+  *reinterpret_cast(&t0) = __hfma2(
+      *reinterpret_cast(&t0), *reinterpret_cast(&double_s),
+      *reinterpret_cast(&MAGIC_NUM));
+  *reinterpret_cast(&t1) = __hfma2(
+      *reinterpret_cast(&t1), *reinterpret_cast(&double_s),
+      *reinterpret_cast(&MAGIC_NUM));
+  // take out the 4 uint8 from 4 half, then convert them to 4 int8 and pack 4
+  // int8 into 1 uint32
+  FragB frag_b;
+  uint32_t uint8s;
+  static constexpr uint32_t MASK_0246 = 0x6420;
+  static constexpr uint32_t UINT8s_TO_INT8s_MASK = 0x80808080;
+  asm volatile("prmt.b32 %0,%1,%2,%3;\n"
+               : "=r"(uint8s)
+               : "r"(t0), "r"(t1), "n"(MASK_0246));
+  frag_b[0] = (uint8s ^ UINT8s_TO_INT8s_MASK);
+  return frag_b;
+}
+
+template shared
+                             // fetch pipeline
+          const int group_blocks = -1  // number of consecutive 16x16 blocks
+                                       // with a separate quantization scale
+          >
+__global__ void Marlin_QQQ(
+    const int4* __restrict__ A,  // int8 input matrix of shape mxk
+    const int4* __restrict__ B,  // 4bit quantized weight matrix of shape kxn
+    int4* __restrict__ C,        // int32 global_reduce buffer of shape
+                           // (max_par*16*4)xn, as int8 tensor core's output is
+                           // int32 dtype
+    int4* __restrict__ D,              // fp16 output buffer of shape mxn
+    const float* __restrict__ s_tok,   // fp32 activation per-token quantization
+                                       // scales of shape mx1
+    const int4* __restrict__ s_ch,     // fp32 weight per-channel quantization
+                                       // scales of shape 1xn
+    const int4* __restrict__ s_group,  // fp16 weight per-group quantization
+                                       // scales of shape (k/groupsize)xn, when
+                                       // group_blocks=-1, it should be nullptr
+    int prob_m,                        // batch dimension m
+    int prob_n,                        // output dimension n
+    int prob_k,                        // reduction dimension k
+    int* locks  // extra global storage for barrier synchronization
+) {
+  // host code or device code with SM >= 80. Marlin only supports SM >= 80.
+#if !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 800
+  // Each threadblock processes one "stripe" of the B matrix with (roughly) the
+  // same size, which might involve multiple column "slices" (of width 16 *
+  // `thread_n_blocks`). Stripes are defined as shown in the 3x3 matrix 5 SM
+  // example:
+  //   0 1 3
+  //   0 2 3
+  //   1 2 4
+  // While this kind of partitioning makes things somewhat more complicated, it
+  // ensures good utilization of all SMs for many kinds of shape and GPU
+  // configurations, while requiring as few slow global cross-threadblock
+  // reductions as possible.
+
+  // For larger GEMMs we run multiple batchsize 64 versions in parallel for a
+  // better partitioning with less reductions
+  int parallel = 1;
+  if (prob_m > 16 * thread_m_blocks) {
+    parallel = prob_m / (16 * thread_m_blocks);
+    prob_m = 16 * thread_m_blocks;
+  }
+
+  int k_tiles = prob_k / 16 / thread_k_blocks;
+  int n_tiles = prob_n / 16 / thread_n_blocks;
+  int iters = ceildiv(k_tiles * n_tiles * parallel, gridDim.x);
+  // Ensure that the number of tiles in each stripe is a multiple of the
+  // groupsize; this avoids an annoying special case where a stripe starts in
+  // the middle of group.
+  if constexpr (group_blocks != -1)
+    iters = (group_blocks / thread_k_blocks) *
+            ceildiv(iters, (group_blocks / thread_k_blocks));
+
+  int slice_row = (iters * blockIdx.x) % k_tiles;
+  int slice_col_par = (iters * blockIdx.x) / k_tiles;
+  int slice_col = slice_col_par;
+  int slice_iters;  // number of threadblock tiles in the current slice
+  int slice_count =
+      0;          // total number of active threadblocks in the current slice
+  int slice_idx;  // index of threadblock in current slice; numbered bottom to
+                  // top
+
+  // We can easily implement parallel problem execution by just remapping
+  // indices and advancing global pointers
+  if (slice_col_par >= n_tiles) {
+    A += (slice_col_par / n_tiles) * 16 * thread_m_blocks * prob_k / 16;
+    C += (slice_col_par / n_tiles) * 16 * thread_m_blocks * prob_n / 4;
+    D += (slice_col_par / n_tiles) * 16 * thread_m_blocks * prob_n / 8;
+    s_tok += (slice_col_par / n_tiles) * 16 * thread_m_blocks;
+    locks += (slice_col_par / n_tiles) * n_tiles;
+    slice_col = slice_col_par % n_tiles;
+  }
+
+  // Compute all information about the current slice which is required for
+  // synchronization.
+  auto init_slice = [&]() {
+    slice_iters =
+        iters * (blockIdx.x + 1) - (k_tiles * slice_col_par + slice_row);
+    if (slice_iters < 0 || slice_col_par >= n_tiles * parallel) slice_iters = 0;
+    if (slice_iters == 0) return;
+    if (slice_row + slice_iters > k_tiles) slice_iters = k_tiles - slice_row;
+    slice_count = 1;
+    slice_idx = 0;
+    int col_first = iters * ceildiv(k_tiles * slice_col_par, iters);
+    if (col_first <= k_tiles * (slice_col_par + 1)) {
+      int col_off = col_first - k_tiles * slice_col_par;
+      slice_count = ceildiv(k_tiles - col_off, iters);
+      if (col_off > 0) slice_count++;
+      int delta_first = iters * blockIdx.x - col_first;
+      if (delta_first < 0 || (col_off == 0 && delta_first == 0))
+        slice_idx = slice_count - 1;
+      else {
+        slice_idx = slice_count - 1 - delta_first / iters;
+        if (col_off > 0) slice_idx--;
+      }
+    }
+    if (slice_col == n_tiles) {
+      A += 16 * thread_m_blocks * prob_k / 16;
+      C += 16 * thread_m_blocks * prob_n / 4;
+      D += 16 * thread_m_blocks * prob_n / 8;
+      s_tok += 16 * thread_m_blocks;
+      locks += n_tiles;
+      slice_col = 0;
+    }
+  };
+  init_slice();
+
+  int a_gl_stride = prob_k / 16;  // stride of the A matrix in global memory
+  // We typically use `constexpr` to indicate that this value is a compile-time
+  // constant
+  constexpr int a_sh_stride =
+      16 * thread_k_blocks / 16;  // stride of an A matrix tile in shared memory
+  constexpr int a_gl_rd_delta_o =
+      16 * thread_k_blocks /
+      16;  // delta between subsequent A tiles in global memory
+  int a_gl_rd_delta_i =
+      a_gl_stride *
+      (threads / a_gl_rd_delta_o);  // between subsequent accesses within a tile
+  constexpr int a_sh_wr_delta =
+      a_sh_stride *
+      (threads / a_gl_rd_delta_o);  // between shared memory writes
+  constexpr int a_sh_rd_delta_o =
+      1 * ((threads / 32) /
+           (thread_n_blocks / 4));  // between shared memory tile reads
+  constexpr int a_sh_rd_delta_i =
+      a_sh_stride * 16;  // within a shared memory tile
+  constexpr int a_sh_stage =
+      a_sh_stride * (16 * thread_m_blocks);  // overall size of a tile
+  constexpr int a_sh_wr_iters =
+      ceildiv(a_sh_stage,
+              a_sh_wr_delta);  // number of shared write iterations for a tile
+
+  int b_gl_stride = 16 * prob_n / 32;
+  constexpr int b_sh_stride = 32 * thread_n_blocks / 4;
+  int b_gl_rd_delta_o = b_gl_stride * thread_k_blocks;
+  int b_gl_rd_delta_i = b_gl_stride * (threads / b_sh_stride);
+  constexpr int b_sh_wr_delta = threads;
+  constexpr int b_sh_rd_delta = threads;
+  constexpr int b_sh_stage = b_sh_stride * thread_k_blocks;
+  constexpr int b_sh_wr_iters = b_sh_stage / b_sh_wr_delta;
+
+  constexpr int s_tok_sh_stride = 16 * thread_m_blocks;
+
+  constexpr int s_ch_sh_stride = 16 * thread_n_blocks / 4;
+
+  int s_group_gl_stride = prob_n / 8;
+  constexpr int s_group_sh_stride = 16 * thread_n_blocks / 8;
+  constexpr int s_group_sh_stage = s_group_sh_stride;
+  int s_group_gl_rd_delta = s_group_gl_stride;
+
+  // Global A read index of current thread.
+  int a_gl_rd = a_gl_stride * (threadIdx.x / a_gl_rd_delta_o) +
+                (threadIdx.x % a_gl_rd_delta_o);
+  a_gl_rd += a_gl_rd_delta_o * slice_row;
+  // Shared write index of current thread.
+  int a_sh_wr = a_sh_stride * (threadIdx.x / a_gl_rd_delta_o) +
+                (threadIdx.x % a_gl_rd_delta_o);
+  // Shared read index.
+  // NOTE(HandH1998): int8 input a only need 16 threads to load 16x16 matrix
+  int a_sh_rd = a_sh_stride * ((threadIdx.x % 32) % 16);
+  a_sh_rd += 1 * ((threadIdx.x / 32) / (thread_n_blocks / 4));
+
+  int b_gl_rd =
+      b_gl_stride * (threadIdx.x / b_sh_stride) + (threadIdx.x % b_sh_stride);
+  b_gl_rd += b_sh_stride * slice_col;
+  b_gl_rd += b_gl_rd_delta_o * slice_row;
+  int b_sh_wr = threadIdx.x;
+  int b_sh_rd = threadIdx.x;
+
+  int s_tok_gl_rd = threadIdx.x;
+  // NOTE(HandH1998): activation scale s_tok need shuffle to [0, 8, 1, 9, 2, 10,
+  // 3, 11, 4, 12, 5, 13, 6, 14, 7, 15] for example, 0, 8 row scales serve for
+  // thread 0, 1, 2, 3. For more details, refer to mma operand A layout as
+  // s_tok's size is not fixed, we can not shuffle before inference we shuffle
+  // it when fetching s_tok from global memory to shared memory, that's why
+  // s_tok_sh_wr is like this
+  int s_tok_sh_wr =
+      (threadIdx.x / 16) * 16 + (threadIdx.x % 8) * 2 + (threadIdx.x % 16) / 8;
+  int s_tok_sh_rd = (threadIdx.x % 32) / 4;
+  bool s_tok_sh_wr_pred = threadIdx.x < prob_m;
+
+  int s_ch_gl_rd = s_ch_sh_stride * slice_col + threadIdx.x;
+  int s_ch_sh_wr = threadIdx.x;
+  int s_ch_sh_rd = 16 * ((threadIdx.x / 32) % (thread_n_blocks / 4)) +
+                   2 * ((threadIdx.x % 32) % 4);
+  bool s_ch_sh_wr_pred = threadIdx.x < s_ch_sh_stride;
+
+  int s_group_gl_rd, s_group_sh_wr, s_group_sh_rd;
+  bool s_group_sh_wr_pred;
+  if constexpr (group_blocks != -1) {
+    s_group_gl_rd =
+        s_group_gl_stride * ((thread_k_blocks * slice_row) / group_blocks) +
+        s_group_sh_stride * slice_col + threadIdx.x;
+    s_group_sh_wr = threadIdx.x;
+    // NOTE(HandH1998): s_group_sh_rd is related to mma output C
+    s_group_sh_rd = 8 * ((threadIdx.x / 32) % (thread_n_blocks / 4)) +
+                    (threadIdx.x % 32) / 4;
+    s_group_sh_wr_pred = threadIdx.x < s_group_sh_stride;
+  }
+
+  // Precompute which thread should not read memory in which iterations; this is
+  // needed if there are more threads than required for a certain tilesize or
+  // when the batchsize is not a multiple of 16.
+  bool a_sh_wr_pred[a_sh_wr_iters];
+  #pragma unroll
+  for (int i = 0; i < a_sh_wr_iters; i++)
+    a_sh_wr_pred[i] = a_sh_wr_delta * i + a_sh_wr < a_sh_stride * prob_m;
+
+  // To ensure that writing and reading A tiles to/from shared memory, the
+  // latter in fragment format, is fully bank conflict free, we need to use a
+  // rather fancy XOR-based layout. The key here is that neither reads nor
+  // writes of the 16-byte `int4` blocks of 8 consecutive threads involve the
+  // same shared memory banks. Further, it seems (based on NSight-Compute) that
+  // each warp must also write a consecutive memory segment?
+  auto transform_a = [&](int i) {
+    int row = i / a_gl_rd_delta_o;
+    return a_gl_rd_delta_o * row + (i % a_gl_rd_delta_o) ^ row;
+  };
+  // Since the computation of this remapping is non-trivial and, due to our main
+  // loop unrolls, all shared memory accesses are static, we simply precompute
+  // both transformed reads and writes.
+  int a_sh_wr_trans[a_sh_wr_iters];
+  #pragma unroll
+  for (int i = 0; i < a_sh_wr_iters; i++)
+    a_sh_wr_trans[i] = transform_a(a_sh_wr_delta * i + a_sh_wr);
+  int a_sh_rd_trans[b_sh_wr_iters][thread_m_blocks];
+  #pragma unroll
+  for (int i = 0; i < b_sh_wr_iters; i++) {
+  #pragma unroll
+    for (int j = 0; j < thread_m_blocks; j++)
+      a_sh_rd_trans[i][j] =
+          transform_a(a_sh_rd_delta_o * i + a_sh_rd_delta_i * j + a_sh_rd);
+  }
+
+  // Since B-accesses have non-constant stride they have to be computed at
+  // runtime; we break dependencies between subsequent accesses with a tile by
+  // maintining multiple pointers (we have enough registers), a tiny
+  // optimization.
+  const int4* B_ptr[b_sh_wr_iters];
+  #pragma unroll
+  for (int i = 0; i < b_sh_wr_iters; i++)
+    B_ptr[i] = B + b_gl_rd_delta_i * i + b_gl_rd;
+
+  extern __shared__ int4 sh[];
+  // Shared memory storage for global fetch pipelines.
+  // NOTE(HandH1998): stages need >= 4, otherwise, sh_s_tok = sh + max(stages *
+  // a_sh_stage + stages * b_sh_stage, 4 * stages * a_sh_stage)
+  int4* sh_a = sh;
+  int4* sh_b = sh_a + (stages * a_sh_stage);
+  int4* sh_s_tok = sh_b + (stages * b_sh_stage);
+  int4* sh_s_ch = sh_s_tok + s_tok_sh_stride;
+  int4* sh_s_group = sh_s_ch + s_ch_sh_stride;
+
+  // Register storage for double buffer of shared memory reads.
+  FragA frag_a[2][thread_m_blocks];
+  I4 frag_b_quant[2];
+  FragC frag_c[thread_m_blocks][4][2];
+  FragS_GROUP frag_s_group[2][4];
+  FragS_CHANNEL frag_s_tok[thread_m_blocks];
+  FragS_CHANNEL frag_s_ch[2][4];
+
+  // Zero accumulators.
+  auto zero_accums = [&]() {
+  #pragma unroll
+    for (int i = 0; i < thread_m_blocks * 4 * 2 * 4; i++)
+      reinterpret_cast(frag_c)[i] = 0;
+  };
+
+  // Asynchronously fetch the next A, B and s tile from global to the next
+  // shared memory pipeline location.
+  auto fetch_to_shared = [&](int pipe, int a_off, bool pred = true) {
+    if (pred) {
+      int4* sh_a_stage = sh_a + a_sh_stage * pipe;
+  #pragma unroll
+      for (int i = 0; i < a_sh_wr_iters; i++) {
+        cp_async4_pred(
+            &sh_a_stage[a_sh_wr_trans[i]],
+            &A[a_gl_rd_delta_i * i + a_gl_rd + a_gl_rd_delta_o * a_off],
+            a_sh_wr_pred[i]);
+      }
+      int4* sh_b_stage = sh_b + b_sh_stage * pipe;
+  #pragma unroll
+      for (int i = 0; i < b_sh_wr_iters; i++) {
+        cp_async4(&sh_b_stage[b_sh_wr_delta * i + b_sh_wr], B_ptr[i]);
+        B_ptr[i] += b_gl_rd_delta_o;
+      }
+      // Only fetch scales if this tile starts a new group
+      if constexpr (group_blocks != -1) {
+        if (pipe % (group_blocks / thread_k_blocks) == 0) {
+          int4* sh_s_group_stage = sh_s_group + s_group_sh_stage * pipe;
+          if (s_group_sh_wr_pred)
+            cp_async4(&sh_s_group_stage[s_group_sh_wr],
+                      &s_group[s_group_gl_rd]);
+          s_group_gl_rd += s_group_gl_rd_delta;
+        }
+      }
+    }
+    // Insert a fence even when we are winding down the pipeline to ensure that
+    // waiting is also correct at this point.
+    cp_async_fence();
+  };
+
+  // Wait until the next thread tile has been loaded to shared memory.
+  auto wait_for_stage = [&]() {
+    // We only have `stages - 2` active fetches since we are double buffering
+    // and can only issue the next fetch when it is guaranteed that the previous
+    // shared memory load is fully complete (as it may otherwise be
+    // overwritten).
+    cp_async_wait();
+    __syncthreads();
+  };
+
+  // Load the next sub-tile from the current location in the shared memory pipe
+  // into the current register buffer.
+  auto fetch_to_registers = [&](int k, int pipe) {
+    // It may seem inefficient that we reload the groups for every sub-tile;
+    // however, this does not seem to be a significant bottleneck, while some
+    // theoretically better attempts have lead to bad instruction ordering by
+    // the compiler and correspondingly a noticeable drop in performance.
+    if constexpr (group_blocks != -1) {
+      int4* sh_s_group_stage =
+          sh_s_group +
+          s_group_sh_stage * ((group_blocks / thread_k_blocks) *
+                              (pipe / (group_blocks / thread_k_blocks)));
+      reinterpret_cast(&frag_s_group[k % 2])[0] =
+          sh_s_group_stage[s_group_sh_rd];
+    }
+    int4* sh_a_stage = sh_a + a_sh_stage * pipe;
+  #pragma unroll
+    for (int i = 0; i < thread_m_blocks; i++)
+      ldsm4(frag_a[k % 2][i], &sh_a_stage[a_sh_rd_trans[k % b_sh_wr_iters][i]]);
+    int4* sh_b_stage = sh_b + b_sh_stage * pipe;
+    frag_b_quant[k % 2] = *reinterpret_cast(
+        &sh_b_stage[b_sh_rd_delta * (k % b_sh_wr_iters) + b_sh_rd]);
+  };
+
+  // Execute the actual tensor core matmul of a sub-tile.
+  auto matmul = [&](int k) {
+  // We have the m dimension as the inner loop in order to encourage overlapping
+  // dequantization and matmul operations.
+  #pragma unroll
+    for (int j = 0; j < 4; j++) {
+      int b_quant = frag_b_quant[k % 2][j];
+      // int b_quant_shift = b_quant << 4;
+      FragB frag_b0, frag_b1;
+      // If there are no groups, we can just scale the final output once and can
+      // avoid doing so for each weight.
+      if constexpr (group_blocks != -1) {
+        int b_quant_shift = b_quant >> 8;
+        frag_b0 = dequant_per_group(b_quant, frag_s_group[k % 2][j], 0);
+        frag_b1 = dequant_per_group(b_quant_shift, frag_s_group[k % 2][j], 1);
+      } else {
+        int b_quant_shift = b_quant << 4;
+        frag_b0 = dequant_per_channel(b_quant);
+        frag_b1 = dequant_per_channel(b_quant_shift);
+      }
+  #pragma unroll
+      for (int i = 0; i < thread_m_blocks; i++) {
+        mma(frag_a[k % 2][i], frag_b0, frag_c[i][j][0]);
+        mma(frag_a[k % 2][i], frag_b1, frag_c[i][j][1]);
+      }
+    }
+  };
+
+  // Since we slice across the k dimension of a tile in order to increase the
+  // number of warps while keeping the n dimension of a tile reasonable, we have
+  // multiple warps that accumulate their partial sums of the same output
+  // location; which we have to reduce over in the end. We do in shared memory.
+  auto thread_block_reduce = [&]() {
+    constexpr int red_off = threads / b_sh_stride / 2;
+    if (red_off >= 1) {
+      int red_idx = threadIdx.x / b_sh_stride;
+      constexpr int red_sh_stride = b_sh_stride * 4 * 2;
+      constexpr int red_sh_delta = b_sh_stride;
+      int red_sh_rd = red_sh_stride * (threadIdx.x / b_sh_stride) +
+                      (threadIdx.x % b_sh_stride);
+
+      // Parallel logarithmic shared memory reduction. We make sure to avoid any
+      // unnecessary read or write iterations, e.g., for two warps we write only
+      // once by warp 1 and read only once by warp 0.
+
+  #pragma unroll
+      for (int m_block = 0; m_block < thread_m_blocks; m_block++) {
+  #pragma unroll
+        for (int i = red_off; i > 0; i /= 2) {
+          if (i <= red_idx && red_idx < 2 * i) {
+  #pragma unroll
+            for (int j = 0; j < 4 * 2; j++) {
+              int red_sh_wr =
+                  red_sh_delta * j + (red_sh_rd - red_sh_stride * i);
+              if (i < red_off) {
+                int* c_rd =
+                    reinterpret_cast(&sh[red_sh_delta * j + red_sh_rd]);
+                int* c_wr = reinterpret_cast(&sh[red_sh_wr]);
+  #pragma unroll
+                for (int k = 0; k < 4; k++)
+                  reinterpret_cast(frag_c)[4 * 2 * m_block + j][k] +=
+                      c_rd[k] + c_wr[k];
+              }
+              sh[red_sh_wr] =
+                  reinterpret_cast(&frag_c)[4 * 2 * m_block + j];
+            }
+          }
+          __syncthreads();
+        }
+        if (red_idx == 0) {
+  #pragma unroll
+          for (int i = 0; i < 4 * 2; i++) {
+            int* c_rd =
+                reinterpret_cast(&sh[red_sh_delta * i + red_sh_rd]);
+  #pragma unroll
+            for (int j = 0; j < 4; j++)
+              reinterpret_cast(frag_c)[4 * 2 * m_block + i][j] +=
+                  c_rd[j];
+          }
+        }
+        __syncthreads();
+      }
+    }
+  };
+
+  // Since multiple threadblocks may process parts of the same column slice, we
+  // finally have to globally reduce over the results. As the striped
+  // partitioning minimizes the number of such reductions and our outputs are
+  // usually rather small, we perform this reduction serially in L2 cache.
+  // global_reduce works on INT32 elements, which are the results of INT8 GEMM.
+  // This is why we need another INT32 maxtrix `C` to reduce instead of the
+  // original half matrix `D`.
+  auto global_reduce = [&](bool first = false, bool last = false) {
+    // We are very careful here to reduce directly in the output buffer to
+    // maximize L2 cache utilization in this step. To do this, we write out
+    // results in FP16 (but still reduce with FP32 compute).
+    constexpr int active_threads = 32 * thread_n_blocks / 4;
+    if (threadIdx.x < active_threads) {
+      int c_gl_stride = prob_n / 4;
+      int c_gl_wr_delta_o = 8 * c_gl_stride;
+      int c_gl_wr_delta_i = 8 * (active_threads / 32);
+      int c_gl_wr = c_gl_stride * ((threadIdx.x % 32) / 4) +
+                    8 * (threadIdx.x / 32) + (threadIdx.x % 4) * 2;
+      c_gl_wr += (4 * thread_n_blocks) * slice_col;
+      constexpr int c_sh_wr_delta = active_threads * 2;
+      int c_sh_wr = 2 * threadIdx.x;
+
+      int row = (threadIdx.x % 32) / 4;
+
+      if (!first) {
+  // Interestingly, doing direct global accesses here really seems to mess up
+  // the compiler and lead to slowdowns, hence we also use async-copies even
+  // though these fetches are not actually asynchronous.
+  #pragma unroll
+        for (int i = 0; i < thread_m_blocks * 4; i++) {
+          cp_async4_pred(
+              &sh[c_sh_wr + c_sh_wr_delta * i],
+              &C[c_gl_wr + c_gl_wr_delta_o * (i / 2) +
+                 c_gl_wr_delta_i * (i % 2)],
+              i < (thread_m_blocks - 1) * 4 || 8 * (i / 2) + row < prob_m);
+          cp_async4_pred(
+              &sh[c_sh_wr + c_sh_wr_delta * i + 1],
+              &C[c_gl_wr + c_gl_wr_delta_o * (i / 2) +
+                 c_gl_wr_delta_i * (i % 2) + 1],
+              i < (thread_m_blocks - 1) * 4 || 8 * (i / 2) + row < prob_m);
+        }
+        cp_async_fence();
+        cp_async_wait<0>();
+      }
+
+  #pragma unroll
+      for (int i = 0; i < thread_m_blocks * 4; i++) {
+        if (i < (thread_m_blocks - 1) * 4 || 8 * (i / 2) + row < prob_m) {
+          if (!first) {
+            int4 d_red1 = sh[c_sh_wr + i * c_sh_wr_delta];
+            int4 d_red2 = sh[c_sh_wr + i * c_sh_wr_delta + 1];
+  #pragma unroll
+            for (int j = 0; j < 4; j++) {
+              reinterpret_cast(
+                  &frag_c)[4 * 2 * 4 * (i / 4) + 4 * j + (i % 4)] +=
+                  reinterpret_cast(&d_red1)[j];
+            }
+  #pragma unroll
+            for (int j = 0; j < 4; j++) {
+              reinterpret_cast(
+                  &frag_c)[4 * 2 * 4 * (i / 4) + 4 * (j + 4) + (i % 4)] +=
+                  reinterpret_cast(&d_red2)[j];
+            }
+          }
+          if (!last) {
+            int4 d1, d2;
+  #pragma unroll
+            for (int j = 0; j < 4; j++) {
+              reinterpret_cast(&d1)[j] = reinterpret_cast(
+                  &frag_c)[4 * 2 * 4 * (i / 4) + 4 * j + (i % 4)];
+            }
+  #pragma unroll
+            for (int j = 0; j < 4; j++) {
+              reinterpret_cast(&d2)[j] = reinterpret_cast(
+                  &frag_c)[4 * 2 * 4 * (i / 4) + 4 * (j + 4) + (i % 4)];
+            }
+            C[c_gl_wr + c_gl_wr_delta_o * (i / 2) + c_gl_wr_delta_i * (i % 2)] =
+                d1;
+            C[c_gl_wr + c_gl_wr_delta_o * (i / 2) + c_gl_wr_delta_i * (i % 2) +
+              1] = d2;
+          }
+        }
+      }
+    }
+  };
+
+  // Write out the reduce final result in the correct layout. We only actually
+  // reshuffle matrix fragments in this step, the reduction above is performed
+  // in fragment layout.
+  auto write_result = [&]() {
+    int d_gl_stride = prob_n / 8;
+    constexpr int d_sh_stride = 2 * thread_n_blocks + 1;
+    int d_gl_wr_delta = d_gl_stride * (threads / (2 * thread_n_blocks));
+    constexpr int d_sh_rd_delta =
+        d_sh_stride * (threads / (2 * thread_n_blocks));
+
+    int d_gl_wr = d_gl_stride * (threadIdx.x / (2 * thread_n_blocks)) +
+                  (threadIdx.x % (2 * thread_n_blocks));
+    d_gl_wr += (2 * thread_n_blocks) * slice_col;
+    int d_sh_wr =
+        (4 * d_sh_stride) * ((threadIdx.x % 32) / 4) + (threadIdx.x % 32) % 4;
+    d_sh_wr += 32 * (threadIdx.x / 32);
+    int d_sh_rd = d_sh_stride * (threadIdx.x / (2 * thread_n_blocks)) +
+                  (threadIdx.x % (2 * thread_n_blocks));
+
+    int d_gl_wr_end = d_gl_stride * prob_m;
+
+    // We first reorder in shared memory to guarantee the most efficient final
+    // global write patterns
+    auto write = [&](int idx, int c0, int c1, float a_s, FragS_CHANNEL& w_s) {
+      float2 deq_res;
+      deq_res.x = int32_to_float(c0) * w_s[0] * a_s;
+      deq_res.y = int32_to_float(c1) * w_s[1] * a_s;
+      ((half2*)sh)[idx] = float2_to_half2(deq_res);
+    };
+
+    if (threadIdx.x / 32 < thread_n_blocks / 4) {
+  #pragma unroll
+      for (int i = 0; i < thread_m_blocks; i++) {
+  #pragma unroll
+        for (int j = 0; j < 4; j++) {
+          int wr = d_sh_wr + 8 * j;
+          write(wr + (4 * d_sh_stride) * 0 + 0, frag_c[i][j][0][0],
+                frag_c[i][j][0][1], frag_s_tok[i][0],
+                frag_s_ch[j / 2][2 * (j % 2) + 0]);
+          write(wr + (4 * d_sh_stride) * 8 + 0, frag_c[i][j][0][2],
+                frag_c[i][j][0][3], frag_s_tok[i][1],
+                frag_s_ch[j / 2][2 * (j % 2) + 0]);
+          write(wr + (4 * d_sh_stride) * 0 + 4, frag_c[i][j][1][0],
+                frag_c[i][j][1][1], frag_s_tok[i][0],
+                frag_s_ch[j / 2][2 * (j % 2) + 1]);
+          write(wr + (4 * d_sh_stride) * 8 + 4, frag_c[i][j][1][2],
+                frag_c[i][j][1][3], frag_s_tok[i][1],
+                frag_s_ch[j / 2][2 * (j % 2) + 1]);
+        }
+        d_sh_wr += 16 * (4 * d_sh_stride);
+      }
+    }
+    __syncthreads();
+
+  #pragma unroll
+    for (int i = 0;
+         i < ceildiv(16 * thread_m_blocks, threads / (2 * thread_n_blocks));
+         i++) {
+      if (d_gl_wr < d_gl_wr_end) {
+        D[d_gl_wr] = sh[d_sh_rd];
+        d_gl_wr += d_gl_wr_delta;
+        d_sh_rd += d_sh_rd_delta;
+      }
+    }
+  };
+
+  // Start global fetch and register load pipelines.
+  auto start_pipes = [&]() {
+  #pragma unroll
+    for (int i = 0; i < stages - 1; i++) fetch_to_shared(i, i, i < slice_iters);
+    zero_accums();
+    wait_for_stage();
+    fetch_to_registers(0, 0);
+    a_gl_rd += a_gl_rd_delta_o * (stages - 1);
+  };
+  start_pipes();
+
+  // Main loop.
+  while (slice_iters) {
+  // We unroll over both the global fetch and the register load pipeline to
+  // ensure all shared memory accesses are static. Note that both pipelines have
+  // even length meaning that the next iteration will always start at index 0.
+  #pragma unroll
+    for (int pipe = 0; pipe < stages;) {
+  #pragma unroll
+      for (int k = 0; k < b_sh_wr_iters; k++) {
+        fetch_to_registers(k + 1, pipe % stages);
+        if (k == b_sh_wr_iters - 2) {
+          fetch_to_shared((pipe + stages - 1) % stages, pipe,
+                          slice_iters >= stages);
+          pipe++;
+          wait_for_stage();
+        }
+        matmul(k);
+      }
+      slice_iters--;
+      if (slice_iters == 0) break;
+    }
+    a_gl_rd += a_gl_rd_delta_o * stages;
+
+    // Process results and, if necessary, proceed to the next column slice.
+    // While this pattern may not be the most readable, other ways of writing
+    // the loop seemed to noticeably worse performance after compilation.
+    if (slice_iters == 0) {
+      cp_async_wait<0>();
+      bool last = slice_idx == slice_count - 1;
+      // For per-column scales, we only fetch them here in the final step before
+      // write-out
+      if (last) {
+        if (s_tok_sh_wr_pred) {
+          cp_async1(&sh_s_tok[s_tok_sh_wr], &s_tok[s_tok_gl_rd]);
+        }
+        if (s_ch_sh_wr_pred) {
+          cp_async4(&sh_s_ch[s_ch_sh_wr], &s_ch[s_ch_gl_rd]);
+        }
+        cp_async_fence();
+      }
+      thread_block_reduce();
+      if (last) {
+        cp_async_wait<0>();
+        __syncthreads();
+        if (threadIdx.x / 32 < thread_n_blocks / 4) {
+  #pragma unroll
+          for (int i = 0; i < thread_m_blocks; i++) {
+            frag_s_tok[i][0] =
+                *reinterpret_cast(&sh_s_tok[16 * i + 2 * s_tok_sh_rd]);
+            frag_s_tok[i][1] = *reinterpret_cast(
+                &sh_s_tok[16 * i + 2 * s_tok_sh_rd + 1]);
+          }
+          reinterpret_cast(&frag_s_ch)[0] = sh_s_ch[s_ch_sh_rd + 0];
+          reinterpret_cast(&frag_s_ch)[1] = sh_s_ch[s_ch_sh_rd + 1];
+          reinterpret_cast(&frag_s_ch)[2] = sh_s_ch[s_ch_sh_rd + 8];
+          reinterpret_cast(&frag_s_ch)[3] = sh_s_ch[s_ch_sh_rd + 9];
+        }
+      }
+      if (slice_count > 1) {  // only globally reduce if there is more than one
+                              // block in a slice
+        barrier_acquire(&locks[slice_col], slice_idx);
+        global_reduce(slice_idx == 0, last);
+        barrier_release(&locks[slice_col], last);
+      }
+      if (last)  // only the last block in a slice actually writes the result
+        write_result();
+      slice_row = 0;
+      slice_col_par++;
+      slice_col++;
+      init_slice();
+      if (slice_iters) {
+        a_gl_rd = a_gl_stride * (threadIdx.x / a_gl_rd_delta_o) +
+                  (threadIdx.x % a_gl_rd_delta_o);
+  #pragma unroll
+        for (int i = 0; i < b_sh_wr_iters; i++)
+          B_ptr[i] += b_sh_stride - b_gl_rd_delta_o * k_tiles;
+        if (slice_col == 0) {
+  #pragma unroll
+          for (int i = 0; i < b_sh_wr_iters; i++) B_ptr[i] -= b_gl_stride;
+        }
+        s_group_gl_rd = s_group_sh_stride * slice_col + threadIdx.x;
+        s_ch_gl_rd = s_ch_sh_stride * slice_col + threadIdx.x;
+        start_pipes();
+      }
+    }
+  }
+#endif
+}
+
+// 8 warps are a good choice since every SM has 4 schedulers and having more
+// than 1 warp per schedule allows some more latency hiding. At the same time,
+// we want relatively few warps to have many registers per warp and small tiles.
+const int USER_THREADS =
+    256;               // Note: This is only used with user-provided thread_k/n
+const int STAGES = 4;  // 4 pipeline stages fit into shared memory
+
+static constexpr int min_thread_n = 64;
+static constexpr int min_thread_k = 64;
+
+static constexpr int tile_size = 16;
+static constexpr int max_par = 16;
+
+static constexpr int pack_factor_4bit =
+    8;  // We have 8 4-bit vals inside a 32 bit
+
+#define __CALL_IF(THREAD_M_BLOCKS, THREAD_N_BLOCKS, THREAD_K_BLOCKS,               \
+                  GROUP_BLOCKS, NUM_THREADS)                                       \
+  else if (thread_m_blocks == THREAD_M_BLOCKS &&                                   \
+           thread_n_blocks == THREAD_N_BLOCKS &&                                   \
+           thread_k_blocks == THREAD_K_BLOCKS &&                                   \
+           group_blocks == GROUP_BLOCKS && num_threads == NUM_THREADS) {           \
+    cudaFuncSetAttribute(Marlin_QQQ,            \
+                         cudaFuncAttributeMaxDynamicSharedMemorySize,              \
+                         max_shared_mem);                                          \
+    Marlin_QQQ                                                   \
+        <<>>(                         \
+            A_ptr, B_ptr, C_ptr, D_ptr, s_tok_ptr, s_ch_ptr, s_group_ptr,          \
+            prob_m, prob_n, prob_k, locks);                                        \
+  }
+
+typedef struct {
+  int thread_k;
+  int thread_n;
+  int num_threads;
+} thread_config_t;
+
+thread_config_t small_batch_thread_configs[] = {
+    // Ordered by priority
+
+    // thread_k, thread_n, num_threads
+    {128, 128, 256},  // Default
+    {128, 64, 128},   // Reduce N 2X, same K
+    {64, 256, 256},   // Reduce K 2X, increase N 2X
+    {64, 128, 128},   // Reduce K 2X, same N
+};
+
+thread_config_t large_batch_thread_configs[] = {
+    // Ordered by priority
+
+    // thread_k, thread_n, num_threads
+    {64, 256, 256},   // Default
+    {128, 128, 256},  // Reduce N 2X, increase K 2X
+    {64, 128, 128},   // Reduce N 2X, same K
+    {128, 64, 128},   // Reduce N 4X, increase K 2X
+};
+
+bool is_valid_config(thread_config_t const& th_config, int prob_m, int prob_n,
+                     int prob_k) {
+  // Sanity
+  if (th_config.thread_k == -1 || th_config.thread_n == -1 ||
+      th_config.num_threads == -1) {
+    return false;
+  }
+
+  // Verify K/N are divisible by thread K/N
+  if (prob_k % th_config.thread_k != 0 || prob_n % th_config.thread_n != 0) {
+    return false;
+  }
+
+  // thread_k can be only 128 or 64 (because it must be less than groupsize
+  // which is 128)
+  if (th_config.thread_k != 128 && th_config.thread_k != 64) {
+    return false;
+  }
+
+  // Verify min for thread K/N
+  if (th_config.thread_n < min_thread_n || th_config.thread_k < min_thread_k) {
+    return false;
+  }
+
+  // num_threads must be at least 128 (= 4 warps)
+  if (th_config.num_threads < 128) {
+    return false;
+  }
+
+  return true;
+}
+
+thread_config_t determine_thread_config(int prob_m, int prob_n, int prob_k) {
+  if (prob_m <= 16) {
+    for (auto th_config : small_batch_thread_configs) {
+      if (is_valid_config(th_config, prob_m, prob_n, prob_k)) {
+        return th_config;
+      }
+    }
+
+  } else {
+    for (auto th_config : large_batch_thread_configs) {
+      if (is_valid_config(th_config, prob_m, prob_n, prob_k)) {
+        return th_config;
+      }
+    }
+  }
+
+  return thread_config_t{-1, -1, -1};
+}
+
+#define CALL_IF(N_BLOCKS, K_BLOCKS, NUM_THREADS)    \
+  __CALL_IF(1, N_BLOCKS, K_BLOCKS, -1, NUM_THREADS) \
+  __CALL_IF(1, N_BLOCKS, K_BLOCKS, 8, NUM_THREADS)  \
+  __CALL_IF(1, N_BLOCKS, K_BLOCKS, -1, NUM_THREADS) \
+  __CALL_IF(1, N_BLOCKS, K_BLOCKS, 8, NUM_THREADS)  \
+  __CALL_IF(2, N_BLOCKS, K_BLOCKS, -1, NUM_THREADS) \
+  __CALL_IF(2, N_BLOCKS, K_BLOCKS, 8, NUM_THREADS)  \
+  __CALL_IF(3, N_BLOCKS, K_BLOCKS, -1, NUM_THREADS) \
+  __CALL_IF(3, N_BLOCKS, K_BLOCKS, 8, NUM_THREADS)  \
+  __CALL_IF(4, N_BLOCKS, K_BLOCKS, -1, NUM_THREADS) \
+  __CALL_IF(4, N_BLOCKS, K_BLOCKS, 8, NUM_THREADS)
+
+void marlin_qqq_cuda(const void* A, const void* B, void* C, void* D,
+                     void* s_tok, void* s_ch, void* s_group, int prob_m,
+                     int prob_n, int prob_k, void* workspace,
+                     int groupsize = -1, int dev = 0, cudaStream_t stream = 0,
+                     int thread_k = -1, int thread_n = -1, int sms = -1,
+                     int max_par = 16) {
+  int tot_m = prob_m;
+  int tot_m_blocks = ceildiv(tot_m, 16);
+  int pad = 16 * tot_m_blocks - tot_m;
+
+  if (sms == -1)
+    cudaDeviceGetAttribute(&sms, cudaDevAttrMultiProcessorCount, dev);
+
+  int max_shared_mem = 0;
+  cudaDeviceGetAttribute(&max_shared_mem,
+                         cudaDevAttrMaxSharedMemoryPerBlockOptin, dev);
+  TORCH_CHECK(max_shared_mem > 0);
+
+  // Set thread config
+  thread_config_t th_config;
+  if (thread_k != -1 && thread_n != -1) {
+    // User-defined config
+    th_config = thread_config_t{thread_k, thread_n, USER_THREADS};
+  } else {
+    // Auto config
+    th_config = determine_thread_config(prob_m, prob_n, prob_k);
+  }
+
+  if (!is_valid_config(th_config, prob_m, prob_n, prob_k)) {
+    throw std::runtime_error(
+        "Invalid thread config: thread_k = " + str(th_config.thread_k) +
+        ", thread_n = " + str(th_config.thread_n) +
+        ", num_threads = " + str(th_config.num_threads) + " for MKN = [" +
+        str(prob_m) + ", " + str(prob_k) + ", " + str(prob_n) + "]");
+  }
+
+  int num_threads = th_config.num_threads;
+  thread_k = th_config.thread_k;
+  thread_n = th_config.thread_n;
+
+  int thread_k_blocks = thread_k / 16;
+  int thread_n_blocks = thread_n / 16;
+  int group_blocks = (groupsize == -1) ? -1 : groupsize / 16;
+  int blocks = sms;
+
+  if (prob_m == 0 || prob_n == 0 || prob_k == 0) {
+    return;
+  }
+
+  TORCH_CHECK(prob_n % thread_n == 0, "prob_n = ", prob_n,
+              " is not divisible by thread_n = ", thread_n);
+  TORCH_CHECK(prob_k % thread_k == 0, "prob_k = ", prob_k,
+              " is not divisible by thread_k = ", thread_k);
+  if (group_blocks != -1) {
+    TORCH_CHECK(prob_k % group_blocks == 0, "prob_k = ", prob_k,
+                " is not divisible by group_blocks = ", group_blocks);
+  }
+
+  const int4* A_ptr = (const int4*)A;
+  const int4* B_ptr = (const int4*)B;
+  int4* C_ptr = (int4*)C;
+  int4* D_ptr = (int4*)D;
+  const float* s_tok_ptr = (const float*)s_tok;
+  const int4* s_ch_ptr = (const int4*)s_ch;
+  const int4* s_group_ptr = (const int4*)s_group;
+
+  int* locks = (int*)workspace;
+
+  for (int i = 0; i < tot_m_blocks; i += 4) {
+    int thread_m_blocks = tot_m_blocks - i;
+    prob_m = tot_m - 16 * i;
+    int par = 1;
+    if (thread_m_blocks > 4) {
+      // Note that parallel > 1 currently only works for inputs without any
+      // padding
+      par = (16 * thread_m_blocks - pad) / 64;
+      if (par > max_par) par = max_par;
+      prob_m = 64 * par;
+      i += 4 * (par - 1);
+      thread_m_blocks = 4;
+    }
+
+    // For compilation speed, we only define the kernel configurations that have
+    // seemed useful (in terms of performance) in our testing, however many more
+    // are, in principle, possible.
+    if (false) {
+    }
+    CALL_IF(8, 8, 256)
+    CALL_IF(16, 4, 256)
+    CALL_IF(8, 4, 128)
+    CALL_IF(4, 8, 128)
+    else {
+      throw std::runtime_error("Unsupported shapes: MKN = [" + str(prob_m) +
+                               ", " + str(prob_k) + ", " + str(prob_n) + "]" +
+                               ", groupsize = " + str(groupsize) +
+                               ", thread_m_blocks = " + str(thread_m_blocks) +
+                               ", thread_n_blocks = " + str(thread_n_blocks) +
+                               ", thread_k_blocks = " + str(thread_k_blocks));
+    }
+
+    A_ptr += 16 * thread_m_blocks * (prob_k / 16) * par;
+    D_ptr += 16 * thread_m_blocks * (prob_n / 8) * par;
+    s_tok_ptr += 16 * thread_m_blocks * par;
+  }
+}
+
+torch::Tensor marlin_qqq_gemm(torch::Tensor const& a,
+                              torch::Tensor const& b_q_weight,
+                              torch::Tensor const& s_tok,
+                              torch::Tensor const& s_ch,
+                              torch::Tensor const& s_group,
+                              torch::Tensor& workspace, int64_t size_m,
+                              int64_t size_n, int64_t size_k) {
+  const auto dprops = at::cuda::getCurrentDeviceProperties();
+  if (dprops->major < 8) {
+    TORCH_CHECK(false, __func__, "requires SM >= 8.0. Current device is SM",
+                dprops->major, ".", dprops->minor);
+  }
+
+  // Verify M
+  TORCH_CHECK(size_m == a.size(0),
+              "Shape mismatch: a.size(0) = " + str(a.size(0)) +
+                  ", size_m = " + str(size_m));
+  TORCH_CHECK(size_m == s_tok.numel(),
+              "Shape mismatch: s_tok.numel() = " + str(s_tok.numel()) +
+                  ", size_m = " + str(size_m));
+
+  // Verify K
+  TORCH_CHECK(size_k == a.size(1),
+              "Shape mismatch: a.size(1) = " + str(a.size(1)) +
+                  ", size_k = " + str(size_k));
+  TORCH_CHECK(size_k % tile_size == 0,
+              "size_k = " + str(size_k) +
+                  " is not divisible by tile_size = " + str(tile_size));
+  TORCH_CHECK(
+      (size_k / tile_size) == b_q_weight.size(0),
+      "Shape mismatch: b_q_weight.size(0) = " + str(b_q_weight.size(0)) +
+          ", size_k = " + str(size_k) + ", tile_size = " + str(tile_size));
+
+  int groupsize = (s_group.numel() == 0) ? -1 : size_k / s_group.size(0);
+  // Verify groupsize
+  TORCH_CHECK(groupsize == -1 || groupsize == 128,
+              "Unexpected groupsize = " + str(groupsize));
+
+  // Verify N
+  TORCH_CHECK(s_ch.numel() == size_n,
+              "Shape mismatch: s_ch.numel() = " + str(s_ch.numel()) +
+                  ", size_n = " + str(size_n));
+  TORCH_CHECK(b_q_weight.size(1) % tile_size == 0,
+              "b_q_weight.size(1) = " + str(b_q_weight.size(1)) +
+                  " is not divisible by tile_size = " + str(tile_size));
+  if (groupsize != -1) {
+    TORCH_CHECK(s_group.size(1) == size_n,
+                "Shape mismatch: s_group.size(1) = " + str(s_group.size(1)) +
+                    ", size_n = " + str(size_n));
+    TORCH_CHECK(
+        size_k % s_group.size(0) == 0,
+        "size_k = " + str(size_k) +
+            ", is not divisible by s_group.size(0) = " + str(s_group.size(0)));
+  }
+
+  int actual_size_n = (b_q_weight.size(1) / tile_size) * pack_factor_4bit;
+  TORCH_CHECK(size_n == actual_size_n,
+              "Shape mismatch: size_n = " + str(size_n) +
+                  ", actual_size_n = " + str(actual_size_n));
+
+  // Verify A device and strides
+  TORCH_CHECK(a.device().is_cuda(), "A is not on GPU");
+  TORCH_CHECK(a.is_contiguous(), "A is not contiguous");
+
+  // Verify B device and strides
+  TORCH_CHECK(b_q_weight.device().is_cuda(), "b_q_weight is not on GPU");
+  TORCH_CHECK(b_q_weight.is_contiguous(), "b_q_weight is not contiguous");
+
+  // Verify s_tok device, strides and dtype
+  TORCH_CHECK(s_tok.device().is_cuda(), "s_tok is not on GPU");
+  TORCH_CHECK(s_tok.is_contiguous(), "s_tok is not contiguous");
+  TORCH_CHECK(s_tok.dtype() == torch::kFloat32, "s_tok's dtype is not float32");
+
+  // Verify s_ch device, strides and dtype
+  TORCH_CHECK(s_ch.device().is_cuda(), "s_ch is not on GPU");
+  TORCH_CHECK(s_ch.is_contiguous(), "s_ch is not contiguous");
+  TORCH_CHECK(s_ch.dtype() == torch::kFloat32, "s_ch's dtype is not float32");
+
+  // Verify s_group device, strides and dtype
+  TORCH_CHECK(s_group.device().is_cuda(), "s_group is not on GPU");
+  TORCH_CHECK(s_group.is_contiguous(), "s_group is not contiguous");
+  TORCH_CHECK(s_group.dtype() == torch::kFloat16,
+              "s_group's dtype is not float16");
+
+  // Verify workspace size
+  TORCH_CHECK(size_n % min_thread_n == 0,
+              "size_n = " + str(size_n) +
+                  ", is not divisible by min_thread_n = " + str(min_thread_n));
+  int min_workspace_size = (size_n / min_thread_n) * max_par;
+  TORCH_CHECK(workspace.numel() >= min_workspace_size,
+              "workspace.numel = " + str(workspace.numel()) +
+                  " is below min_workspace_size = " + str(min_workspace_size));
+
+  // Alloc C matrix
+  const at::cuda::OptionalCUDAGuard device_guard(device_of(a));
+  auto options_c = torch::TensorOptions().dtype(torch::kInt).device(a.device());
+  torch::Tensor c = torch::empty({max_par * 64, size_n}, options_c);
+
+  // Alloc D matrix
+  auto options_d =
+      torch::TensorOptions().dtype(torch::kFloat16).device(a.device());
+  torch::Tensor d = torch::empty({size_m, size_n}, options_d);
+
+  // thread_k: `k` size of a thread_tile in `weights` (can usually be left as
+  // auto -1)
+  int thread_k = -1;
+  // thread_n: `n` size of a thread_tile in `weights` (can usually be left as
+  // auto -1)
+  int thread_n = -1;
+  // sms: number of SMs to use for the kernel (can usually be left as auto -1)
+  int sms = -1;
+
+  int dev = a.get_device();
+  marlin_qqq_cuda(
+      a.data_ptr(), b_q_weight.data_ptr(), c.data_ptr(), d.data_ptr(),
+      s_tok.data_ptr(), s_ch.data_ptr(), s_group.data_ptr(), size_m, size_n,
+      size_k, workspace.data_ptr(), groupsize, dev,
+      at::cuda::getCurrentCUDAStream(dev), thread_k, thread_n, sms, max_par);
+
+  return d;
+}
+
+TORCH_LIBRARY_IMPL(torchao, CUDA, m) {
+  m.impl("torchao::marlin_qqq_gemm", &marlin_qqq_gemm);
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/mx_kernels/mx_fp_cutlass_kernels.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/mx_kernels/mx_fp_cutlass_kernels.cu
new file mode 100644
index 0000000000000000000000000000000000000000..7c34faf56a5ee8539bdf2e640bf7401c9a6ed047
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/mx_kernels/mx_fp_cutlass_kernels.cu
@@ -0,0 +1,260 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#if defined(TORCHAO_USE_CUTLASS) && !defined(_WIN32) &&                   \
+    defined(CUDA_VERSION) && (CUDA_VERSION >= 12080)
+#define BUILD_MX_KERNELS_CUTLASS
+#endif
+
+#if defined(BUILD_MX_KERNELS_CUTLASS)
+
+#include "cute/tensor.hpp"
+#include "cutlass/detail/sm100_blockscaled_layout.hpp"
+#include "cutlass/epilogue/collective/collective_builder.hpp"
+#include "cutlass/epilogue/thread/linear_combination.h"
+#include "cutlass/gemm/collective/collective_builder.hpp"
+#include "cutlass/gemm/device/gemm_universal_adapter.h"
+#include "cutlass/util/packed_stride.hpp"
+
+
+#endif
+
+namespace torchao {
+
+#if defined(BUILD_MX_KERNELS_CUTLASS)
+namespace {
+
+using namespace cute;
+
+template
+constexpr int GetAlignment() {
+    if constexpr (std::is_same_v>)
+        return 32;
+    return 16;
+}
+
+template 
+void run_gemm(at::Tensor& a, at::Tensor& b, at::Tensor& a_scale,
+             at::Tensor& b_scale, at::Tensor& out, int M, int K, int N) {
+  // A matrix configuration
+  using         LayoutATag  = cutlass::layout::RowMajor;                      // Layout type for A matrix operand
+  constexpr int AlignmentA  = GetAlignment();    // Memory access granularity/alignment of A matrix in units of elements (up to 16 bytes)
+
+  // B matrix configuration
+  using         LayoutBTag  = cutlass::layout::ColumnMajor;                   // Layout type for B matrix operand
+  constexpr int AlignmentB  = GetAlignment();    // Memory access granularity/alignment of B matrix in units of elements (up to 16 bytes)
+
+  // C/D matrix configuration
+  using         ElementC    = cutlass::bfloat16_t;                            // Element type for C matrix operand
+  using         LayoutCTag  = cutlass::layout::RowMajor;                      // Layout type for C matrix operand
+  using         LayoutDTag  = cutlass::layout::RowMajor;                      // Layout type for D matrix operand
+  constexpr int AlignmentD  = 128 / cutlass::sizeof_bits::value;    // Memory access granularity/alignment of D matrix in units of elements (up to 16 bytes)
+  constexpr int AlignmentC  = 128 / cutlass::sizeof_bits::value;    // Memory access granularity/alignment of C matrix in units of elements (up to 16 bytes)
+  // Kernel functional config
+  using ElementAccumulator  = float;                                          // Element type for internal accumulation
+  using ArchTag             = cutlass::arch::Sm100;                           // Tag indicating the minimum SM that supports the intended feature
+  using OperatorClass       = cutlass::arch::OpClassBlockScaledTensorOp;      // Operator class tag
+
+
+  using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
+      ArchTag, OperatorClass,
+      PerSmTileShape_MNK, ClusterShape,
+      cutlass::epilogue::collective::EpilogueTileAuto,
+      ElementAccumulator, ElementAccumulator,
+      ElementC, LayoutCTag, AlignmentC,
+      ElementD, LayoutDTag, AlignmentD,
+      cutlass::epilogue::collective::EpilogueScheduleAuto                      // Epilogue schedule policy
+    >::CollectiveOp;
+
+  using CollectiveMainloop = typename cutlass::gemm::collective::CollectiveBuilder<
+      ArchTag, OperatorClass,
+      ElementA, LayoutATag, AlignmentA,
+      ElementB, LayoutBTag, AlignmentB,
+      ElementAccumulator,
+      MmaTileShape, ClusterShape,
+      cutlass::gemm::collective::StageCountAutoCarveout(sizeof(typename CollectiveEpilogue::SharedStorage))>,
+      cutlass::gemm::collective::KernelScheduleAuto                             // Kernel schedule policy. Auto or using targeted scheduling policy
+    >::CollectiveOp;
+
+  using GemmKernel = cutlass::gemm::kernel::GemmUniversal<
+      Shape,                                                   // Indicates ProblemShape
+      CollectiveMainloop,
+      CollectiveEpilogue,
+      void>;
+
+  using Gemm = cutlass::gemm::device::GemmUniversalAdapter;
+
+  // Reference device GEMM implementation type
+  using StrideA   = typename Gemm::GemmKernel::StrideA;
+  using StrideB   = typename Gemm::GemmKernel::StrideB;
+  using StrideC   = typename Gemm::GemmKernel::StrideC;
+  using StrideD   = typename Gemm::GemmKernel::StrideD;
+  using LayoutSFA = typename Gemm::GemmKernel::CollectiveMainloop::LayoutSFA;
+  using LayoutSFB = typename Gemm::GemmKernel::CollectiveMainloop::LayoutSFB;
+  using Sm100BlkScaledConfig = typename Gemm::GemmKernel::CollectiveMainloop::Sm1xxBlkScaledConfig;
+
+  // Initialize strides using packed stride configuration
+  auto stride_A = cutlass::make_cute_packed_stride(StrideA{}, make_shape(M, K, 1));
+  auto stride_B = cutlass::make_cute_packed_stride(StrideB{}, make_shape(N, K, 1));
+  auto stride_D = cutlass::make_cute_packed_stride(StrideD{}, make_shape(M, N, 1));
+
+  // Initialize scale factor layouts using block scaled configuration
+  auto layout_SFA = Sm100BlkScaledConfig::tile_atom_to_shape_SFA(make_shape(M, N, K, 1));
+  auto layout_SFB = Sm100BlkScaledConfig::tile_atom_to_shape_SFB(make_shape(M, N, K, 1));
+
+  using DtypeA = typename ElementA::DataType;
+  using DtypeB = typename ElementB::DataType;
+  using DtypeScaleA = typename ElementA::ScaleFactorType;
+  using DtypeScaleB = typename ElementB::ScaleFactorType;
+  using DtypeOut = ElementD;
+
+  Gemm gemm;
+
+  auto A_ptr = reinterpret_cast(a.data_ptr());
+  auto B_ptr = reinterpret_cast(b.data_ptr());
+  auto SFA_ptr = reinterpret_cast(a_scale.data_ptr());
+  auto SFB_ptr = reinterpret_cast(b_scale.data_ptr());
+  auto out_ptr = reinterpret_cast(out.data_ptr());
+
+  typename Gemm::Arguments arguments{
+    cutlass::gemm::GemmUniversalMode::kGemm,
+    {M, N, K, 1},
+    { // Mainloop arguments
+      A_ptr, stride_A,
+      B_ptr, stride_B,
+      SFA_ptr, layout_SFA,
+      SFB_ptr, layout_SFB
+    },
+    { // Epilogue arguments
+      {1.0, 0.0},
+      nullptr, StrideC{},  // No bias for now
+      out_ptr, stride_D
+    }
+  };
+
+  // arguments.scheduler.max_swizzle_size = 8;
+
+  // Check the problem size is supported or not
+  cutlass::Status status = gemm.can_implement(arguments);
+  TORCH_CHECK(status == cutlass::Status::kSuccess, "Cutlass cannot implement");
+  // Allocate workspace memory
+  size_t workspace_size = Gemm::get_workspace_size(arguments);
+  auto workspace = a.new_empty(
+      {static_cast(workspace_size)},
+      at::TensorOptions().dtype(at::kByte));
+
+
+  // Initialize CUTLASS kernel with arguments and workspace pointer
+  status = gemm.initialize(arguments, workspace.data_ptr());
+  TORCH_CHECK(status == cutlass::Status::kSuccess, "Cutlass cannot initialize");
+
+  status = gemm.run(at::cuda::getCurrentCUDAStream());
+  TORCH_CHECK(status == cutlass::Status::kSuccess, "Cutlass cannot run", cutlass::cutlassGetStatusString(status));
+
+  C10_CUDA_KERNEL_LAUNCH_CHECK();
+
+}
+}
+#endif
+
+void validate(at::Tensor a, at::Tensor b, at::Tensor a_scale, at::Tensor b_scale){
+    TORCH_CHECK(a.is_cuda(), "a must be CUDA tensor");
+    TORCH_CHECK(b.is_cuda(), "b must be CUDA tensor");
+    TORCH_CHECK(a_scale.is_cuda(), "a_scale must be CUDA tensor");
+    TORCH_CHECK(b_scale.is_cuda(), "b_scale must be CUDA tensor");
+
+    // Check matrix dimensions
+    TORCH_CHECK(a.dim() == 2, "a must be a matrix");
+    TORCH_CHECK(b.dim() == 2, "b must be a matrix");
+
+    // Get dimensions
+    auto M = a.size(0);
+    auto K = a.size(1);
+    auto N = b.size(1);
+
+    TORCH_CHECK(b.size(0) == K,
+        "Incompatible matrix dimensions: a is ", M, "x", K, " but b is ", b.size(0), "x", N);
+
+    // Needed for TMA store
+    TORCH_CHECK(N % 8 == 0, "N must be a multiple of 16 but got, ", N);
+
+    // Check 16-byte alignment for input tensors
+    TORCH_CHECK(
+        reinterpret_cast(a.data_ptr()) % 16 == 0,
+        "Input tensor 'a' must be 16-byte aligned");
+    TORCH_CHECK(
+        reinterpret_cast(b.data_ptr()) % 16 == 0,
+        "Input tensor 'b' must be 16-byte aligned");
+
+    auto ceil_div = [](auto a, auto b) { return (a + b - 1) / b; };
+    auto num_k_blocks = ceil_div(K, 32);
+    // For a_scale, we expect elements or M* ceil(K/32) elements
+    auto expected_a_scale_size = 128 * ceil_div(M, 128) * num_k_blocks;
+    TORCH_CHECK(a_scale.numel() == expected_a_scale_size, "Expected b_scale_size to be ", expected_a_scale_size, " but got ", a_scale.numel());
+
+    // For b_scale, we expect N * ceil(K/32) elements
+    auto expected_b_scale_size = 128 * ceil_div(N, 128) * num_k_blocks;
+    TORCH_CHECK(b_scale.numel() == expected_b_scale_size, "Expected a_scale_size to be ", expected_b_scale_size, " but got ", b_scale.numel());
+
+    // Check tensor strides for optimal memory layout
+    TORCH_CHECK(
+        a.stride(1) == 1,
+        "Input tensor 'a' must be contiguous in the K dimension (row-major)");
+    TORCH_CHECK(
+        b.stride(0) == 1,
+        "Input tensor 'b' must be contiguous in the K dimension (column-major)");
+}
+
+at::Tensor mx_fp4_bf16(at::Tensor a, at::Tensor b, at::Tensor a_scale,
+                       at::Tensor b_scale) {
+#if defined(BUILD_MX_KERNELS_CUTLASS)
+  TORCH_CHECK(a.is_cuda(), "a must be CUDA tensor");
+  TORCH_CHECK(b.is_cuda(), "b must be CUDA tensor");
+  TORCH_CHECK(a_scale.is_cuda(), "a_scale must be CUDA tensor");
+  TORCH_CHECK(b_scale.is_cuda(), "b_scale must be CUDA tensor");
+
+  auto M = a.size(0);
+  auto K = a.size(1) * 2;
+  auto N = b.size(1);
+
+  auto out =
+      at::empty({M, N}, a.options().dtype(at::kBFloat16));
+  using ElementA = cutlass::mx_float4_t;
+  using ElementB = cutlass::mx_float4_t;
+  using ElementD = cutlass::bfloat16_t;
+
+  using MmaTileShape        = Shape<_128,_128,_128>;
+  using ClusterShape        = Shape<_2,_1,_1>;
+  using PerSmTileShape_MNK  = Shape<_128,_128,_128>;
+
+  run_gemm(a, b, a_scale, b_scale, out, M, K, N);
+  return out;
+#else
+  TORCH_CHECK_NOT_IMPLEMENTED(false, __func__);
+  return at::Tensor{};
+#endif
+}
+
+TORCH_LIBRARY_IMPL(torchao, CUDA, m) {
+  m.impl("torchao::mx_fp4_bf16", &mx_fp4_bf16);
+}
+
+
+
+} // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_cutlass/rowwise_scaled_linear_cutlass_s4s4.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_cutlass/rowwise_scaled_linear_cutlass_s4s4.cu
new file mode 100644
index 0000000000000000000000000000000000000000..ceca6ef0c863f5032c6c736ff0736880954eff44
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_cutlass/rowwise_scaled_linear_cutlass_s4s4.cu
@@ -0,0 +1,40 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#include 
+
+#include "rowwise_scaled_linear_cutlass.cuh"
+
+namespace torchao {
+
+at::Tensor
+rowwise_scaled_linear_cutlass_s4s4(
+    const at::Tensor& Xq, const at::Tensor& X_scale, const at::Tensor& Wq,
+    const at::Tensor& W_scale,
+    const std::optional& bias_opt = std::nullopt,
+    const std::optional out_dtype_opt = std::nullopt) {
+  // Validate input datatypes.
+  TORCH_CHECK(Xq.dtype() == at::kChar && Wq.dtype() == at::kChar,
+              __func__, " : The input datatypes combination ", Xq.dtype(),
+              " for Xq and ", Wq.dtype(), " for Wq is not supported");
+
+#if defined(BUILD_ROWWISE_SCALED_LINEAR_CUTLASS)
+  // Dispatch to appropriate kernel template.
+  using ElementA = cutlass::int4b_t;
+  using ElementB = cutlass::int4b_t;
+  return rowwise_scaled_linear_cutlass(
+    Xq, X_scale, Wq, W_scale, bias_opt, out_dtype_opt);
+#else
+  TORCH_CHECK_NOT_IMPLEMENTED(false, OPERATOR_NAME);
+  return at::Tensor{};
+#endif
+}
+
+TORCH_LIBRARY_IMPL(torchao, CUDA, m) {
+  m.impl("torchao::rowwise_scaled_linear_cutlass_s4s4",
+         &rowwise_scaled_linear_cutlass_s4s4);
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_cutlass/rowwise_scaled_linear_cutlass_s8s4.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_cutlass/rowwise_scaled_linear_cutlass_s8s4.cu
new file mode 100644
index 0000000000000000000000000000000000000000..613ec60af89339cc681341cf7209204f4bda5693
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_cutlass/rowwise_scaled_linear_cutlass_s8s4.cu
@@ -0,0 +1,40 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#include 
+
+#include "rowwise_scaled_linear_cutlass.cuh"
+
+namespace torchao {
+
+at::Tensor
+rowwise_scaled_linear_cutlass_s8s4(
+    const at::Tensor& Xq, const at::Tensor& X_scale, const at::Tensor& Wq,
+    const at::Tensor& W_scale,
+    const std::optional& bias_opt = std::nullopt,
+    const std::optional out_dtype_opt = std::nullopt) {
+  // Validate input datatypes.
+  TORCH_CHECK(Xq.dtype() == at::kChar && Wq.dtype() == at::kChar,
+              __func__, " : The input datatypes combination ", Xq.dtype(),
+              " for Xq and ", Wq.dtype(), " for Wq is not supported");
+
+#if defined(BUILD_ROWWISE_SCALED_LINEAR_CUTLASS)
+  // Dispatch to appropriate kernel template.
+  using ElementA = int8_t;
+  using ElementB = cutlass::int4b_t;
+  return rowwise_scaled_linear_cutlass(
+    Xq, X_scale, Wq, W_scale, bias_opt, out_dtype_opt);
+#else
+  TORCH_CHECK_NOT_IMPLEMENTED(false, OPERATOR_NAME);
+  return at::Tensor{};
+#endif
+}
+
+TORCH_LIBRARY_IMPL(torchao, CUDA, m) {
+  m.impl("torchao::rowwise_scaled_linear_cutlass_s8s4",
+         &rowwise_scaled_linear_cutlass_s8s4);
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e4m3e4m3.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e4m3e4m3.cu
new file mode 100644
index 0000000000000000000000000000000000000000..0d233d02ccaa00b43f5bb61821609e34210f6a29
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e4m3e4m3.cu
@@ -0,0 +1,34 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#include "rowwise_scaled_linear_sparse_cutlass.cuh"
+#include "rowwise_scaled_linear_sparse_cutlass_e4m3e4m3.h"
+
+namespace torchao {
+
+at::Tensor
+rowwise_scaled_linear_sparse_cutlass_e4m3e4m3(
+    const at::Tensor& Xq, const at::Tensor& X_scale, const at::Tensor& Wq,
+    const at::Tensor& W_meta, const at::Tensor& W_scale,
+    const std::optional& bias_opt,
+    const std::optional out_dtype_opt) {
+  // Validate input datatypes.
+  TORCH_CHECK(
+    Xq.dtype() == at::kFloat8_e4m3fn && Wq.dtype() == at::kFloat8_e4m3fn,
+    __func__, " : The input datatypes combination ", Xq.dtype(), " for Xq and ",
+    Wq.dtype(), " for Wq is not supported");
+
+#if defined(BUILD_ROWWISE_SCALED_LINEAR_SPARSE_CUTLASS)
+  using DtypeXq = cutlass::float_e4m3_t;
+  using DtypeWq = cutlass::float_e4m3_t;
+  return rowwise_scaled_linear_sparse_cutlass(
+      Xq, X_scale, Wq, W_meta, W_scale, bias_opt, out_dtype_opt);
+#else
+  TORCH_CHECK_NOT_IMPLEMENTED(false, OPERATOR_NAME);
+  return at::Tensor{};
+#endif
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e4m3e5m2.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e4m3e5m2.cu
new file mode 100644
index 0000000000000000000000000000000000000000..d8fa7b69290fbed822fdbf5dd11dde03d50c3b6b
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e4m3e5m2.cu
@@ -0,0 +1,34 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#include "rowwise_scaled_linear_sparse_cutlass.cuh"
+#include "rowwise_scaled_linear_sparse_cutlass_e4m3e5m2.h"
+
+namespace torchao {
+
+at::Tensor
+rowwise_scaled_linear_sparse_cutlass_e4m3e5m2(
+    const at::Tensor& Xq, const at::Tensor& X_scale, const at::Tensor& Wq,
+    const at::Tensor& W_meta, const at::Tensor& W_scale,
+    const std::optional& bias_opt,
+    const std::optional out_dtype_opt) {
+  // Validate input datatypes.
+  TORCH_CHECK(
+    Xq.dtype() == at::kFloat8_e4m3fn && Wq.dtype() == at::kFloat8_e5m2,
+    __func__, " : The input datatypes combination ", Xq.dtype(), " for Xq and ",
+    Wq.dtype(), " for Wq is not supported");
+
+#if defined(BUILD_ROWWISE_SCALED_LINEAR_SPARSE_CUTLASS)
+  using DtypeXq = cutlass::float_e4m3_t;
+  using DtypeWq = cutlass::float_e5m2_t;
+  return rowwise_scaled_linear_sparse_cutlass(
+      Xq, X_scale, Wq, W_meta, W_scale, bias_opt, out_dtype_opt);
+#else
+  TORCH_CHECK_NOT_IMPLEMENTED(false, OPERATOR_NAME);
+  return at::Tensor{};
+#endif
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e5m2e4m3.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e5m2e4m3.cu
new file mode 100644
index 0000000000000000000000000000000000000000..0188b550ef7ffd48d237156605b4656bc32dea92
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e5m2e4m3.cu
@@ -0,0 +1,34 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#include "rowwise_scaled_linear_sparse_cutlass.cuh"
+#include "rowwise_scaled_linear_sparse_cutlass_e5m2e4m3.h"
+
+namespace torchao {
+
+at::Tensor
+rowwise_scaled_linear_sparse_cutlass_e5m2e4m3(
+    const at::Tensor& Xq, const at::Tensor& X_scale, const at::Tensor& Wq,
+    const at::Tensor& W_meta, const at::Tensor& W_scale,
+    const std::optional& bias_opt,
+    const std::optional out_dtype_opt) {
+  // Validate input datatypes.
+  TORCH_CHECK(
+    Xq.dtype() == at::kFloat8_e5m2 && Wq.dtype() == at::kFloat8_e4m3fn,
+    __func__, " : The input datatypes combination ", Xq.dtype(), " for Xq and ",
+    Wq.dtype(), " for Wq is not supported");
+
+#if defined(BUILD_ROWWISE_SCALED_LINEAR_SPARSE_CUTLASS)
+  using DtypeXq = cutlass::float_e5m2_t;
+  using DtypeWq = cutlass::float_e4m3_t;
+  return rowwise_scaled_linear_sparse_cutlass(
+      Xq, X_scale, Wq, W_meta, W_scale, bias_opt, out_dtype_opt);
+#else
+  TORCH_CHECK_NOT_IMPLEMENTED(false, OPERATOR_NAME);
+  return at::Tensor{};
+#endif
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e5m2e5m2.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e5m2e5m2.cu
new file mode 100644
index 0000000000000000000000000000000000000000..bee9069406b98e7ca4ff19124a89e554eecd37e5
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_e5m2e5m2.cu
@@ -0,0 +1,34 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#include "rowwise_scaled_linear_sparse_cutlass.cuh"
+#include "rowwise_scaled_linear_sparse_cutlass_e5m2e5m2.h"
+
+namespace torchao {
+
+at::Tensor
+rowwise_scaled_linear_sparse_cutlass_e5m2e5m2(
+    const at::Tensor& Xq, const at::Tensor& X_scale, const at::Tensor& Wq,
+    const at::Tensor& W_meta, const at::Tensor& W_scale,
+    const std::optional& bias_opt,
+    const std::optional out_dtype_opt) {
+  // Validate input datatypes.
+  TORCH_CHECK(
+    Xq.dtype() == at::kFloat8_e5m2 && Wq.dtype() == at::kFloat8_e5m2,
+    __func__, " : The input datatypes combination ", Xq.dtype(), " for Xq and ",
+    Wq.dtype(), " for Wq is not supported");
+
+#if defined(BUILD_ROWWISE_SCALED_LINEAR_SPARSE_CUTLASS)
+  using DtypeXq = cutlass::float_e5m2_t;
+  using DtypeWq = cutlass::float_e5m2_t;
+  return rowwise_scaled_linear_sparse_cutlass(
+      Xq, X_scale, Wq, W_meta, W_scale, bias_opt, out_dtype_opt);
+#else
+  TORCH_CHECK_NOT_IMPLEMENTED(false, OPERATOR_NAME);
+  return at::Tensor{};
+#endif
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_f8f8.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_f8f8.cu
new file mode 100644
index 0000000000000000000000000000000000000000..492d682d6aec58226fd1ab0d6a899f6c8df6ae1b
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/rowwise_scaled_linear_sparse_cutlass/rowwise_scaled_linear_sparse_cutlass_f8f8.cu
@@ -0,0 +1,54 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#include 
+
+#include "rowwise_scaled_linear_sparse_cutlass_e4m3e4m3.h"
+#include "rowwise_scaled_linear_sparse_cutlass_e4m3e5m2.h"
+#include "rowwise_scaled_linear_sparse_cutlass_e5m2e4m3.h"
+#include "rowwise_scaled_linear_sparse_cutlass_e5m2e5m2.h"
+
+namespace torchao {
+
+at::Tensor
+rowwise_scaled_linear_sparse_cutlass_f8f8(
+    const at::Tensor& Xq, const at::Tensor& X_scale, const at::Tensor& Wq,
+    const at::Tensor& W_meta, const at::Tensor& W_scale,
+    const std::optional& bias_opt = std::nullopt,
+    const std::optional out_dtype_opt = std::nullopt) {
+  // Validate input datatypes.
+  TORCH_CHECK(
+      (Xq.dtype() == at::kFloat8_e4m3fn && Wq.dtype() == at::kFloat8_e4m3fn) ||
+      (Xq.dtype() == at::kFloat8_e4m3fn && Wq.dtype() == at::kFloat8_e5m2) ||
+      (Xq.dtype() == at::kFloat8_e5m2 && Wq.dtype() == at::kFloat8_e4m3fn) ||
+      (Xq.dtype() == at::kFloat8_e5m2 && Wq.dtype() == at::kFloat8_e5m2),
+      __func__, " : The input datatypes combination ", Xq.dtype(),
+      " for Xq and ", Wq.dtype(), " for Wq is not supported");
+
+  // Dispatch to appropriate kernel template.
+  if (Xq.dtype() == at::kFloat8_e4m3fn && Wq.dtype() == at::kFloat8_e4m3fn) {
+    return rowwise_scaled_linear_sparse_cutlass_e4m3e4m3(
+      Xq, X_scale, Wq, W_meta, W_scale, bias_opt, out_dtype_opt);
+  } else if (Xq.dtype() == at::kFloat8_e4m3fn &&
+             Wq.dtype() == at::kFloat8_e5m2) {
+    return rowwise_scaled_linear_sparse_cutlass_e4m3e5m2(
+      Xq, X_scale, Wq, W_meta, W_scale, bias_opt, out_dtype_opt);
+  } else if (Xq.dtype() == at::kFloat8_e5m2 &&
+             Wq.dtype() == at::kFloat8_e4m3fn) {
+    return rowwise_scaled_linear_sparse_cutlass_e5m2e4m3(
+      Xq, X_scale, Wq, W_meta, W_scale, bias_opt, out_dtype_opt);
+  } else if (Xq.dtype() == at::kFloat8_e5m2 && Wq.dtype() == at::kFloat8_e5m2) {
+    return rowwise_scaled_linear_sparse_cutlass_e5m2e5m2(
+      Xq, X_scale, Wq, W_meta, W_scale, bias_opt, out_dtype_opt);
+  }
+  return at::Tensor{};
+}
+
+TORCH_LIBRARY_IMPL(torchao, CUDA, m) {
+  m.impl("torchao::rowwise_scaled_linear_sparse_cutlass_f8f8",
+         &rowwise_scaled_linear_sparse_cutlass_f8f8);
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/sparse_marlin/marlin_kernel_nm.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/sparse_marlin/marlin_kernel_nm.cu
new file mode 100644
index 0000000000000000000000000000000000000000..bd64930c4b70c6ad85b11e567243ad268d3b7fa9
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/sparse_marlin/marlin_kernel_nm.cu
@@ -0,0 +1,1134 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+/*
+ * Notice: This file was modified by Neuralmagic inc to include 8-bit support
+ *
+ * Copyright (C) 2024 Roberto Lopez Castro (roberto.lopez.castro@udc.es). All
+ * Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file is a modified version of the original Marlin kernel from the file:
+// https://github.com/neuralmagic/nm-vllm/blob/9daca33a6fdc429802f448e1ea71630c996c9740/csrc/quantization/marlin/sparse/marlin_24_cuda_kernel.cu
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include "base.h"
+#include "mem.h"
+#include "mma.h"
+
+template 
+inline std::string str(T x) {
+  return std::to_string(x);
+}
+
+namespace torchao {
+
+// 8 warps are a good choice since every SM has 4 schedulers and having more
+// than 1 warp per schedule allows some more latency hiding. At the same time,
+// we want relatively few warps to have many registers per warp and small tiles.
+static constexpr int THREADS = 256;
+static constexpr int STAGES = 4;
+
+static constexpr int min_thread_n = 128;
+
+static constexpr int tile_size = 16;
+static constexpr int max_par = 64;
+
+#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 800 && !defined(USE_ROCM)
+
+template shared
+                             // fetch pipeline
+          const int group_blocks = -1  // number of consecutive 16x16 blocks
+                                       // with a separate quantization scale
+          >
+__global__ void Marlin_24(
+    const int4* __restrict__ A,     // fp16 input matrix of shape mxk
+    const int4* __restrict__ B,     // 4bit quantized weight matrix of shape kxn
+    const int4* __restrict__ meta,  // 2bit metadata information about 2:4
+                                    // format on B
+    int4* __restrict__ C,           // fp16 output buffer of shape mxn
+    const int4* __restrict__ s,     // fp16 quantization scales of shape
+                                    // (k/groupsize)xn
+    int prob_m,                     // batch dimension m
+    int prob_n,                     // output dimension n
+    int prob_k,                     // reduction dimension k
+    int* locks  // extra global storage for barrier synchronization
+) {}
+
+torch::Tensor marlin_24_gemm(torch::Tensor& a, torch::Tensor& b_q_weight,
+                                  torch::Tensor& b_meta,
+                                  torch::Tensor& b_scales,
+                                  torch::Tensor& workspace, int64_t num_bits,
+                                  int64_t size_m, int64_t size_n,
+                                  int64_t size_k) {
+  TORCH_CHECK_NOT_IMPLEMENTED(
+      false, "marlin_24_gemm(..) requires CUDA_ARCH >= 8.0");
+  return torch::empty({1, 1});
+}
+
+#else
+
+template shared
+                             // fetch pipeline
+          const int group_blocks = -1  // number of consecutive 16x16 blocks
+                                       // with a separate quantization scale
+          >
+__global__ void Marlin_24(
+    const int4* __restrict__ A,     // fp16 input matrix of shape mxk
+    const int4* __restrict__ B,     // 4bit quantized weight matrix of shape kxn
+    const int4* __restrict__ meta,  // 2bit metadata information about 2:4
+                                    // format on B
+    int4* __restrict__ C,           // fp16 output buffer of shape mxn
+    const int4* __restrict__ s,     // fp16 quantization scales of shape
+                                    // (k/groupsize)xn
+    int prob_m,                     // batch dimension m
+    int prob_n,                     // output dimension n
+    int prob_k,                     // reduction dimension k
+    int* locks  // extra global storage for barrier synchronization
+) {
+  // Each threadblock processes one "stripe" of the B matrix with (roughly) the
+  // same size, which might involve multiple column "slices" (of width 16 *
+  // `thread_n_blocks`). Stripes are defined as shown in the 3x3 matrix 5 SM
+  // example:
+  //   0 1 3
+  //   0 2 3
+  //   1 2 4
+  // While this kind of partitioning makes things somewhat more complicated, it
+  // ensures good utilization of all SMs for many kinds of shape and GPU
+  // configurations, while requiring as few slow global cross-threadblock
+  // reductions as possible.
+
+  // For larger GEMMs we run multiple batchsize 64 versions in parallel for a
+  // better partitioning with less reductions
+  int parallel = 1;
+  if (prob_m > 16 * thread_m_blocks) {
+    parallel = prob_m / (16 * thread_m_blocks);
+    prob_m = 16 * thread_m_blocks;
+  }
+
+  // number of thread_k_blocks in k-dim
+  int k_tiles = prob_k / 32 / thread_k_blocks;
+  // number of thread_n_blocks in n-dim
+  int n_tiles = prob_n / 16 / thread_n_blocks;
+  // iters needed to cover all slices
+  int iters = ceildiv(k_tiles * n_tiles * parallel, gridDim.x);
+
+  // Ensure that the number of tiles in each stripe is a multiple of the
+  // groupsize; this avoids an annoying special case where a stripe starts in
+  // the middle of group.
+  if (group_blocks != -1)
+    iters = (group_blocks / thread_k_blocks) *
+            ceildiv(iters, (group_blocks / thread_k_blocks));
+
+  int slice_row = (iters * blockIdx.x) % k_tiles;
+  int slice_col_par = (iters * blockIdx.x) / k_tiles;
+  int slice_col = slice_col_par;
+  // number of threadblock tiles in the current slice
+  int slice_iters;
+  // total number of active threadblocks in the current slice
+  int slice_count = 0;
+  // index of threadblock in current slice; numbered bottom to top
+  int slice_idx;
+
+  // We can easily implement parallel problem execution by just remapping
+  // indices and advancing global pointers
+  if (slice_col_par >= n_tiles) {
+    A += (slice_col_par / n_tiles) * 16 * thread_m_blocks * prob_k / 8;
+    C += (slice_col_par / n_tiles) * 16 * thread_m_blocks * prob_n / 8;
+    locks += (slice_col_par / n_tiles) * n_tiles;
+    slice_col = slice_col_par % n_tiles;
+  }
+
+  // Compute all information about the current slice which is required for
+  // synchronization.
+  auto init_slice = [&]() {
+    slice_iters =
+        iters * (blockIdx.x + 1) - (k_tiles * slice_col_par + slice_row);
+    if (slice_iters < 0 || slice_col_par >= n_tiles * parallel) slice_iters = 0;
+    if (slice_iters == 0) return;
+    if (slice_row + slice_iters > k_tiles) slice_iters = k_tiles - slice_row;
+    slice_count = 1;
+    slice_idx = 0;
+    int col_first = iters * ceildiv(k_tiles * slice_col_par, iters);
+    if (col_first <= k_tiles * (slice_col_par + 1)) {
+      int col_off = col_first - k_tiles * slice_col_par;
+      slice_count = ceildiv(k_tiles - col_off, iters);
+      if (col_off > 0) slice_count++;
+      int delta_first = iters * blockIdx.x - col_first;
+      if (delta_first < 0 || (col_off == 0 && delta_first == 0))
+        slice_idx = slice_count - 1;
+      else {
+        slice_idx = slice_count - 1 - delta_first / iters;
+        if (col_off > 0) slice_idx--;
+      }
+    }
+    if (slice_col == n_tiles) {
+      A += 16 * thread_m_blocks * prob_k / 8;
+      C += 16 * thread_m_blocks * prob_n / 8;
+      locks += n_tiles;
+      slice_col = 0;
+    }
+  };
+  init_slice();
+
+  // RLC: 8 is vec_size -> 128-bit instructions, 8 fp16 elements
+  int a_gl_stride = prob_k / 8;  // stride of the A matrix in global memory
+
+  // stride of an A matrix tile in shared memory
+  constexpr int a_sh_stride = 32 * thread_k_blocks / 8;
+  // delta between subsequent A tiles in global memory
+  constexpr int a_gl_rd_delta_o = 32 * thread_k_blocks / 8;
+  // between subsequent accesses within a tile
+  int a_gl_rd_delta_i = a_gl_stride * (threads / a_gl_rd_delta_o);
+  // between shared memory writes
+  constexpr int a_sh_wr_delta = a_sh_stride * (threads / a_gl_rd_delta_o);
+  // between shared memory tile reads //RLC: 2 * #warps k-dim
+  constexpr int a_sh_rd_delta_o = 4 * ((threads / 32) / (thread_n_blocks / 4));
+  // within a shared memory tile
+  constexpr int a_sh_rd_delta_i = a_sh_stride * 16;
+  // overall size of a tile
+  constexpr int a_sh_stage = a_sh_stride * (16 * thread_m_blocks);
+  // number of shared write iterations for a tile
+  constexpr int a_sh_wr_iters = ceildiv(a_sh_stage, a_sh_wr_delta);
+
+  constexpr int pack_factor = 32 / num_bits;
+
+  int b_gl_stride = 16 * prob_n / (pack_factor * 4);
+  constexpr int b_sh_stride = ((thread_n_blocks * 16) * 16 / pack_factor) / 4;
+  constexpr int b_thread_vecs = num_bits == 4 ? 1 : 2;
+  constexpr int b_sh_stride_threads = b_sh_stride / b_thread_vecs;
+  int b_gl_rd_delta_o = b_gl_stride * thread_k_blocks;
+  int b_gl_rd_delta_i = b_gl_stride * (threads / b_sh_stride_threads);
+  constexpr int b_sh_wr_delta = threads * b_thread_vecs;
+  constexpr int b_sh_rd_delta = threads * b_thread_vecs;
+  constexpr int b_sh_stage = b_sh_stride * thread_k_blocks;
+  constexpr int b_sh_wr_iters = b_sh_stage / b_sh_wr_delta;
+
+  int m_gl_stride = 2 * prob_n / 8;  // (16*2*4 / 8) = 16
+  constexpr int m_sh_stride =
+      (16 * thread_n_blocks) / 4;  // #warps n-dim * threads/warp
+  int m_gl_rd_delta_o = m_gl_stride * thread_k_blocks;
+  int m_gl_rd_delta_i = m_gl_stride * (threads / m_sh_stride);
+  constexpr int m_sh_wr_delta = threads / 2;
+  constexpr int m_sh_rd_delta = threads / 2;
+  constexpr int m_sh_stage = m_sh_stride * thread_k_blocks;
+  constexpr int m_sh_iters = ceildiv(m_sh_stage, m_sh_wr_delta);
+
+  int s_gl_stride = prob_n / 8;
+  constexpr int s_sh_stride = 16 * thread_n_blocks / 8;
+  constexpr int s_sh_stage = s_sh_stride;
+  int s_gl_rd_delta = s_gl_stride;
+
+  // Global A read index of current thread.
+  int a_gl_rd = a_gl_stride * (threadIdx.x / a_gl_rd_delta_o) +
+                (threadIdx.x % a_gl_rd_delta_o);
+  a_gl_rd += a_gl_rd_delta_o * slice_row;
+  // Shared write index of current thread.
+  int a_sh_wr = a_sh_stride * (threadIdx.x / a_gl_rd_delta_o) +
+                (threadIdx.x % a_gl_rd_delta_o);
+  // Shared read index.
+  int a_sh_rd =
+      a_sh_stride * ((threadIdx.x % 32) % 16) + (threadIdx.x % 32) / 16;
+  a_sh_rd += 4 * ((threadIdx.x / 32) / (thread_n_blocks / 4));
+
+  int b_gl_rd = b_gl_stride * (threadIdx.x / b_sh_stride_threads) +
+                (threadIdx.x % b_sh_stride_threads) * b_thread_vecs;
+  b_gl_rd += b_sh_stride * slice_col;
+  b_gl_rd += b_gl_rd_delta_o * slice_row;
+  int b_sh_wr = threadIdx.x * b_thread_vecs;
+  int b_sh_rd = threadIdx.x * b_thread_vecs;
+
+  int m_gl_rd = m_gl_stride * (threadIdx.x / (m_sh_stride)) +
+                (threadIdx.x % (m_sh_stride));
+  m_gl_rd += (m_sh_stride)*slice_col;
+  m_gl_rd += m_gl_rd_delta_o * slice_row;
+  int m_sh_wr = threadIdx.x;
+  int m_sh_rd = threadIdx.x % 16 + (threadIdx.x / 32) * 16;
+
+  int s_gl_rd;
+  if constexpr (group_blocks == -1) {
+    s_gl_rd = s_sh_stride * slice_col + threadIdx.x;
+  } else {
+    s_gl_rd = s_gl_stride * ((thread_k_blocks * slice_row) / group_blocks) +
+              s_sh_stride * slice_col + threadIdx.x;
+  }
+
+  int s_sh_wr = threadIdx.x;
+  int s_sh_rd;
+  // We use a different scale layout for grouped and column-wise quantization as
+  // we scale a `half2` tile in column-major layout in the former and in
+  // row-major in the latter case.
+  if (group_blocks != -1) {
+    s_sh_rd = 8 * ((threadIdx.x / 32) % (thread_n_blocks / 4)) +
+              (threadIdx.x % 32) / 4;
+  } else {
+    s_sh_rd = 8 * ((threadIdx.x / 32) % (thread_n_blocks / 4)) +
+              (threadIdx.x % 32) / 4;
+  }
+
+  // Precompute which thread should not read memory in which iterations; this is
+  // needed if there are more threads than required for a certain tilesize or
+  // when the batchsize is not a multiple of 16.
+  bool a_sh_wr_pred[a_sh_wr_iters];
+  #pragma unroll
+  for (int i = 0; i < a_sh_wr_iters; i++) {
+    a_sh_wr_pred[i] = a_sh_wr_delta * i + a_sh_wr < a_sh_stride * prob_m;
+  }
+  bool s_sh_wr_pred = threadIdx.x < s_sh_stride;
+
+  // To ensure that writing and reading A tiles to/from shared memory, the
+  // latter in fragment format, is fully bank conflict free, we need to use a
+  // rather fancy XOR-based layout. The key here is that neither reads nor
+  // writes of the 16-byte `int4` blocks of 8 consecutive threads involve the
+  // same shared memory banks. Further, it seems (based on NSight-Compute) that
+  // each warp must also write a consecutive memory segment?
+  auto transform_a = [&](int i) {
+    int row = i / a_gl_rd_delta_o;
+    return a_gl_rd_delta_o * row + (i % a_gl_rd_delta_o) ^ row;
+  };
+  // Since the computation of this remapping is non-trivial and, due to our main
+  // loop unrolls, all shared memory accesses are static, we simply precompute
+  // both transformed reads and writes.
+  int a_sh_wr_trans[a_sh_wr_iters];
+  #pragma unroll
+  for (int i = 0; i < a_sh_wr_iters; i++)
+    a_sh_wr_trans[i] = transform_a(a_sh_wr_delta * i + a_sh_wr);
+  int a_sh_rd_trans[2][b_sh_wr_iters][thread_m_blocks];
+  #pragma unroll
+  for (int i = 0; i < b_sh_wr_iters; i++) {
+  #pragma unroll
+    for (int j = 0; j < thread_m_blocks; j++) {
+      a_sh_rd_trans[0][i][j] =
+          transform_a(a_sh_rd_delta_o * i + a_sh_rd_delta_i * j + a_sh_rd);
+      a_sh_rd_trans[1][i][j] =
+          transform_a(a_sh_rd_delta_o * i + a_sh_rd_delta_i * j + a_sh_rd + 2);
+    }
+  }
+
+  // Since B-accesses have non-constant stride they have to be computed at
+  // runtime; we break dependencies between subsequent accesses with a tile by
+  // maintining multiple pointers (we have enough registers), a tiny
+  // optimization.
+  const int4* B_ptr[b_sh_wr_iters];
+  #pragma unroll
+  for (int i = 0; i < b_sh_wr_iters; i++)
+    B_ptr[i] = B + b_gl_rd_delta_i * i + b_gl_rd;
+
+  bool m_sh_wr_pred = threadIdx.x < m_sh_wr_delta;
+  const int4* meta_ptr[m_sh_iters];
+  #pragma unroll
+  for (int i = 0; i < m_sh_iters; i++)
+    meta_ptr[i] = meta + m_gl_rd_delta_i * i + m_gl_rd;
+
+  extern __shared__ int4 sh[];
+  // Shared memory storage for global fetch pipelines.
+  int4* sh_a = sh;
+  int4* sh_b = sh_a + (stages * a_sh_stage);
+  int4* sh_s = sh_b + (stages * b_sh_stage);
+  int4* sh_m = sh_s + (stages * s_sh_stage);
+  // Register storage for double buffer of shared memory reads.
+  FragA frag_a[2][thread_m_blocks][2];
+  I4 frag_b_quant[2][b_thread_vecs];
+  FragM frag_m[2][2];
+  FragC frag_c[thread_m_blocks][4][2];
+  FragS frag_s[2][4];
+
+  // Zero accumulators.
+  auto zero_accums = [&]() {
+  #pragma unroll
+    for (int i = 0; i < thread_m_blocks * 4 * 2 * 4; i++)
+      reinterpret_cast(frag_c)[i] = 0;
+  };
+
+  // Asynchronously fetch the next A, B and s tile from global to the next
+  // shared memory pipeline location.
+  auto fetch_to_shared = [&](int pipe, int a_off, bool pred = true) {
+    if (pred) {
+      int4* sh_a_stage = sh_a + a_sh_stage * pipe;
+  #pragma unroll
+      for (int i = 0; i < a_sh_wr_iters; i++) {
+        cp_async4_pred(
+            &sh_a_stage[a_sh_wr_trans[i]],
+            &A[a_gl_rd_delta_i * i + a_gl_rd + a_gl_rd_delta_o * a_off],
+            a_sh_wr_pred[i]);
+      }
+      int4* sh_b_stage = sh_b + b_sh_stage * pipe;
+  #pragma unroll
+      for (int i = 0; i < b_sh_wr_iters; i++) {
+  #pragma unroll
+        for (int j = 0; j < b_thread_vecs; j++) {
+          cp_async4(&sh_b_stage[b_sh_wr_delta * i + b_sh_wr + j], B_ptr[i] + j);
+        }
+        B_ptr[i] += b_gl_rd_delta_o;
+      }
+      int4* sh_meta_stage = sh_m + m_sh_stage * pipe;
+  #pragma unroll
+      for (int i = 0; i < m_sh_iters; i++) {
+        if (m_sh_wr_pred)
+          cp_async4(&sh_meta_stage[m_sh_wr_delta * i + m_sh_wr], meta_ptr[i]);
+        meta_ptr[i] += m_gl_rd_delta_o;
+      }
+      // Only fetch scales if this tile starts a new group
+      if constexpr (group_blocks != -1) {
+        if (pipe % (group_blocks / thread_k_blocks) == 0) {
+          int4 *sh_s_stage = sh_s + s_sh_stage * pipe;
+          if (s_sh_wr_pred)
+            cp_async4(&sh_s_stage[s_sh_wr], &s[s_gl_rd]);
+          s_gl_rd += s_gl_rd_delta;
+        }
+      }
+    }
+    // Insert a fence even when we are winding down the pipeline to ensure that
+    // waiting is also correct at this point.
+    cp_async_fence();
+  };
+
+  // Wait until the next thread tile has been loaded to shared memory.
+  auto wait_for_stage = [&]() {
+    // We only have `stages - 2` active fetches since we are double buffering
+    // and can only issue the next fetch when it is guaranteed that the previous
+    // shared memory load is fully complete (as it may otherwise be
+    // overwritten).
+    cp_async_wait();
+    __syncthreads();
+  };
+
+  // Load the next sub-tile from the current location in the shared memory pipe
+  // into the current register buffer.
+  auto fetch_to_registers = [&](int k, int pipe) {
+    // It may seem inefficient that we reload the groups for every sub-tile;
+    // however, this does not seem to be a significant bottleneck, while some
+    // theoretically better attempts have lead to bad instruction ordering by
+    // the compiler and correspondingly a noticeable drop in performance.
+    if constexpr (group_blocks != -1) {
+      int4* sh_s_stage =
+          sh_s + s_sh_stage * ((group_blocks / thread_k_blocks) *
+                               (pipe / (group_blocks / thread_k_blocks)));
+      reinterpret_cast(&frag_s[k % 2])[0] = sh_s_stage[s_sh_rd];
+    }
+    int4* sh_a_stage = sh_a + a_sh_stage * pipe;
+  #pragma unroll
+    for (int i = 0; i < thread_m_blocks; i++) {
+      ldsm4(frag_a[k % 2][i][0],
+            &sh_a_stage[a_sh_rd_trans[0][k % b_sh_wr_iters][i]]);
+      ldsm4(frag_a[k % 2][i][1],
+            &sh_a_stage[a_sh_rd_trans[1][k % b_sh_wr_iters][i]]);
+    }
+
+    int4* sh_b_stage = sh_b + b_sh_stage * pipe;
+  #pragma unroll
+    for (int i = 0; i < b_thread_vecs; i++) {
+      frag_b_quant[k % 2][i] = *reinterpret_cast(
+          &sh_b_stage[b_sh_rd_delta * (k % b_sh_wr_iters) + b_sh_rd + i]);
+    }
+
+    // Load meta with ldsm4
+    int4* sh_m_stage = sh_m + m_sh_stage * pipe;
+    ldsm4_m(frag_m[k % 2][0],
+            &sh_m_stage[m_sh_rd_delta * (k % m_sh_iters) + m_sh_rd]);
+  };
+
+  // Execute the actual tensor core matmul of a sub-tile.
+  auto matmul = [&](int k) {
+  // We have the m dimension as the inner loop in order to encourage overlapping
+  // dequantization and matmul operations.
+  #pragma unroll
+    for (int j = 0; j < 4; j++) {
+      FragB frag_b0;
+      FragB frag_b1;
+
+      if constexpr (num_bits == 4) {
+        int b_quant = frag_b_quant[k % 2][0][j];
+        int b_quant_shift = b_quant >> 8;
+
+        frag_b0 = dequant_4bit(b_quant);
+        frag_b1 = dequant_4bit(b_quant_shift);
+
+      } else {
+        int* frag_b_quant_ptr = reinterpret_cast(frag_b_quant[k % 2]);
+        int b_quant_0 = frag_b_quant_ptr[j * 2 + 0];
+        int b_quant_1 = frag_b_quant_ptr[j * 2 + 1];
+
+        frag_b0 = dequant_8bit(b_quant_0);
+        frag_b1 = dequant_8bit(b_quant_1);
+      }
+
+      // If there are no groups, we can just scale the final output once and can
+      // avoid doing so for each weight.
+      if constexpr (group_blocks != -1) {
+        scale(frag_b0, frag_s[k % 2][j], 0);
+      }
+      if constexpr (group_blocks != -1) {
+        scale(frag_b1, frag_s[k % 2][j], 1);
+      }
+
+  #pragma unroll
+      for (int i = 0; i < thread_m_blocks; i++) {
+        mma_sp(frag_b0, frag_b1, frag_a[k % 2][i][0], frag_c[i][j][0],
+               frag_m[k % 2][j / 2], j % 2);
+      }
+    }
+  };
+
+  // Since we slice across the k dimension of a tile in order to increase the
+  // number of warps while keeping the n dimension of a tile reasonable, we have
+  // multiple warps that accumulate their partial sums of the same output
+  // location; which we have to reduce over in the end. We do in shared memory.
+  auto thread_block_reduce = [&]() {
+    constexpr int red_off = threads / b_sh_stride_threads / 2;
+    if (red_off >= 1) {
+      int red_idx = threadIdx.x / b_sh_stride_threads;
+      constexpr int red_sh_stride = b_sh_stride_threads * 4 * 2;
+      constexpr int red_sh_delta = b_sh_stride_threads;
+      int red_sh_rd = red_sh_stride * (threadIdx.x / b_sh_stride_threads) +
+                      (threadIdx.x % b_sh_stride_threads);
+
+  // Parallel logarithmic shared memory reduction. We make sure to avoid any
+  // unnecessary read or write iterations, e.g., for two warps we write only
+  // once by warp 1 and read only once by warp 0.
+  #pragma unroll
+      for (int m_block = 0; m_block < thread_m_blocks; m_block++) {
+  #pragma unroll
+        for (int i = red_off; i > 0; i /= 2) {
+          if (i <= red_idx && red_idx < 2 * i) {
+  #pragma unroll
+            for (int j = 0; j < 4 * 2; j++) {
+              int red_sh_wr =
+                  red_sh_delta * j + (red_sh_rd - red_sh_stride * i);
+              if (i < red_off) {
+                float* c_rd =
+                    reinterpret_cast(&sh[red_sh_delta * j + red_sh_rd]);
+                float* c_wr = reinterpret_cast(&sh[red_sh_wr]);
+  #pragma unroll
+                for (int k = 0; k < 4; k++)
+                  reinterpret_cast(frag_c)[4 * 2 * m_block + j][k] +=
+                      c_rd[k] + c_wr[k];
+              }
+              sh[red_sh_wr] =
+                  reinterpret_cast(&frag_c)[4 * 2 * m_block + j];
+            }
+          }
+          __syncthreads();
+        }
+        if (red_idx == 0) {
+  #pragma unroll
+          for (int i = 0; i < 4 * 2; i++) {
+            float* c_rd =
+                reinterpret_cast(&sh[red_sh_delta * i + red_sh_rd]);
+  #pragma unroll
+            for (int j = 0; j < 4; j++)
+              reinterpret_cast(frag_c)[4 * 2 * m_block + i][j] +=
+                  c_rd[j];
+          }
+        }
+        __syncthreads();
+      }
+    }
+  };
+
+  // Since multiple threadblocks may process parts of the same column slice, we
+  // finally have to globally reduce over the results. As the striped
+  // partitioning minimizes the number of such reductions and our outputs are
+  // usually rather small, we perform this reduction serially in L2 cache.
+  auto global_reduce = [&](bool first = false, bool last = false) {
+    // We are very careful here to reduce directly in the output buffer to
+    // maximize L2 cache utilization in this step. To do this, we write out
+    // results in FP16 (but still reduce with FP32 compute).
+    constexpr int active_threads = 32 * thread_n_blocks / 4;
+    if (threadIdx.x < active_threads) {
+      int c_gl_stride = prob_n / 8;
+      int c_gl_wr_delta_o = 2 * 4 * c_gl_stride;
+      int c_gl_wr_delta_i =
+          c_gl_stride;  // 8 threads (e.g., 0,4,8,12,16,20,24,28)
+      int c_gl_wr = 2 * c_gl_stride * (threadIdx.x % 4) +
+                    8 * (threadIdx.x / 32) + (threadIdx.x % 32) / 4;
+      c_gl_wr += (2 * thread_n_blocks) * slice_col;
+      constexpr int c_sh_wr_delta = active_threads;
+      int c_sh_wr = threadIdx.x;
+
+      int col = 2 * ((threadIdx.x % 32) % 4);
+
+      if (!first) {
+  // Interestingly, doing direct global accesses here really seems to mess up
+  // the compiler and lead to slowdowns, hence we also use async-copies even
+  // though these fetches are not actually asynchronous.
+  #pragma unroll
+        for (int i = 0; i < thread_m_blocks * 4; i++) {
+          cp_async4_pred(&sh[c_sh_wr + c_sh_wr_delta * i],
+                         &C[c_gl_wr + c_gl_wr_delta_o * (i / 2) +
+                            c_gl_wr_delta_i * (i % 2)],
+                         i < (thread_m_blocks - 1) * 4 ||
+                             8 * (i / 2) + col + (i % 2) < prob_m);
+        }
+        cp_async_fence();
+        cp_async_wait<0>();
+      }
+
+  #pragma unroll
+      for (int i = 0; i < thread_m_blocks * 4; i++) {
+        if (i < (thread_m_blocks - 1) * 4 ||
+            8 * (i / 2) + col + (i % 2) < prob_m) {
+          if (!first) {
+            int4 c_red = sh[c_sh_wr + i * c_sh_wr_delta];
+  #pragma unroll
+            for (int j2 = 0; j2 < 2; j2++) {
+  #pragma unroll
+              for (int j1 = 0; j1 < 4; j1++) {
+                reinterpret_cast(
+                    &frag_c)[4 * 2 * 4 * (i / 4) + 8 * j1 + 2 * j2 +
+                             4 * ((i % 4) / 2) + i % 2] +=
+                    __half2float(
+                        reinterpret_cast<__half*>(&c_red)[(j2 * 4 + j1)]);
+              }
+            }
+          }
+          if (!last) {
+            int4 c;
+  #pragma unroll
+            for (int j2 = 0; j2 < 2; j2++) {
+  #pragma unroll
+              for (int j1 = 0; j1 < 4; j1++) {
+                reinterpret_cast<__half*>(&c)[(j2 * 4 + j1)] =
+                    __float2half(reinterpret_cast(
+                        &frag_c)[4 * 2 * 4 * (i / 4) + 8 * j1 + 2 * j2 +
+                                 4 * ((i % 4) / 2) + i % 2]);
+              }
+            }
+            C[c_gl_wr + c_gl_wr_delta_o * (i / 2) + c_gl_wr_delta_i * (i % 2)] =
+                c;
+          }
+        }
+      }
+    }
+  };
+
+  // Write out the reduce final result in the correct layout. We only actually
+  // reshuffle matrix fragments in this step, the reduction above is performed
+  // in fragment layout.
+  auto write_result = [&]() {
+    int c_gl_stride = prob_n / 8;
+
+    constexpr int c_sh_stride = 2 * thread_n_blocks;              // RLC:
+    constexpr int c_sh_stride_2 = 2 * c_sh_stride + 2;            // RLC:
+    constexpr int c_sh_stride_3 = 2 * (2 * thread_n_blocks) + 2;  // RLC:
+
+    int c_gl_wr_delta = c_gl_stride * (threads / (2 * thread_n_blocks));
+
+    int c_gl_wr = c_gl_stride * (threadIdx.x / (2 * thread_n_blocks)) +
+                  (threadIdx.x % (2 * thread_n_blocks));
+    c_gl_wr += (2 * thread_n_blocks) * slice_col;
+
+    int c_sh_wr = c_sh_stride_2 * ((threadIdx.x % 32) % 4) +
+                  ((threadIdx.x % 32) / 4);  // RLC:
+    c_sh_wr += 8 * (threadIdx.x / 32);       // 128/4(half4)
+
+    constexpr int c_sh_rd_delta =
+        c_sh_stride_3 * (threads / (2 * 2 * thread_n_blocks));  // RLC:
+    int c_sh_rd = c_sh_stride_3 * (threadIdx.x / (2 * 2 * thread_n_blocks)) +
+                  (threadIdx.x % (2 * 2 * thread_n_blocks));
+
+    int c_gl_wr_end = c_gl_stride * prob_m;
+
+    auto write = [&](int idx, float c0, float c1, float c2, float c3, FragS& s0,
+                     float c4, float c5, float c6, float c7, FragS& s1) {
+      uint2 res[2];
+      res[0] = to_half4(c0, c1, c2, c3);
+      res[1] = to_half4(c4, c5, c6, c7);
+      half2* tmp = (half2*)&res;
+      // for per-column quantization we finally apply the scale here
+      if constexpr (group_blocks == -1 && num_bits == 4) {
+        tmp[0] = __hmul2(tmp[0], s0[0]);
+        tmp[1] = __hmul2(tmp[1], s0[1]);
+        tmp[2] = __hmul2(tmp[2], s1[0]);
+        tmp[3] = __hmul2(tmp[3], s1[1]);
+      }
+      ((int4*)sh)[idx] = *((int4*)&res[0]);
+    };
+
+    // RLC:  only warp 0 and 1 baseline example
+    if (threadIdx.x / 32 < thread_n_blocks / 4) {
+  #pragma unroll
+      for (int i = 0; i < thread_m_blocks; i++) {
+        int wr = c_sh_wr;
+        write(wr, frag_c[i][0][0][0], frag_c[i][1][0][0], frag_c[i][2][0][0],
+              frag_c[i][3][0][0], frag_s[0][0], frag_c[i][0][0][2],
+              frag_c[i][1][0][2], frag_c[i][2][0][2], frag_c[i][3][0][2],
+              frag_s[0][2]);
+        write(wr + c_sh_stride, frag_c[i][0][0][1], frag_c[i][1][0][1],
+              frag_c[i][2][0][1], frag_c[i][3][0][1], frag_s[0][0],
+              frag_c[i][0][0][3], frag_c[i][1][0][3], frag_c[i][2][0][3],
+              frag_c[i][3][0][3], frag_s[0][2]);
+        write(wr + 4 * c_sh_stride_2, frag_c[i][0][1][0], frag_c[i][1][1][0],
+              frag_c[i][2][1][0], frag_c[i][3][1][0], frag_s[0][0],
+              frag_c[i][0][1][2], frag_c[i][1][1][2], frag_c[i][2][1][2],
+              frag_c[i][3][1][2], frag_s[0][2]);
+        write(wr + 4 * c_sh_stride_2 + c_sh_stride, frag_c[i][0][1][1],
+              frag_c[i][1][1][1], frag_c[i][2][1][1], frag_c[i][3][1][1],
+              frag_s[0][0], frag_c[i][0][1][3], frag_c[i][1][1][3],
+              frag_c[i][2][1][3], frag_c[i][3][1][3], frag_s[0][2]);
+
+        c_sh_wr += 8 * c_sh_stride_2;
+      }
+    }
+    __syncthreads();
+
+  #pragma unroll
+    for (int i = 0;
+         i < ceildiv(16 * thread_m_blocks, threads / (2 * thread_n_blocks));
+         i++) {
+      if (c_gl_wr < c_gl_wr_end) {
+        C[c_gl_wr] = sh[c_sh_rd];
+        c_gl_wr += c_gl_wr_delta;
+        c_sh_rd += c_sh_rd_delta;
+      }
+    }
+  };
+
+  // Start global fetch and register load pipelines.
+  auto start_pipes = [&]() {
+  #pragma unroll
+    for (int i = 0; i < stages - 1; i++) fetch_to_shared(i, i, i < slice_iters);
+    zero_accums();
+    wait_for_stage();
+    fetch_to_registers(0, 0);
+    a_gl_rd += a_gl_rd_delta_o * (stages - 1);
+  };
+  start_pipes();
+
+  // Main loop.
+  while (slice_iters) {
+  // We unroll over both the global fetch and the register load pipeline to
+  // ensure all shared memory accesses are static. Note that both pipelines have
+  // even length meaning that the next iteration will always start at index 0.
+  #pragma unroll
+    for (int pipe = 0; pipe < stages;) {
+      fetch_to_shared((pipe + stages - 1) % stages, pipe,
+                      slice_iters >= stages);
+      matmul(pipe);
+      wait_for_stage();
+
+      fetch_to_registers(pipe + 1, (pipe + 1) % stages);
+
+      pipe++;
+      slice_iters--;
+      if (slice_iters == 0) break;
+    }
+    a_gl_rd += a_gl_rd_delta_o * stages;
+
+    // Process results and, if necessary, proceed to the next column slice.
+    // While this pattern may not be the most readable, other ways of writing
+    // the loop seemed to noticeably worse performance after compilation.
+    if (slice_iters == 0) {
+      cp_async_wait<0>();
+      bool last = slice_idx == slice_count - 1;
+      // For per-column scales, we only fetch them here in the final step before
+      // write-out
+      if constexpr (group_blocks == -1) {
+        if constexpr (num_bits == 8) {
+          if (s_sh_wr_pred) cp_async4(&sh_s[s_sh_wr], &s[s_gl_rd]);
+          cp_async_fence();
+        } else {
+          if (last) {
+            if (s_sh_wr_pred) cp_async4(&sh_s[s_sh_wr], &s[s_gl_rd]);
+            cp_async_fence();
+          }
+        }
+      }
+      thread_block_reduce();
+
+      if constexpr (group_blocks == -1) {
+        if constexpr (num_bits == 8) {
+          cp_async_wait<0>();
+          __syncthreads();
+          if (threadIdx.x / 32 < thread_n_blocks / 4) {
+            *(float4*)(frag_s) = *(float4*)(&sh_s[s_sh_rd]);
+          }
+        } else {
+          if (last) {
+            cp_async_wait<0>();
+            __syncthreads();
+            if (threadIdx.x / 32 < thread_n_blocks / 4) {
+              *(float4*)(frag_s) = *(float4*)(&sh_s[s_sh_rd]);
+            }
+          }
+        }
+      }
+
+      // For 8-bit channelwise, we apply the scale before the global reduction
+      // that converts the fp32 results to fp16 (so that we avoid possible
+      // overflow in fp16)
+      if constexpr (group_blocks == -1 && num_bits == 8) {
+        if (threadIdx.x / 32 < thread_n_blocks / 4) {
+  #pragma unroll
+          for (int i = 0; i < thread_m_blocks; i++) {
+            scale_floats(&frag_c[i][0][0][0], &frag_c[i][1][0][0],
+                         &frag_c[i][2][0][0], &frag_c[i][3][0][0], frag_s[0][0],
+                         &frag_c[i][0][0][2], &frag_c[i][1][0][2],
+                         &frag_c[i][2][0][2], &frag_c[i][3][0][2],
+                         frag_s[0][2]);
+
+            scale_floats(&frag_c[i][0][0][1], &frag_c[i][1][0][1],
+                         &frag_c[i][2][0][1], &frag_c[i][3][0][1], frag_s[0][0],
+                         &frag_c[i][0][0][3], &frag_c[i][1][0][3],
+                         &frag_c[i][2][0][3], &frag_c[i][3][0][3],
+                         frag_s[0][2]);
+
+            scale_floats(&frag_c[i][0][1][0], &frag_c[i][1][1][0],
+                         &frag_c[i][2][1][0], &frag_c[i][3][1][0], frag_s[0][0],
+                         &frag_c[i][0][1][2], &frag_c[i][1][1][2],
+                         &frag_c[i][2][1][2], &frag_c[i][3][1][2],
+                         frag_s[0][2]);
+
+            scale_floats(&frag_c[i][0][1][1], &frag_c[i][1][1][1],
+                         &frag_c[i][2][1][1], &frag_c[i][3][1][1], frag_s[0][0],
+                         &frag_c[i][0][1][3], &frag_c[i][1][1][3],
+                         &frag_c[i][2][1][3], &frag_c[i][3][1][3],
+                         frag_s[0][2]);
+          }
+        }
+      }
+
+      if (slice_count > 1) {  // only globally reduce if there is more than one
+                              // block in a slice
+        barrier_acquire(&locks[slice_col], slice_idx);
+        global_reduce(slice_idx == 0, last);
+        barrier_release(&locks[slice_col], last);
+      }
+      if (last)  // only the last block in a slice actually writes the result
+        write_result();
+
+      slice_row = 0;
+      slice_col_par++;
+      slice_col++;
+      init_slice();
+      if (slice_iters) {
+        a_gl_rd = a_gl_stride * (threadIdx.x / a_gl_rd_delta_o) +
+                  (threadIdx.x % a_gl_rd_delta_o);
+  #pragma unroll
+        for (int i = 0; i < b_sh_wr_iters; i++)
+          B_ptr[i] += b_sh_stride - b_gl_rd_delta_o * k_tiles;
+  #pragma unroll
+        for (int i = 0; i < m_sh_iters; i++)
+          meta_ptr[i] += (m_sh_stride)-m_gl_rd_delta_o * k_tiles;
+        if (slice_col == 0) {
+  #pragma unroll
+          for (int i = 0; i < b_sh_wr_iters; i++) B_ptr[i] -= b_gl_stride;
+  #pragma unroll
+          for (int i = 0; i < m_sh_iters; i++) meta_ptr[i] -= m_gl_stride;
+        }
+        s_gl_rd = s_sh_stride * slice_col + threadIdx.x;
+        start_pipes();
+      }
+    }
+  }
+}
+
+#define CALL_IF_2_4(NUM_BITS, THREAD_M_BLOCKS, THREAD_N_BLOCKS,               \
+                    THREAD_K_BLOCKS, GROUP_BLOCKS)                            \
+  else if (num_bits == NUM_BITS && thread_m_blocks == THREAD_M_BLOCKS &&      \
+           thread_n_blocks == THREAD_N_BLOCKS &&                              \
+           thread_k_blocks == THREAD_K_BLOCKS &&                              \
+           group_blocks == GROUP_BLOCKS) {                                    \
+    cudaFuncSetAttribute(                                                     \
+        Marlin_24,                     \
+        cudaFuncAttributeMaxDynamicSharedMemorySize, max_shared_mem);         \
+    Marlin_24                          \
+        <<>>(A_ptr, B_ptr, meta_ptr, \
+                                                      C_ptr, s_ptr, prob_n,   \
+                                                      prob_m, prob_k, locks); \
+  }
+
+void marlin_cuda_2_4(const void* A, const void* B, const void* meta, void* C,
+                     void* s, int prob_m, int prob_n, int prob_k,
+                     void* workspace, int num_bits, int groupsize = -1,
+                     int dev = 0, cudaStream_t stream = 0, int thread_k = -1,
+                     int thread_m = -1, int sms = -1, int max_par = 16) {
+  int tot_n = prob_n;
+  int tot_n_blocks = ceildiv(tot_n, 16);
+  int pad = 16 * tot_n_blocks - tot_n;
+
+  if (sms == -1) {
+    cudaDeviceGetAttribute(&sms, cudaDevAttrMultiProcessorCount, dev);
+  }
+  TORCH_CHECK(sms > 0);
+
+  int max_shared_mem = 0;
+  cudaDeviceGetAttribute(&max_shared_mem,
+                         cudaDevAttrMaxSharedMemoryPerBlockOptin, dev);
+  TORCH_CHECK(max_shared_mem > 0);
+
+  if (thread_k == -1 || thread_m == -1) {
+    if (prob_n <= 16) {
+      // For small batchizes, better partitioningif is slightly more important
+      // than better compute utilization
+      thread_k = 128;
+      thread_m = 128;
+    } else if (prob_n <= 256) {
+      thread_k = 64;
+      thread_m = 256;
+    } else {
+      thread_k = 32;
+      thread_m = 512;
+    }
+  }
+
+  int thread_k_blocks = thread_k / 32;  // 2:4 version with m16n8k32 instruction
+  int thread_m_blocks = thread_m / 16;
+  int group_blocks = (groupsize == -1) ? -1 : groupsize / 16;
+  int blocks = sms;
+
+  TORCH_CHECK(prob_m % thread_m == 0, "prob_m = ", prob_m,
+              " is not divisible by thread_m = ", thread_m);
+  TORCH_CHECK(prob_k % thread_k == 0, "prob_k = ", prob_k,
+              " is not divisible by thread_k = ", thread_k);
+  if (group_blocks != -1) {
+    TORCH_CHECK((prob_k / 2) % group_blocks == 0, "prob_k/2 = ", prob_k / 2,
+                " is not divisible by group_blocks = ", group_blocks);
+  }
+
+  TORCH_CHECK(prob_m > 0 && prob_n > 0 && prob_k > 0, "Invalid MNK = [", prob_m,
+              ", ", prob_n, ", ", prob_k, "]");
+
+  const int4* A_ptr = (const int4*)A;
+  const int4* B_ptr = (const int4*)B;
+  const int4* meta_ptr = (const int4*)meta;
+  int4* C_ptr = (int4*)C;
+  const int4* s_ptr = (const int4*)s;
+
+  constexpr int max_m_blocks = 4;
+
+  int* locks = (int*)workspace;
+  for (int i = 0; i < tot_n_blocks; i += max_m_blocks) {
+    int thread_n_blocks = tot_n_blocks - i;
+    prob_n = tot_n - 16 * i;
+    int par = 1;
+    if (thread_n_blocks > max_m_blocks) {
+      // Note that parallel > 1 currently only works for inputs without any
+      // padding
+      par = (16 * thread_n_blocks - pad) / (max_m_blocks * 16);
+      if (par > max_par) par = max_par;
+      prob_n = (max_m_blocks * 16) * par;
+      i += max_m_blocks * (par - 1);
+      thread_n_blocks = max_m_blocks;
+    }
+
+    // For compilation speed, we only define the kernel configurations that have
+    // seemed useful (in terms of performance) in our testing, however many more
+    // are, in principle, possible.
+
+    // the false is start of the CALL_IF macros
+    if (false) {
+    }  //         BMxBNxBK,   group
+    // 4-bit
+    CALL_IF_2_4(4, 8, 1, 4, -1)  // e.g., 16x128x128
+    CALL_IF_2_4(4, 8, 1, 4, 4)   // e.g., 16x128x128, 64
+
+    CALL_IF_2_4(4, 16, 1, 2, -1)  // e.g., 16x256x64
+    CALL_IF_2_4(4, 16, 1, 2, 4)   // e.g., 16x256x64,  64
+    CALL_IF_2_4(4, 16, 2, 2, -1)  // e.g.. 32x256x64
+    CALL_IF_2_4(4, 16, 2, 2, 4)
+    CALL_IF_2_4(4, 16, 3, 2, -1)
+    CALL_IF_2_4(4, 16, 3, 2, 4)
+    CALL_IF_2_4(4, 16, 4, 2, -1)
+    CALL_IF_2_4(4, 16, 4, 2, 4)
+
+    CALL_IF_2_4(4, 32, 1, 1, -1)  // e.g., 16x256x64
+    CALL_IF_2_4(4, 32, 1, 1, 4)   // e.g., 16x256x64,  64
+    CALL_IF_2_4(4, 32, 2, 1, -1)  // e.g.. 32x256x64
+    CALL_IF_2_4(4, 32, 2, 1, 4)
+    CALL_IF_2_4(4, 32, 3, 1, -1)
+    CALL_IF_2_4(4, 32, 3, 1, 4)
+    CALL_IF_2_4(4, 32, 4, 1, -1)
+    CALL_IF_2_4(4, 32, 4, 1, 4)
+
+    // 8-bit
+    CALL_IF_2_4(8, 8, 1, 4, -1)  // e.g., 16x128x128
+    CALL_IF_2_4(8, 8, 1, 4, 4)   // e.g., 16x128x128, 64
+
+    CALL_IF_2_4(8, 16, 1, 2, -1)  // e.g., 16x256x64
+    CALL_IF_2_4(8, 16, 1, 2, 4)   // e.g., 16x256x64,  64
+    CALL_IF_2_4(8, 16, 2, 2, -1)  // e.g.. 32x256x64
+    CALL_IF_2_4(8, 16, 2, 2, 4)
+    CALL_IF_2_4(8, 16, 3, 2, -1)
+    CALL_IF_2_4(8, 16, 3, 2, 4)
+    CALL_IF_2_4(8, 16, 4, 2, -1)
+    CALL_IF_2_4(8, 16, 4, 2, 4)
+
+    CALL_IF_2_4(8, 32, 1, 1, -1)  // e.g., 16x256x64
+    CALL_IF_2_4(8, 32, 1, 1, 4)   // e.g., 16x256x64,  64
+    CALL_IF_2_4(8, 32, 2, 1, -1)  // e.g.. 32x256x64
+    CALL_IF_2_4(8, 32, 2, 1, 4)
+    CALL_IF_2_4(8, 32, 3, 1, -1)
+    CALL_IF_2_4(8, 32, 3, 1, 4)
+    CALL_IF_2_4(8, 32, 4, 1, -1)
+    CALL_IF_2_4(8, 32, 4, 1, 4)
+    else {
+      throw std::runtime_error("Unsupported shapes: MKN = [" + str(prob_m) +
+                               ", " + str(prob_k) + ", " + str(prob_n) + "]" +
+                               ", groupsize = " + str(groupsize) +
+                               ", thread_m_blocks = " + str(thread_m_blocks) +
+                               ", thread_n_blocks = " + str(thread_n_blocks) +
+                               ", thread_k_blocks = " + str(thread_k_blocks));
+    }
+
+    A_ptr += 16 * thread_n_blocks * (prob_k / 8) * par;
+    C_ptr += 16 * thread_n_blocks * (prob_m / 8) * par;
+  }
+}
+
+torch::Tensor marlin_24_gemm(torch::Tensor& a, torch::Tensor& b_q_weight,
+                                  torch::Tensor& b_meta,
+                                  torch::Tensor& b_scales,
+                                  torch::Tensor& workspace, int64_t num_bits,
+                                  int64_t size_m, int64_t size_n,
+                                  int64_t size_k) {
+  // Verify num_bits
+  TORCH_CHECK(num_bits == 4 || num_bits == 8,
+              "num_bits must be 4 or 8. Got = ", num_bits);
+  int pack_factor = 32 / num_bits;
+
+  // Verify M
+  TORCH_CHECK(size_m == a.size(0),
+              "Shape mismatch: a.size(0) = " + str(a.size(0)) +
+                  ", size_m = " + str(size_m));
+
+  // Verify K
+  TORCH_CHECK(size_k == a.size(1),
+              "Shape mismatch: a.size(1) = " + str(a.size(1)) +
+                  ", size_k = " + str(size_k));
+  TORCH_CHECK(size_k % torchao::tile_size == 0,
+              "size_k = " + str(size_k) + " is not divisible by tile_size = " +
+                  str(torchao::tile_size));
+  TORCH_CHECK((size_k / torchao::tile_size / 2) == b_q_weight.size(0),
+              "Shape mismatch: b_q_weight.size(0) = " +
+                  str(b_q_weight.size(0)) + ", size_k = " + str(size_k) +
+                  ", tile_size = " + str(torchao::tile_size));
+
+  // Verify N
+  TORCH_CHECK(b_scales.size(1) == size_n,
+              "b_scales.size(1) = " + str(b_scales.size(1)) +
+                  ", size_n = " + str(size_n));
+  TORCH_CHECK(
+      b_q_weight.size(1) % torchao::tile_size == 0,
+      "b_q_weight.size(1) = " + str(b_q_weight.size(1)) +
+          " is not divisible by tile_size = " + str(torchao::tile_size));
+
+  int actual_size_n = (b_q_weight.size(1) / torchao::tile_size) * pack_factor;
+  TORCH_CHECK(
+      size_n == actual_size_n,
+      "size_n = " + str(size_n) + ", actual_size_n = " + str(actual_size_n));
+
+  // Verify meta
+  TORCH_CHECK(b_meta.size(0) == size_k / 8 / 2 / 2,
+              "b_meta.size(0) = ", b_meta.size(0),
+              " is not size_k / 8 / 2 / 2 = ", size_k / 8 / 2 / 2);
+  TORCH_CHECK(b_meta.size(1) == size_n * 2, "b_meta.size(1) = ", b_meta.size(1),
+              " is not size_n * 2 = ", size_n * 2);
+
+  // Verify A device and strides
+  TORCH_CHECK(a.device().is_cuda(), "A is not on GPU");
+  TORCH_CHECK(a.is_contiguous(), "A is not contiguous");
+
+  // Verify B device and strides
+  TORCH_CHECK(b_q_weight.device().is_cuda(), "b_q_weight is not on GPU");
+  TORCH_CHECK(b_q_weight.is_contiguous(), "b_q_weight is not contiguous");
+
+  // Verify b_meta device and strides
+  TORCH_CHECK(b_meta.device().is_cuda(), "b_meta is not on GPU");
+  TORCH_CHECK(b_meta.is_contiguous(), "b_meta is not contiguous");
+
+  // Verify scales device and strides
+  TORCH_CHECK(b_scales.device().is_cuda(), "b_scales is not on GPU");
+  TORCH_CHECK(b_scales.is_contiguous(), "b_scales is not contiguous");
+
+  // Alloc C matrix
+  const at::cuda::OptionalCUDAGuard device_guard(device_of(a));
+  auto options = torch::TensorOptions().dtype(a.dtype()).device(a.device());
+  torch::Tensor c = torch::empty({size_m, size_n}, options);
+
+  int thread_k = -1;
+  int thread_m = -1;
+  int sms = -1;
+  int max_par = torchao::max_par;
+
+  int groupsize = -1;
+  if (b_scales.size(0) > 1) {
+    TORCH_CHECK(size_k % b_scales.size(0) == 0,
+                "size_k = " + str(size_k) +
+                    ", is not divisible by b_scales.size(0) = " +
+                    str(b_scales.size(0)));
+    groupsize = size_k / b_scales.size(0);
+    groupsize /= 2;  // Because of 24
+  }
+
+  // Verify groupsize
+  TORCH_CHECK(groupsize == -1 || groupsize == 64,
+              "Unexpected groupsize = " + str(groupsize));
+
+  // Verify workspace size
+  TORCH_CHECK(size_n % torchao::min_thread_n == 0,
+              "size_n = " + str(size_n) +
+                  ", is not divisible by min_thread_n = " +
+                  str(torchao::min_thread_n));
+  int min_workspace_size =
+      (size_n / torchao::min_thread_n) * torchao::max_par;
+  TORCH_CHECK(workspace.numel() >= min_workspace_size,
+              "workspace.numel = " + str(workspace.numel()) +
+                  " is below min_workspace_size = " + str(min_workspace_size));
+
+  int dev = a.get_device();
+  torchao::marlin_cuda_2_4(
+      a.data_ptr(), b_q_weight.data_ptr(), b_meta.data_ptr(), c.data_ptr(),
+      b_scales.data_ptr(), size_n, size_m, size_k, workspace.data_ptr(),
+      num_bits, groupsize, dev, at::cuda::getCurrentCUDAStream(dev), thread_k,
+      thread_m, sms, max_par);
+
+  return c;
+}
+
+#endif
+
+TORCH_LIBRARY_IMPL(torchao, CUDA, m) {
+  m.impl("torchao::marlin_24_gemm", &marlin_24_gemm);
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/tensor_core_tiled_layout/tensor_core_tiled_layout.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/tensor_core_tiled_layout/tensor_core_tiled_layout.cu
new file mode 100644
index 0000000000000000000000000000000000000000..cfbabf08dd6d2c210eef4e536735e309c1ff112b
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/tensor_core_tiled_layout/tensor_core_tiled_layout.cu
@@ -0,0 +1,376 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#if (defined(USE_ROCM) && ROCM_VERSION >= 60200) || !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 800
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#if defined(USE_ROCM)
+#include 
+#include 
+#include 
+#endif
+
+template 
+constexpr __host__ __device__ auto divUp(U a, V b) -> decltype(a + b) {
+  static_assert(std::is_integral::value && std::is_integral::value, "");
+  const uint64_t blocks = a / b + (a % b != 0);
+  return blocks;
+}
+
+#if defined(USE_ROCM)
+constexpr int32_t kWarpSize = 64;
+#else
+constexpr int32_t kWarpSize = 32;
+#endif
+
+//Simple data structure to represent 4 pairs of bfloat16s, used for vectorized dequantization
+//https://github.com/pytorch/pytorch/blob/b6689e0fb83a1578959ab0d9c6d2d9e11f7df21a/aten/src/ATen/native/cuda/int4mm.cu#L178-L180
+struct __align__(16) bf16x2x4 {
+  __nv_bfloat162 vals[4];
+};
+
+//Copied from https://github.com/pytorch/pytorch/blob/b6689e0fb83a1578959ab0d9c6d2d9e11f7df21a/aten/src/ATen/native/cuda/int4mm.cu#L195C1-L241C1
+inline __device__ bf16x2x4 convert_i4x8_to_bf16x2x4(uint32_t source) {
+  bf16x2x4 result;
+  constexpr int kElements = 8;
+
+  uint32_t* h = reinterpret_cast(&result);
+  uint32_t const source_i4s = source;
+
+  // First, we extract the i4s and construct an intermediate fp16 number.
+#if !defined(USE_ROCM)
+  static constexpr uint32_t immLut = (0xf0 & 0xcc) | 0xaa;
+#endif
+  static constexpr uint32_t MASK = 0x000f000f;
+  static constexpr uint32_t I4s_TO_BF16s_MAGIC_NUM = 0x43004300;
+
+  // We don't have enough mantissa to remove as much shift overhead as FP16, so
+  // we must loop. No shift needed for first item.
+  uint32_t i4s = source_i4s;
+// AMD MI300X ISA that performs two bitwise operations in a single instruction:
+// v_and_or_b32 performs H[0] = (i4s & MASK) | I4s_TO_BF16s_MAGIC_NUM
+//   - First ANDs `i4s` with `MASK` (0x000f000f) to extract 4-bit values
+//   - Then ORs the result with `I4s_TO_BF16s_MAGIC_NUM` (0x43004300) to convert them to bfloat16
+#if defined(USE_ROCM)
+  asm volatile("v_and_or_b32 %0, %1, %2, %3"
+               : "=v"(h[0])
+               : "v"(i4s), "v"(MASK), "v"(I4s_TO_BF16s_MAGIC_NUM));
+#else
+  asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
+               : "=r"(h[0])
+               : "r"(i4s), "n"(MASK), "n"(I4s_TO_BF16s_MAGIC_NUM), "n"(immLut));
+#endif
+
+#pragma unroll
+  for (int ii = 1; ii < kElements / 2; ++ii) {
+    i4s >>= 4; // or is it 8?
+    // (i4s & 0x000f000f) | 0x43004300
+#if defined(USE_ROCM)
+    asm volatile("v_and_or_b32 %0, %1, %2, %3"
+        : "=v"(h[ii])
+        : "v"(i4s), "v"(MASK), "v"(I4s_TO_BF16s_MAGIC_NUM));
+#else
+    asm volatile(
+        "lop3.b32 %0, %1, %2, %3, %4;\n"
+        : "=r"(h[ii])
+        : "r"(i4s), "n"(MASK), "n"(I4s_TO_BF16s_MAGIC_NUM), "n"(immLut));
+#endif
+  }
+
+  // This is the BF16 {-136, -136} represented as an integer.
+#if defined(USE_ROCM)
+#if ROCM_VERSION >= 60200
+  auto BF16_SCALE_FACTOR = __bfloat162bfloat162(__hip_bfloat16(__hip_bfloat16_raw{0xC308}));
+  auto BF16_UNIT_VALUE = __bfloat162bfloat162(__hip_bfloat16(__hip_bfloat16_raw{0x3F80}));
+#else
+  auto BF16_SCALE_FACTOR = __bfloat162bfloat162(__hip_bfloat16{0xC308});
+  auto BF16_UNIT_VALUE = __bfloat162bfloat162(__hip_bfloat16{0x3F80});
+#endif
+#else
+  static constexpr uint32_t BF16_SCALE_FACTOR = 0xC308C308;
+  static constexpr uint32_t BF16_UNIT_VALUE = 0x3F803F80;
+#endif
+
+// Finally, we construct the output numbers.
+#pragma unroll
+  for (int ii = 0; ii < kElements / 2; ++ii) {
+    // Since this section is for Ampere+, we use bf16 fma to do the bias
+    // subtraction
+#if defined(USE_ROCM)
+    result.vals[ii] = __hfma2(result.vals[ii], BF16_UNIT_VALUE, BF16_SCALE_FACTOR);
+#else
+    asm("fma.rn.bf16x2 %0, %1, %2, %3;\n"
+        : "=r"(h[ii])
+        : "r"(h[ii]), "r"(BF16_UNIT_VALUE), "r"(BF16_SCALE_FACTOR));
+#endif
+  }
+
+  return result;
+}
+// in size [ceil(n / 8)][ceil(k / (InnerKTiles * 16))][32][InnerKTiles / 2]
+// scales_and_zeros size [numQGroups][n][2]
+// out size [n][k]
+template 
+__global__ void _dequantize_int4_kernel(
+    const at::PackedTensorAccessor32 in,
+    at::PackedTensorAccessor32 out,
+    std::optional> scales_and_zeros = std::nullopt)
+{
+
+  constexpr int32_t kNTileSize = 8;
+  constexpr int32_t kKTileSize = 16;
+
+  auto kOuterTile = blockIdx.x;
+  auto nTile = blockIdx.y;
+  auto t = threadIdx.x;
+
+  // n dimension that this lane loads from
+  auto n0 = nTile * kNTileSize + (t / 4);
+
+  // 8 k-tile values, 4 per m16n8k16 mma.sync operand B
+  // int32_t ks[8];
+  //Only need 4 offsets since TC layout for single tile is 2x2 (2 pairs of 2 contiguous values)
+  int32_t ks[4];
+
+  // Store address base offset
+  auto pOut = &out[n0][0];
+
+// Unpack 2 k-tiles at a time since min pack size is InnerKTiles = 2
+#pragma unroll
+  for (int innerKTile = 0; innerKTile < InnerKTiles; innerKTile += 2) {
+    //Tensor-core layout for m16n8k16 is such that each tile has 2 pairs of 2 contiguous values
+    //Hence, we only need 4 offsets
+    // Offsets of innerTile0
+    auto kBase0 = (kOuterTile * InnerKTiles + innerKTile) * kKTileSize;
+    ks[0] = kBase0 + (t % 4) * 2;
+    ks[1] = ks[0] + 8;
+
+    // Offsets of innerTile1
+    auto kBase1 = kBase0 + kKTileSize;
+    ks[2] = kBase1 + (t % 4) * 2;
+    ks[3] = ks[2] + 8;
+
+    // inner k-tiles unpack two at a time
+    int32_t pack = in[nTile][kOuterTile][t][innerKTile / 2];
+
+    if constexpr(kDequant) {
+      // static_assert(scales_and_zeros.has_value(), "scales_and_zeros must be set when dequantizing");
+      static_assert(std::is_same::value, "Out must be BFloat16 when dequantizing");
+      // __nv_bfloat16 v[8];
+
+      // // Extract u4, convert to s4 by subtracting by 2 ** nbits / 2, then convert to bfloat16
+      bf16x2x4 v_bf16x2x4 = convert_i4x8_to_bf16x2x4(pack);
+
+      // All b values within a 16x16 tile should fall within the same q group
+      // Hence we load 1 scale and zero per loop
+      int qgroup = ks[0] /  groupSize;
+#if defined(USE_ROCM)
+      __nv_bfloat162 scale2 = __bfloat162bfloat162(__hip_bfloat16(1.0f));
+      __nv_bfloat162 zero2 = __bfloat162bfloat162(__hip_bfloat16(1.0f));
+
+      if (scales_and_zeros) {
+        const auto& sz = *scales_and_zeros;
+        const __nv_bfloat16* pSZ = reinterpret_cast(&sz[qgroup][n0][0]);
+
+        scale2 = __bfloat162bfloat162(pSZ[0]);
+        zero2 = __bfloat162bfloat162(pSZ[1]);
+      }
+#else
+      const __nv_bfloat16 *pSZ = reinterpret_cast(&scales_and_zeros.value()[qgroup][n0][0]);
+      __nv_bfloat162 scale2 = __bfloat162bfloat162(pSZ[0]);
+      __nv_bfloat162 zero2 = __bfloat162bfloat162(pSZ[1]);
+#endif
+
+  #pragma unroll
+      for (int i = 0; i < 4; i++) {
+        reinterpret_cast<__nv_bfloat162*>(&pOut[ks[i]])[0] = __hfma2(v_bf16x2x4.vals[i], scale2, zero2);
+      }
+    }
+    else {
+      static_assert(std::is_same::value, "Out must be int32_t when unpacking to int");
+      int32_t v[8];
+
+      v[0] = pack & 0x0000000f;
+      v[2] = (pack >> 4) & 0x0000000f;
+      v[4] = (pack >> 8) & 0x0000000f;
+      v[6] = (pack >> 12) & 0x0000000f;
+      v[1] = (pack >> 16) & 0x0000000f;
+      v[3] = (pack >> 20) & 0x0000000f;
+      v[5] = (pack >> 24) & 0x0000000f;
+      v[7] = (pack >> 28) & 0x0000000f;
+      int2* v_i32x2 = reinterpret_cast(v);
+
+    #pragma unroll
+      for (int i = 0; i < 4; ++i) {
+        reinterpret_cast(&pOut[ks[i]])[0] = v_i32x2[i];
+      }
+    }
+  }
+}
+
+// output is [n][k] (int32 dtype)
+// input is [n / 8][k / (InnerKTiles * 16)][32][innerKTiles / 2]
+// scales_and_zeros is [numQGroups][n][2]
+// qGroupSize is 32, 64, 128 or 256
+at::Tensor _dequantize_tensor_core_tiled_layout(
+    const at::Tensor& packed_w,
+    const at::Tensor& scales_and_zeros,
+    int64_t group_size,
+    int64_t innerKTiles)
+{
+
+  constexpr int32_t kNTileSize = 8;
+  constexpr int32_t kKTileSize = 16;
+
+  c10::cuda::CUDAGuard g(packed_w.device());
+
+  // packed_w preconditions
+  TORCH_CHECK(packed_w.dim() == 4);
+  TORCH_CHECK(packed_w.dtype() == at::kInt);
+  TORCH_CHECK(packed_w.is_contiguous());
+  TORCH_CHECK(packed_w.size(2) == 32);
+  TORCH_CHECK(packed_w.size(3) == innerKTiles / 2);
+  TORCH_CHECK(innerKTiles == 2 || innerKTiles == 4 || innerKTiles == 8);
+
+  auto numQGroups = scales_and_zeros.size(0);
+  int N = packed_w.size(0) * kNTileSize;
+  int K = packed_w.size(1) * innerKTiles * kKTileSize;
+
+  // scales_and_zeros preconditions
+  TORCH_CHECK(
+      group_size == 32 || group_size == 64 || group_size == 128 ||
+      group_size == 256);
+  TORCH_CHECK(numQGroups == K / group_size);
+  TORCH_CHECK(scales_and_zeros.dim() == 3);
+  TORCH_CHECK(scales_and_zeros.size(1) == N);
+  TORCH_CHECK(scales_and_zeros.size(2) == 2);
+
+  auto nTiles = divUp(N, kNTileSize);
+  auto kSuperTiles = divUp(K, innerKTiles * kKTileSize);
+  auto out = at::empty(
+      {N, K},
+      at::TensorOptions().dtype(at::kBFloat16).device(packed_w.device()));
+
+  auto stream = at::cuda::getCurrentCUDAStream();
+  dim3 grid(kSuperTiles, nTiles);
+
+#define RUN_DEQUANT(QGROUPSIZE) \
+  do { \
+    switch(innerKTiles) { \
+      case 2: \
+        _dequantize_int4_kernel<<>>( \
+        packed_w.packed_accessor32(), \
+        out.packed_accessor32(), \
+        scales_and_zeros.packed_accessor32()); \
+        break; \
+      case 4: \
+        _dequantize_int4_kernel<<>>( \
+        packed_w.packed_accessor32(), \
+        out.packed_accessor32(), \
+        scales_and_zeros.packed_accessor32()); \
+        break; \
+      case 8: \
+        _dequantize_int4_kernel<<>>( \
+        packed_w.packed_accessor32(), \
+        out.packed_accessor32(), \
+        scales_and_zeros.packed_accessor32()); \
+        break; \
+      default: \
+        break; \
+    } \
+  } while(false)
+
+#define DISPATCH_Q_GROUP() \
+  do { \
+    switch (group_size) { \
+      case 32: \
+        RUN_DEQUANT(32); \
+        break; \
+      case 64: \
+        RUN_DEQUANT(64); \
+        break; \
+      case 128: \
+        RUN_DEQUANT(128); \
+        break; \
+      case 256: \
+        RUN_DEQUANT(256); \
+        break; \
+      default: \
+        break; \
+    } \
+  } while(false)
+
+  DISPATCH_Q_GROUP();
+  #undef DISPATCH_Q_GROUP
+  #undef RUN_DEQUANT
+
+  return out;
+}
+
+// output is [n][k] (int32 dtype)
+// input is [n / 8][k / (InnerKTiles * 16)][32][innerKTiles / 2]
+at::Tensor _unpack_tensor_core_tiled_layout(
+    const at::Tensor& packed_w,
+    int64_t innerKTiles)
+{
+
+  c10::cuda::CUDAGuard g(packed_w.device());
+
+  TORCH_CHECK(packed_w.dim() == 4);
+  TORCH_CHECK(packed_w.dtype() == at::kInt);
+  TORCH_CHECK(packed_w.is_contiguous());
+
+  TORCH_CHECK(packed_w.size(2) == 32);
+  TORCH_CHECK(packed_w.size(3) == innerKTiles / 2);
+  TORCH_CHECK(innerKTiles == 2 || innerKTiles == 4 || innerKTiles == 8);
+
+  int N = packed_w.size(0) * 8;
+  int K = packed_w.size(1) * innerKTiles * 16;
+
+  constexpr int32_t kNTileSize = 8;
+  constexpr int32_t kKTileSize = 16;
+
+  auto nTiles = divUp(N, kNTileSize);
+
+  auto kSuperTiles = divUp(K, innerKTiles * kKTileSize);
+
+  auto out = at::empty(
+      {N, K},
+      at::TensorOptions().dtype(at::kInt).device(packed_w.device()));
+
+  auto stream = at::cuda::getCurrentCUDAStream();
+  dim3 grid(kSuperTiles, nTiles);
+
+  if (innerKTiles == 2) {
+    _dequantize_int4_kernel<<>>(
+        packed_w.packed_accessor32(),
+        out.packed_accessor32());
+  }
+   else if (innerKTiles == 4) {
+    _dequantize_int4_kernel<<>>(
+        packed_w.packed_accessor32(),
+        out.packed_accessor32());
+  } else if (innerKTiles == 8) {
+    _dequantize_int4_kernel<<>>(
+        packed_w.packed_accessor32(),
+        out.packed_accessor32());
+  }
+
+  return out;
+}
+
+TORCH_LIBRARY_IMPL(torchao, CUDA, m) {
+  m.impl("torchao::unpack_tensor_core_tiled_layout", &_unpack_tensor_core_tiled_layout);
+  m.impl("torchao::dequantize_tensor_core_tiled_layout", &_dequantize_tensor_core_tiled_layout);
+
+}
+
+#endif
diff --git a/lib/python3.12/site-packages/torchao/csrc/cuda/to_sparse_semi_structured_cutlass_sm9x/to_sparse_semi_structured_cutlass_sm9x_f8.cu b/lib/python3.12/site-packages/torchao/csrc/cuda/to_sparse_semi_structured_cutlass_sm9x/to_sparse_semi_structured_cutlass_sm9x_f8.cu
new file mode 100644
index 0000000000000000000000000000000000000000..cbca3e0333f5b37fc9d76ec151a078b726d7f6d2
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/csrc/cuda/to_sparse_semi_structured_cutlass_sm9x/to_sparse_semi_structured_cutlass_sm9x_f8.cu
@@ -0,0 +1,40 @@
+// Copyright (c) Meta Platforms, Inc. and affiliates.
+// All rights reserved.
+//
+// This source code is licensed under the BSD 3-Clause license found in the
+// LICENSE file in the root directory of this source tree.
+#include 
+
+#include "to_sparse_semi_structured_cutlass_sm9x.cuh"
+
+namespace torchao {
+
+std::tuple
+to_sparse_semi_structured_cutlass_sm9x_f8(const at::Tensor& W) {
+  // Validate input datatypes.
+  TORCH_CHECK(W.dtype() == at::kFloat8_e5m2 || W.dtype() == at::kFloat8_e4m3fn,
+              __func__, " : The input datatype ", W.dtype(),
+              " is not supported");
+
+#if defined(BUILD_TO_SPARSE_SEMI_STRUCTURED_CUTLASS_SM9X)
+  // Dispatch to appropriate kernel template.
+  if (W.dtype() == at::kFloat8_e5m2) {
+    using DtypeW = cutlass::float_e5m2_t;
+    return to_sparse_semi_structured_cutlass_sm9x(W);
+  } else if (W.dtype() == at::kFloat8_e4m3fn) {
+    using DtypeW = cutlass::float_e4m3_t;
+    return to_sparse_semi_structured_cutlass_sm9x(W);
+  }
+  return std::tuple(at::Tensor{}, at::Tensor{});
+#else
+  TORCH_CHECK_NOT_IMPLEMENTED(false, OPERATOR_NAME);
+  return std::tuple(at::Tensor{}, at::Tensor{});
+#endif
+}
+
+TORCH_LIBRARY_IMPL(torchao, CUDA, m) {
+  m.impl("torchao::to_sparse_semi_structured_cutlass_sm9x_f8",
+         &to_sparse_semi_structured_cutlass_sm9x_f8);
+}
+
+}  // namespace torchao
diff --git a/lib/python3.12/site-packages/torchao/ops.py b/lib/python3.12/site-packages/torchao/ops.py
new file mode 100644
index 0000000000000000000000000000000000000000..82de7528ecbf630cf6c3a4d94f8d297658c24e9e
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/ops.py
@@ -0,0 +1,788 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import functools
+from typing import Optional
+
+import torch
+from torch import Tensor
+
+from torchao.utils import TORCH_VERSION_AT_LEAST_2_4
+
+lib = torch.library.Library("torchao", "FRAGMENT")
+lib.define(
+    "quant_llm_linear(int EXPONENT, int MANTISSA, Tensor _in_feats, Tensor _weights, Tensor _scales, int splitK) -> Tensor"
+)
+lib.define(
+    "unpack_tensor_core_tiled_layout(Tensor packed_w, int inner_k_tiles) -> Tensor"
+)
+lib.define(
+    "dequantize_tensor_core_tiled_layout(Tensor packed_w, Tensor scales_and_zeros, int group_size, int inner_k_tiles) -> Tensor"
+)
+lib.define(
+    "marlin_24_gemm(Tensor x, Tensor weight_marlin, Tensor meta, Tensor s, Tensor workspace, int bits, int size_m, int size_n, int size_k) -> Tensor"
+)
+lib.define(
+    "marlin_qqq_gemm(Tensor x, Tensor weight_marlin, Tensor s_tok, Tensor s_ch, Tensor s_group, Tensor workspace, int size_m, int size_n, int size_k) -> Tensor"
+)
+lib.define(
+    "rowwise_scaled_linear_cutlass_s8s4(Tensor input, Tensor input_scale, Tensor weight, Tensor weight_scale, Tensor? bias=None, ScalarType? out_dtype=None) -> Tensor"
+)
+lib.define(
+    "rowwise_scaled_linear_cutlass_s4s4(Tensor input, Tensor input_scale, Tensor weight, Tensor weight_scale, Tensor? bias=None, ScalarType? out_dtype=None) -> Tensor"
+)
+lib.define(
+    "rowwise_scaled_linear_sparse_cutlass_f8f8(Tensor input, Tensor input_scale, Tensor weight, Tensor weight_meta, Tensor weight_scale, Tensor? bias=None, ScalarType? out_dtype=None) -> Tensor"
+)
+lib.define(
+    "to_sparse_semi_structured_cutlass_sm9x_f8(Tensor weight) -> (Tensor, Tensor)"
+)
+# Note: we need to add the `torch._C.Tag.needs_fixed_stride_order` tag in order for inductor
+# to honor the layout constraints for `b` in the two ops below.
+lib.define(
+    "mx_fp8_bf16(Tensor a, Tensor b, Tensor a_scale, Tensor b_scale) -> Tensor",
+    tags=[torch._C.Tag.needs_fixed_stride_order],
+)
+lib.define(
+    "mx_fp4_bf16(Tensor a, Tensor b, Tensor a_scale, Tensor b_scale) -> Tensor",
+    tags=[torch._C.Tag.needs_fixed_stride_order],
+)
+
+
+def register_custom_op(name):
+    def decorator(func):
+        if TORCH_VERSION_AT_LEAST_2_4:
+            return torch.library.register_fake(f"{name}")(func)
+        else:
+            return torch.library.impl_abstract(f"{name}")(func)
+
+    return decorator
+
+
+def register_custom_op_impl(name):
+    def decorator(func):
+        if TORCH_VERSION_AT_LEAST_2_4:
+            return torch.library.custom_op(f"{name}", mutates_args=())(func)
+        else:
+            return torch.library.impl(f"{name}", "CUDA")(func)
+
+    return decorator
+
+
+@functools.lru_cache
+def cached_compute_capability():
+    device_props = torch.cuda.get_device_properties(torch.cuda.current_device())
+    compute_capability = device_props.major * 10 + device_props.minor
+    return compute_capability
+
+
+def quant_llm_linear(
+    EXPONENT: int,
+    MANTISSA: int,
+    _in_feats: Tensor,
+    _weights: Tensor,
+    _scales: Tensor,
+    splitK: int = 1,
+) -> Tensor:
+    """
+    Quant-LLM linear layer A @ W.T. See https://arxiv.org/abs/2401.14112 for more details.
+
+    Arguments
+        EXPONENT: number of exponent bits
+        MANTISSA: number of mantissa bits
+        _in_feats: input activations in FP16
+        _weights: packed Floatx weights
+        _scales: scale
+        splitK: split K
+
+    Returns
+        output of linear layer
+    """
+    # Check if we're on a supported architecture (sm7.5 or higher)
+    compute_capability = cached_compute_capability()
+    torch._check(
+        compute_capability >= 75,
+        lambda: f"quant_llm_linear requires sm7.5+ GPU architecture, but current device has sm{compute_capability}",
+    )
+    return torch.ops.torchao.quant_llm_linear.default(
+        EXPONENT, MANTISSA, _in_feats, _weights, _scales, splitK
+    )
+
+
+@register_custom_op("torchao::quant_llm_linear")
+def _(
+    EXPONENT: int,
+    MANTISSA: int,
+    _in_feats: Tensor,
+    _weights: Tensor,
+    _scales: Tensor,
+    splitK: int = 1,
+) -> Tensor:
+    torch._check(
+        _in_feats.dim() == 2,
+        lambda: f"input should be a 2d tensor, got {_in_feats.dim()}D",
+    )
+    torch._check(
+        _in_feats.dtype in (torch.float16, torch.bfloat16),
+        lambda: f"weight must be FP16 or BF16, got {_in_feats.dtype}",
+    )
+    torch._check(
+        _weights.dim() == 2,
+        lambda: f"weight should be a 2d tensor, got {_weights.dim()}D",
+    )
+    torch._check(
+        _weights.dtype is torch.uint8,
+        lambda: f"weight must be UINT8, got {_weights.dtype}",
+    )
+    torch._check(
+        _scales.dim() == 1, lambda: f"scale should be a 2d tensor, got {_scales.dim()}D"
+    )
+    torch._check(
+        _scales.dtype in (torch.float16, torch.bfloat16),
+        lambda: f"scale must be FP16 or BF16, got {_scales.dtype}",
+    )
+
+    BS, IC = _in_feats.shape
+    OC, _ = _weights.shape
+    N_BITS = 1 + EXPONENT + MANTISSA
+    torch._check(IC // 8 * N_BITS == _weights.shape[1], lambda: "Dimensions mismatched")
+    torch._check(OC == _scales.shape[0], lambda: "Dimensions mismatched")
+
+    return _in_feats.new_empty((BS, OC))
+
+
+def unpack_tensor_core_tiled_layout(packed_w: Tensor, inner_k_tiles: int) -> Tensor:
+    """
+    Unpacks weights that were packed with `torch.ops.aten._convert_weight_to_int4pack` to original tensor of shape `N x K`.
+
+    Assumes that the packed weights were generated with `torch.ops.aten._convert_weight_to_int4pack` with `inner_k_tiles = 2 | 4 | 8`"
+
+    Args:
+        packed_w: torch.tensor: 4D tensor with shape (N / 8) x (K / (inner_k_tiles * 16)) x 32 x inner_k_tiles, dtype is torch.int32
+        inner_k_tiles: int
+
+    Returns:
+        torch.tensor of shape is N x K, dtype is torch.int32
+
+    """
+    return torch.ops.torchao.unpack_tensor_core_tiled_layout.default(
+        packed_w=packed_w, inner_k_tiles=inner_k_tiles
+    )
+
+
+@register_custom_op("torchao::unpack_tensor_core_tiled_layout")
+def _(packed_w: Tensor, inner_k_tiles: int) -> Tensor:
+    torch._check(
+        packed_w.dim() == 4,
+        lambda: f"packed weight should be a 42d tensor, got {packed_w.dim()}D",
+    )
+    torch._check(
+        packed_w.dtype is torch.int32,
+        lambda: f"weight must be INT32, got {packed_w.dtype}",
+    )
+    torch._check(
+        inner_k_tiles == 2 or inner_k_tiles == 4 or inner_k_tiles == 8,
+        lambda: "inner_k_tiles must be 2, 4, or 8",
+    )
+    torch._check(packed_w.size(2) == 32, lambda: "packed weight must have 32 at dim 2")
+    torch._check(
+        packed_w.size(3) == inner_k_tiles / 2,
+        lambda: "packed weight must have inner_k_tiles/2 at dim 3",
+    )
+    N = packed_w.size(0) * 8
+    K = packed_w.size(1) * inner_k_tiles * 16
+
+    return torch.empty((N, K), dtype=torch.int32, device=packed_w.device)
+
+
+def dequantize_tensor_core_tiled_layout(
+    packed_w: Tensor, scales_and_zeros: Tensor, group_size: int, inner_k_tiles: int
+) -> Tensor:
+    """
+    Dequantizes by:
+    - Unpacking weights that were packed with `torch.ops.aten._convert_weight_to_int4pack` to original tensor of shape `N x K`
+    - Upcasting to bfloat16
+    - Dequantizing with the scales_and_zeros that were packed with `torchao.quantization.utils.pack_tinygemm_scales_and_zeros`
+
+    Assumes:
+    - packed weights were generated with `torch.ops.aten._convert_weight_to_int4pack` with `inner_k_tiles = 2 | 4 | 8`"
+    - packed scales_and_zeros were generated with `torchao.quantization.utils.pack_tinygemm_scales_and_zeros`
+    - qGroupSize is 32 | 64 | 128 | 256
+
+    Args:
+        packed_w: torch.tensor: 4D tensor with shape `(N / 8) x (K / (inner_k_tiles * 16)) x 32 x inner_k_tiles / 2`, dtype is torch.int32
+        scales_and_zeros: torch.tensor: 3D tensor with shape `numQGroups x N x 2`, dtype is torch.bfloat16 where numQGroups is K / qGroupSize
+        group_size: int
+        inner_k_tiles: int
+
+    Returns:
+        torch.tensor of shape is N x K, dtype is torch.bfloat16
+
+    """
+    return torch.ops.torchao.dequantize_tensor_core_tiled_layout.default(
+        packed_w, scales_and_zeros, group_size, inner_k_tiles
+    )
+
+
+@register_custom_op("torchao::dequantize_tensor_core_tiled_layout")
+def _(
+    packed_w: Tensor, scales_and_zeros: Tensor, group_size: int, inner_k_tiles: int
+) -> Tensor:
+    # packed_w preconditions
+    torch._check(
+        packed_w.dim() == 4,
+        lambda: f"packed weight should be a 4d tensor, got {packed_w.dim()}D",
+    )
+    torch._check(
+        packed_w.dtype is torch.int32,
+        lambda: f"weight must be INT32, got {packed_w.dtype}",
+    )
+    torch._check(
+        inner_k_tiles == 2 or inner_k_tiles == 4 or inner_k_tiles == 8,
+        lambda: "inner_k_tiles must be 2, 4, or 8",
+    )
+    torch._check(packed_w.size(2) == 32, lambda: "packed weight must have 32 at dim 2")
+    torch._check(
+        packed_w.size(3) == inner_k_tiles / 2,
+        lambda: "packed weight must have inner_k_tiles/2 at dim 3",
+    )
+    N = packed_w.size(0) * 8
+    K = packed_w.size(1) * inner_k_tiles * 16
+
+    # scales_and_zeros preconditions
+    torch._check(
+        scales_and_zeros.dtype is torch.bfloat16,
+        lambda: "scales_and_zeros must be bfloat16",
+    )
+    torch._check(
+        scales_and_zeros.dim() == 3,
+        lambda: "scales_and_zeros must be 3D, got {scales_and_zeros.dim()}",
+    )
+    torch._check(
+        group_size == 32 or group_size == 64 or group_size == 128 or group_size == 256,
+        lambda: "qGroupSize must be 32, 64, 128, or 256",
+    )
+    torch._check(
+        scales_and_zeros.size(0) == K // group_size,
+        lambda: "scales_and_zeros must have K // qGroupSize at dim 0",
+    )
+    torch._check(
+        scales_and_zeros.size(1) == N, lambda: "scales_and_zeros must have N at dim 1"
+    )
+    torch._check(
+        scales_and_zeros.size(2) == 2, lambda: "scales_and_zeros must have 2 at dim 2"
+    )
+
+    return torch.empty((N, K), dtype=torch.bfloat16, device=packed_w.device)
+
+
+def marlin_24_gemm(
+    x: Tensor,
+    weight_marlin: Tensor,
+    meta: Tensor,
+    s: Tensor,
+    workspace: Tensor,
+    bits: int,
+    size_m: int,
+    size_n: int,
+    size_k: int,
+) -> Tensor:
+    """
+    Sparse Marlin 2:4 matrix multiplication. Reference: https://github.com/IST-DASLab/Sparse-Marlin/tree/main
+    Args:
+        x: input matrix of shape `(n, k/2)` in column-major layout.
+        weight_marlin: weight matrix of original shape `(m, k)` in Marlin format; see `Layer.pack()`.
+        meta: metadata information for 2:4 sparsity.
+        s: scales of shape `(n / groupsize / 2, m)`.
+        workspace: tensor with at least `m / 128 * max_par` entries that are all zero.
+        bits: number of bits for quantization.
+        size_m: number of rows in input matrix.
+        size_n: number of columns in weight matrix.
+        size_k: number of columns in input matrix.
+    Returns:
+        output matrix of shape `(n, m)` in column-major layout.
+    """
+    return torch.ops.torchao.marlin_24_gemm.default(
+        x, weight_marlin, meta, s, workspace, bits, size_m, size_n, size_k
+    )
+
+
+@register_custom_op("torchao::marlin_24_gemm")
+def _(
+    x: Tensor,
+    weight_marlin: Tensor,
+    meta: Tensor,
+    s: Tensor,
+    workspace: Tensor,
+    bits: int,
+    size_m: int,
+    size_n: int,
+    size_k: int,
+) -> Tensor:
+    TILE_SIZE = 16
+    MIN_THREAD_N = 128
+    MAX_PARALLELISM = 64
+
+    # Verify num_bits
+    torch._check(
+        bits == 4 or bits == 8, lambda: f"num_bits must be 4 or 8. Got = {bits}"
+    )
+    pack_factor = 32 // bits
+
+    # Verify M
+    torch._check(
+        size_m == x.size(0),
+        lambda: f"Shape mismatch: x.size(0) = {x.size(0)}, size_m = {size_m}",
+    )
+
+    # Verify K
+    torch._check(
+        size_k == x.size(1),
+        lambda: f"Shape mismatch: x.size(1) = {x.size(1)}, size_k = {size_k}",
+    )
+    torch._check(
+        size_k % TILE_SIZE == 0,
+        lambda: f"size_k = {size_k} is not divisible by tile_size = {TILE_SIZE}",
+    )
+    torch._check(
+        (size_k // TILE_SIZE // 2) == weight_marlin.size(0),
+        lambda: f"Shape mismatch: weight_marlin.size(0) = {weight_marlin.size(0)}, size_k = {size_k}, tile_size = {TILE_SIZE}",
+    )
+
+    # Verify N
+    torch._check(
+        s.size(1) == size_n, lambda: f"s.size(1) = {s.size(1)}, size_n = {size_n}"
+    )
+    torch._check(
+        weight_marlin.size(1) % TILE_SIZE == 0,
+        lambda: f"weight_marlin.size(1) = {weight_marlin.size(1)} is not divisible by tile_size = {TILE_SIZE}",
+    )
+
+    actual_size_n = (weight_marlin.size(1) // TILE_SIZE) * pack_factor
+    torch._check(
+        size_n == actual_size_n,
+        lambda: f"size_n = {size_n}, actual_size_n = {actual_size_n}",
+    )
+
+    # Verify meta
+    torch._check(
+        meta.size(0) == size_k // 8 // 2 // 2,
+        lambda: f"meta.size(0) = {meta.size(0)} is not size_k / 8 / 2 / 2 = {size_k // 8 // 2 // 2}",
+    )
+    torch._check(
+        meta.size(1) == size_n * 2,
+        lambda: f"meta.size(1) = {meta.size(1)} is not size_n * 2 = {size_n * 2}",
+    )
+
+    # Verify A device and strides
+    torch._check(x.is_cuda, lambda: "x is not on GPU")
+    torch._check(x.is_contiguous(), lambda: "x is not contiguous")
+
+    # Verify B device and strides
+    torch._check(weight_marlin.is_cuda, lambda: "weight_marlin is not on GPU")
+    torch._check(
+        weight_marlin.is_contiguous(), lambda: "weight_marlin is not contiguous"
+    )
+
+    # Verify meta device and strides
+    torch._check(meta.is_cuda, lambda: "meta is not on GPU")
+    torch._check(meta.is_contiguous(), lambda: "meta is not contiguous")
+
+    # Verify scales device and strides
+    torch._check(s.is_cuda, lambda: "s is not on GPU")
+    torch._check(s.is_contiguous(), lambda: "s is not contiguous")
+
+    # Verify groupsize
+    groupsize = -1
+    if s.size(0) > 1:
+        torch._check(
+            size_k % s.size(0) == 0,
+            lambda: f"size_k = {size_k} is not divisible by s.size(0) = {s.size(0)}",
+        )
+        groupsize = size_k // s.size(0)
+        groupsize //= 2  # Because of 24
+    torch._check(
+        groupsize == -1 or groupsize == 64,
+        lambda: f"Unexpected groupsize = {groupsize}",
+    )
+
+    # Verify workspace size
+    torch._check(
+        size_n % MIN_THREAD_N == 0,
+        lambda: f"size_n = {size_n} is not divisible by min_thread_n = {MIN_THREAD_N}",
+    )
+    min_workspace_size = (size_n // MIN_THREAD_N) * MAX_PARALLELISM
+    torch._check(
+        workspace.numel() >= min_workspace_size,
+        lambda: f"workspace.numel = {workspace.numel()} is below min_workspace_size = {min_workspace_size}",
+    )
+
+    return torch.empty((x.size(0), s.size(1)), dtype=x.dtype, device=x.device)
+
+
+def marlin_qqq_gemm(
+    x: Tensor,
+    weight_marlin: Tensor,
+    s_tok: Tensor,
+    s_ch: Tensor,
+    s_group: Tensor,
+    workspace: Tensor,
+    size_m: int,
+    size_n: int,
+    size_k: int,
+) -> Tensor:
+    """
+    Marlin for W4A8 mixed precision matrix multiplication.
+    See https://arxiv.org/pdf/2406.09904 for more details.
+    Reference: https://github.com/HandH1998/QQQ/tree/main
+    Args:
+        x: `torch.int8` input matrix of shape `(m, k)` in standard row-major layout.
+        weight_marlin: `torch.int32` weight matrix of original shape `(k, n)` in the specified format.
+        s_tok: `torch.float32` activation per-token quantization scales of shape `(m, 1)`.
+        s_ch: `torch.float32` weight per-channel quantization scales of shape `(1, n)`.
+        s_group: `torch.half` weight per-group quantization scales of shape `(m / groupsize, n)`, it should be empty when group_size != -1.
+        workspace: `torch.int32` tensor with at least `n / 128 * max_par` entries that are all zero.
+        size_m: number of rows in input matrix.
+        size_n: number of columns in weight matrix.
+        size_k: number of columns in input matrix.
+    Returns:
+        `torch.half` out matrix of shape `(m, n)` in standard row-major layout.
+    """
+    return torch.ops.torchao.marlin_qqq_gemm.default(
+        x, weight_marlin, s_tok, s_ch, s_group, workspace, size_m, size_n, size_k
+    )
+
+
+@register_custom_op("torchao::marlin_qqq_gemm")
+def _(
+    x: Tensor,
+    weight_marlin: Tensor,
+    s_tok: Tensor,
+    s_ch: Tensor,
+    s_group: Tensor,
+    workspace: Tensor,
+    size_m: int,
+    size_n: int,
+    size_k: int,
+) -> Tensor:
+    TILE_SIZE = 16
+    MIN_THREAD_N = 64
+    MAX_PARALLELISM = 16
+    PACK_FACTOR = 32 // 4
+
+    # Verify M
+    torch._check(
+        size_m == x.size(0),
+        lambda: f"Shape mismatch: x.size(0) = {x.size(0)}, size_m = {size_m}",
+    )
+    torch._check(
+        size_m == s_tok.numel(),
+        lambda: f"Shape mismatch: s_tok.numel() = {s_tok.numel()}, size_m = {size_m}",
+    )
+
+    # Verify K
+    torch._check(
+        size_k == x.size(1),
+        lambda: f"Shape mismatch: x.size(1) = {x.size(1)}, size_k = {size_k}",
+    )
+    torch._check(
+        size_k % TILE_SIZE == 0,
+        lambda: f"size_k = {size_k} is not divisible by tile_size = {TILE_SIZE}",
+    )
+    torch._check(
+        (size_k // TILE_SIZE) == weight_marlin.size(0),
+        lambda: f"Shape mismatch: weight_marlin.size(0) = {weight_marlin.size(0)}, size_k = {size_k}, tile_size = {TILE_SIZE}",
+    )
+
+    # Verify groupsize
+    groupsize = -1 if s_group.numel() == 0 else size_k // s_group.size(0)
+    torch._check(groupsize in [-1, 128], lambda: f"Unexpected groupsize = {groupsize}")
+
+    # Verify N
+    torch._check(
+        s_ch.numel() == size_n,
+        lambda: f"Shape mismatch: s_ch.numel() = {s_ch.numel()}, size_n = {size_n}",
+    )
+    torch._check(
+        weight_marlin.size(1) % TILE_SIZE == 0,
+        lambda: f"weight_marlin.size(1) = {weight_marlin.size(1)} is not divisible by tile_size = {TILE_SIZE}",
+    )
+    if groupsize != -1:
+        torch._check(
+            s_group.size(1) == size_n,
+            lambda: f"Shape mismatch: s_group.size(1) = {s_group.size(1)}, size_n = {size_n}",
+        )
+        torch._check(
+            size_k % s_group.size(0) == 0,
+            lambda: f"size_k = {size_k} is not divisible by s_group.size(0) = {s_group.size(0)}",
+        )
+
+    actual_size_n = (weight_marlin.size(1) // TILE_SIZE) * PACK_FACTOR
+    torch._check(
+        size_n == actual_size_n,
+        lambda: f"Shape mismatch: size_n = {size_n}, actual_size_n = {actual_size_n}",
+    )
+
+    # Verify A device and strides
+    torch._check(x.is_cuda, lambda: "x is not on GPU")
+    torch._check(x.is_contiguous(), lambda: "x is not contiguous")
+
+    # Verify B device and strides
+    torch._check(weight_marlin.is_cuda, lambda: "weight_marlin is not on GPU")
+    torch._check(
+        weight_marlin.is_contiguous(), lambda: "weight_marlin is not contiguous"
+    )
+
+    # Verify s_tok device, strides and dtype
+    torch._check(s_tok.is_cuda, lambda: "s_tok is not on GPU")
+    torch._check(s_tok.is_contiguous(), lambda: "s_tok is not contiguous")
+    torch._check(s_tok.dtype == torch.float32, lambda: "s_tok's dtype is not float32")
+
+    # Verify s_ch device, strides and dtype
+    torch._check(s_ch.is_cuda, lambda: "s_ch is not on GPU")
+    torch._check(s_ch.is_contiguous(), lambda: "s_ch is not contiguous")
+    torch._check(s_ch.dtype == torch.float32, lambda: "s_ch's dtype is not float32")
+
+    # Verify s_group device, strides and dtype
+    torch._check(s_group.is_cuda, lambda: "s_group is not on GPU")
+    torch._check(s_group.is_contiguous(), lambda: "s_group is not contiguous")
+    torch._check(s_group.dtype == torch.float16, "s_group's dtype is not float16")
+
+    # Verify workspace size
+    torch._check(
+        size_n % MIN_THREAD_N == 0,
+        lambda: f"size_n = {size_n} is not divisible by min_thread_n = {MIN_THREAD_N}",
+    )
+    min_workspace_size = (size_n // MIN_THREAD_N) * MAX_PARALLELISM
+    torch._check(
+        workspace.numel() >= min_workspace_size,
+        lambda: f"workspace.numel() = {workspace.numel()} is below min_workspace_size = {min_workspace_size}",
+    )
+
+    return torch.empty((size_m, size_n), dtype=torch.float16, device=x.device)
+
+
+def rowwise_scaled_linear_cutlass_s8s4(
+    input: Tensor,
+    input_scale: Tensor,
+    weight: Tensor,
+    weight_scale: Tensor,
+    bias: Optional[Tensor] = None,
+    out_dtype: Optional[torch.dtype] = None,
+) -> Tensor:
+    """
+    CUTLASS-based row-wise scaled W4A8 linear operator.
+    Args:
+        input: quantized input tensor, in row-major layout.
+        input_scale: scale factors for input tensor, has to be tensor of the same shape as the input tensor, minus the last dimension.
+        weight: quantized weight matrix, in row-major layout.
+        weight_scale: scale factors for weight tensor, one value per row of weight matrix (thus also tensor of the same shape as the weight tensor, minus the last dimension).
+        bias: an optional vector of size equal to number of rows of weight tensor, or None.
+        out_dtype: optional data type for output tensor.
+    Returns:
+        output: result tensor, in row-major layout.
+    """
+
+    return torch.ops.torchao.rowwise_scaled_linear_cutlass_s8s4.default(
+        input,
+        input_scale,
+        weight,
+        weight_scale,
+        bias,
+        out_dtype,
+    )
+
+
+@register_custom_op("torchao::rowwise_scaled_linear_cutlass_s8s4")
+def _(
+    input: Tensor,
+    input_scale: Tensor,
+    weight: Tensor,
+    weight_scale: Tensor,
+    bias: Optional[Tensor] = None,
+    out_dtype: Optional[torch.dtype] = None,
+) -> Tensor:
+    # No checks here, as detailed checks are performed by the
+    # operator itself.
+
+    dtype = out_dtype if out_dtype is not None else input_scale.dtype
+    device = input.device
+    return torch.empty((*input.shape[:-1], weight.shape[0]), dtype=dtype, device=device)
+
+
+def rowwise_scaled_linear_cutlass_s4s4(
+    input: Tensor,
+    input_scale: Tensor,
+    weight: Tensor,
+    weight_scale: Tensor,
+    bias: Optional[Tensor] = None,
+    out_dtype: Optional[torch.dtype] = None,
+) -> Tensor:
+    """
+    CUTLASS-based row-wise scaled W4A4 linear operator.
+    Args:
+        input: quantized input tensor, in row-major layout.
+        input_scale: scale factors for input tensor, has to be tensor of the same shape as the input tensor, minus the last dimension.
+        weight: quantized weight matrix, in row-major layout.
+        weight_scale: scale factors for weight tensor, one value per row of weight matrix (thus also tensor of the same shape as the weight tensor, minus the last dimension).
+        bias: an optional vector of size equal to number of rows of weight tensor, or None.
+        out_dtype: optional data type for output tensor.
+    Returns:
+        output: result tensor, in row-major layout.
+    """
+
+    return torch.ops.torchao.rowwise_scaled_linear_cutlass_s4s4.default(
+        input, input_scale, weight, weight_scale, bias, out_dtype
+    )
+
+
+@register_custom_op("torchao::rowwise_scaled_linear_cutlass_s4s4")
+def _(
+    input: Tensor,
+    input_scale: Tensor,
+    weight: Tensor,
+    weight_scale: Tensor,
+    bias: Optional[Tensor] = None,
+    out_dtype: Optional[torch.dtype] = None,
+) -> Tensor:
+    # No checks here, as detailed checks are performed by the
+    # operator itself.
+
+    dtype = out_dtype if out_dtype is not None else input_scale.dtype
+    device = input.device
+    return torch.empty((*input.shape[:-1], weight.shape[0]), dtype=dtype, device=device)
+
+
+def rowwise_scaled_linear_sparse_cutlass_f8f8(
+    input: Tensor,
+    input_scale: Tensor,
+    weight: Tensor,
+    weight_meta: Tensor,
+    weight_scale: Tensor,
+    bias: Optional[Tensor] = None,
+    out_dtype: Optional[torch.dtype] = None,
+) -> Tensor:
+    """
+    CUTLASS-based row-wise scaled F8F8 linear operator, for sparsified weight case.
+    Args:
+        input: quantized input tensor, in row-major layout.
+        input_scale: scale factors for input tensor, has to be tensor of the same shape as the input tensor, minus the last dimension.
+        weight: sparsified quantized weight matrix, in row-major layout.
+        weight_meta: sparsify metadata for weight tensor.
+        weight_scale: scale factors for weight tensor, one value per row of weight matrix (thus also tensor of the same shape as the weight tensor, minus the last dimension).
+        bias: an optional vector of size equal to number of rows of weight tensor, or None.
+        out_dtype: optional data type for output tensor.
+    Returns:
+        output: result tensor, in row-major layout.
+    """
+
+    return torch.ops.torchao.rowwise_scaled_linear_sparse_cutlass_f8f8.default(
+        input, input_scale, weight, weight_meta, weight_scale, bias, out_dtype
+    )
+
+
+@register_custom_op("torchao::rowwise_scaled_linear_sparse_cutlass_f8f8")
+def _(
+    input: Tensor,
+    input_scale: Tensor,
+    weight: Tensor,
+    weight_meta: Tensor,
+    weight_scale: Tensor,
+    bias: Optional[Tensor] = None,
+    out_dtype: Optional[torch.dtype] = None,
+) -> Tensor:
+    # No checks here, as detailed checks are performed by the
+    # operator itself.
+
+    dtype = out_dtype if out_dtype is not None else input_scale.dtype
+    device = input.device
+    return torch.empty((*input.shape[:-1], weight.shape[0]), dtype=dtype, device=device)
+
+
+def to_sparse_semi_structured_cutlass_sm9x_f8(
+    weight: Tensor,
+) -> (Tensor, Tensor):
+    """
+    CUTLASS-based conversion from sparsified input tensor to corresponding compressed tensor, along with corresponding metadata tensor.
+    Args:
+        weight: input tensor, in row-major layout.
+    Returns:
+        weight_compressed: compressed weight tensor, with sparsity eliminated, in row-major layout.
+        weight_meta: metadata tensor, describing the sparsity structure of the input tensor, also in row-major layout.
+    """
+
+    return torch.ops.torchao.to_sparse_semi_structured_cutlass_sm9x_f8.default(weight)
+
+
+@register_custom_op("torchao::to_sparse_semi_structured_cutlass_sm9x_f8")
+def _(
+    weight: Tensor,
+) -> (Tensor, Tensor):
+    # No checks here, as detailed checks are performed by the
+    # operator itself.
+
+    return (
+        weight.new_empty(weight[0], weight[1] // 2),
+        weight.new_empty(weight[0], max(weight[1] // 8, 16), dtype=torch.char),
+    )
+
+
+@functools.lru_cache()
+def _get_dtypes():
+    """TODO: when e8m0 is hardened and major release lets remove uint8 support"""
+    if hasattr(torch, "float8_e8m0fnu"):
+        return (torch.uint8, torch.float8_e8m0fnu)
+    return (torch.uint8,)
+
+
+def _check_scale_dtypes(A_scale, B_scale):
+    allowed_dtypes = _get_dtypes()
+
+    torch._check(
+        A_scale.dtype in allowed_dtypes,
+        lambda: f"A_scale tensor must be uint8 or float8_e8m0fnu, got {A_scale.dtype}",
+    )
+    torch._check(
+        B_scale.dtype in allowed_dtypes,
+        lambda: f"B_scale tensor must be uint8 or float8_e8m0fnu, got {B_scale.dtype}",
+    )
+
+
+@register_custom_op("torchao::mx_fp8_bf16")
+def meta_mx_fp8_bf16(A: Tensor, B: Tensor, A_scale: Tensor, B_scale: Tensor):
+    """Meta impl for mx_fp8_bf16"""
+    return torch.empty((A.size(0), B.size(1)), dtype=torch.bfloat16, device=A.device)
+
+
+def mx_fp4_bf16(A: Tensor, B: Tensor, A_scale: Tensor, B_scale: Tensor):
+    """Defines a matmul between two fp4 tensors w/ MX scales in E8MO and returns a bf16 tensor.
+
+    The expected format is fp4_e2m1 specified:
+    https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final.pdf (Section 5.3.3)
+
+    Note: The mx scales are E8MO tensors stored in uint8 tensors (for now).
+        The layout of the scales is very particular, see:
+        https://docs.nvidia.com/cuda/cublas/index.html#d-block-scaling-factors-layout
+
+
+    Args:
+        A: fp4 tensor (2 fp4 elements are packed into 1 byte -> elem0|elem1)
+        B: fp4 tensor (2 fp4 elements are packed into 1 byte -> elem0|elem1)
+        A_scale: E8M0 scale tensor for A with groupsize=32 in swizzled layout
+        B_scale: E8M0 scale tensor for B with groupsize=32 in swizzled layout
+
+    Returns:
+        MXN bf16 Tensor
+
+    """
+    _check_scale_dtypes(A_scale, B_scale)
+    return torch.ops.torchao.mx_fp4_bf16.default(A, B, A_scale, B_scale)
+
+
+@register_custom_op("torchao::mx_fp4_bf16")
+def meta_mx_fp4_bf16(A: Tensor, B: Tensor, A_scale: Tensor, B_scale: Tensor):
+    """Meta impl for mx_fp4_bf16"""
+    # Assume that the contraction happens in the K dim thus M,N are perserved post bit pack
+    return torch.empty((A.size(0), B.size(1)), dtype=torch.bfloat16, device=A.device)
diff --git a/lib/python3.12/site-packages/torchao/prototype/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..78401a97a63d22a84611e266db6346a6e6ed3d82
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/__pycache__/custom_fp_utils.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/__pycache__/custom_fp_utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..72729e7a0d932de2e6a27636f95f672c4e618202
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/__pycache__/custom_fp_utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/__init__.py b/lib/python3.12/site-packages/torchao/prototype/autoround/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ae0d7ecb222bb0bfdf8ab5eb4dec27fa9d5d3c6
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/autoround/__init__.py
@@ -0,0 +1,11 @@
+from torchao.prototype.autoround.core import (
+    apply_auto_round,
+    prepare_model_for_applying_auto_round_,
+)
+from torchao.prototype.autoround.multi_tensor import MultiTensor
+
+__all__ = [
+    "apply_auto_round",
+    "prepare_model_for_applying_auto_round_",
+    "MultiTensor",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4e1a5496af78ca46ccb291d608df95e782f31507
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/autoround_llm.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/autoround_llm.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..101cac6c7864d6fbf259f5c5b044769230c126ac
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/autoround_llm.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/core.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/core.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b57e1736361e3bd6cbe179d0879972f5de3352dd
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/core.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/eval_autoround.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/eval_autoround.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e4fa812ff45331ad5409004ad97dbc070b43de35
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/eval_autoround.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/multi_tensor.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/multi_tensor.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8571c80a45f0e8fbaccefeae38dc139e8a0f31e8
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/multi_tensor.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6b116df772ad16bbe02ec3c84ecea72f576c24ee
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/autoround/__pycache__/utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/autoround_llm.py b/lib/python3.12/site-packages/torchao/prototype/autoround/autoround_llm.py
new file mode 100644
index 0000000000000000000000000000000000000000..822ee6554bc475c0ae1cffe815bbee45151756b4
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/autoround/autoround_llm.py
@@ -0,0 +1,212 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import argparse
+from typing import Optional
+
+import torch
+
+import torchao
+import torchao.prototype.autoround.utils as ar_utils
+from torchao.prototype.autoround.core import (
+    apply_auto_round,
+    prepare_model_for_applying_auto_round_,
+)
+from torchao.prototype.autoround.multi_tensor import MultiTensor
+from torchao.quantization import quantize_
+
+ar_utils.freeze_random(42)
+
+
+@torch.no_grad()
+def quantize_model_with_autoround_(
+    model,
+    tokenizer,
+    is_target_module,
+    bits: int = 4,
+    group_size: int = 128,
+    iters: int = 200,
+    seqlen: int = 2048,
+    dataset_name: str = "NeelNanda/pile-10k",
+    batch_size: int = 8,
+    nsamples: int = 128,
+    use_optimized_layer_output: bool = False,
+    gradient_accumulate_steps: Optional[int] = 1,
+    compile_optimization_process: Optional[bool] = False,
+):
+    # Step 1. Prepare the model for applying auto-round
+
+    model_device = next(model.parameters()).device
+    device = "cuda" if torch.cuda.is_available() else "cpu"
+
+    prepare_model_for_applying_auto_round_(
+        model,
+        is_target_module,
+        bits,
+        group_size,
+        iters,
+        use_optimized_layer_output,
+        gradient_accumulate_steps,
+        compile_optimization_process,
+        device=device,
+    )
+
+    # Step 2. Caliration and optimization
+    dataloader = ar_utils.import_dataloader()(
+        tokenizer,
+        seqlen=seqlen,
+        dataset_name=dataset_name,
+        bs=batch_size,
+        nsamples=nsamples,
+    )
+    input_ids_lst = []
+    for data in dataloader:
+        input_ids_lst.append(data["input_ids"].to(model_device))
+    print(
+        f"Number of batches: {len(input_ids_lst)}, shape of all batches: {[inp.shape for inp in input_ids_lst]}"
+    )
+
+    multi_t_input_ids = MultiTensor(input_ids_lst)
+
+    # The optimization is applied during the forward pass
+    model(multi_t_input_ids)
+
+    # Step 3. Apply the quantization
+    quantize_(model, apply_auto_round(), is_target_module, device=device)
+
+    num_quantized_weight = ar_utils.count_tensor_of_type(
+        model, torchao.dtypes.AffineQuantizedTensor
+    )
+    print(f"Quantized {num_quantized_weight} Linear layers.")
+
+    return model
+
+
+def main(args):
+    # Get the model, tokenizer, and decoder_cls
+    model_name_or_path = args.model_name_or_path
+    model, tokenizer, decoder_cls = ar_utils.get_float_model_info(
+        model_name_or_path, torch_dtype=torch.bfloat16
+    )
+    # Disable the `use_cache` for calibration stage.
+    model.config.use_cache = False
+    ar_utils.gen_text(model, tokenizer, "Float model", max_length=50)
+
+    model = model.to(args.model_device)
+
+    # User need to prepare a `is_target_module` function for identifying the target modules that need to be quantized.
+    if args.quant_lm_head:
+        is_target_module = (
+            lambda mod, fqn: isinstance(mod, decoder_cls) or "lm_head" in fqn
+        )
+    else:
+        is_target_module = lambda mod, fqn: isinstance(mod, decoder_cls)
+
+    quantize_model_with_autoround_(
+        model=model,
+        tokenizer=tokenizer,
+        is_target_module=is_target_module,
+        bits=args.bits,
+        iters=args.iters,
+        seqlen=args.seqlen,
+        dataset_name=args.dataset_name,
+        batch_size=args.batch_size,
+        nsamples=args.nsamples,
+        use_optimized_layer_output=args.use_optimized_layer_output,
+        gradient_accumulate_steps=args.gradient_accumulate_steps,
+        compile_optimization_process=args.compile_optimization_process,
+    )
+    # Revert the `use_cache` for generation stage.
+    model.config.use_cache = True
+
+    # Generate text using the quantized model
+    ar_utils.gen_text(model, tokenizer, "Quantized model", max_length=50)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter
+    )
+    parser.add_argument(
+        "-m",
+        "--model_name_or_path",
+        type=str,
+        default="facebook/opt-125m",
+        help="Pretrained model name or path",
+    )
+    parser.add_argument(
+        "--dataset_name",
+        type=str,
+        default="NeelNanda/pile-10k",
+        help="Dataset name for calibration",
+    )
+    parser.add_argument(
+        "--iters",
+        default=200,
+        type=int,
+        help="Number of steps for optimizing each block",
+    )
+    parser.add_argument(
+        "--bits", default=4, type=int, help="Number of bits for quantization"
+    )
+    parser.add_argument(
+        "--batch_size", default=8, type=int, help="Batch size for calibration"
+    )
+    parser.add_argument(
+        "--nsamples",
+        default=128,
+        type=int,
+        help="Number of samples for calibration process",
+    )
+    parser.add_argument(
+        "--group_size",
+        default=128,
+        type=int,
+        help="Group size for quantization",
+    )
+    parser.add_argument(
+        "--seqlen",
+        default=2048,
+        type=int,
+        help="Sequence length for each samples",
+    )
+    parser.add_argument(
+        "--gradient_accumulate_steps",
+        default=1,
+        type=int,
+        help=(
+            "Number of steps for accumulating gradients before performing"
+            "the backward pass when optimizing each target module"
+        ),
+    )
+    parser.add_argument(
+        "--quant_lm_head",
+        default=False,
+        action="store_true",
+        help="Whether to quantize the `lm_head`",
+    )
+    parser.add_argument(
+        "--use_optimized_layer_output",
+        default=False,
+        action="store_true",
+        help="Whether to use optimized layer output as input for the next layer",
+    )
+    parser.add_argument(
+        "-c",
+        "--compile_optimization_process",
+        default=False,
+        action="store_true",
+        help="Whether to compile the optimization process",
+    )
+    parser.add_argument(
+        "-d",
+        "--model_device",
+        default="cuda",
+        type=str,
+        choices=["cpu", "cuda"],
+        help="Device for loading the float model",
+    )
+    args = parser.parse_args()
+    main(args)
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/core.py b/lib/python3.12/site-packages/torchao/prototype/autoround/core.py
new file mode 100644
index 0000000000000000000000000000000000000000..859e1cfe02117b19776782a52022a9df0f5c3ec1
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/autoround/core.py
@@ -0,0 +1,372 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import dataclasses
+import logging
+from typing import Any, Callable, Dict, Optional, Tuple
+
+import torch
+
+import torchao.prototype.autoround.utils as ar_utils
+import torchao.quantization as ao_quant
+from torchao.dtypes import TensorCoreTiledLayout, to_affine_quantized_intx_static
+from torchao.prototype.autoround.multi_tensor import MultiTensor, _multi_tensor_config
+from torchao.quantization.quant_primitives import ZeroPointDomain
+from torchao.utils import find_multiple
+
+
+@ar_utils.singleton
+@dataclasses.dataclass
+class _AutoRoundConfig:
+    bits: int = 4
+    group_size: int = 128
+    iters: int = 200
+    use_optimized_layer_output: bool = False
+    gradient_accumulate_steps: int = 1
+    compile_optimization_process: bool = False
+
+
+_auto_round_config = _AutoRoundConfig()
+
+
+@ar_utils.singleton
+@dataclasses.dataclass
+class _OptimizationTracker:
+    num_layers: int = 0
+    optimized_layers: int = 0
+
+    def reset(self):
+        self.num_layers = 0
+        self.optimized_layers = 0
+
+
+_optimization_tracker = _OptimizationTracker()
+
+
+def _replace_model_buffers_and_params(model, replacement_fn):
+    model = replacement_fn(model)
+    for name, child in model.named_children():
+        new_child = _replace_model_buffers_and_params(child, replacement_fn)
+        if new_child is not child:
+            setattr(model, name, new_child)
+    return model
+
+
+def _tensor_to_multi_tensor(model):
+    for name, buf in model.named_buffers(recurse=False):
+        setattr(model, name, MultiTensor([buf]))
+    for name, param in model.named_parameters(recurse=False):
+        setattr(model, name, torch.nn.Parameter(MultiTensor([param]), False))
+    return model
+
+
+def _multi_tensor_to_tensor(model):
+    for name, buf in model.named_buffers(recurse=False):
+        if isinstance(buf, MultiTensor):
+            assert len(buf.values) == 1, (
+                f"The buffer should only have one tensor, but got {buf.count}."
+            )
+            model.register_buffer(name, buf.values[0])
+    for name, param in model.named_parameters(recurse=False):
+        if isinstance(param, MultiTensor):
+            assert len(param.values) == 1, (
+                f"The parameter should only have one tensor, but got {param.count}."
+            )
+            setattr(
+                model, name, torch.nn.Parameter(param.values[0], requires_grad=False)
+            )
+    return model
+
+
+@torch.no_grad()
+def prepare_model_for_applying_auto_round_(
+    model: torch.nn.Module,
+    is_target_module: Callable[[torch.nn.Module, str], bool],
+    bits: int = 4,
+    group_size: int = 128,
+    iters: int = 200,
+    use_optimized_layer_output: bool = False,
+    gradient_accumulate_steps: Optional[int] = 1,
+    compile_optimization_process: Optional[bool] = False,
+    device: Optional[torch.types.Device] = None,
+):
+    """Prepares the model for applying auto round optimization.
+
+    Args:
+        model (torch.nn.Module): The floating-point model to be quantized.
+        is_target_module (Callable[[torch.nn.Module, str], bool]): A function that determines
+            whether a module is a target module.
+        bits (int, optional): The number of bits for quantization. Defaults to 4, options are 1 to 8.
+        group_size (int, optional): The group size for quantization. Defaults to 128.
+        iters (int, optional): The number of iterations for optimization. Defaults to 200.
+        use_optimized_layer_output (bool, optional): Whether to use optimized layer output. Defaults to False.
+        gradient_accumulate_steps (Optional[int]): Number of steps for accumulating gradients before
+            performing the backward pass when optimizing each target module. Defaults to 1.
+        compile_optimization_process (Optional[bool]): Whether to compile the optimization process. Defaults to False.
+        device (Optional[torch.types.Device]): The device to use for accelrating optimization and calibration.
+            Defaults to None.
+    """
+    _multi_tensor_config.device = device
+    _multi_tensor_config.offload = next(model.parameters()).device.type != device
+    _optimization_tracker.reset()
+
+    _auto_round_config.bits = bits
+    _auto_round_config.group_size = group_size
+    _auto_round_config.iters = iters
+    _auto_round_config.use_optimized_layer_output = use_optimized_layer_output
+    _auto_round_config.gradient_accumulate_steps = gradient_accumulate_steps
+    _auto_round_config.compile_optimization_process = compile_optimization_process
+
+    logging.warning(f"config {_auto_round_config}")
+
+    # Wrap the model buffers and parameters with `MultiTensor`
+    model = _replace_model_buffers_and_params(model, _tensor_to_multi_tensor)
+
+    def _revert_buffers_and_params_fn(
+        module,
+        input: Tuple[MultiTensor],
+        output: Tuple[MultiTensor],
+    ):
+        module._forward_hook_handle_for_revert_buffers_and_params.remove()
+        _replace_model_buffers_and_params(module, _multi_tensor_to_tensor)
+        return output
+
+    # Register forward hook for reverting the replacement of buffers and parameters
+    model._forward_hook_handle_for_revert_buffers_and_params = (
+        model.register_forward_hook(_revert_buffers_and_params_fn)
+    )
+
+    # Register forward hook for applying auto-round optimization
+    def auto_round_optimization_hook(
+        module,
+        args: Tuple[MultiTensor],
+        kwargs: Dict[str, MultiTensor],
+        output: Tuple[MultiTensor],
+    ):
+        apply_auto_round_optimization(
+            module, args, kwargs, output, config=_auto_round_config
+        )
+        return output
+
+    def _register_forward_hook(module: torch.nn.Module):
+        forward_hook_handle = module.register_forward_hook(
+            auto_round_optimization_hook, with_kwargs=True
+        )
+        module._forward_hook_handle_for_auto_round = forward_hook_handle
+        _optimization_tracker.num_layers += 1
+        return module
+
+    model.eval()
+    ao_quant.quant_api._replace_with_custom_fn_if_matches_filter(
+        model, _register_forward_hook, is_target_module
+    )
+
+
+def apply_auto_round():
+    """Create the quantized model from the model optimized by auto-round.
+
+    More details about the auto-round can be found at https://arxiv.org/abs/2309.05516.
+    """
+
+    raise AssertionError(
+        "Please migrate this function to direct configuration, see https://github.com/pytorch/ao/issues/1690 for details"
+    )
+
+    def _apply_auto_round(optimized_model: torch.nn.Module):
+        """
+        The `optimized_model` includes `Linear` layers optimized by auto-round, which includes `qdq_weight`, `scale`, `zp`.
+        """
+
+        @torch.no_grad()
+        def convert_weight_to_affine_quantized_tensor(observed_linear: torch.nn.Module):
+            device = observed_linear.weight.device
+            scale = observed_linear.scale.to(device)
+            zero_point = observed_linear.zp.to(device)
+
+            def to_uintx_weight(input_float):
+                quant_min = 0
+                quant_max = _auto_round_config.bits**2 - 1
+                block_size = (1, observed_linear.group_size)
+                from torchao.dtypes.uintx.uintx import (
+                    _BIT_WIDTH_TO_DTYPE,
+                    UintxLayout,
+                )
+                from torchao.quantization.quant_primitives import ZeroPointDomain
+
+                assert _auto_round_config.bits in _BIT_WIDTH_TO_DTYPE, (
+                    f"Invalid bits: {_auto_round_config.bits}"
+                )
+                dtype = _BIT_WIDTH_TO_DTYPE[_auto_round_config.bits]
+                pack_dim = -1
+                _layout = UintxLayout(dtype=dtype, pack_dim=pack_dim)
+                return to_affine_quantized_intx_static(
+                    input_float=input_float,
+                    scale=scale.to(input_float.dtype),
+                    zero_point=zero_point,
+                    block_size=block_size,
+                    target_dtype=torch.uint8,
+                    quant_min=quant_min,
+                    quant_max=quant_max,
+                    zero_point_domain=ZeroPointDomain.INT,
+                    _layout=_layout,
+                )
+
+            def to_int4_tinygemm_weight(input_float):
+                # TODO(Yi): check the weight shape, `group_size`, and `inner_k_tiles` to make sure the tinygemm can handle it
+                inner_k_tiles = 8
+                quant_min = 0
+                quant_max = _auto_round_config.bits**2 - 1
+                # Shift the `zero_point` to align with tiny gemm.
+                # The dequantization process in tiny gemm:
+                #   tiny_dequant = (tiny_quant - 8) * scale + tiny_zp
+                # The dequantization porcess in auto-round
+                #   dequant = (quant - zp) * scale
+                # To align with tiny gemm:
+                #   dequant = (quant - 8 + 8 - zp) * scale
+                #           = (quant - 8) * scale + (8 - zp) * scale
+                #              \__/                 \______________/
+                #            tiny_quant                 tiny_zp
+                mid_point = (quant_max + quant_min + 1) / 2
+                shifted_zero_point = (mid_point - zero_point) * scale
+                block_size = (1, observed_linear.group_size)
+                orig_out_features, orig_in_features = input_float.shape
+                in_features = find_multiple(orig_in_features, 1024)
+                out_features = find_multiple(orig_out_features, 8)
+                orig_num_groups = orig_in_features // observed_linear.group_size
+                new_num_groups = in_features // observed_linear.group_size
+                # pad scale/zero_point from [orig_out_features, orig_num_groups] to [out_features, new_num_groups]
+                pad_scale = torch.nn.functional.pad(
+                    scale,
+                    (
+                        0,
+                        new_num_groups - orig_num_groups,
+                        0,
+                        out_features - orig_out_features,
+                    ),
+                )
+                pad_shifted_zero_point = torch.nn.functional.pad(
+                    shifted_zero_point,
+                    (
+                        0,
+                        new_num_groups - orig_num_groups,
+                        0,
+                        out_features - orig_out_features,
+                    ),
+                )
+                return to_affine_quantized_intx_static(
+                    input_float=input_float,
+                    scale=pad_scale.to(torch.bfloat16),
+                    zero_point=pad_shifted_zero_point.to(torch.bfloat16),
+                    block_size=block_size,
+                    target_dtype=torch.int32,
+                    quant_min=quant_min,
+                    quant_max=quant_max,
+                    zero_point_domain=ZeroPointDomain.FLOAT,
+                    _layout=TensorCoreTiledLayout(inner_k_tiles=inner_k_tiles),
+                )
+
+            # TODO(Yi): better way to select the weight quantization function
+            if (
+                _auto_round_config.bits == 4
+                and observed_linear.weight.device.type == "cuda"
+            ):
+                weight_func = to_int4_tinygemm_weight
+            else:
+                weight_func = to_uintx_weight
+
+            observed_linear.weight = torch.nn.Parameter(
+                weight_func(observed_linear.weight), requires_grad=False
+            )
+            del observed_linear.scale
+            del observed_linear.zp
+            return observed_linear
+
+        def _is_observed_linear(mod: torch.nn.Module, fqn: str):
+            return hasattr(mod, "scale")
+
+        qmodel = ao_quant.quant_api._replace_with_custom_fn_if_matches_filter(
+            optimized_model,
+            convert_weight_to_affine_quantized_tensor,
+            _is_observed_linear,
+        )
+        return qmodel
+
+    return _apply_auto_round
+
+
+@torch.no_grad()
+def _apply_auto_round_optimization(
+    block, block_inputs, block_outputs, config: _AutoRoundConfig
+):
+    # Call the auto-round to execute the optimization process.
+    # https://github.com/intel/auto-round/tree/patch-for-ao-2
+    # TODO(Yi), make the branch more stable
+    if ar_utils.is_auto_round_available():
+        import auto_round
+    else:
+        raise ImportError(
+            (
+                "This example requires the `auto-round` library."
+                "Please install it with `pip install git+https://github.com/intel/auto-round.git@patch-for-ao-2`"
+            )
+        )
+    orig_device = next(block.parameters()).device
+    block = block.to(_multi_tensor_config.device)
+    _optimization_tracker.optimized_layers += 1
+    logging.warning(
+        "Apply auto-round optimization on layer %d / %d.",
+        _optimization_tracker.optimized_layers,
+        _optimization_tracker.num_layers,
+    )
+
+    # Start the training process to update the v, alpha and beta.
+    rounder = auto_round.AutoRound(
+        model=block,
+        tokenizer=None,
+        sym=False,
+        bits=config.bits,
+        iters=config.iters,
+        group_size=config.group_size,
+        gradient_accumulate_steps=config.gradient_accumulate_steps,
+        amp=True,
+        model_dtype=next(block.parameters()).dtype,
+    )
+    if config.compile_optimization_process:
+        rounder.quant_block_v2_ = torch.compile(rounder.quant_block_v2_)
+
+    with torch.enable_grad():
+        rounder.quant_block_v2_(
+            block,
+            inputs=block_inputs,
+            outputs=block_outputs,
+            device=_multi_tensor_config.device,
+        )
+    block.to(orig_device)
+
+
+@ar_utils.dump_elapsed_time(record=True)
+@torch.no_grad()
+def apply_auto_round_optimization(
+    module: torch.nn.Module,
+    args: Tuple[MultiTensor],
+    kwargs: Dict[str, Any],
+    output: Any,
+    config: _AutoRoundConfig,
+):
+    # Remove the hook to avoid recursive calls
+    module._forward_hook_handle_for_auto_round.remove()
+    # Revert the model to the original state for applying auto-round optimization
+    module = _replace_model_buffers_and_params(module, _multi_tensor_to_tensor)
+
+    block_inputs = MultiTensor.revert_to_tensor_pairs(args, kwargs)
+    block_outputs = MultiTensor.revert_to_tensor_pairs(output)
+
+    _apply_auto_round_optimization(module, block_inputs, block_outputs, config)
+    # Get the new output of the optimized model
+    if config.use_optimized_layer_output:
+        # Re-replace the model buffers and parameters with `MultiTensor`
+        _replace_model_buffers_and_params(module, _tensor_to_multi_tensor)
+        output = module(*args, **kwargs)
+    return output
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/eval_autoround.py b/lib/python3.12/site-packages/torchao/prototype/autoround/eval_autoround.py
new file mode 100644
index 0000000000000000000000000000000000000000..16c173684376932c95a99834388cf8ec963287c6
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/autoround/eval_autoround.py
@@ -0,0 +1,278 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import argparse
+import logging
+import os
+
+import torch
+
+import torchao
+import torchao.prototype.autoround.utils as ar_utils
+import torchao.quantization
+from torchao.utils import TORCH_VERSION_AT_LEAST_2_5
+
+logger = logging.getLogger(__name__)
+
+ar_utils.freeze_random(42)
+
+
+def _use_deterministic():
+    torch.backends.cudnn.deterministic = True
+    torch.backends.cudnn.benchmark = False
+    torch.use_deterministic_algorithms(True, warn_only=False)
+    os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8"
+    logger.warning(
+        (
+            "Reproducibility is enabled with `AO_USE_DETERMINISTIC_ALGORITHMS=1`, which sets "
+            "`torch.use_deterministic_algorithms(True, warn_only=False)` and "
+            "environment variable `CUBLAS_WORKSPACE_CONFIG` to `:4096:8`.\n"
+            "Please note that this may impact performance, or cause crashes if the model includes non-deterministic operations."
+        )
+    )
+
+
+AO_USE_DETERMINISTIC_ALGORITHMS = (
+    os.environ.get("AO_USE_DETERMINISTIC_ALGORITHMS", "0") == "1"
+)
+if AO_USE_DETERMINISTIC_ALGORITHMS:
+    _use_deterministic()
+
+
+@ar_utils.dump_elapsed_time()
+def run_evaluation(model, tokenizer, tasks, compile=False, batch_size=4):
+    try:
+        from lm_eval.evaluator import evaluate
+        from lm_eval.models.huggingface import HFLM
+        from lm_eval.tasks import get_task_dict
+    except ImportError:
+        print(
+            """
+    Error: The 'lm_eval' module was not found.
+    To install, follow these steps:
+    pip install git+https://github.com/EleutherAI/lm-evaluation-harness.git
+    """
+        )
+        raise  # Re-raise the ImportError
+
+    with torch.no_grad():
+        result = evaluate(
+            HFLM(pretrained=model, tokenizer=tokenizer, batch_size=batch_size),
+            get_task_dict(tasks),
+        )
+        torch.cuda.empty_cache()
+        from lm_eval.utils import make_table
+
+        print(make_table(result))
+
+
+def bench_accuracy(model, tokenizer, tasks, msg=""):
+    with torch.no_grad():
+        print(f"==================== {msg} ====================")
+        print(f"tasks: {tasks}")
+        from torchao.prototype.autoround.hf_eval_utils import run_evaluation
+
+        torch.cuda.empty_cache()
+        run_evaluation(model, tokenizer, tasks=tasks)
+        torch.cuda.empty_cache()
+
+
+def _is_linear_but_not_lm_head(mod, fqn):
+    return isinstance(mod, torch.nn.Linear) and "lm_head" not in fqn
+
+
+def main(args):
+    with torch.no_grad():
+        model_name_or_path = args.model_name_or_path
+        model, tokenizer, decoder_cls = ar_utils.get_float_model_info(
+            model_name_or_path, torch_dtype=torch.bfloat16
+        )
+        model.eval()
+        model_device = args.model_device
+        # `sorted_logits` does not have a deterministic implementation
+        if not AO_USE_DETERMINISTIC_ALGORITHMS:
+            ar_utils.gen_text(model, tokenizer, "Float model", max_length=50)
+        model = model.to(model_device)
+        model.config.use_cache = False
+        msg = "Float-model" if args.eval_float_model else "Quantized-model"
+        if not args.eval_float_model:
+            filter_fn = None if args.quant_lm_head else _is_linear_but_not_lm_head
+            # Evaluate the quantized model
+            if args.woq_int4:
+                msg += " (int4wo)"
+                from torchao.quantization import int4_weight_only, quantize_
+
+                quantize_(
+                    model,
+                    int4_weight_only(group_size=args.group_size),
+                    filter_fn=filter_fn,
+                    device=model_device,
+                )
+            elif args.uintx:
+                msg += f" (uintx {args.bits} bits)"
+                from torchao.dtypes.uintx.uintx import _BIT_WIDTH_TO_DTYPE
+                from torchao.quantization.quant_api import quantize_, uintx_weight_only
+
+                bits = args.bits
+                assert bits in _BIT_WIDTH_TO_DTYPE, f"Invalid bits: {bits}"
+                dtype = _BIT_WIDTH_TO_DTYPE[bits]
+                quantize_(
+                    model,
+                    uintx_weight_only(dtype=dtype, group_size=args.group_size),
+                    filter_fn=filter_fn,
+                    device=model_device,
+                )
+
+            else:
+                msg += f" (auto-round {args.bits} bits)"
+                torch.cuda.empty_cache()
+                from torchao.prototype.autoround.autoround_llm import (
+                    quantize_model_with_autoround_,
+                )
+
+                # User need to prepare a `is_target_module` function for identifying the target modules that need to be quantized.
+                if args.quant_lm_head:
+                    is_target_module = (
+                        lambda mod, fqn: isinstance(mod, decoder_cls)
+                        or "lm_head" in fqn
+                    )
+                else:
+                    is_target_module = lambda mod, fqn: isinstance(mod, decoder_cls)
+
+                model = quantize_model_with_autoround_(
+                    model=model,
+                    tokenizer=tokenizer,
+                    is_target_module=is_target_module,
+                    bits=args.bits,
+                    group_size=args.group_size,
+                    iters=args.iters,
+                    seqlen=args.seqlen,
+                    batch_size=args.batch_size,
+                    nsamples=args.nsamples,
+                    use_optimized_layer_output=args.use_optimized_layer_output,
+                    gradient_accumulate_steps=args.gradient_accumulate_steps,
+                    compile_optimization_process=args.compile_optimization_process,
+                )
+            quantized_layer_cnt = ar_utils.count_tensor_of_type(
+                model, torchao.dtypes.AffineQuantizedTensor
+            )
+            msg += f" quantized {quantized_layer_cnt} Linear layers "
+        if not AO_USE_DETERMINISTIC_ALGORITHMS:
+            ar_utils.gen_text(model, tokenizer, msg, max_length=50)
+
+        bench_accuracy(model, tokenizer, tasks=args.tasks, msg=msg)
+
+
+if __name__ == "__main__" and TORCH_VERSION_AT_LEAST_2_5 and torch.cuda.is_available():
+    parser = argparse.ArgumentParser(
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter
+    )
+    parser.add_argument(
+        "-m",
+        "--model_name_or_path",
+        type=str,
+        default="facebook/opt-125m",
+        help="Pretrained model name or path",
+    )
+    parser.add_argument(
+        "--dataset_name",
+        type=str,
+        default="NeelNanda/pile-10k",
+        help="Dataset name for calibration",
+    )
+    parser.add_argument(
+        "--iters",
+        default=200,
+        type=int,
+        help="Number of steps for optimizing each block",
+    )
+    parser.add_argument(
+        "--bits", default=4, type=int, help="Number of bits for quantization"
+    )
+    parser.add_argument(
+        "--batch_size", default=8, type=int, help="Batch size for calibration"
+    )
+    parser.add_argument(
+        "--nsamples",
+        default=128,
+        type=int,
+        help="Number of samples for calibration process",
+    )
+    parser.add_argument(
+        "--group_size",
+        default=128,
+        type=int,
+        help="Group size for quantization",
+    )
+    parser.add_argument(
+        "--seqlen",
+        default=2048,
+        type=int,
+        help="Sequence length for each samples",
+    )
+    parser.add_argument(
+        "--gradient_accumulate_steps",
+        default=1,
+        type=int,
+        help=(
+            "Number of steps for accumulating gradients before performing"
+            "the backward pass when optimizing each target module"
+        ),
+    )
+    parser.add_argument(
+        "--quant_lm_head",
+        default=False,
+        action="store_true",
+        help="Whether to quantize the `lm_head`",
+    )
+    parser.add_argument(
+        "--use_optimized_layer_output",
+        default=False,
+        action="store_true",
+        help="Whether to use optimized layer output as input for the next layer",
+    )
+    parser.add_argument(
+        "-c",
+        "--compile_optimization_process",
+        default=False,
+        action="store_true",
+        help="Whether to compile the optimization process",
+    )
+    parser.add_argument(
+        "-d",
+        "--model_device",
+        default="cuda",
+        type=str,
+        choices=["cpu", "cuda"],
+        help="Device for loading the float model",
+    )
+    parser.add_argument(
+        "--eval_float_model",
+        default=False,
+        action="store_true",
+        help="Evaluate the float model",
+    )
+    parser.add_argument(
+        "--woq_int4",
+        default=False,
+        action="store_true",
+        help="Quantize the model with int4 weight only",
+    )
+    parser.add_argument(
+        "--uintx",
+        default=False,
+        action="store_true",
+        help="Quantize the model with int4 weight only",
+    )
+    parser.add_argument(
+        "--tasks",
+        nargs="+",
+        type=str,
+        default=["wikitext"],
+        help="List of lm-eluther tasks to evaluate usage: --tasks task1 task2",
+    )
+    args = parser.parse_args()
+
+    main(args)
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/multi_tensor.py b/lib/python3.12/site-packages/torchao/prototype/autoround/multi_tensor.py
new file mode 100644
index 0000000000000000000000000000000000000000..32378c2e7141023c4aa1673183834a1c10e02d2e
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/autoround/multi_tensor.py
@@ -0,0 +1,177 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import dataclasses
+from typing import List
+
+import torch
+from torch.utils._pytree import tree_flatten, tree_unflatten
+
+
+@dataclasses.dataclass
+class _MultiTensorConfig:
+    device: str = "cuda" if torch.cuda.is_available() else "cpu"
+    ops_to_accelerate: List[str] = dataclasses.field(
+        default_factory=lambda: [
+            torch.nn.functional.linear,
+            torch.matmul,
+            torch.bmm,
+            torch.nn.functional.scaled_dot_product_attention,
+        ]
+    )
+    offload: bool = False
+
+
+# Note: As the `MultiTensor` includes a list of tensors, during the calibration stage,
+# placing all output tensors on the GPU would consume a significant amount of GPU memory.
+# This is especially true for models with a large `lm-head`, such as Llama-3.1.
+# In these cases, we load the model onto the DRAM and only transfer tensors to the GPU for compute-intensive operations.
+_multi_tensor_config = _MultiTensorConfig()
+
+
+class MultiTensor(torch.Tensor):
+    # Modified from https://gist.github.com/HDCharles/a1b575bbf8875f994af8a01b225e1227
+    @staticmethod
+    def __new__(cls, input, **kwargs):
+        if isinstance(input, (list, tuple)):
+            input = input[0]
+        kwargs["dtype"] = kwargs.get("dtype", input.dtype)
+        shape = kwargs.pop("shape", input.shape)
+        return torch.Tensor._make_wrapper_subclass(cls, shape, **kwargs)
+
+    def __init__(self, input, **kwargs):
+        self.values = []
+        self.count = 0
+        self.add_tensors(input)
+        self.debug = True
+
+    def __repr__(self):
+        return f"{self.__class__.__name__}(data={self.values})"
+
+    def add_tensors(self, input):
+        if isinstance(input, (tuple, list)):
+            for inp in input:
+                self.add_tensors(inp)
+        else:
+            assert isinstance(input, torch.Tensor), (
+                f"MultiTensor can only use add_tensors for Tensors or lists of tensors but got {type(input)}"
+            )
+            self.count += 1
+            self.values.append(input)
+        return self
+
+    def get_value(self, i):
+        # Instead of copy the last tensor to pad the MultiTensor, we use this function to do fake padding
+        # to avoid introducing extra memory usage.
+        if i + 1 <= self.count:
+            return self.values[i]
+        else:
+            return self.values[-1]
+
+    @classmethod
+    def flat_to_grouped(cls, flat):
+        # size of biggest MultiTensor
+        multi_tensor_size = max(
+            [x.count if isinstance(x, MultiTensor) else 1 for x in flat]
+        )
+
+        grouped = []
+        for i in range(multi_tensor_size):
+            sub_group = []
+            for x in flat:
+                if isinstance(x, MultiTensor):
+                    sub_group.append(x.get_value(i))
+                else:
+                    sub_group.append(x)
+            grouped.append(sub_group)
+        return grouped
+
+    @classmethod
+    def grouped_to_flat(cls, grouped):
+        # convert [[A,b1,c1], [A,b2,c2] [A,b3,c3]] => [A, MultiTensor(b1,b2,b3), MultiTensor(c1,c2,c3)]
+        # where A is nontensor, b's,c's are tensors
+        # convert [[A,b1,c1], [A,b2,c2] [A,b3,c3]] => [(A,A,A), (b1,b2,b3), (c1,c2,c3)]
+        flat_tups = list(zip(*grouped))
+        # convert [(A,A,A), (b1,b2,b3), (c1,c2,c3)] => [A, MultiTensor(b1,b2,b3), MultiTensor(c1,c2,c3)]
+        flattened = [
+            cls(tup) if isinstance(tup[0], torch.Tensor) else tup[0]
+            for tup in flat_tups
+        ]
+        # need to check that getting rid of all but one from each nonTensor tuple is OK
+        non_tensors_equal = min(
+            [True]
+            + [
+                min(
+                    [True]
+                    + [  # handle situation where tuples have size 0
+                        tup[0] == x
+                        for x in tup  # check all elements match
+                    ]
+                )
+                for tup in flat_tups
+                if not isinstance(tup[0], torch.Tensor)  # look at tuples of nonTensors
+            ]
+        )
+        return flattened, non_tensors_equal
+
+    @classmethod
+    def revert_to_tensor_pairs(cls, args, kwargs=None):
+        if kwargs is None:
+            kwargs = {}
+        # combine args and kwargs and remove lists and tuples
+        flat_args, spec = tree_flatten((args, kwargs))
+        # convert [A, MultiTensor(b1,b2,b3), MultiTensor(c1,c2,c3)] => [[A,b1,c1], [A,b2,c2] [A,b3,c3]]
+        grouped_args = cls.flat_to_grouped(flat_args)
+        args_kwargs_pairs = []
+        for i, inp in enumerate(grouped_args):
+            cur_args, cur_kwargs = tree_unflatten(inp, spec)
+            args_kwargs_pairs.append((cur_args, cur_kwargs))
+        return args_kwargs_pairs
+
+    @classmethod
+    def __torch_function__(cls, func, types, args=(), kwargs=None):
+        args_kwargs_pairs = cls.revert_to_tensor_pairs(args, kwargs)
+        # run function for each of the multitensors and return a multitensor
+        outputs = []
+        with torch._C.DisableTorchFunctionSubclass():
+            for cur_args, cur_kwargs in args_kwargs_pairs:
+                if func in _multi_tensor_config.ops_to_accelerate:
+                    device = _multi_tensor_config.device
+                    cur_args = [
+                        (arg.to(device) if isinstance(arg, torch.Tensor) else arg)
+                        for arg in cur_args
+                    ]
+                    cur_kwargs = {
+                        k: (v.to(device) if isinstance(v, torch.Tensor) else v)
+                        for k, v in cur_kwargs.items()
+                    }
+                out = func(*cur_args, **cur_kwargs)
+                offload = _multi_tensor_config.offload
+                outputs.append(
+                    out.to("cpu") if isinstance(out, torch.Tensor) and offload else out
+                )
+            grouped_outputs = [tree_flatten(x)[0] for x in outputs]
+            out_spec = tree_flatten(outputs[0])[1]
+            # convert [[A,b1,c1], [A,b2,c2] [A,b3,c3]] => [A, MultiTensor(b1,b2,b3), MultiTensor(c1,c2,c3)]
+            flat_outputs, non_tensors_equal = cls.grouped_to_flat(grouped_outputs)
+            assert non_tensors_equal, (
+                f"ERR: found a function in model: {func} which "
+                "caused an error in MultiTensor, the function dispatch only works for functions"
+                " with Tensor outputs or that have the same non-Tensor output value for all across all inputs"
+            )
+            return tree_unflatten(flat_outputs, out_spec)
+
+    @classmethod
+    def __torch_dispatch__(cls, func, types, args=(), kwargs={}):
+        pass
+
+    def __tensor_flatten__(self):
+        return ["values"], None
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls, tensor_data_dict, tensor_attributes, outer_size, outer_stride
+    ):
+        return cls(tensor_data_dict["values"])
diff --git a/lib/python3.12/site-packages/torchao/prototype/autoround/utils.py b/lib/python3.12/site-packages/torchao/prototype/autoround/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ca0d83fd37081adcb0f79446d09a96239dbe6db
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/autoround/utils.py
@@ -0,0 +1,198 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+# ==------------------------------------------------------------------------------------------==
+# Utils for the auto-round
+# ==------------------------------------------------------------------------------------------==
+import collections
+import logging
+import random
+
+import numpy as np
+import torch
+
+
+def _is_package_available(pkg_name, metadata_name=None):
+    # Copied from Accelerate https://github.com/huggingface/accelerate
+    import importlib
+
+    # Check we're not importing a "pkg_name" directory somewhere but the actual library by trying to grab the version
+    package_exists = importlib.util.find_spec(pkg_name) is not None
+    if package_exists:
+        try:
+            # Some libraries have different names in the metadata
+            _ = importlib.metadata.metadata(
+                pkg_name if metadata_name is None else metadata_name
+            )
+            return True
+        except importlib.metadata.PackageNotFoundError:
+            return False
+
+
+def is_auto_round_available() -> bool:
+    return _is_package_available("auto_round")
+
+
+def import_dataloader():
+    if is_auto_round_available():
+        import auto_round
+
+        get_dataloader = auto_round.calib_dataset.get_dataloader
+        return get_dataloader
+    else:
+        raise ImportError(
+            (
+                "This example requires the `auto-round` library."
+                "Please install it with `pip install git+https://github.com/intel/auto-round.git@patch-for-ao-2`"
+            )
+        )
+
+
+def singleton(cls):
+    """Singleton decorator."""
+    instances = {}
+
+    def _singleton(*args, **kw):
+        """Create a singleton object."""
+        if cls not in instances:
+            instances[cls] = cls(*args, **kw)
+        return instances[cls]
+
+    return _singleton
+
+
+def freeze_random(seed=0):
+    random.seed(seed)
+
+    torch.manual_seed(seed)
+
+    np.random.seed(seed)
+
+    g = torch.Generator()
+    g.manual_seed(seed)
+
+    if torch.cuda.is_available():
+        torch.cuda.manual_seed(seed)
+        torch.cuda.manual_seed_all(seed)
+
+
+def count_tensor_of_type(mod, cls):
+    res = 0
+    for name, param in mod.named_parameters():
+        if isinstance(param, cls):
+            res += 1
+    return res
+
+
+def see_memory_usage(message: str = "", force=True):
+    # Modified from DeepSpeed https://github.com/microsoft/DeepSpeed
+    import gc
+    import logging
+
+    import torch.distributed as dist
+
+    if not force:
+        return
+    if dist.is_initialized() and not dist.get_rank() == 0:
+        return
+
+    gc.collect()
+
+    # Print message except when distributed but not rank 0
+    logging.warning(message)
+    bytes_to_gb = 1024 * 1024 * 1024
+    logging.warning(
+        f"AllocatedMem {round(torch.cuda.memory_allocated() / (bytes_to_gb), 2)} GB \
+        MaxAllocatedMem {round(torch.cuda.max_memory_allocated() / (bytes_to_gb), 2)} GB \
+        ReservedMem {round(torch.cuda.memory_reserved() / (bytes_to_gb), 2)} GB \
+        MaxReservedMem {round(torch.cuda.max_memory_reserved() / (bytes_to_gb))} GB "
+    )
+
+    # get the peak memory to report correct data, so reset the counter for the next call
+    torch.cuda.reset_peak_memory_stats()
+
+
+@torch.no_grad()
+def gen_text(model, tokenizer, msg="", device=None, prompt="What's AI?", max_length=20):
+    if device is None:
+        device = "cuda" if torch.cuda.is_available() else "cpu"
+    inputs = tokenizer(prompt, return_tensors="pt")
+    model = model.to(device)
+    new_tokens = model.generate(**inputs.to(device), max_length=max_length)
+    text = tokenizer.decode(new_tokens[0], skip_special_tokens=True)
+    print(f"Generated text ({msg}): {text}")
+
+
+def gen_example_inputs(tokenizer, device, max_length=20):
+    inputs = tokenizer(
+        "What's AI?", return_tensors="pt", padding="max_length", max_length=max_length
+    )
+    input_ids = inputs["input_ids"].to(device)
+    return (input_ids,)
+
+
+def _auto_detect_decoder_cls(model):
+    for name, module in model.named_modules():
+        if isinstance(module, torch.nn.ModuleList):
+            first_module = module[0]
+            return type(first_module)
+
+
+def get_float_model_info(model_name_or_path, torch_dtype=torch.float32):
+    import transformers
+
+    model = transformers.AutoModelForCausalLM.from_pretrained(
+        model_name_or_path, torch_dtype=torch_dtype
+    )
+    tokenizer = transformers.AutoTokenizer.from_pretrained(model_name_or_path)
+    decoder_cls = _auto_detect_decoder_cls(model)
+    logging.warning(f"Detected decoder class: {decoder_cls}")
+    if decoder_cls is None:
+        raise ValueError(
+            "Cannot detect the decoder class from the model, please provide it manually."
+        )
+    return model, tokenizer, decoder_cls
+
+
+execution_records = collections.defaultdict(list)
+
+
+def dump_elapsed_time(customized_msg="", record=False):
+    """Get the elapsed time for decorated functions.
+
+    Args:
+        customized_msg (string, optional): The parameter passed to decorator. Defaults to None.
+    """
+    import logging
+    import time
+
+    def f(func):
+        def fi(*args, **kwargs):
+            start = time.time()
+            res = func(*args, **kwargs)
+            end = time.time()
+            dur = round((end - start) * 1000, 2)
+            if record:
+                execution_records[func.__qualname__].append(dur)
+            logging.warning(
+                "%s elapsed time: %s ms"
+                % (
+                    customized_msg if customized_msg else func.__qualname__,
+                    dur,
+                )
+            )
+            if record:
+                avg_time = sum(execution_records[func.__qualname__]) / len(
+                    execution_records[func.__qualname__]
+                )
+                std_time = np.std(execution_records[func.__qualname__])
+                logging.warning(
+                    f"For {func.__qualname__}, the average elapsed time: {avg_time: .2f} ms, the std: {std_time: .2f} ms"
+                )
+            return res
+
+        return fi
+
+    return f
diff --git a/lib/python3.12/site-packages/torchao/prototype/awq/__init__.py b/lib/python3.12/site-packages/torchao/prototype/awq/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..570b0821d4d54fef6685c72b39fc438a7a8c0e80
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/awq/__init__.py
@@ -0,0 +1,8 @@
+from .api import awq_uintx, insert_awq_observer_
+from .core import AWQObservedLinear
+
+__all__ = [
+    "awq_uintx",
+    "insert_awq_observer_",
+    "AWQObservedLinear",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c4dcfda2e13d2128c0a72d80a3a2daac1e63ee8d
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/api.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/api.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..64d6677811b51d145c23d41285847d26e511def8
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/api.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/core.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/core.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0186218a153a634d01dedc1e5f5a83895962a0bb
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/core.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/example.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/example.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..553c92cfb78bb3893527e01e5ad46ad081037129
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/awq/__pycache__/example.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/awq/api.py b/lib/python3.12/site-packages/torchao/prototype/awq/api.py
new file mode 100644
index 0000000000000000000000000000000000000000..2d6059c0579b6919d2356f7a38f84e9c7407b6e2
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/awq/api.py
@@ -0,0 +1,187 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import types
+from dataclasses import dataclass
+
+import torch
+
+import torchao
+from torchao.core.config import AOBaseConfig
+from torchao.dtypes import (
+    TensorCoreTiledLayout,
+    to_affine_quantized_intx,
+)
+from torchao.dtypes.uintx.uintx_layout import _DTYPE_TO_BIT_WIDTH, UintxLayout
+from torchao.quantization import to_weight_tensor_with_linear_activation_scale_metadata
+from torchao.quantization.granularity import PerGroup
+from torchao.quantization.quant_api import (
+    _linear_extra_repr,
+    _replace_with_custom_fn_if_matches_filter,
+)
+from torchao.quantization.quant_primitives import (
+    _DTYPE_TO_QVALUE_BOUNDS,
+    MappingType,
+    ZeroPointDomain,
+)
+from torchao.quantization.transform_module import (
+    register_quantize_module_handler,
+)
+
+from .core import (
+    AWQObservedLinear,
+    AWQObserver,
+)
+
+assert len(_DTYPE_TO_BIT_WIDTH) > 0, (
+    "Error importing low bit torch.uint dtypes. Please upgrade to torch 2.3+"
+)
+
+
+def insert_awq_observer_(
+    model: torch.nn.Module,
+    n_validation_examples: int,
+    validation_sequence_len: int,
+    quant_dtype: torch.dtype = torch.uint4,
+    scale_search_space_size: int = 20,
+    group_size: int = 128,
+):
+    """
+    Inserts AWQObserver into Linear layers of a given model.
+
+    Args:
+        model: The model to be modified (in place). Ensure model is on the desired device for calibration
+        n_validation_examples: Number of examples used to validate scale options
+        validation_sequence_len: Number of tokens in each validation example
+        quant_dtype: The data type of the quantized weights. Currently only torch.uint4 is intended to be used but can be used with torch.uint1 -> torch.uint8
+        scale search space size: how many different scale options to try. Original AWQ implementation uses 20. A larger size can lead to better results but takes longer to calibrate
+        group_size: Quantization granularity. Use -1 for channel wise quantization
+    """
+    _is_linear = lambda m, fqn: isinstance(m, torch.nn.Linear)
+    assert quant_dtype in _DTYPE_TO_BIT_WIDTH or quant_dtype == torch.uint8, (
+        "Invalid quant_dtype. Please use torch.uint1 .. torch.uint8"
+    )
+    # AQT config
+    mapping_type = MappingType.ASYMMETRIC
+    quantization_granularity = PerGroup(group_size)
+    quant_min = 0
+    quant_max = (
+        255 if quant_dtype == torch.uint8 else 2 ** _DTYPE_TO_BIT_WIDTH[quant_dtype] - 1
+    )
+    eps = torch.finfo(torch.float32).eps
+    preserve_zero = True
+    zero_point_dtype = torch.int64
+    zero_point_domain = ZeroPointDomain.INT
+
+    def replace_with_observer(layer):
+        # creates observer and replaces linear layers with AWQObservedLinear layers
+        observer = AWQObserver(
+            layer.weight,
+            layer.bias,
+            quantization_granularity,
+            mapping_type,
+            quant_dtype,
+            n_validation_examples,
+            validation_sequence_len,
+            scale_search_space_size,
+            preserve_zero=preserve_zero,
+            zero_point_domain=zero_point_domain,
+            zero_point_dtype=zero_point_dtype,
+            quant_min=quant_min,
+            quant_max=quant_max,
+            eps=eps,
+        )
+        return AWQObservedLinear.from_float(layer, observer)
+
+    _replace_with_custom_fn_if_matches_filter(model, replace_with_observer, _is_linear)
+
+
+@dataclass
+class AWQUIntXConfig(AOBaseConfig):
+    """
+    Configuration for quantizing linear layers when passed into quantize_()
+
+    Args:
+        quant_dtype: The data type of the quantized weights. Currently only torch.uint4 is intended to be used but can be used with torch.uint1 -> torch.uint8
+        group_size: Quantization granularity. Use -1 for channel wise quantization
+        weight_quant_fn: The quantization function to be used, which takes in the weight and returns the quantized weight. If None, then affine uint4 quantization is used
+        set_inductor_config: if True, adjusts `torchinductor` settings to recommended values.
+    """
+
+    quant_dtype: torch.dtype = torch.uint4
+    group_size: int = 64
+    use_hqq: bool = False
+    set_inductor_config: bool = True
+
+
+# for bc
+awq_uintx = AWQUIntXConfig
+
+
+@register_quantize_module_handler(AWQUIntXConfig)
+def _awq_uintx_transform(
+    module: torch.nn.Module,
+    config: AWQUIntXConfig,
+) -> torch.nn.Module:
+    quant_dtype = config.quant_dtype
+    group_size = config.group_size
+    use_hqq = config.use_hqq
+    if config.set_inductor_config:
+        torchao.quantization.utils.recommended_inductor_config_setter()
+    observed_linear = module
+
+    assert quant_dtype in _DTYPE_TO_BIT_WIDTH or quant_dtype == torch.uint8, (
+        "Invalid quant_dtype. Please use torch.uint1 .. torch.uint8"
+    )
+
+    equalization_scale = observed_linear.act_obs.calculate_qparams()
+    # AQT config
+    if quant_dtype == torch.uint4:
+        target_dtype = torch.int32
+        eps = 1e-6
+        preserve_zero = False
+        zero_point_dtype = torch.bfloat16
+        zero_point_domain = ZeroPointDomain.FLOAT
+        _layout = TensorCoreTiledLayout(inner_k_tiles=8)
+    else:
+        target_dtype = torch.uint8
+        eps = torch.finfo(torch.float32).eps
+        preserve_zero = True
+        zero_point_dtype = torch.int64
+        zero_point_domain = ZeroPointDomain.INT
+        _layout = UintxLayout(quant_dtype)
+
+    mapping_type = MappingType.ASYMMETRIC
+    block_size = (1, group_size)
+    quant_min = _DTYPE_TO_QVALUE_BOUNDS[quant_dtype][0]
+    quant_max = _DTYPE_TO_QVALUE_BOUNDS[quant_dtype][1]
+    qw = to_affine_quantized_intx(
+        observed_linear.weight * equalization_scale,
+        mapping_type,
+        block_size,
+        target_dtype,
+        quant_min,
+        quant_max,
+        eps,
+        zero_point_dtype=zero_point_dtype,
+        preserve_zero=preserve_zero,
+        zero_point_domain=zero_point_domain,
+        _layout=_layout,
+        use_hqq=use_hqq,
+    )
+
+    qw = to_weight_tensor_with_linear_activation_scale_metadata(qw, equalization_scale)
+
+    linear = torch.nn.Linear(
+        observed_linear.in_features,
+        observed_linear.out_features,
+        observed_linear.bias != None,
+        device=observed_linear.weight.device,
+        dtype=observed_linear.weight.dtype,
+    )
+    linear.weight = torch.nn.Parameter(qw, requires_grad=False)
+    linear.extra_repr = types.MethodType(_linear_extra_repr, module)
+    linear.bias = observed_linear.bias
+    return linear
diff --git a/lib/python3.12/site-packages/torchao/prototype/awq/core.py b/lib/python3.12/site-packages/torchao/prototype/awq/core.py
new file mode 100644
index 0000000000000000000000000000000000000000..e5ee96fea2fbca68287bbf7a9b99cd6c0ea58835
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/awq/core.py
@@ -0,0 +1,178 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+from typing import Optional
+
+import torch
+import torch.nn.functional as F
+
+from torchao.dtypes import to_affine_quantized_intx
+from torchao.dtypes.uintx.uintx_layout import UintxLayout
+from torchao.quantization.granularity import Granularity
+from torchao.quantization.observer import (
+    AffineQuantizedObserverBase,
+)
+from torchao.quantization.quant_primitives import (
+    MappingType,
+    ZeroPointDomain,
+)
+
+
+class AWQObserver(AffineQuantizedObserverBase):
+    def __init__(
+        self,
+        weight: torch.Tensor,
+        bias: torch.Tensor,
+        quantization_granularity: Granularity,
+        mapping_type: MappingType,
+        target_dtype: torch.dtype,
+        n_validation_examples: int,
+        validation_sequence_len: int,
+        scale_search_space_size: int = 20,
+        quant_min: Optional[int] = None,
+        quant_max: Optional[int] = None,
+        eps: Optional[float] = None,
+        scale_dtype: Optional[torch.dtype] = None,
+        zero_point_dtype: Optional[torch.dtype] = None,
+        preserve_zero: Optional[bool] = True,
+        zero_point_domain=ZeroPointDomain.INT,
+    ):
+        """
+        A custom observer for Activation aware Weight Quantization (AWQ)
+
+        Args:
+            weight: The weight tensor to be observed.
+            bias: The bias tensor to be observed.
+            quantization_granularity: Granularity which specifies how many weights share the same scale/zero point
+            input_dtype: The data type of the input tensor.
+            mapping_type: Always set to asymmetric
+            target_dtype: The target data type of the quantized tensor
+            n_validation_examples: Number of examples used to calibrate observer
+            validation_sequence_len: Number of tokens in each example
+            scale_search_space_size: The number of scales to search for.
+            quant_min: The minimum quantized value
+            quant_max: The maximum quantized value
+            eps: The minimum scale.
+            scale_dtype: The data type of the scale tensor.
+            zero_point_dtype: The data type of the zero point tensor.
+            preserve_zero: A flag to indicate whether we need zero to be exactly
+                representable or not.
+            zero_point_domain: The domain of the zero point.
+        """
+        super().__init__(
+            mapping_type,
+            target_dtype,
+            quantization_granularity,
+            quant_min=quant_min,
+            quant_max=quant_max,
+            eps=eps,
+            scale_dtype=scale_dtype,
+            zero_point_dtype=zero_point_dtype,
+            preserve_zero=preserve_zero,
+            zero_point_domain=zero_point_domain,
+        )
+        self.quantization_granularity = quantization_granularity
+        self.weight = weight
+        self.bias = bias
+        self.n_validation_examples = n_validation_examples
+        self.validation_sequence_len = validation_sequence_len
+        self.calibration_token_count = 0
+        self.inputs = []
+        self.outputs = []
+        self.scale_options = scale_search_space_size
+        self.device = self.weight.device
+        self.average = torch.zeros((1, weight.shape[1]), device=self.device)
+        if self.bias is not None:
+            self.bias.to(self.device)
+
+    @torch.no_grad()
+    def forward(self, input: torch.Tensor, output: torch.Tensor):
+        # import pdb
+        # pdb.set_trace()
+        # print(input.shape, input.abs().sum(1).shape, self.average.shape)
+        if len(self.inputs) < self.n_validation_examples:
+            self.inputs.append(input.to("cpu"))
+            self.outputs.append(output.to("cpu"))
+        self.calibration_token_count += input.shape[-2]
+        self.average += input.abs().sum(-2)
+
+    def calculate_qparams(self):
+        # import pdb
+        # pdb.set_trace()
+        assert self.outputs != None, (
+            "calibrate observer first by running model on exemplar data"
+        )
+        self.average /= self.calibration_token_count
+        for i in range(self.n_validation_examples):
+            self.inputs[i] = self.inputs[i].to(self.device)
+            self.outputs[i] = self.outputs[i].to(self.device)
+
+        best_loss = float("inf")
+        best_scales = None
+        for i in range(self.scale_options):
+            ratio = i * 1 / self.scale_options
+            scales = self.average.pow(ratio).to(self.weight.dtype)
+            scales = scales / (scales.max() * scales.min()).sqrt()
+            layout = UintxLayout(self.target_dtype)
+            # regardless of weight dtype, we have to store as packed uint8 tensors
+            tensor_dtype = torch.uint8
+            w = to_affine_quantized_intx(
+                self.weight * scales,
+                self.mapping_type,
+                (1, self.quantization_granularity.group_size),
+                tensor_dtype,
+                quant_min=self.quant_min,
+                quant_max=self.quant_max,
+                eps=self.eps,
+                scale_dtype=self.scale_dtype,
+                zero_point_dtype=self.zero_point_dtype,
+                preserve_zero=self.preserve_zero,
+                zero_point_domain=self.zero_point_domain,
+                _layout=layout,
+            )
+            loss = 0
+            for i in range(self.n_validation_examples):
+                q_out = F.linear(self.inputs[i] / scales, w, self.bias)
+                loss += (self.outputs[i] - q_out).pow(2).mean().item()
+            if loss < best_loss:
+                best_scales = scales
+                best_loss = loss
+            for i in range(self.n_validation_examples):
+                self.inputs[i].to("cpu")
+                self.outputs[i].to("cpu")
+        return best_scales.detach()
+
+
+class AWQObservedLinear(torch.nn.Linear):
+    def __init__(
+        self,
+        in_features: int,
+        out_features: int,
+        act_obs: torch.nn.Module,
+        bias: bool = True,
+        device=None,
+        dtype=None,
+    ):
+        super().__init__(in_features, out_features, bias, device, dtype)
+        self.act_obs = act_obs
+
+    def forward(self, input: torch.Tensor):
+        output = F.linear(input, self.weight, self.bias)
+        self.act_obs(input, output)
+        return output
+
+    @classmethod
+    def from_float(cls, float_linear: torch.nn.Linear, act_obs: AWQObserver):
+        observed_linear = cls(
+            float_linear.in_features,
+            float_linear.out_features,
+            act_obs,
+            False,
+            device=float_linear.weight.device,
+            dtype=float_linear.weight.dtype,
+        )
+        observed_linear.weight = float_linear.weight
+        observed_linear.bias = float_linear.bias
+        return observed_linear
diff --git a/lib/python3.12/site-packages/torchao/prototype/awq/example.py b/lib/python3.12/site-packages/torchao/prototype/awq/example.py
new file mode 100644
index 0000000000000000000000000000000000000000..ba1ba6834c05485d3781de515e42f76e4b1cf0c0
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/awq/example.py
@@ -0,0 +1,326 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import argparse
+import time
+
+import torch
+from datasets import load_dataset
+from tqdm import tqdm
+from transformers import AutoModelForCausalLM, AutoTokenizer
+
+from torchao.prototype.awq import AWQObservedLinear, awq_uintx, insert_awq_observer_
+from torchao.quantization import int4_weight_only, quantize_
+
+
+# adapted from: https://github.com/mit-han-lab/llm-awq/blob/main/awq/entry.py#L255
+def get_calib_dataset(tokenizer=None, n_samples=100, block_size=512):
+    dataset = load_dataset("mit-han-lab/pile-val-backup", split="validation")
+    samples = []
+    n_tokens = n_samples * block_size
+    n_run = n_tokens
+    for data in dataset:
+        line = data["text"]
+        line = line.strip()
+        line_encoded = tokenizer.encode(line)
+        if len(line_encoded) > 512:
+            continue
+        sample = torch.tensor([line_encoded])
+        if sample.numel() == 0:
+            continue
+        samples.append(sample)
+        n_run -= len(line_encoded)
+        if n_run <= n_samples:
+            break
+
+    cat_samples = torch.cat(samples, dim=1)
+    return [
+        cat_samples[:, i * block_size : (i + 1) * block_size] for i in range(n_samples)
+    ]
+
+
+# from https://github.com/mobiusml/hqq/blob/master/examples/llama2_benchmark/eval_model.py
+def wiki2_eval(
+    model, tokenizer, sequence_length, stride=512, verbose=True, device="cuda"
+):
+    model.eval()
+    tokenizer.pad_token = tokenizer.eos_token
+    tokenizer.padding_side = "right"
+    tokenizer.add_eos_token = False
+
+    dataset = load_dataset("wikitext", "wikitext-2-raw-v1", split="test")
+    encodings = tokenizer("\n\n".join(dataset["text"]), return_tensors="pt")
+
+    encodings["input_ids"] = encodings["input_ids"].to(device)
+
+    lls, t = [], []
+    for i in tqdm(
+        range(0, encodings["input_ids"].size(1), stride), disable=not verbose
+    ):
+        begin_loc = max(i + stride - sequence_length, 0)
+        end_loc = min(i + stride, encodings["input_ids"].size(1))
+        trg_len = end_loc - i
+        input_ids = encodings["input_ids"][:, begin_loc:end_loc]
+        target_ids = input_ids.clone()
+        target_ids[:, :-trg_len] = -100  # ignore context
+
+        t1 = time.time()
+        with torch.no_grad():
+            log_likelihood = model(input_ids, labels=target_ids).loss * trg_len
+        if device.startswith("cuda"):
+            torch.cuda.synchronize()
+        t2 = time.time()
+        t.append((t2 - t1))
+        lls.append(log_likelihood)
+
+        del input_ids, target_ids
+
+    ppl = float(torch.exp(torch.stack(lls).sum() / end_loc))
+    pred_time = sum(t) / len(t)
+    if verbose:
+        print("perplexity", ppl)
+        print("time", str(pred_time) + "  sec")
+
+    return {"perplexity": ppl, "prediction_time": pred_time}
+
+
+# adapted from Hicham Badri (@mobicham)
+def benchmark(model, tokenizer, max_length, tasks=None, device="cuda"):
+    import lm_eval
+    import numpy as np
+
+    model.eval()
+    model.config.use_cache = False
+    try:
+        lm_eval.tasks.initialize_tasks()
+    except:
+        pass
+    model_eval = lm_eval.models.huggingface.HFLM(pretrained=model, tokenizer=tokenizer)
+    eval_batch_size = 1  # 8
+    if tasks is None:
+        tasks = [
+            "PPL",
+            "truthfulqa_mc2",
+            "winogrande",
+            "arc_challenge",
+            "hellaswag",
+            "gsm8k",
+            "mmlu",
+        ]
+    results = {}
+    if "PPL" in tasks:
+        results["perplexity"] = wiki2_eval(
+            model, tokenizer, 512, verbose=True, device=device
+        )
+    ############################################
+    if "truthfulqa_mc2" in tasks:
+        for task in [("truthfulqa_mc2", 0)]:
+            tag, fewshot = task
+            results[tag] = lm_eval.evaluator.simple_evaluate(
+                model_eval, tasks=[tag], num_fewshot=fewshot, batch_size=eval_batch_size
+            )["results"]
+            print(tag, results[tag])
+    if "winogrande" in tasks:
+        for task in [("winogrande", 5)]:
+            tag, fewshot = task
+            results[tag] = lm_eval.evaluator.simple_evaluate(
+                model_eval, tasks=[tag], num_fewshot=fewshot, batch_size=eval_batch_size
+            )["results"]
+            print(tag, results[tag])
+    if "arc_challenge" in tasks:
+        for task in [("arc_challenge", 25)]:
+            tag, fewshot = task
+            results[tag] = lm_eval.evaluator.simple_evaluate(
+                model_eval, tasks=[tag], num_fewshot=fewshot, batch_size=eval_batch_size
+            )["results"]
+            print(tag, results[tag])
+
+    # ############################################
+    if "hellaswag" in tasks:
+        for task in [("hellaswag", 10)]:
+            tag, fewshot = task
+            results[tag] = lm_eval.evaluator.simple_evaluate(
+                model_eval, tasks=[tag], num_fewshot=fewshot, batch_size=eval_batch_size
+            )["results"]
+            print(tag, results[tag])
+    if "gsm8k" in tasks:
+        for task in [("gsm8k", 5)]:
+            tag, fewshot = task
+            results[tag] = lm_eval.evaluator.simple_evaluate(
+                model_eval, tasks=[tag], num_fewshot=fewshot, batch_size=eval_batch_size
+            )["results"]
+            print(tag, results[tag])
+    # ############################################
+
+    if "mmlu" in tasks:
+        # MMLU
+        results_mmlu = {}
+        for task in [("mmlu", 5)]:
+            tag, fewshot = task
+            results_mmlu[tag] = lm_eval.evaluator.simple_evaluate(
+                model_eval, tasks=[tag], num_fewshot=fewshot, batch_size=eval_batch_size
+            )["results"]
+            print(tag, results_mmlu[tag])
+
+        mmlu_list = "hendrycksTest-abstract_algebra,hendrycksTest-anatomy,hendrycksTest-astronomy,hendrycksTest-business_ethics,hendrycksTest-clinical_knowledge,hendrycksTest-college_biology,hendrycksTest-college_chemistry,hendrycksTest-college_computer_science,hendrycksTest-college_mathematics,hendrycksTest-college_medicine,hendrycksTest-college_physics,hendrycksTest-computer_security,hendrycksTest-conceptual_physics,hendrycksTest-econometrics,hendrycksTest-electrical_engineering,hendrycksTest-elementary_mathematics,hendrycksTest-formal_logic,hendrycksTest-global_facts,hendrycksTest-high_school_biology,hendrycksTest-high_school_chemistry,hendrycksTest-high_school_computer_science,hendrycksTest-high_school_european_history,hendrycksTest-high_school_geography,hendrycksTest-high_school_government_and_politics,hendrycksTest-high_school_macroeconomics,hendrycksTest-high_school_mathematics,hendrycksTest-high_school_microeconomics,hendrycksTest-high_school_physics,hendrycksTest-high_school_psychology,hendrycksTest-high_school_statistics,hendrycksTest-high_school_us_history,hendrycksTest-high_school_world_history,hendrycksTest-human_aging,hendrycksTest-human_sexuality,hendrycksTest-international_law,hendrycksTest-jurisprudence,hendrycksTest-logical_fallacies,hendrycksTest-machine_learning,hendrycksTest-management,hendrycksTest-marketing,hendrycksTest-medical_genetics,hendrycksTest-miscellaneous,hendrycksTest-moral_disputes,hendrycksTest-moral_scenarios,hendrycksTest-nutrition,hendrycksTest-philosophy,hendrycksTest-prehistory,hendrycksTest-professional_accounting,hendrycksTest-professional_law,hendrycksTest-professional_medicine,hendrycksTest-professional_psychology,hendrycksTest-public_relations,hendrycksTest-security_studies,hendrycksTest-sociology,hendrycksTest-us_foreign_policy,hendrycksTest-virology,hendrycksTest-world_religions"
+        mmlu_list = [l.replace("hendrycksTest-", "") for l in mmlu_list.split(",")]
+        results_mmlu = results_mmlu["mmlu"]
+
+        k = []
+        for r in results_mmlu:
+            if np.any([(l in r) for l in mmlu_list]):
+                k.append(results_mmlu[r]["acc,none"])
+
+        assert len(k) == 57
+        print("MMLU avg acc", np.mean(k))
+
+        results["mmlu"] = np.mean(k)
+    return results
+
+
+def wikitext2_ppl(
+    repo_id: str,
+    quant: str,
+    tasks: list[str],
+    calibration_size: int,
+    validation_size: int,
+    device: str,
+    precision: torch.dtype,
+    sequence_length: int,
+    compile: bool,
+    model_save_path: str,
+):
+    print(f"Loading model on {device}...")
+    torch.manual_seed(34)
+    t0 = time.time()
+    # load any model with torch.nn.linear layers
+    tokenizer = AutoTokenizer.from_pretrained(repo_id)
+    model = (
+        AutoModelForCausalLM.from_pretrained(repo_id, torch_dtype=precision)
+        .eval()
+        .to(device)
+    )
+    print(f"Time to load model: {time.time() - t0:.02f} seconds")
+    if quant.startswith("awq"):
+        quant_dtype = quant.split("-")[1]
+        group_size = int(quant.split("-")[2])
+        quant_dtype = getattr(torch, quant_dtype, torch.bfloat16)
+        print(f"running {quant_dtype} calibration")
+        t0 = time.time()
+        # insert observers to find average magnitude and calculate scales
+        insert_awq_observer_(
+            model,
+            validation_size,
+            sequence_length,
+            quant_dtype=quant_dtype,
+            group_size=group_size,
+        )
+        calibration_data = get_calib_dataset(
+            tokenizer=tokenizer, n_samples=calibration_size, block_size=sequence_length
+        )
+        for batch in calibration_data:
+            model(batch.to(device))
+            batch.to("cpu")
+        print(f"time for calibration: {time.time() - t0:.02f} seconds")
+
+        is_observed_linear = lambda m, fqn: isinstance(m, AWQObservedLinear)
+        use_hqq = "hqq" in quant
+        print(f"running {quant_dtype} quantization")
+        t0 = time.time()
+        quantize_(
+            model,
+            awq_uintx(quant_dtype=quant_dtype, group_size=group_size, use_hqq=use_hqq),
+            is_observed_linear,
+        )
+        print(f"time for quantization: {time.time() - t0:.02f} seconds")
+        if model_save_path is not None:
+            print(f"Saving model to {model_save_path}")
+            torch.save(model, model_save_path)
+    elif quant.startswith("int4wo"):
+        group_size = int(quant.split("-")[1])
+        use_hqq = "hqq" in quant
+        print(f"running {quant} quantization with group size {group_size}")
+        quantize_(model, int4_weight_only(group_size=group_size, use_hqq=use_hqq))
+    if compile:
+        model = torch.compile(model)
+
+    return benchmark(model, tokenizer, sequence_length, tasks=tasks, device=device)
+
+
+if __name__ == "__main__":
+    parser = argparse.ArgumentParser(
+        description="Evaluate a model with the specified parameters."
+    )
+
+    # Optional arguments with default values
+    parser.add_argument("repo", type=str, help="Repository ID of the model.")
+    parser.add_argument(
+        "quant",
+        type=str,
+        help="Quantization method. Options are either awq-uint- for x =[1..8], int4wo-, or int4wo--hqq.",
+    )
+    parser.add_argument(
+        "--tasks",
+        type=list[str],
+        help="Task to benchmark model on. Either PPL or QA",
+        default=["PPL"],
+    )
+    parser.add_argument(
+        "--calibration_samples",
+        type=int,
+        default=10,
+        help="Number of samples to use for calibration. Default is 10.",
+    )
+    parser.add_argument(
+        "--validation_size", type=int, default=1, help="Validation size. Default is 1."
+    )
+    parser.add_argument(
+        "--device",
+        type=str,
+        default="cuda",
+        help="Device to run the evaluation on. Default is 'cuda'.",
+    )
+    parser.add_argument(
+        "--precision",
+        type=str,
+        default="bfloat16",
+        help="Precision type. Default is 'bfloat16'.",
+    )
+    parser.add_argument(
+        "--seq_len",
+        type=int,
+        default=512,
+        help="Length of examples to calibrate and evaluate model on. Default is 512",
+    )
+    parser.add_argument(
+        "--compile",
+        action="store_true",
+        help="Flag to indicate if compilation is required.",
+    )
+    parser.add_argument(
+        "--model_save_path",
+        type=str,
+        default=None,
+        help="Path to store the scale values.",
+    )
+
+    args = parser.parse_args()
+
+    # Convert precision argument to torch dtype
+    precision_dtype = getattr(torch, args.precision, torch.bfloat16)
+    ppl = wikitext2_ppl(
+        args.repo,
+        args.quant,
+        args.tasks,
+        args.calibration_samples,
+        args.validation_size,
+        args.device,
+        args.precision,
+        args.seq_len,
+        args.compile,
+        args.model_save_path,
+    )
+
+    print(f"{args.quant} Results: {ppl}")
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/__init__.py b/lib/python3.12/site-packages/torchao/prototype/common/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/common/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..568b603d730a8bcc21550f345c3f530335b6e8cc
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/common/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/__pycache__/profiling_tools.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/common/__pycache__/profiling_tools.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f465d0fcdbaff4ceb1d7366b55eae3f2d5b1fa7e
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/common/__pycache__/profiling_tools.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/profiling_tools.py b/lib/python3.12/site-packages/torchao/prototype/common/profiling_tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..d2650d3e6ce2d4fadf9acf69b54e0b6c0eba00f4
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/common/profiling_tools.py
@@ -0,0 +1,273 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import os
+import types
+from datetime import datetime
+from functools import partial
+
+import pandas as pd
+import torch
+import torch.autograd.profiler_util
+from tabulate import tabulate
+from torch.autograd.profiler import record_function
+from torch.cuda.nvtx import range as nvtx_range
+from triton.testing import do_bench
+
+# from torch.cuda.nvtx import range_pop, range_push
+
+TIME_FORMAT_STR: str = "%m_%d"
+PROFILE_DIR = "./profiles"
+
+
+def simple_bench(fn, *args, **kwargs):
+    t = do_bench(lambda: fn(*args, **kwargs))
+    return t
+
+
+def check(expected, actual, atol=1e-3):
+    diff = (expected - actual).abs().max()
+    print(f"diff: {diff}")
+    # assert diff < atol
+
+
+def benchmark_mm(
+    test_fn, xs, weight, ref_fn=torch.matmul, headers=["M", "K", "N", "test", "ref"]
+):
+    timings = []
+    for x in xs:
+        M, K = x.shape
+        _, N = weight.shape
+        assert x.shape[1] == weight.shape[0]
+        print(f"Benchmarking {(M, K, N)}")
+        test_times = do_bench(lambda: test_fn(x, weight))
+        ref_times = do_bench(lambda: ref_fn(x, weight))
+        timings.append([M, K, N, test_times, ref_times])
+    return pd.DataFrame(timings, columns=headers)
+
+
+def run_bench(xs, weight):
+    df = benchmark_mm(xs, weight)
+    print(tabulate(df, headers="keys", floatfmt=".4f"))
+    return df
+
+
+class CudaProfilerCtx:
+    def __enter__(self):
+        print("Starting cuda profiler")
+        torch.cuda.cudart().cudaProfilerStart()
+        return self
+
+    def __exit__(self, exc_type, exc_value, exc_traceback) -> None:
+        print("Stopping cuda profiler")
+        torch.cuda.cudart().cudaProfilerStop()
+        if exc_type is not None:
+            print(f"Exception occurred: {exc_type}, {exc_value}")
+        # Return True to suppress the exception
+        return True
+
+    def step(self):
+        pass
+
+
+def trace_handler(
+    prof: torch.profiler.profile,
+    group_by_stack: int = 5,
+    group_by_input_shapes: bool = False,
+    prefix="",
+    out_dir=None,
+    export_events=False,
+    export_trace=True,
+    export_memory_timeline=False,
+):
+    # Prefix for file names.
+    out_dir = out_dir or PROFILE_DIR
+    timestamp = datetime.now().strftime(TIME_FORMAT_STR)
+    file_prefix = os.path.join(out_dir, f"{prefix}-{timestamp}")
+
+    if export_events:
+        evt_list = prof.key_averages(
+            group_by_stack_n=group_by_stack, group_by_input_shape=group_by_input_shapes
+        )
+        torch.save(evt_list, f"{file_prefix}-key_averages.pt")
+
+    # Construct the trace file.
+    if export_trace:
+        prof.export_chrome_trace(f"{file_prefix}-chrome-trace.json")
+
+    # Construct the memory timeline file.
+    if export_memory_timeline:
+        prof.export_memory_timeline(
+            f"{file_prefix}-memory-timeline.html", device="cuda:0"
+        )
+        prof.export_memory_timeline(
+            f"{file_prefix}-memory-timeline.json", device="cuda:0"
+        )
+
+
+# print(prof.key_averages().table(sort_by="self_cuda_time_total", row_limit=10))
+
+
+def get_torch_profiler(
+    name,
+    with_stack=True,
+    with_flops=True,
+    with_modules=True,
+    record_shapes=False,
+    export_events=False,
+    export_trace=True,
+    export_memory_timeline=False,
+    out_dir=None,
+    warmup=1,
+    active=5,
+):
+    if not os.path.exists(out_dir):
+        os.makedirs(out_dir)
+    callback = partial(
+        trace_handler,
+        prefix=name,
+        out_dir=out_dir,
+        group_by_input_shapes=record_shapes,
+        group_by_stack=5 if export_events else None,
+        export_events=export_events,
+        export_trace=export_trace,
+        export_memory_timeline=export_memory_timeline,
+    )
+    return torch.profiler.profile(
+        activities=[
+            torch.profiler.ProfilerActivity.CPU,
+            torch.profiler.ProfilerActivity.CUDA,
+        ],
+        record_shapes=record_shapes,
+        with_stack=with_stack,
+        with_flops=with_flops,
+        with_modules=with_modules,
+        profile_memory=export_memory_timeline,
+        schedule=torch.profiler.schedule(wait=0, warmup=warmup, active=active),
+        on_trace_ready=callback,
+    )
+
+
+class TorchProfilerCtx:
+    @staticmethod
+    def profiler(
+        name,
+        out_dir,
+        warmup=1,
+        active=5,
+        record_shapes=False,
+        with_stack=True,
+        export_events=False,
+        export_trace=True,
+        export_memory_timeline=False,
+    ):
+        return get_torch_profiler(
+            name,
+            with_stack=with_stack,
+            record_shapes=export_memory_timeline or record_shapes,
+            export_events=export_events,
+            export_trace=export_trace,
+            export_memory_timeline=export_memory_timeline,
+            out_dir=out_dir,
+            warmup=warmup,
+            active=active,
+        )
+
+
+def get_annotation_ctx(profiler_type):
+    assert profiler_type in ["nsys", "torch"]
+    if profiler_type == "nsys":
+        return nvtx_range
+    else:
+        return record_function
+
+
+_PERF_COLUMNS = [
+    "key",
+    "count",
+    "cpu_children",
+    "cpu_parent",
+    "self_device_time_total",
+    "cuda_time",
+    "flops",
+    "self_cpu_time",
+    "self_cpu_time_total",
+    "cpu_time",
+    "cpu_time_totalself_device_memory_usage",
+    "device_memory_usage",
+    "self_cpu_memory_usage",
+    "cpu_memory_usage",
+]
+PERF_COLS_SELECT = [
+    "key",
+    "cpu_parent",
+    "cpu_children",
+    # "self_cpu_time",
+    # "self_cpu_time_total",
+    "cpu_time",
+    "cpu_time_total",
+    "cuda_time",
+    "self_device_time_total",
+]
+
+
+# cuda_time, cpu_time are avg times -- corresponds to CUDA time avg and CPU time avg in table() above
+# "self" times is not meaningful for annotated regions, since they only have child regions
+def is_function(obj):
+    return isinstance(obj, types.FunctionType)
+
+
+def is_method(obj):
+    return isinstance(obj, types.MethodType)
+
+
+def is_private(prop):
+    return prop.startswith("_")
+
+
+def should_exclude(obj, prop):
+    return (
+        is_function(getattr(obj, prop))
+        or is_method(getattr(obj, prop))
+        or is_private(prop)
+    )
+
+
+def _get_event_props(event: torch.autograd.profiler_util.FunctionEvent):
+    props = [p for p in dir(event) if not should_exclude(event, p)]
+    return props
+
+
+def get_events_df(events: torch.autograd.profiler_util.EventList):
+    event_props = _get_event_props(events[0])
+    data = [{p: getattr(e, p) for p in event_props} for e in events]
+    return pd.DataFrame(data)
+
+
+def get_perf_df(events: torch.autograd.profiler_util.EventList, sort=True):
+    df = get_events_df(events).filter(PERF_COLS_SELECT)
+    if sort:
+        df = df.sort_values(["cpu_time", "cuda_time"], ascending=False)
+    return df
+
+
+def pivot_df(
+    df,
+    id_cols: str | list[str],
+    columns: str | list[str],
+    values: str | list[str],
+    column_order: list[str] = None,
+    show: bool = True,
+):
+    df = df.pivot_table(
+        index=id_cols,
+        columns=columns,
+        values=values,
+    ).reset_index()
+    if column_order is not None:
+        df = df[column_order]
+    if show:
+        print(df.to_string(index=False))
+    return df
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/triton/__init__.py b/lib/python3.12/site-packages/torchao/prototype/common/triton/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/triton/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/common/triton/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cc7f01d8224481f5c08f92a88b482d73d305f041
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/common/triton/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/triton/__pycache__/matmul.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/common/triton/__pycache__/matmul.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..49431b202ab4492e62ac7c70367860e6a6d564ba
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/common/triton/__pycache__/matmul.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/triton/__pycache__/matmul_perf_model.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/common/triton/__pycache__/matmul_perf_model.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0b921b9edebe8f6298513be49fbaa60f8a46c0a7
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/common/triton/__pycache__/matmul_perf_model.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/triton/matmul.py b/lib/python3.12/site-packages/torchao/prototype/common/triton/matmul.py
new file mode 100644
index 0000000000000000000000000000000000000000..b88fb3e35de9a82f06146cdd3a57d712e0dd0d59
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/common/triton/matmul.py
@@ -0,0 +1,372 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import torch
+from triton import Config, autotune, cdiv, heuristics, jit
+from triton import language as tl
+
+from .matmul_perf_model import early_config_prune, estimate_matmul_time
+
+_ordered_datatypes = [torch.int8, torch.float16, torch.bfloat16, torch.float32]
+
+
+def upcast_if_fp8(a):
+    if "fp8" in str(a):
+        return torch.float16
+    return a
+
+
+def get_higher_dtype(a, b):
+    a = upcast_if_fp8(a)
+    b = upcast_if_fp8(b)
+    if a is b:
+        return a
+
+    assert a in _ordered_datatypes
+    assert b in _ordered_datatypes
+
+    for d in _ordered_datatypes:
+        if a is d:
+            return b
+        if b is d:
+            return a
+
+
+def init_to_zero(name):
+    return lambda nargs: nargs[name].zero_()
+
+
+def get_configs_io_bound():
+    configs = []
+    for num_stages in [2, 3, 4, 5, 6]:
+        for block_m in [16, 32]:
+            for block_k in [32, 64]:
+                for block_n in [32, 64, 128, 256]:
+                    num_warps = 2 if block_n <= 64 else 4
+                    configs.append(
+                        Config(
+                            {
+                                "BLOCK_M": block_m,
+                                "BLOCK_N": block_n,
+                                "BLOCK_K": block_k,
+                                "SPLIT_K": 1,
+                            },
+                            num_stages=num_stages,
+                            num_warps=num_warps,
+                        )
+                    )
+                    # split_k
+                    for split_k in [2, 4, 8, 16]:
+                        configs.append(
+                            Config(
+                                {
+                                    "BLOCK_M": block_m,
+                                    "BLOCK_N": block_n,
+                                    "BLOCK_K": block_k,
+                                    "SPLIT_K": split_k,
+                                },
+                                num_stages=num_stages,
+                                num_warps=num_warps,
+                                pre_hook=init_to_zero("C"),
+                            )
+                        )
+    return configs
+
+
+@autotune(
+    configs=[
+        # basic configs for compute-bound matmuls
+        Config(
+            {"BLOCK_M": 128, "BLOCK_N": 256, "BLOCK_K": 32, "SPLIT_K": 1},
+            num_stages=3,
+            num_warps=8,
+        ),
+        Config(
+            {"BLOCK_M": 256, "BLOCK_N": 128, "BLOCK_K": 32, "SPLIT_K": 1},
+            num_stages=3,
+            num_warps=8,
+        ),
+        Config(
+            {"BLOCK_M": 256, "BLOCK_N": 64, "BLOCK_K": 32, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 64, "BLOCK_N": 256, "BLOCK_K": 32, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 128, "BLOCK_N": 128, "BLOCK_K": 32, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 128, "BLOCK_N": 64, "BLOCK_K": 32, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 64, "BLOCK_N": 128, "BLOCK_K": 32, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 128, "BLOCK_N": 32, "BLOCK_K": 32, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 64, "BLOCK_N": 32, "BLOCK_K": 32, "SPLIT_K": 1},
+            num_stages=5,
+            num_warps=2,
+        ),
+        # good for int8
+        Config(
+            {"BLOCK_M": 128, "BLOCK_N": 256, "BLOCK_K": 128, "SPLIT_K": 1},
+            num_stages=3,
+            num_warps=8,
+        ),
+        Config(
+            {"BLOCK_M": 256, "BLOCK_N": 128, "BLOCK_K": 128, "SPLIT_K": 1},
+            num_stages=3,
+            num_warps=8,
+        ),
+        Config(
+            {"BLOCK_M": 256, "BLOCK_N": 64, "BLOCK_K": 128, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 64, "BLOCK_N": 256, "BLOCK_K": 128, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 128, "BLOCK_N": 128, "BLOCK_K": 128, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 128, "BLOCK_N": 64, "BLOCK_K": 64, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 64, "BLOCK_N": 128, "BLOCK_K": 64, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 128, "BLOCK_N": 32, "BLOCK_K": 64, "SPLIT_K": 1},
+            num_stages=4,
+            num_warps=4,
+        ),
+        Config(
+            {"BLOCK_M": 64, "BLOCK_N": 32, "BLOCK_K": 64, "SPLIT_K": 1},
+            num_stages=5,
+            num_warps=2,
+        ),
+    ]
+    + get_configs_io_bound(),
+    key=["M", "N", "K"],
+    prune_configs_by={
+        "early_config_prune": early_config_prune,
+        "perf_model": estimate_matmul_time,
+        "top_k": 10,
+    },
+)
+@heuristics(
+    {
+        "EVEN_K": lambda args: args["K"] % (args["BLOCK_K"] * args["SPLIT_K"]) == 0,
+    }
+)
+@jit
+def _kernel(
+    A,
+    B,
+    C,
+    M,
+    N,
+    K,  #
+    stride_am,
+    stride_ak,  #
+    stride_bk,
+    stride_bn,  #
+    stride_cm,
+    stride_cn,  #
+    acc_dtype: tl.constexpr,  #
+    input_precision: tl.constexpr,  #
+    fp8_fast_accum: tl.constexpr,  #
+    BLOCK_M: tl.constexpr,
+    BLOCK_N: tl.constexpr,
+    BLOCK_K: tl.constexpr,  #
+    GROUP_M: tl.constexpr,
+    SPLIT_K: tl.constexpr,
+    EVEN_K: tl.constexpr,
+    AB_DTYPE: tl.constexpr,  #
+):
+    # matrix multiplication
+    pid = tl.program_id(0)
+    pid_z = tl.program_id(1)
+    grid_m = tl.cdiv(M, BLOCK_M)
+    grid_n = tl.cdiv(N, BLOCK_N)
+    # re-order program ID for better L2 performance
+    width = GROUP_M * grid_n
+    group_id = pid // width
+    group_size = min(grid_m - group_id * GROUP_M, GROUP_M)
+    pid_m = group_id * GROUP_M + (pid % group_size)
+    pid_n = (pid % width) // (group_size)
+    # do matrix multiplication
+    rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
+    rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
+    ram = tl.max_contiguous(tl.multiple_of(rm % M, BLOCK_M), BLOCK_M)
+    rbn = tl.max_contiguous(tl.multiple_of(rn % N, BLOCK_N), BLOCK_N)
+    rk = pid_z * BLOCK_K + tl.arange(0, BLOCK_K)
+    # pointers
+    A = A + (ram[:, None] * stride_am + rk[None, :] * stride_ak)
+    B = B + (rk[:, None] * stride_bk + rbn[None, :] * stride_bn)
+    acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=acc_dtype)
+    for k in range(0, tl.cdiv(K, BLOCK_K * SPLIT_K)):
+        if EVEN_K:
+            a = tl.load(A)
+            b = tl.load(B)
+        else:
+            k_remaining = K - k * (BLOCK_K * SPLIT_K)
+            _0 = tl.zeros((1, 1), dtype=C.dtype.element_ty)
+            a = tl.load(A, mask=rk[None, :] < k_remaining, other=_0)
+            b = tl.load(B, mask=rk[:, None] < k_remaining, other=_0)
+        if AB_DTYPE is not None:
+            a = a.to(AB_DTYPE)
+            b = b.to(AB_DTYPE)
+        if fp8_fast_accum:
+            acc = tl.dot(
+                a, b, acc, out_dtype=acc_dtype, input_precision=input_precision
+            )
+        else:
+            acc += tl.dot(a, b, out_dtype=acc_dtype, input_precision=input_precision)
+        A += BLOCK_K * SPLIT_K * stride_ak
+        B += BLOCK_K * SPLIT_K * stride_bk
+    acc = acc.to(C.dtype.element_ty)
+    # rematerialize rm and rn to save registers
+    rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
+    rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
+    C = C + (rm[:, None] * stride_cm + rn[None, :] * stride_cn)
+    mask = (rm < M)[:, None] & (rn < N)[None, :]
+    # handles write-back with reduction-splitting
+    if SPLIT_K == 1:
+        tl.store(C, acc, mask=mask)
+    else:
+        tl.atomic_add(C, acc, mask=mask)
+
+
+class _matmul(torch.autograd.Function):
+    kernel = _kernel
+
+    _locks = {}
+
+    @staticmethod
+    def _call(a, b, acc_dtype, input_precision, fp8_fast_accum, output_dtype):
+        device = a.device
+        # handle non-contiguous inputs if necessary
+        if a.stride(0) > 1 and a.stride(1) > 1:
+            a = a.contiguous()
+        if b.stride(0) > 1 and b.stride(1) > 1:
+            b = b.contiguous()
+        # checks constraints
+        assert a.shape[1] == b.shape[0], (
+            f"incompatible dimensions {a.shape} and {b.shape}"
+        )
+        M, K = a.shape
+        _, N = b.shape
+
+        # common type between a and b
+        ab_dtype = get_higher_dtype(a.dtype, b.dtype)
+
+        # allocates output
+        if output_dtype is None:
+            output_dtype = ab_dtype
+
+        c = torch.empty((M, N), device=device, dtype=output_dtype)
+
+        # Allowed types for acc_type given the types of a and b.
+        supported_acc_dtypes = {
+            torch.float16: (torch.float32, torch.float16),
+            torch.bfloat16: (torch.float32, torch.bfloat16),
+            torch.float32: (torch.float32,),
+            torch.int8: (torch.int32,),
+        }
+
+        if acc_dtype is None:
+            acc_dtype = supported_acc_dtypes[ab_dtype][0]
+        else:
+            assert isinstance(acc_dtype, torch.dtype), "acc_dtype must be a torch.dtype"
+            assert acc_dtype in supported_acc_dtypes[a.dtype], (
+                "acc_dtype not compatible with the type of a"
+            )
+            assert acc_dtype in supported_acc_dtypes[b.dtype], (
+                "acc_dtype not compatible with the type of b"
+            )
+
+        def to_tl_type(ty):
+            return getattr(tl, str(ty).split(".")[-1])
+
+        acc_dtype = to_tl_type(acc_dtype)
+        ab_dtype = to_tl_type(ab_dtype)
+        output_dtype = to_tl_type(output_dtype)
+
+        # Tensor cores support input with mixed float8 types.
+        if a.dtype in [tl.float8e4nv, tl.float8e5] and b.dtype in [
+            tl.float8e4nv,
+            tl.float8e5,
+        ]:
+            ab_dtype = None
+        # launch kernel
+        grid = lambda META: (
+            cdiv(M, META["BLOCK_M"]) * cdiv(N, META["BLOCK_N"]),
+            META["SPLIT_K"],
+        )
+        _kernel[grid](
+            a,
+            b,
+            c,
+            M,
+            N,
+            K,  #
+            a.stride(0),
+            a.stride(1),  #
+            b.stride(0),
+            b.stride(1),  #
+            c.stride(0),
+            c.stride(1),  #
+            acc_dtype=acc_dtype,  #
+            input_precision=input_precision,  #
+            fp8_fast_accum=fp8_fast_accum,  #
+            GROUP_M=8,
+            AB_DTYPE=ab_dtype,
+        )
+        return c
+
+    @staticmethod
+    def forward(
+        ctx,
+        a,
+        b,
+        acc_dtype=None,
+        input_precision=None,
+        fp8_fast_accum=True,
+        output_dtype=None,
+    ):
+        return _matmul._call(
+            a,
+            b,
+            acc_dtype=acc_dtype,
+            input_precision=input_precision,
+            fp8_fast_accum=fp8_fast_accum,
+            output_dtype=output_dtype,
+        )
+
+
+matmul = _matmul.apply
diff --git a/lib/python3.12/site-packages/torchao/prototype/common/triton/matmul_perf_model.py b/lib/python3.12/site-packages/torchao/prototype/common/triton/matmul_perf_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..03dd631143b12ec458cafa34516d9780a0a5914f
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/common/triton/matmul_perf_model.py
@@ -0,0 +1,261 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+# Source: https://github.com/triton-lang/kernels/blob/main/kernels/matmul_perf_model.py
+
+# This file is taken from the upstream triton-lang/kernels repo.
+# Currently that repo does not have a license file, so disabling
+# the license lint for now:
+# @lint-ignore-every LICENSELINT
+
+# flake8: noqa
+# pyre-ignore-all-errors
+import functools
+import heapq
+
+import torch
+
+from triton import cdiv
+from triton.runtime import driver
+from triton.testing import (
+    get_dram_gbps,
+    get_max_simd_tflops,
+    get_max_tensorcore_tflops,
+    nvsmi,
+)
+
+
+@functools.lru_cache()
+def get_clock_rate_in_khz():
+    try:
+        return nvsmi(["clocks.max.sm"])[0] * 1e3
+    except FileNotFoundError:
+        import pynvml
+
+        pynvml.nvmlInit()
+        handle = pynvml.nvmlDeviceGetHandleByIndex(0)
+        return pynvml.nvmlDeviceGetMaxClockInfo(handle, pynvml.NVML_CLOCK_SM) * 1e3
+
+
+def get_tensorcore_tflops(device, num_ctas, num_warps, dtype):
+    """return compute throughput in TOPS"""
+    total_warps = num_ctas * min(num_warps, 4)
+    if hasattr(driver, "active"):
+        num_subcores = (
+            driver.active.utils.get_device_properties(device)["multiprocessor_count"]
+            * 4
+        )  # on recent GPUs
+    else:
+        num_subcores = (
+            driver.utils.get_device_properties(device)["multiprocessor_count"] * 4
+        )  # on recent GPUs
+
+    tflops = (
+        min(num_subcores, total_warps)
+        / num_subcores
+        * get_max_tensorcore_tflops(dtype, get_clock_rate_in_khz(), device)
+    )
+    return tflops
+
+
+def get_simd_tflops(device, num_ctas, num_warps, dtype):
+    """return compute throughput in TOPS"""
+    total_warps = num_ctas * min(num_warps, 4)
+    if hasattr(driver, "active"):
+        num_subcores = (
+            driver.active.utils.get_device_properties(device)["multiprocessor_count"]
+            * 4
+        )  # on recent GPUs
+    else:
+        num_subcores = (
+            driver.utils.get_device_properties(device)["multiprocessor_count"] * 4
+        )  # on recent GPUs
+
+    tflops = (
+        min(num_subcores, total_warps)
+        / num_subcores
+        * get_max_simd_tflops(dtype, get_clock_rate_in_khz(), device)
+    )
+    return tflops
+
+
+def get_tflops(device, num_ctas, num_warps, dtype):
+    capability = torch.cuda.get_device_capability(device)
+    if capability[0] < 8 and dtype == torch.float32:
+        return get_simd_tflops(device, num_ctas, num_warps, dtype)
+    return get_tensorcore_tflops(device, num_ctas, num_warps, dtype)
+
+
+def estimate_matmul_time(
+    # backend, device,
+    num_warps,
+    num_stages,  #
+    A,
+    B,
+    C,  #
+    M,
+    N,
+    K,  #
+    BLOCK_M,
+    BLOCK_N,
+    BLOCK_K,
+    SPLIT_K,  #
+    debug=False,
+    **kwargs,  #
+):
+    """return estimated running time in ms
+    = max(compute, loading) + store"""
+    device = torch.cuda.current_device()
+    dtype = A.dtype
+    dtsize = A.element_size()
+
+    num_cta_m = cdiv(M, BLOCK_M)
+    num_cta_n = cdiv(N, BLOCK_N)
+    num_cta_k = SPLIT_K
+    num_ctas = num_cta_m * num_cta_n * num_cta_k
+
+    # If the input is smaller than the block size
+    M, N = max(M, BLOCK_M), max(N, BLOCK_N)
+
+    # time to compute
+    total_ops = 2 * M * N * K / (1024 * 1024 * 1024)  # GOPS
+    tput = get_tflops(device, num_ctas, num_warps, dtype)
+    compute_ms = total_ops / tput
+
+    # time to load data
+    if hasattr(driver, "active"):
+        num_sm = driver.active.utils.get_device_properties(device)[
+            "multiprocessor_count"
+        ]
+    else:
+        num_sm = driver.utils.get_device_properties(device)["multiprocessor_count"]
+
+    active_cta_ratio = min(1, num_ctas / num_sm)
+    active_cta_ratio_bw1 = min(
+        1, num_ctas / 32
+    )  # 32 active ctas are enough to saturate
+    active_cta_ratio_bw2 = max(
+        min(1, (num_ctas - 32) / (108 - 32)), 0
+    )  # 32-108, remaining 5%
+    dram_bw = get_dram_gbps(device) * (
+        active_cta_ratio_bw1 * 0.95 + active_cta_ratio_bw2 * 0.05
+    )  # in GB/s
+    l2_bw = dram_bw * 4  # rough estimation (should be 4.7 for A100?)
+    # assume 80% of (following) loads are in L2 cache
+    load_a_dram = M * K * dtsize * (1 + 0.2 * (num_cta_n - 1))
+    load_a_l2 = M * K * dtsize * 0.8 * (num_cta_n - 1)
+    load_b_dram = N * K * dtsize * (1 + 0.2 * (num_cta_m - 1))
+    load_b_l2 = N * K * dtsize * 0.8 * (num_cta_m - 1)
+    # total
+    total_dram = (load_a_dram + load_b_dram) / (1024 * 1024)  # MB
+    total_l2 = (load_a_l2 + load_b_l2) / (1024 * 1024)
+    # loading time in ms
+    load_ms = total_dram / dram_bw + total_l2 / l2_bw
+
+    # estimate storing time
+    store_bw = dram_bw * 0.6  # :o
+    store_c_dram = M * N * dtsize * SPLIT_K / (1024 * 1024)  # MB
+    if SPLIT_K == 1:
+        store_ms = store_c_dram / store_bw
+    else:
+        reduce_bw = store_bw
+        store_ms = store_c_dram / reduce_bw
+        # c.zero_()
+        zero_ms = M * N * 2 / (1024 * 1024) / store_bw
+        store_ms += zero_ms
+
+    total_time_ms = max(compute_ms, load_ms) + store_ms
+    if debug:
+        print(
+            f"Total time: {total_time_ms}ms, compute time: {compute_ms}ms, "
+            f"loading time: {load_ms}ms, store time: {store_ms}ms, "
+            f"Activate CTAs: {active_cta_ratio * 100}%"
+        )
+    return total_time_ms
+
+
+def early_config_prune(configs, named_args, **kwargs):
+    device = torch.cuda.current_device()
+    capability = torch.cuda.get_device_capability()
+    # BLOCK_M, BLOCK_N, BLOCK_K, SPLIT_K, num_warps, num_stages
+    dtsize = named_args["A"].element_size()
+    dtype = named_args["A"].dtype
+
+    # 1. make sure we have enough smem
+    pruned_configs = []
+    for config in configs:
+        kw = config.kwargs
+        BLOCK_M, BLOCK_N, BLOCK_K, num_stages = (
+            kw["BLOCK_M"],
+            kw["BLOCK_N"],
+            kw["BLOCK_K"],
+            config.num_stages,
+        )
+        if hasattr(driver, "active"):
+            max_shared_memory = driver.active.utils.get_device_properties(device)[
+                "max_shared_mem"
+            ]
+        else:
+            max_shared_memory = driver.utils.get_device_properties(device)[
+                "max_shared_mem"
+            ]
+
+        required_shared_memory = (BLOCK_M + BLOCK_N) * BLOCK_K * num_stages * dtsize
+        if required_shared_memory <= max_shared_memory:
+            pruned_configs.append(config)
+    configs = pruned_configs
+
+    # Some dtypes do not allow atomic_add
+    if dtype not in [torch.float16, torch.float32]:
+        configs = [config for config in configs if config.kwargs["SPLIT_K"] == 1]
+
+    # group configs by (BLOCK_M,_N,_K, SPLIT_K, num_warps)
+    configs_map = {}
+    for config in configs:
+        kw = config.kwargs
+        BLOCK_M, BLOCK_N, BLOCK_K, SPLIT_K, num_warps, num_stages = (
+            kw["BLOCK_M"],
+            kw["BLOCK_N"],
+            kw["BLOCK_K"],
+            kw["SPLIT_K"],
+            config.num_warps,
+            config.num_stages,
+        )
+
+        key = (BLOCK_M, BLOCK_N, BLOCK_K, SPLIT_K, num_warps)
+        if key in configs_map:
+            configs_map[key].append((config, num_stages))
+        else:
+            configs_map[key] = [(config, num_stages)]
+
+    pruned_configs = []
+    for k, v in configs_map.items():
+        BLOCK_M, BLOCK_N, BLOCK_K, SPLIT_K, num_warps = k
+        if capability[0] >= 8:
+            # compute cycles (only works for ampere GPUs)
+            mmas = BLOCK_M * BLOCK_N * BLOCK_K / (16 * 8 * 16)
+            mma_cycles = mmas / min(4, num_warps) * 8
+
+            ldgsts_latency = 300  # Does this matter?
+            optimal_num_stages = ldgsts_latency / mma_cycles
+
+            # nearest stages, prefer large #stages
+            nearest = heapq.nsmallest(
+                2,
+                v,
+                key=lambda x: (
+                    10 + abs(x[1] - optimal_num_stages)
+                    if (x[1] - optimal_num_stages) < 0
+                    else x[1] - optimal_num_stages
+                ),
+            )
+
+            for n in nearest:
+                pruned_configs.append(n[0])
+        else:  # Volta & Turing only supports num_stages <= 2
+            random_config = v[0][0]
+            random_config.num_stages = 2
+            pruned_configs.append(random_config)
+    return pruned_configs
diff --git a/lib/python3.12/site-packages/torchao/prototype/galore/kernels/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/galore/kernels/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b91158ae043f4141176e1909c8275ae98c3e5744
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/galore/kernels/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/galore/kernels/__pycache__/quant.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/galore/kernels/__pycache__/quant.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f1c0bc78496c507ad83e534a6eb766c0cd56a2aa
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/galore/kernels/__pycache__/quant.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/moe_quant/__init__.py b/lib/python3.12/site-packages/torchao/prototype/moe_quant/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f45569b13848ccf660bcc1a9ef093af45cf6b6d2
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/llama4_quant.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/llama4_quant.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..94dd2e6b011492c68fbfa6d3306a3417c89f02a1
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/llama4_quant.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/quantizable_moe_modules.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/quantizable_moe_modules.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1bb515462ec27460b909e04e47f2e545f16cf14f
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/quantizable_moe_modules.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..53b1a2221780b4771e11ec0fe4a4a9fc33a92f59
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/moe_quant/__pycache__/utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/moe_quant/llama4_quant.py b/lib/python3.12/site-packages/torchao/prototype/moe_quant/llama4_quant.py
new file mode 100644
index 0000000000000000000000000000000000000000..36e684d47dd2ac8010d5799caac77702fadf446e
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/moe_quant/llama4_quant.py
@@ -0,0 +1,92 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+
+# T tokens
+# E experts
+# D dim
+# I intermediate dim
+# A activated experts
+# T'(e) tokens for expert e
+
+import torch
+import torch.nn as nn
+from transformers import AutoTokenizer, Llama4ForCausalLM
+from transformers.models.llama4.modeling_llama4 import Llama4TextMoe
+
+from torchao.prototype.moe_quant.quantizable_moe_modules import (
+    MOEFeedForwardAOQuantizable,
+)
+from torchao.quantization.quant_api import _replace_with_custom_fn_if_matches_filter
+
+
+def llama4_moe_filter_fn(module, fqn):
+    return isinstance(module, Llama4TextMoe)
+
+
+def convert_fn(module):
+    # get data
+    hidden_dim = module.hidden_dim
+    expert_dim = module.experts.expert_dim
+    num_experts = module.num_experts
+    top_k = module.top_k
+    act_fn = module.experts.act_fn
+    shared_expert = module.shared_expert
+    return_scores = True
+    new_mod = MOEFeedForwardAOQuantizable(
+        hidden_dim,
+        expert_dim,
+        num_experts,
+        top_k,
+        act_fn,
+        shared_expert,
+        return_scores,
+    )
+
+    router = module.router
+    up_proj = module.experts.gate_up_proj
+    w1, w3 = up_proj.permute(0, 2, 1).chunk(2, dim=1)
+    w2 = module.experts.down_proj.permute(0, 2, 1)
+
+    new_mod.router = router
+    new_mod.experts.w1 = nn.Parameter(w1, requires_grad=False)
+    new_mod.experts.w2 = nn.Parameter(w2, requires_grad=False)
+    new_mod.experts.w3 = nn.Parameter(w3, requires_grad=False)
+    return new_mod
+
+
+model_id = "meta-llama/Llama-4-Scout-17B-16E-Instruct"
+model = Llama4ForCausalLM.from_pretrained(model_id, torch_dtype=torch.bfloat16)
+tokenizer = AutoTokenizer.from_pretrained(model_id)
+
+_replace_with_custom_fn_if_matches_filter(
+    model,
+    convert_fn,
+    llama4_moe_filter_fn,
+)
+
+model = model
+
+from torchao.prototype.moe_quant.utils import (
+    MoEQuantConfig,
+    cond_ffn_filter,
+)
+from torchao.quantization import Int4WeightOnlyConfig, quantize_
+
+quantize_(model, MoEQuantConfig(Int4WeightOnlyConfig()), cond_ffn_filter, device="cuda")
+
+model.cuda()
+
+model = torch.compile(model, mode="reduce-overhead")
+
+prompt = "He is here, the one who will tear apart the very stars"
+inputs = tokenizer(prompt, return_tensors="pt")
+model.generate(inputs.input_ids.cuda(), max_length=30)
+model.generate(inputs.input_ids.cuda(), max_length=30)
+generate_ids = model.generate(inputs.input_ids.cuda(), max_length=50)
+out = tokenizer.batch_decode(
+    generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False
+)[0]
+print(out)
diff --git a/lib/python3.12/site-packages/torchao/prototype/moe_quant/quantizable_moe_modules.py b/lib/python3.12/site-packages/torchao/prototype/moe_quant/quantizable_moe_modules.py
new file mode 100644
index 0000000000000000000000000000000000000000..d806f50b4fb8d8cca1d14d943c3798e4b43962ba
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/moe_quant/quantizable_moe_modules.py
@@ -0,0 +1,191 @@
+import torch
+import torch.nn.functional as F
+from torch import Tensor, nn
+
+from torchao.prototype.moe_quant.utils import FakeExtraDimTensor
+
+
+class MOEFeedForwardAOQuantizable(nn.Module):
+    def __init__(
+        self,
+        hidden_dim,
+        expert_dim,
+        num_experts,
+        top_k,
+        act_fn=F.silu,
+        shared_expert=None,
+        return_scores=False,
+        empty_init=True,
+    ) -> None:
+        super().__init__()
+        self.router = nn.Linear(hidden_dim, num_experts, bias=False)
+        self.experts = ConditionalFeedForwardAOQuantizable(
+            num_experts, hidden_dim, expert_dim, act_fn, empty_init
+        )
+        self.hidden_dim = hidden_dim
+        self.top_k = top_k
+        self.shared_expert = shared_expert
+        self.return_scores = return_scores
+
+    def forward(self, x: Tensor) -> Tensor:
+        batch_size = x.shape[0]
+        x = x.view(-1, self.hidden_dim)  # x: [T, D]
+        scores = self.router(x)  # [T, E]
+        scores = F.softmax(scores, dim=-1)
+        scores, expert_indices = torch.topk(
+            scores, self.top_k, dim=-1
+        )  # [T, A], [T, A]
+        scores /= scores.sum(dim=-1, keepdim=True).to(x.dtype)  # [T, A]
+
+        out = self.experts(x, expert_indices, scores, self.top_k)
+        if self.shared_expert:
+            out += self.shared_expert(x)
+
+        if self.return_scores:
+            return out.reshape(batch_size, -1, self.hidden_dim), scores
+        else:
+            return out.reshape(batch_size, -1, self.hidden_dim)
+
+
+class ConditionalFeedForwardAOQuantizable(nn.Module):
+    def __init__(self, num_experts, hidden_dim, expert_dim, act_fn, empty_init=True):
+        super().__init__()
+        if empty_init:
+            self.w1 = nn.Parameter(
+                torch.empty(num_experts, expert_dim, hidden_dim)
+            )  # E, I, D
+            self.w2 = nn.Parameter(
+                torch.empty(num_experts, hidden_dim, expert_dim)
+            )  # E, D, I
+            self.w3 = nn.Parameter(
+                torch.empty(num_experts, expert_dim, hidden_dim)
+            )  # E, I, D
+        else:
+            self.w1 = nn.Parameter(
+                torch.randn(num_experts, expert_dim, hidden_dim)
+            )  # E, I, D
+            self.w2 = nn.Parameter(
+                torch.randn(num_experts, hidden_dim, expert_dim)
+            )  # E, D, I
+            self.w3 = nn.Parameter(
+                torch.randn(num_experts, expert_dim, hidden_dim)
+            )  # E, I, D
+        self.num_experts = num_experts
+        self.act_fn = act_fn
+        self.hidden_dim = hidden_dim
+        self.expert_dim = expert_dim
+
+    def forward(
+        self,
+        x: Tensor,  # T, D
+        expert_indices: Tensor,  # T, A
+        expert_weights: Tensor,  # T, A
+        top_k: int,
+    ) -> Tensor:
+        num_tokens, _hidden_dim = x.shape
+        num_token_activations = num_tokens * top_k
+
+        if x.shape[0] == 1 and not isinstance(
+            self.w1, FakeExtraDimTensor
+        ):  # only 1 token (can be done without graph breaks when compiled)
+            outs = []
+            expert_indices = expert_indices.view(top_k)
+            # collect used experts
+            w1 = self.w1[expert_indices]
+            w2 = self.w2[expert_indices]
+            w3 = self.w3[expert_indices]
+            # run token through each expert
+            for index in range(top_k):
+                y1 = F.silu(F.linear(x, w1[index]))
+                y3 = F.linear(x, w3[index])
+                y2 = w2[index]
+
+                cur_out = F.linear(y1 * y3, y2)
+                outs.append(cur_out)
+
+            # combine outputs
+            final_out = (
+                (torch.cat(outs, dim=0) * expert_weights.view(-1, 1))
+                .sum(dim=0)
+                .reshape(x.shape)
+            )
+            return final_out
+        else:
+            expert_list = [x for x in range(self.num_experts)]
+
+            # shuffle tokens into groups for each expert
+            ordered_token_activations = expert_indices.view(-1).argsort(
+                stable=True
+            )  # [A]
+            ordered_token_indices = (
+                ordered_token_activations.div(top_k).floor().to(torch.int64)
+            )  #  [T]
+            if not expert_indices.is_cuda:  # histc doesn't work on cpu for integers
+                num_tokens_per_expert = torch.bincount(
+                    expert_indices.view(-1) + 1, minlength=self.num_experts + 1
+                )
+            else:
+                num_tokens_per_expert = torch.histc(
+                    expert_indices,
+                    bins=self.num_experts + 1,
+                    min=-1,
+                    max=self.num_experts,
+                )  #  [E+1] (added leading 0 so can be used for indexing)
+            cum_tokens_per_expert = num_tokens_per_expert.cumsum(0).to(
+                torch.int64
+            )  #  [E+1]
+
+            @torch._dynamo.disable()
+            def group_tokens_by_expert(
+                ordered_token_indices, cum_tokens_per_expert, expert_list
+            ):
+                token_indices_per_expert = [
+                    ordered_token_indices[
+                        cum_tokens_per_expert[expert] : cum_tokens_per_expert[
+                            expert + 1
+                        ]
+                    ].to(torch.int64)
+                    for expert in expert_list
+                ]  # [T'(e1)], [T'(e2)] ...
+                return token_indices_per_expert
+
+            token_indices_per_expert = group_tokens_by_expert(
+                ordered_token_indices, cum_tokens_per_expert, expert_list
+            )
+            tokens_grouped_by_expert = [
+                x[indices] for indices in token_indices_per_expert
+            ]
+
+            # calculate outputs for each expert
+            outs = []
+            for cur_x, expert in zip(tokens_grouped_by_expert, expert_list):
+                w1 = self.w1[expert]  # I, D
+                w2 = self.w2[expert]  # D, I
+                w3 = self.w3[expert]  # I, D
+
+                y1 = F.silu(F.linear(cur_x, w1))
+                y3 = F.linear(cur_x, w3)
+                y2 = w2
+
+                cur_out = F.linear(y1 * y3, y2)  # [T'(e), D]
+                outs.append(cur_out)
+
+            # weigh outputs
+            ordered_outs = torch.cat(outs, dim=0)  # [T*A, D]
+            ordered_token_activation_weights = expert_weights.view(-1, 1)[
+                ordered_token_activations
+            ].view(-1, 1)  # [T*A, 1]
+            weighted_ordered_outs = (
+                ordered_outs * ordered_token_activation_weights
+            )  # [T*A, D]
+
+            # sum weighted token-activation outputs together for each token
+            final_out = torch.zeros_like(x)  #  [T, D]
+            final_out = final_out.scatter_add(
+                dim=0,
+                index=ordered_token_indices.unsqueeze(-1)
+                .expand(num_token_activations, self.hidden_dim)
+                .to(torch.int64),
+                src=weighted_ordered_outs,
+            )
+        return final_out
diff --git a/lib/python3.12/site-packages/torchao/prototype/moe_quant/utils.py b/lib/python3.12/site-packages/torchao/prototype/moe_quant/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..16fa8c8d3321610cfff80d2357d5dce4a6926478
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/moe_quant/utils.py
@@ -0,0 +1,308 @@
+import torch
+from torch.utils._python_dispatch import (
+    return_and_correct_aliasing,
+)
+
+aten = torch.ops.aten
+
+from enum import Enum, auto
+from typing import List, Optional, Tuple, Union
+
+from torchao.quantization.quant_api import (
+    _QUANTIZE_CONFIG_HANDLER,
+    AOBaseConfig,
+    dataclass,
+    register_quantize_module_handler,
+)
+from torchao.utils import fill_defaults
+
+
+class DummyModule(torch.nn.Module):
+    """This is used because the TorchAO quantization functions tend to operate on modules so to apply the transform to a tensor, we can load a
+    DummyModule with the target tensor and then apply the transformation to the module and then extract the transformed tensor.
+    """
+
+    def __init__(self, weight: torch.Tensor, bias: Optional[torch.Tensor] = None):
+        super().__init__()
+        self.weight = weight
+        self.bias = bias
+
+
+class FakeExtraDimTensor(torch.Tensor):
+    """This is a subclass of torch.Tensor that simulates a tensor of n+1 dimensions, akin to concatenating several tensors along the 0th dimension.
+    It takes a list of tensors with the same dtype, device and shape and creates a representation of shape (num_tensors, orig_shape). It can handle a
+    variety of ops like detach and clone but most importantly, supports any slicing and indexing along the extra dimension.
+    This is most useful when you have another tensor subclass that you'd like to concatenate together but don't want to support all the necessary
+    pieces of 3D scaffolding required to make it work.
+
+    The structure of this tensor subclass is a linked_list of tensors with each instance of FakeExtraDimTensor containing a head tensor and a tail consisting of
+    either another intance of FakeExtraDimTensor or None if we've reached the end of the linked list. This implementation structure is necessary to
+    support compilation of this tensor subclass since compile requires each tensor component of the tensor subclass to have its own attribute.
+    """
+
+    def __new__(
+        cls,
+        tensors: Union[Tuple[torch.Tensor], List[torch.Tensor]],
+        tensor_tail: Optional["FakeExtraDimTensor"] = None,
+    ):
+        assert len(tensors) > 0 or tensor_tail is not None
+        num_tensors = len(tensors)
+        if tensor_tail is not None:
+            num_tensors += tensor_tail.num_tensors
+            test_tensor = tensor_tail.head_tensor
+        else:
+            test_tensor = tensors[0]
+
+        dtype = test_tensor.dtype
+        shape = test_tensor.shape
+        device = test_tensor.device
+        layout = test_tensor.layout
+        for tensor in tensors:
+            assert tensor.dtype == dtype, (
+                f"all tensors in FakeExtraDimTensor must have same dtype but got {tensor.dtype} and {dtype}"
+            )
+            assert tensor.shape == shape, (
+                f"all tensors in FakeExtraDimTensor must have same shape but got {tensor.shape} and {shape}"
+            )
+            assert tensor.device == device, (
+                f"all tensors in FakeExtraDimTensor must have same device but got {tensor.device} and {device}"
+            )
+            assert tensor.layout == layout, (
+                f"all tensors in FakeExtraDimTensor must have same layout but got {tensor.layout} and {layout}"
+            )
+        kwargs = {}
+        kwargs["dtype"] = dtype
+        kwargs["layout"] = layout
+        kwargs["device"] = device
+        kwargs["requires_grad"] = False
+        new_shape = (num_tensors, *shape)
+        return torch.Tensor._make_wrapper_subclass(cls, new_shape, **kwargs)
+
+    def __repr__(
+        self,
+    ):
+        return f"{self.__class__.__name__}(shape={self.shape}, containing {self.num_tensors}: {self.head_tensor})"
+
+    def __init__(
+        self,
+        tensors: Union[Tuple[torch.Tensor], List[torch.Tensor]],
+        tensor_tail: Optional["FakeExtraDimTensor"] = None,
+    ):
+        tensors = list(tensors)
+        assert len(tensors) > 0 or tensor_tail is not None
+
+        # count num_tensors and make tensor_list
+        self.num_tensors = len(tensors)
+        if tensor_tail is not None:
+            self.num_tensors += tensor_tail.num_tensors
+            tail_list = tensor_tail.tensor_list
+        else:
+            tail_list = []
+        self.tensor_list = tensors + tail_list
+
+        # 3 cases
+        # 0) tensors has 0 elements -> take element from tail then do case 1 instead
+        # 1) tensors has 1 element,  -> pop element and tail is None
+        # 2) tensors has >1 elements, -> pop element and recurse
+
+        # convert case 0 to case 1 by taking 1 element from tail
+        if len(tensors) == 0 and tensor_tail is not None:
+            tensors = [
+                tensor_tail.head_tensor,
+            ]
+            tensor_tail = tensor_tail.tensor_tail
+
+        if len(tensors) > 1:
+            # case (1): remove first element from tensors, then recurse
+            self.head_tensor = tensors[0]  # remove one
+            self.tensor_tail = self.__class__(tensors[1:], tensor_tail)  # recurse
+        elif len(tensors) == 1:
+            # case (2) take final element from tensors, attach tensor_tail then stop recursion
+            self.head_tensor = tensors[0]
+            self.tensor_tail = tensor_tail
+
+    def _apply_fn_to_data(self, fn):
+        self.head_tensor = fn(self.head_tensor)
+        if self.tensor_tail is not None:
+            self.tensor_tail = self.tensor_tail._apply_fn_to_data(fn)
+        return self.__class__([self.head_tensor], self.tensor_tail)
+
+    def __tensor_flatten__(self):
+        if self.tensor_tail is None:
+            return [
+                "head_tensor",
+            ], [self.num_tensors]
+        else:
+            return [
+                "head_tensor",
+                "tensor_tail",
+            ], [self.num_tensors]
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls,
+        tensor_data_dict,
+        tensor_attributes,
+        outer_size,
+        outer_stride,
+    ):
+        head_tensor = tensor_data_dict["head_tensor"]
+        tensor_tail = tensor_data_dict.get("tensor_tail", None)
+        return cls([head_tensor], tensor_tail)
+
+    @classmethod
+    def __torch_function__(cls, func, types, args, kwargs=None):
+        kwargs = {} if kwargs is None else kwargs
+        if func is torch.nn.functional.linear:
+            x, w, bias = (
+                args[0],
+                args[1],
+                args[2] if len(args) > 2 else None,
+            )
+            assert w.num_tensors == 1, (
+                "FakeExtraDimTensor used in a linear op when it had multiple tensors"
+            )
+            return func(x, w.head_tensor, bias)
+        try:
+            with torch._C.DisableTorchFunctionSubclass():
+                return func(*args, **kwargs)
+        except Exception as e:
+            print(f"ERR: subclass {cls} doesn't implement {func}, got error: {e}")
+
+    @classmethod
+    def __torch_dispatch__(cls, func, types, args, kwargs):
+        kwargs = {} if kwargs is None else kwargs
+
+        if func == aten.slice.Tensor:
+            self, dim, start, end, step = fill_defaults(args, 5, [0, None, None, 1])
+            if dim == 0:
+                return return_and_correct_aliasing(
+                    func, args, kwargs, cls(self.tensor_list[start:end:step])
+                )
+
+        elif func == aten.select.int:
+            self, dim, index = fill_defaults(args, 3, [0, 0])
+            if dim == 0:
+                return return_and_correct_aliasing(
+                    func, args, kwargs, cls([self.tensor_list[index]])
+                )
+        elif func == aten.index.Tensor:
+            self, indices, dim = fill_defaults(args, 3, [0])
+            if dim == 0:
+                # this handles a weird bug where indices gets turned into a list
+                # between the function dispatch and torch dispatch but just for this function
+                if isinstance(indices, list) and len(indices) == 1:
+                    indices = indices[0]
+                return return_and_correct_aliasing(
+                    func,
+                    args,
+                    kwargs,
+                    cls([self.tensor_list[index] for index in indices]),
+                )
+        try:
+            return return_and_correct_aliasing(
+                func,
+                args,
+                kwargs,
+                args[0]._apply_fn_to_data(lambda x: func(x, *args[1:], **kwargs)),
+            )
+        except Exception as e:
+            print(
+                f"function {func} failed for FakeExtraDimTensor, following error occured when trying to"
+                "run function on its elements: "
+            )
+            raise e
+
+
+class UseFakeExtraDimTensor(Enum):
+    """Enum that indicate whether to use FakeExtraDimTensor"""
+
+    TRUE = auto()
+    FALSE = auto()
+    AS_FALLBACK = auto()
+
+
+@dataclass
+class MoEQuantConfig(AOBaseConfig):
+    """Configuration for applying quantization to MoE
+    Args:
+        `base_config`: normal AO Config
+    """
+
+    base_config: AOBaseConfig
+    use_fake_extra_dim_tensor: UseFakeExtraDimTensor = UseFakeExtraDimTensor.AS_FALLBACK
+    set_inductor_config: bool = True
+
+
+# Module-level flag to track if we've already printed the error
+_moe_quant_tensor_has_printed_error = False
+
+
+def _moe_quant_tensor(weight, config):
+    def _moe_quant_tensor_base(weight, config):
+        base_config_handler = _QUANTIZE_CONFIG_HANDLER[type(config.base_config)]
+        dummy_mod = DummyModule(weight)
+        quant_mod = base_config_handler(dummy_mod, config.base_config)
+        return quant_mod.weight
+
+    def _moe_quant_tensor_fake_extra_dim_tensor(weight, config):
+        base_config_handler = _QUANTIZE_CONFIG_HANDLER[type(config.base_config)]
+        # break 3D tensor
+        tensors = [weight[i] for i in range(weight.shape[0])]
+        # put tensors into modules since the handlers target modules not tensors
+        dummy_modules = [DummyModule(tensor) for tensor in tensors]
+        # apply handler to each module
+        quant_mods = list(
+            map(lambda x: base_config_handler(x, config.base_config), dummy_modules)
+        )
+        # pack quantized subclasses into FakeExtraDimTensor
+        quant_weight = FakeExtraDimTensor([mod.weight for mod in quant_mods])
+        return quant_weight
+
+    global _moe_quant_tensor_has_printed_error
+
+    use_fake = config.use_fake_extra_dim_tensor
+    if use_fake == UseFakeExtraDimTensor.FALSE:
+        return _moe_quant_tensor_base(weight, config)
+    elif use_fake == UseFakeExtraDimTensor.AS_FALLBACK:
+        try:
+            return _moe_quant_tensor_base(weight, config)
+        except Exception as e:
+            if not _moe_quant_tensor_has_printed_error:
+                print(f"tried to do moe_quant but got error: {e}")
+                _moe_quant_tensor_has_printed_error = True
+            return _moe_quant_tensor_fake_extra_dim_tensor(weight, config)
+    else:  # This handles UseFakeExtraDimTensor.TRUE
+        return _moe_quant_tensor_fake_extra_dim_tensor(weight, config)
+
+
+@register_quantize_module_handler(MoEQuantConfig)
+def moe_quant_fn(module, config: MoEQuantConfig):
+    import warnings
+
+    warnings.simplefilter("ignore", lineno=84)
+    warnings.simplefilter("ignore", lineno=105)
+    assert "ConditionalFeedForwardAOQuantizable" in str(type(module))
+
+    for weight_attr in ["w1", "w2", "w3"]:
+        param = getattr(module, weight_attr)
+        assert param.dim() == 3, (
+            f"when applying moe_quant to {module} expected 3D tensor for {weight_attr} but got {param.dim()}"
+        )
+        assert isinstance(config.base_config, AOBaseConfig), (
+            f"MoEQuantConfig expected to be initialized with an AOBaseConfig but got {type(config.base_config)}"
+            + "this can happen if you initiaze with MoEQuantConfig(AOConfig) rather than MoEQuantConfig(AOConfig())"
+        )
+        new_param = _moe_quant_tensor(param, config)
+        new_param = torch.nn.Parameter(new_param, requires_grad=False)
+        setattr(module, weight_attr, new_param)
+        del param
+    return module
+
+
+def moe_filter(module, fqn):
+    return "MOEFeedForwardAOQuantizable" in str(type(module))
+
+
+def cond_ffn_filter(module, fqn):
+    return "ConditionalFeedForwardAOQuantizable" in str(type(module))
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__init__.py b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7252c33dc9d1fa30b409af4345e24905dfb572d2
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__init__.py
@@ -0,0 +1,17 @@
+from torchao.prototype.mx_formats.config import (
+    MXGemmKernelChoice,
+    MXInferenceLinearConfig,
+    MXLinearConfig,
+    MXLinearRecipeName,
+)
+
+# import mx_linear here to register the quantize_ transform logic
+# ruff: noqa: I001
+import torchao.prototype.mx_formats.mx_linear  # noqa: F401
+
+__all__ = [
+    "MXGemmKernelChoice",
+    "MXInferenceLinearConfig",
+    "MXLinearConfig",
+    "MXLinearRecipeName",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e61c1d1d162abe6207af727fdfae74682a7dd450
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/config.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/config.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..8b73c1d77ec3cf92bef353f3cc3b1f6ae7886f1a
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/config.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/constants.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/constants.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b24046423542e42db73ba10e6f3d43c5456c8967
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/constants.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/custom_cast.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/custom_cast.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7e57d767eddf2a82f7ae509c9ab99f07d28acf81
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/custom_cast.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/fp_format_spec.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/fp_format_spec.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..296048dbe6e457d1a865ebcc544d35878fdb83dd
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/fp_format_spec.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/mx_linear.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/mx_linear.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bff929ed54499a6fb1afd606fa08b104efaa19f1
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/mx_linear.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/mx_ops.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/mx_ops.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0520c7b935f79931c6270c05dc822f5e1adbecf0
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/mx_ops.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/mx_tensor.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/mx_tensor.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5823f9eb089249a13fd3b78107e7bd1a5e415d82
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/mx_tensor.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..94113d7b36a6a75e321b9d4eae90e54fb95dccff
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/mx_formats/__pycache__/utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/config.py b/lib/python3.12/site-packages/torchao/prototype/mx_formats/config.py
new file mode 100644
index 0000000000000000000000000000000000000000..c49e1595a8c8f1e9b88c391e70103b68f4796d88
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/mx_formats/config.py
@@ -0,0 +1,196 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+from dataclasses import dataclass
+from enum import Enum
+from typing import Any, Optional, Union
+
+import torch
+
+from torchao.core.config import AOBaseConfig
+from torchao.prototype.mx_formats.constants import (
+    DTYPE_FP4,
+    DTYPE_FP6_E2M3,
+    DTYPE_FP6_E3M2,
+    DTYPE_TO_SHORT_STR,
+    SUPPORTED_ELEM_DTYPES,
+)
+
+
+class MXGemmKernelChoice(Enum):
+    # always available - MX operands are dequantized and a high precision
+    # gemm is run
+    EMULATED = "emulated"
+
+    # available only when CUDA capability is greater than or equal to 10.0
+    CUTLASS = "cutlass"
+
+    # available only when CUDA capability is greater than or equal to 10.0
+    # available on recent versions of PyTorch nightly, with https://github.com/pytorch/pytorch/pull/147548
+    # note: torch.compile does not work yet, see https://github.com/pytorch/pytorch/issues/147873
+    CUBLAS = "cublas"
+
+
+# Pre-made recipes for common configurations
+class MXLinearRecipeName(Enum):
+    MXFP8_EMULATED = "mxfp8_emulated"
+    MXFP8_CUBLAS = "mxfp8_cublas"
+    MXFP4_EMULATED = "mxfp4_emulated"
+    MXFP4_CUTLASS = "mxfp4_cutlass"
+
+
+def _validate_elem_dtype(elem_dtype):
+    assert elem_dtype in SUPPORTED_ELEM_DTYPES, (
+        f"elem_dtype: expected one of {SUPPORTED_ELEM_DTYPES}, got {elem_dtype}"
+    )
+
+
+def _validate_gemm_kernel_choice(gemm_kernel_choice, block_size, elem_dtype):
+    if gemm_kernel_choice == MXGemmKernelChoice.CUTLASS:
+        assert block_size == 32, (
+            f"block_size must be 32 to use the CUTLASS MX gemm kernels, got {block_size}"
+        )
+        valid_dtypes = [torch.float8_e4m3fn, DTYPE_FP4]
+        assert elem_dtype in valid_dtypes, (
+            f"elem_dtype must be one of {valid_dtypes} to use the CUTLASS MX gemm kernels, got {elem_dtype}"
+        )
+    elif gemm_kernel_choice == MXGemmKernelChoice.CUBLAS:
+        assert block_size == 32, (
+            f"block_size must be 32 to use the cuBLAS MX gemm kernels, got {block_size}"
+        )
+        valid_dtypes = [torch.float8_e4m3fn]
+        assert elem_dtype in valid_dtypes, (
+            f"elem_dtype must be one of {valid_dtypes} to use the CUTLASS MX gemm kernels, got {elem_dtype}"
+        )
+
+
+@dataclass
+class MXLinearConfig(AOBaseConfig):
+    # block size for scaling, default is 32 to match
+    # https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf,
+    # section 5.2
+    block_size: int = 32
+
+    # element dtype, used for activations, weights and gradients
+    elem_dtype: Any = torch.float8_e4m3fn
+
+    # overrides for element dtype for weights and gradients
+    # TODO(future PR): refactor to make this cleaner
+    elem_dtype_weight_override: Optional[Any] = None
+    elem_dtype_grad_output_override: Optional[Any] = None
+
+    # defines the gemm kernel choice, if the chosen kernel is not supported
+    # on the given hardware an exception will be thrown
+    gemm_kernel_choice: MXGemmKernelChoice = MXGemmKernelChoice.EMULATED
+
+    # If True, uses a custom triton kernel for cast to mxfp8 across dim1
+    # TODO(1945): remove this config option once torch.compile gives us
+    # a fast kernel
+    use_fp8_dim1_cast_triton_kernel: bool = False
+
+    # If True, uses a custom triton kernel for fp4 dequantize
+    use_fp4_custom_triton_dequant_kernel: bool = False
+
+    def __post_init__(self):
+        _validate_elem_dtype(self.elem_dtype)
+        _validate_gemm_kernel_choice(
+            self.gemm_kernel_choice, self.block_size, self.elem_dtype
+        )
+        if self.elem_dtype_weight_override is not None:
+            _validate_elem_dtype(self.elem_dtype_weight_override)
+            assert self.gemm_kernel_choice == MXGemmKernelChoice.EMULATED, "unsupported"
+        if self.elem_dtype_grad_output_override is not None:
+            _validate_elem_dtype(self.elem_dtype_grad_output_override)
+            assert self.gemm_kernel_choice == MXGemmKernelChoice.EMULATED, "unsupported"
+
+    @staticmethod
+    def from_recipe_name(
+        recipe_name: Union[MXLinearRecipeName, str],
+    ) -> "MXLinearConfig":
+        """
+        Input: `MXLinearRecipeName` value, or a string representing a `MXLinearRecipeName` value
+        Output: a `MXLinearConfig` configured to implement the specified recipe
+        """
+        if type(recipe_name) == str:
+            valid_names = [n.value for n in MXLinearRecipeName]
+            assert recipe_name in valid_names, (
+                f"recipe_name {recipe_name} not in valid names {valid_names}"
+            )
+            recipe_name = MXLinearRecipeName(recipe_name)
+
+        if recipe_name is MXLinearRecipeName.MXFP8_EMULATED:
+            return MXLinearConfig()
+        elif recipe_name is MXLinearRecipeName.MXFP8_CUBLAS:
+            return MXLinearConfig(gemm_kernel_choice=MXGemmKernelChoice.CUBLAS)
+        elif recipe_name is MXLinearRecipeName.MXFP4_EMULATED:
+            return MXLinearConfig(elem_dtype=DTYPE_FP4)
+        elif recipe_name is MXLinearRecipeName.MXFP4_CUTLASS:
+            return MXLinearConfig(
+                elem_dtype=DTYPE_FP4, gemm_kernel_choice=MXGemmKernelChoice.CUTLASS
+            )
+        else:
+            raise AssertionError(f"unknown recipe_name {recipe_name}")
+
+    def short_str(self) -> str:
+        """
+        Returns a concise representation of the current config.
+        """
+        s = f"bl_sz={self.block_size}, lp_dtype={DTYPE_TO_SHORT_STR[self.elem_dtype]}"
+        if self.elem_dtype_weight_override is not None:
+            s += (
+                f", lp_w_override={DTYPE_TO_SHORT_STR[self.elem_dtype_weight_override]}"
+            )
+        if self.elem_dtype_grad_output_override is not None:
+            s += f", lp_go_override={DTYPE_TO_SHORT_STR[self.elem_dtype_grad_output_override]}"
+        s += f", kernel={self.gemm_kernel_choice.value}"
+        if self.use_fp8_dim1_cast_triton_kernel:
+            s += ", use_fp8_dim1_cast_triton_kernel=True"
+        if self.use_fp4_custom_triton_dequant_kernel:
+            s += ", use_fp4_custom_triton_dequant_kernel=True"
+        return s
+
+
+@dataclass
+class MXInferenceLinearConfig(AOBaseConfig):
+    # block size for scaling, default is 32 to match
+    # https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf,
+    # section 5.2
+    block_size: int = 32
+
+    # element dtype, used for activations, weights and gradients
+    elem_dtype: Any = torch.float8_e4m3fn
+    # TODO(future PR): support different elem_dtype for activations vs weights
+
+    # defines the gemm kernel choice, if the chosen kernel is not supported
+    # on the given hardware an exception will be thrown
+    gemm_kernel_choice: MXGemmKernelChoice = MXGemmKernelChoice.EMULATED
+
+    # If True, uses a custom triton kernel for fp4 dequantize
+    use_fp4_custom_triton_dequant_kernel: bool = False
+
+    # If True, packs 4xFP6 into 3xuint8 containers for inference, using custom triton
+    # kernels (fused unpack/dequantize).
+    pack_fp6: bool = True
+
+    def __post_init__(self):
+        _validate_elem_dtype(self.elem_dtype)
+        _validate_gemm_kernel_choice(
+            self.gemm_kernel_choice, self.block_size, self.elem_dtype
+        )
+
+    def short_str(self) -> str:
+        """
+        Returns a concise representation of the current config.
+        """
+        s = f"bl_sz={self.block_size}, lp_dtype={DTYPE_TO_SHORT_STR[self.elem_dtype]}"
+        s += f", kernel={self.gemm_kernel_choice.value}"
+        if self.use_fp4_custom_triton_dequant_kernel:
+            s += ", use_fp4_custom_triton_dequant_kernel=True"
+        if self.elem_dtype in (DTYPE_FP6_E2M3, DTYPE_FP6_E3M2) and self.pack_fp6:
+            s += ", pack_fp6=True"
+        return s
+
+    # TODO(future PR): add a recipe to config API for inference
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/constants.py b/lib/python3.12/site-packages/torchao/prototype/mx_formats/constants.py
new file mode 100644
index 0000000000000000000000000000000000000000..94c63b11e50dc9421da7bdddda5f397a606c137a
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/mx_formats/constants.py
@@ -0,0 +1,65 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import torch
+
+# This is conceptually an enum of non-core dtypes
+# TODO(future PR): change to a cleaner way to represent this without
+# regressing torch.compile and while keeping things readable.
+DTYPE_FP4 = "fp4_e2m1"
+DTYPE_FP6_E3M2 = "fp6_e3m2"
+DTYPE_FP6_E2M3 = "fp6_e2m3"
+
+# Supported element dtypes
+# TODO(future PR): add support for MX int8
+SUPPORTED_ELEM_DTYPES = [
+    torch.float8_e4m3fn,
+    torch.float8_e5m2,
+    DTYPE_FP6_E2M3,
+    DTYPE_FP6_E3M2,
+    DTYPE_FP4,
+]
+
+DTYPE_TO_SHORT_STR = {
+    torch.float8_e4m3fn: "f8e4m3",
+    torch.float8_e5m2: "f8e5m2",
+    DTYPE_FP6_E2M3: "f6e2m3",
+    DTYPE_FP6_E3M2: "f6e3m2",
+    DTYPE_FP4: "f4e2m1",
+}
+
+F8E4M3_MAX = torch.finfo(torch.float8_e4m3fn).max  # 448.0
+F8E5M2_MAX = torch.finfo(torch.float8_e5m2).max  # 57344.0
+
+F8E4M3_MAX_POW2 = 8  # 256
+F8E5M2_MAX_POW2 = 15  # 32768
+F6_E2M3_MAX_POW2 = 2  # 4
+F6_E3M2_MAX_POW2 = 4  # 16
+F4_E2M1_MAX_POW2 = 2  # 4
+
+E8M0_EXPONENT_BIAS = 127
+E8M0_EXPONENT_NAN_VAL = 255
+
+F32_EXP_BIAS = 127
+BF16_EXP_BIAS = 127
+F6_E2M3_EXP_BIAS = 1
+F6_E3M2_EXP_BIAS = 3
+F4_E2M1_EXP_BIAS = 1
+
+F32_MIN_NORMAL = 2 ** (-F32_EXP_BIAS + 1)
+
+F6_E2M3_MAX = 7.5
+F6_E2M3_MIN_NORMAL = 1.0
+F6_E2M3_MAX_INT = 31  # integer corresponding to 0b00011111
+
+F6_E3M2_MAX = 28.0
+F6_E3M2_MIN_NORMAL = 0.25
+F6_E3M2_MAX_INT = 31  # integer corresponding to 0b00011111
+
+F4_E2M1_MAX = 6.0
+F4_E2M1_MIN_NORMAL = 1.0
+F4_E2M1_MAX_INT = 7
+
+BLOCK_SIZE_DEFAULT = 32
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/custom_cast.py b/lib/python3.12/site-packages/torchao/prototype/mx_formats/custom_cast.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f870b4f289af8d7e29e53f59ed218f18e63f60f
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/mx_formats/custom_cast.py
@@ -0,0 +1,1396 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+from typing import Tuple
+
+import numpy as np
+import torch
+from torch.utils._triton import has_triton
+
+from torchao.prototype.custom_fp_utils import (
+    _f32_to_floatx_unpacked,
+    _floatx_unpacked_to_f32,
+)
+from torchao.utils import TORCH_VERSION_AT_LEAST_2_4, TORCH_VERSION_AT_LEAST_2_7
+
+# TODO(future): if needed, make the below work on previous PyTorch versions,
+# just need to hunt down the previous location of `libdevice`. An assert
+# at the callsite prevents usage of this on unsupported versions.
+if TORCH_VERSION_AT_LEAST_2_4 and has_triton():
+    from torch._inductor.runtime.triton_helpers import libdevice
+
+from torchao.prototype.mx_formats.constants import (
+    E8M0_EXPONENT_BIAS,
+    E8M0_EXPONENT_NAN_VAL,
+    F4_E2M1_EXP_BIAS,
+    F6_E2M3_EXP_BIAS,
+    F6_E3M2_EXP_BIAS,
+    F32_EXP_BIAS,
+)
+
+
+def get_bits(x: torch.Tensor) -> str:
+    bits_per_byte = 8
+    # Numpy has a nice function to get the string representation of binary.
+    # Since we are using ints as views of floats, need to specify the width
+    # to avoid numpy from using two's complement for negative numbers.
+    return np.binary_repr(x.cpu().numpy(), width=x.element_size() * bits_per_byte)  # noqa: E501
+
+
+EBITS_F32, MBITS_F32 = 8, 23
+EBITS_F4_E2M1, MBITS_F4_E2M1 = 2, 1
+EBITS_F6_E2M3, MBITS_F6_E2M3 = 2, 3
+EBITS_F6_E3M2, MBITS_F6_E3M2 = 3, 2
+
+SIGN_MASK_F4 = 0x8  # 1000
+MANTISSA_MASK_F4 = 0x1  # 0001
+
+SIGN_MASK_F6_E2M3 = 0x20  # 100000
+MANTISSA_MASK_F6_E2M3 = 0x7  # 000111
+
+SIGN_MASK_F6_E3M2 = 0x20  # 100000
+MANTISSA_MASK_F6_E3M2 = 0x3  # 000011
+
+ZERO_BITS_F32 = 0x0
+ZERO_POINT_FIVE_BITS_F32 = 0x3F000000
+
+
+def f32_to_f4_unpacked(x):
+    """
+    Input: torch.Tensor of dtype torch.float
+    Output: torch.Tensor of dtype torch.uint8, with bits 0-3 empty and
+      bits 4-7 in fp4_e2m1
+    """
+    return _f32_to_floatx_unpacked(x, EBITS_F4_E2M1, MBITS_F4_E2M1)
+
+
+def f32_to_f6_e2m3_unpacked(x):
+    """
+    Input: torch.Tensor of dtype torch.float
+    Output: torch.Tensor of dtype torch.uint8, with bits 0-1 empty and
+      bits 2-7 in fp6_e2m3
+    """
+    return _f32_to_floatx_unpacked(x, EBITS_F6_E2M3, MBITS_F6_E2M3)
+
+
+def f32_to_f6_e3m2_unpacked(x):
+    """
+    Input: torch.Tensor of dtype torch.float
+    Output: torch.Tensor of dtype torch.uint8, with bits 0-1 empty and
+      bits 2-7 in fp6_e3m2
+    """
+    return _f32_to_floatx_unpacked(x, EBITS_F6_E3M2, MBITS_F6_E3M2)
+
+
+def f4_unpacked_to_f32(x: torch.Tensor):
+    """
+    Input: torch.Tensor of dtype uint8, with bits 0-3 empty and bits 4-7
+      containing an fp4_e2m1 encoding
+    Output: torch.Tensor of dtype fp32 with the dequantized value
+    """
+    return _floatx_unpacked_to_f32(x, EBITS_F4_E2M1, MBITS_F4_E2M1)
+
+
+def f6_e2m3_unpacked_to_f32(x: torch.Tensor):
+    """
+    Input: torch.Tensor of dtype uint8, with bits 0-1 empty and bits 2-7
+      containing an fp6_e3m2 encoding
+    Output: torch.Tensor of dtype fp32 with the dequantized value
+    """
+    return _floatx_unpacked_to_f32(x, EBITS_F6_E2M3, MBITS_F6_E2M3)
+
+
+def f6_e3m2_unpacked_to_f32(x: torch.Tensor):
+    """
+    Input: torch.Tensor of dtype uint8, with bits 0-1 empty and bits 2-7
+      containing an fp6_e3m2 encoding
+    Output: torch.Tensor of dtype fp32 with the dequantized value
+    """
+    return _floatx_unpacked_to_f32(x, EBITS_F6_E3M2, MBITS_F6_E3M2)
+
+
+if has_triton():
+    import triton
+    import triton.language as tl
+
+    @triton.jit
+    def _fp4_packed_to_bf16(
+        x_packed,
+        sign_mask_f4,
+        mantissa_mask_f4,
+        mbits_f4_e2m1,
+        ebits_f4_e2m1,
+        f4_e2m1_exp_bias,
+        mbits_f32,
+        ebits_f32,
+        f32_exp_bias,
+        zero_bits_f32,
+        zero_point_five_bits_f32,
+    ):
+        """
+        Input: a tensor of packed fp4 values
+        Output: a tensor of bfloat16 values
+        """
+
+        # low-bits: original location 0:3
+        # high-bits: original location 4:7
+        x_low_bits = x_packed >> 4
+        x_high_bits = x_packed & 0xF
+        x = tl.interleave(x_low_bits, x_high_bits)
+
+        # cast logic below
+        # output = x_unpacked.to(tl.float32)
+
+        # save the sign
+        sign_f4 = x & sign_mask_f4
+
+        # set everything to positive, will add sign back at the end
+        x_pos = x ^ sign_f4
+
+        # Special case zero
+        zero_mask = x_pos == 0
+
+        # There is only one denormal value in fp4: s001, which is 0.5 in f32
+        # Special case it.
+        # TODO(later): will it be faster to repeat this for all 8 positive
+        # values instead of the bit manipulations?
+        denormal_mask = x_pos == 1
+
+        # calculate the new exponent and shift it to bits 2:9 of the result
+        exp_biased_f4 = x_pos >> mbits_f4_e2m1
+        exp_biased_f32 = exp_biased_f4 - f4_e2m1_exp_bias + f32_exp_bias
+        exp_biased_f32 = exp_biased_f32.to(tl.int32) << mbits_f32
+
+        # shift the mantissa to bits 10:32 of the result
+        mantissa_f4 = x_pos & mantissa_mask_f4
+        mantissa_f32 = mantissa_f4.to(tl.int32) << (mbits_f32 - mbits_f4_e2m1)
+        output = mantissa_f32
+
+        # combine the pieces
+        result = exp_biased_f32 | mantissa_f32
+        # result[zero_mask] = ZERO_BITS_F32
+        result = tl.where(zero_mask, zero_bits_f32, result)
+        # result[denormal_mask] = ZERO_POINT_FIVE_BITS_F32
+        result = tl.where(denormal_mask, zero_point_five_bits_f32, result)
+
+        # add sign back
+        sign_f32 = sign_f4.to(tl.int32) << (
+            mbits_f32 - mbits_f4_e2m1 + ebits_f32 - ebits_f4_e2m1
+        )
+        result = result | sign_f32
+
+        # The bit shifting above is for float32, so for now we
+        # bitcast to float32 and then regular cast to bfloat16
+        # TODO(later): it should be pretty easy to cast directly to bf16, just
+        # need to adjust the mbits/ebits/special values. Perf impact is likely
+        # to be small as we would not be chaning memory access patterns.
+        output = result.to(tl.float32, bitcast=True)
+        output = output.to(tl.bfloat16)
+        return output
+
+    @triton.jit
+    def triton_f4_to_bf16_kernel(
+        x_ptr,
+        output_ptr,
+        n_elements_in,
+        sign_mask_f4: tl.constexpr,
+        mantissa_mask_f4: tl.constexpr,
+        mbits_f4_e2m1: tl.constexpr,
+        ebits_f4_e2m1: tl.constexpr,
+        f4_e2m1_exp_bias: tl.constexpr,
+        mbits_f32: tl.constexpr,
+        ebits_f32: tl.constexpr,
+        f32_exp_bias: tl.constexpr,
+        zero_bits_f32: tl.constexpr,
+        zero_point_five_bits_f32: tl.constexpr,
+        BLOCK_SIZE_IN: tl.constexpr,
+    ):
+        pid = tl.program_id(axis=0)
+        n_elements_out = n_elements_in * 2
+        BLOCK_SIZE_OUT: tl.constexpr = BLOCK_SIZE_IN * 2
+
+        block_start_in = pid * BLOCK_SIZE_IN
+        offsets_in = block_start_in + tl.arange(0, BLOCK_SIZE_IN)
+
+        mask_in = offsets_in < n_elements_in
+
+        # packed uint8
+        x_packed = tl.load(x_ptr + offsets_in, mask=mask_in)
+        output = _fp4_packed_to_bf16(
+            x_packed,
+            sign_mask_f4,
+            mantissa_mask_f4,
+            mbits_f4_e2m1,
+            ebits_f4_e2m1,
+            f4_e2m1_exp_bias,
+            mbits_f32,
+            ebits_f32,
+            f32_exp_bias,
+            zero_bits_f32,
+            zero_point_five_bits_f32,
+        )
+
+        # set up output offsets
+        block_start_out = pid * BLOCK_SIZE_OUT
+        offsets_out = block_start_out + tl.arange(0, BLOCK_SIZE_OUT)
+        mask_out = offsets_out < n_elements_out
+
+        tl.store(output_ptr + offsets_out, output, mask=mask_out)
+
+    @triton.autotune(
+        configs=[
+            triton.Config({"BLOCK_SIZE_IN": 128}),
+            triton.Config({"BLOCK_SIZE_IN": 256}),
+            triton.Config({"BLOCK_SIZE_IN": 512}),
+            triton.Config({"BLOCK_SIZE_IN": 1024}),
+            triton.Config({"BLOCK_SIZE_IN": 2048}),
+        ],
+        key=["n_elements_in"],
+    )
+    @triton.jit
+    def triton_f4_to_scaled_bf16_kernel(
+        x_ptr,
+        s_ptr,
+        output_ptr,
+        n_elements_in,
+        mx_block_size: tl.constexpr,
+        sign_mask_f4: tl.constexpr,
+        mantissa_mask_f4: tl.constexpr,
+        mbits_f4_e2m1: tl.constexpr,
+        ebits_f4_e2m1: tl.constexpr,
+        f4_e2m1_exp_bias: tl.constexpr,
+        mbits_f32: tl.constexpr,
+        ebits_f32: tl.constexpr,
+        f32_exp_bias: tl.constexpr,
+        zero_bits_f32: tl.constexpr,
+        zero_point_five_bits_f32: tl.constexpr,
+        e8m0_exponent_bias: tl.constexpr,
+        e8m0_exponent_nan_val: tl.constexpr,
+        BLOCK_SIZE_IN: tl.constexpr,
+    ):
+        pid = tl.program_id(axis=0)
+        n_elements_out = n_elements_in * 2
+        n_elements_s = n_elements_out // 32
+
+        BLOCK_SIZE_S: tl.constexpr = BLOCK_SIZE_IN // 16
+        BLOCK_SIZE_OUT: tl.constexpr = BLOCK_SIZE_IN * 2
+
+        block_start_in = pid * BLOCK_SIZE_IN
+        offsets_in = block_start_in + tl.arange(0, BLOCK_SIZE_IN)
+        mask_in = offsets_in < n_elements_in
+        # packed uint8
+        x_packed = tl.load(x_ptr + offsets_in, mask=mask_in)
+        output = _fp4_packed_to_bf16(
+            x_packed,
+            sign_mask_f4,
+            mantissa_mask_f4,
+            mbits_f4_e2m1,
+            ebits_f4_e2m1,
+            f4_e2m1_exp_bias,
+            mbits_f32,
+            ebits_f32,
+            f32_exp_bias,
+            zero_bits_f32,
+            zero_point_five_bits_f32,
+        )
+
+        # load scale
+        block_start_s = pid * BLOCK_SIZE_S
+        offsets_s = block_start_s + tl.arange(0, BLOCK_SIZE_S)
+        mask_s = offsets_s < n_elements_s
+        s = tl.load(s_ptr + offsets_s, mask=mask_s)
+
+        # create the scale in bf16
+        s_offset = s.to(tl.int16) - e8m0_exponent_bias
+        s_fp = libdevice.pow(2.0, s_offset).to(tl.bfloat16)
+        s_fp = tl.where(s != e8m0_exponent_nan_val, s_fp, float("nan"))
+
+        # multiply output by scale
+        # TODO(later): see if manipulating the exponent instead of fp
+        # multiplication is going to give a significant speedup
+        output = tl.reshape(output, (BLOCK_SIZE_OUT // mx_block_size, mx_block_size))  # noqa: E501
+        s_fp = tl.reshape(s_fp, (BLOCK_SIZE_S // 1, 1))
+        output = output * s_fp
+        output = tl.reshape(output, (BLOCK_SIZE_OUT,))
+
+        # set up output offsets
+        block_start_out = pid * BLOCK_SIZE_OUT
+        offsets_out = block_start_out + tl.arange(0, BLOCK_SIZE_OUT)
+        mask_out = offsets_out < n_elements_out
+
+        tl.store(output_ptr + offsets_out, output, mask=mask_out)
+
+    @triton.jit
+    def _fp6_packed_to_bf16(
+        packed_4bits_a,
+        packed_4bits_b,
+        packed_2bits,
+        sign_mask_f6,
+        mbits_f6,
+        f6_exp_bias,
+        mbits_f32,
+        f32_exp_bias,
+    ):
+        """
+        Input: a tensor of packed fp6 values
+        Output: a tensor of bfloat16 values
+        """
+
+        # L/R shift and combine back into uint8 with first 2 bits empty (i.e. unpacked)
+        x_0 = ((packed_4bits_a >> 2) & 0x3C) | ((packed_2bits & 0xC0) >> 6)
+        x_1 = ((packed_4bits_a << 2) & 0x3C) | ((packed_2bits & 0x30) >> 4)
+        x_2 = ((packed_4bits_b >> 2) & 0x3C) | ((packed_2bits & 0xC) >> 2)
+        x_3 = ((packed_4bits_b << 2) & 0x3C) | (packed_2bits & 0x3)
+
+        # repeat_interleave not supported yet, see https://github.com/triton-lang/triton/issues/1426
+        # instead we can interleave(interleave(4*i, 4*i+2), interleave(4*i+1, 4*i+3))
+        # TODO: is there a more performant way?
+        # We could stack all 4, then transpose and ravel and do it that way?
+        x_02 = tl.interleave(x_0, x_2)  # [x_0_0, x_2_0, x_0_1, x_2_1, ...]
+        x_13 = tl.interleave(x_1, x_3)  # [x_1_0, x_3_0, x_1_1, x_3_1, ...]
+        x = tl.interleave(x_02, x_13)  # [x_0_0, x_1_0, x_2_0, x_3_0, x_0_1, ...]
+
+        # save the sign
+        sign_f6 = x & sign_mask_f6
+
+        # set everything to positive, will add sign back at the end
+        x_pos = x ^ sign_f6
+
+        # shift the exponent and mantissa
+        result = x_pos.to(tl.int32) << (mbits_f32 - mbits_f6)
+
+        # add sign back
+        # left shift is always 26 regardless of fp6 variant
+        sign_f32 = sign_f6.to(tl.int32) << 26
+        result = result | sign_f32
+
+        # The bit shifting above is for float32, so for now we
+        # bitcast to float32 and then regular cast to bfloat16
+        # TODO(later): it should be pretty easy to cast directly to bf16, just
+        # need to adjust the mbits/ebits/special values. Perf impact is likely
+        # to be small as we would not be changing memory access patterns.
+        output = result.to(tl.float32, bitcast=True)
+
+        # Scale the fp32 exponent afterwards, handles the denorms correctly
+        output *= 2.0 ** (f32_exp_bias - f6_exp_bias)
+
+        output = output.to(tl.bfloat16)
+        return output
+
+    @triton.autotune(
+        configs=[
+            triton.Config({"BLOCK_SIZE_IN": 2}, num_warps=1),
+            triton.Config({"BLOCK_SIZE_IN": 4}, num_warps=1),
+            triton.Config({"BLOCK_SIZE_IN": 8}, num_warps=1),
+            triton.Config({"BLOCK_SIZE_IN": 16}, num_warps=1),
+        ],
+        key=["n_mx_blocks"],
+    )
+    @triton.jit
+    def triton_f6_to_bf16_kernel(
+        x_ptr,
+        output_ptr,
+        n_mx_blocks,
+        mx_block_size: tl.constexpr,
+        packed_mx_block_size: tl.constexpr,
+        sign_mask_f6: tl.constexpr,
+        mbits_f6: tl.constexpr,
+        f6_exp_bias: tl.constexpr,
+        mbits_f32: tl.constexpr,
+        f32_exp_bias: tl.constexpr,
+        BLOCK_SIZE_IN: tl.constexpr,
+    ):
+        pid = tl.program_id(axis=0)
+        block_start = pid * BLOCK_SIZE_IN
+
+        offsets_rows = block_start + tl.arange(0, BLOCK_SIZE_IN)
+        offsets_cols = tl.arange(0, packed_mx_block_size // 3)
+        mask_in = (offsets_rows[:, None] < n_mx_blocks) & (
+            offsets_cols[None, :] < packed_mx_block_size // 3
+        )
+        offsets_in = (
+            offsets_rows[:, None] * packed_mx_block_size + offsets_cols[None, :]
+        )
+
+        # packed 4 x fp6 into 3 x uint8
+        packed_4bits_a = tl.load(x_ptr + offsets_in, mask=mask_in, other=0)
+        packed_4bits_b = tl.load(
+            x_ptr + offsets_in + (packed_mx_block_size // 3), mask=mask_in, other=0
+        )
+        packed_2bits = tl.load(
+            x_ptr + offsets_in + (2 * packed_mx_block_size // 3), mask=mask_in, other=0
+        )
+
+        output = _fp6_packed_to_bf16(
+            packed_4bits_a,
+            packed_4bits_b,
+            packed_2bits,
+            sign_mask_f6,
+            mbits_f6,
+            f6_exp_bias,
+            mbits_f32,
+            f32_exp_bias,
+        )
+
+        # set up output offsets
+        offsets_rows_out = block_start + tl.arange(0, BLOCK_SIZE_IN)
+        offsets_cols_out = tl.arange(0, mx_block_size)
+        offsets_out = (
+            offsets_rows_out[:, None] * mx_block_size + offsets_cols_out[None, :]
+        )
+        mask_out = (offsets_rows_out[:, None] < n_mx_blocks) & (
+            offsets_cols_out[None, :] < mx_block_size
+        )
+
+        tl.store(output_ptr + offsets_out, output, mask=mask_out)
+
+    @triton.autotune(
+        configs=[
+            triton.Config({"BLOCK_SIZE_IN": 2}, num_warps=1),
+            triton.Config({"BLOCK_SIZE_IN": 4}, num_warps=1),
+            triton.Config({"BLOCK_SIZE_IN": 8}, num_warps=1),
+            triton.Config({"BLOCK_SIZE_IN": 16}, num_warps=1),
+        ],
+        key=["n_mx_blocks"],
+    )
+    @triton.jit
+    def triton_f6_to_scaled_bf16_kernel(
+        x_ptr,
+        s_ptr,
+        output_ptr,
+        n_mx_blocks,
+        mx_block_size: tl.constexpr,
+        packed_mx_block_size: tl.constexpr,
+        sign_mask_f6: tl.constexpr,
+        mbits_f6: tl.constexpr,
+        f6_exp_bias: tl.constexpr,
+        mbits_f32: tl.constexpr,
+        f32_exp_bias: tl.constexpr,
+        e8m0_exponent_bias: tl.constexpr,
+        e8m0_exponent_nan_val: tl.constexpr,
+        BLOCK_SIZE_IN: tl.constexpr,
+    ):
+        pid = tl.program_id(axis=0)
+
+        block_start = pid * BLOCK_SIZE_IN
+
+        offsets_rows = block_start + tl.arange(0, BLOCK_SIZE_IN)
+        offsets_cols = tl.arange(0, packed_mx_block_size // 3)
+        mask_in = (offsets_rows[:, None] < n_mx_blocks) & (
+            offsets_cols[None, :] < packed_mx_block_size // 3
+        )
+        offsets_in = (
+            offsets_rows[:, None] * packed_mx_block_size + offsets_cols[None, :]
+        )
+
+        # packed 4 x fp6 into 3 x uint8
+        packed_4bits_a = tl.load(x_ptr + offsets_in, mask=mask_in, other=0)
+        packed_4bits_b = tl.load(
+            x_ptr + offsets_in + (packed_mx_block_size // 3), mask=mask_in, other=0
+        )
+        packed_2bits = tl.load(
+            x_ptr + offsets_in + (2 * packed_mx_block_size // 3), mask=mask_in, other=0
+        )
+
+        output = _fp6_packed_to_bf16(
+            packed_4bits_a,
+            packed_4bits_b,
+            packed_2bits,
+            sign_mask_f6,
+            mbits_f6,
+            f6_exp_bias,
+            mbits_f32,
+            f32_exp_bias,
+        )
+
+        # load scale
+        offsets_s = block_start + tl.arange(0, BLOCK_SIZE_IN)
+        mask_s = offsets_s < n_mx_blocks
+        s = tl.load(s_ptr + offsets_s, mask=mask_s)
+
+        # create the scale in bf16
+        s_offset = s.to(tl.float32) - e8m0_exponent_bias
+        s_fp = libdevice.pow(2.0, s_offset).to(tl.bfloat16)
+        s_fp = tl.where(s != e8m0_exponent_nan_val, s_fp, float("nan"))
+
+        # multiply output by scale
+        # TODO(later): see if manipulating the exponent instead of fp
+        # multiplication is going to give a significant speedup
+        output = tl.reshape(output, (BLOCK_SIZE_IN, mx_block_size))  # noqa: E501
+        s_fp = tl.reshape(s_fp, (BLOCK_SIZE_IN // 1, 1))
+        output = output * s_fp
+        output = tl.reshape(output, (BLOCK_SIZE_IN, mx_block_size))
+
+        # set up output offsets
+        offsets_rows_out = block_start + tl.arange(0, BLOCK_SIZE_IN)
+        offsets_cols_out = tl.arange(0, mx_block_size)
+        offsets_out = (
+            offsets_rows_out[:, None] * mx_block_size + offsets_cols_out[None, :]
+        )
+        mask_out = (offsets_rows_out[:, None] < n_mx_blocks) & (
+            offsets_cols_out[None, :] < mx_block_size
+        )
+
+        tl.store(output_ptr + offsets_out, output, mask=mask_out)
+
+    @triton.autotune(
+        configs=[
+            triton.Config({"BLOCK_SIZE_IN": 2}, num_warps=1),
+            triton.Config({"BLOCK_SIZE_IN": 4}, num_warps=1),
+            triton.Config({"BLOCK_SIZE_IN": 8}, num_warps=1),
+            triton.Config({"BLOCK_SIZE_IN": 16}, num_warps=1),
+        ],
+        key=["n_mx_blocks"],
+    )
+    @triton.jit
+    def triton_pack_uint6_kernel(
+        input_ptr,
+        output_ptr,
+        n_mx_blocks,
+        MX_BLOCK_SIZE: tl.constexpr,
+        PACKED_MX_BLOCK_SIZE: tl.constexpr,
+        BLOCK_SIZE_IN: tl.constexpr,
+    ):
+        pid = tl.program_id(axis=0)
+        block_start = pid * BLOCK_SIZE_IN
+
+        # input_ptr is shape [n_mx_blocks, MX_BLOCK_SIZE]
+        # Load BLOCK_SIZE rows of input_ptr
+        offsets_rows = block_start + tl.arange(0, BLOCK_SIZE_IN)
+        offsets_cols = tl.arange(0, MX_BLOCK_SIZE // 4)
+        offsets = offsets_rows[:, None] * MX_BLOCK_SIZE + (4 * offsets_cols[None, :])
+        mask = (offsets_rows[:, None] < n_mx_blocks) & (
+            offsets_cols[None, :] < MX_BLOCK_SIZE // 4
+        )
+
+        # x is shape [BLOCK_SIZE, MX_BLOCK_SIZE]
+        x_0 = tl.load(input_ptr + offsets, mask=mask)
+        x_1 = tl.load(input_ptr + offsets + 1, mask=mask)
+        x_2 = tl.load(input_ptr + offsets + 2, mask=mask)
+        x_3 = tl.load(input_ptr + offsets + 3, mask=mask)
+
+        # OR between remainder 0/1, 2/3 elements to pack 2 x first-4-bit partial representations
+        # next to each other. These are the middle 4 bits of the uint8, so some gymnastics required.
+        # i.e. (00abcd00 >> 2) | (00wxyz00 << 2) = 0000abcd | wxyz0000 = wxyzabcd
+        bits_packed_4_a = (x_1 >> 2) | ((x_0 << 2) & 0xF0)
+        bits_packed_4_b = (x_3 >> 2) | ((x_2 << 2) & 0xF0)
+        # Similarly pack 4 remaining 2-bit partial representations into one uint8
+        # e.g. 000000ab, 0000cd00, 00ef0000, gh000000 --> abcdefgh
+        bits_packed_2 = (
+            (x_0 << 6) | ((x_1 << 4) & 0x30) | ((x_2 << 2) & 0xC) | (x_3 & 0x3)
+        )
+
+        # Store values in a uint8 tensor of length `3 * MX_BLOCK_SIZE / 4`
+        offsets_out_4_a = (
+            offsets_rows[:, None] * PACKED_MX_BLOCK_SIZE + offsets_cols[None, :]
+        )
+        offsets_out_4_b = (
+            offsets_rows[:, None] * PACKED_MX_BLOCK_SIZE
+            + offsets_cols[None, :]
+            + (MX_BLOCK_SIZE // 4)
+        )
+        offsets_out_2 = (
+            offsets_rows[:, None] * PACKED_MX_BLOCK_SIZE
+            + offsets_cols[None, :]
+            + (MX_BLOCK_SIZE // 2)
+        )
+
+        # Store into output tensor
+        tl.store(
+            output_ptr + offsets_out_4_a,
+            bits_packed_4_a,
+            mask=mask,
+        )
+
+        tl.store(
+            output_ptr + offsets_out_4_b,
+            bits_packed_4_b,
+            mask=mask,
+        )
+
+        tl.store(
+            output_ptr + offsets_out_2,
+            bits_packed_2,
+            mask=mask,
+        )
+
+else:
+
+    def triton_f4_to_bf16_kernel(
+        x_ptr,
+        output_ptr,
+        n_elements_in,
+        sign_mask_f4,
+        mantissa_mask_f4,
+        mbits_f4_e2m1,
+        ebits_f4_e2m1,
+        f4_e2m1_exp_bias,
+        mbits_f32,
+        ebits_f32,
+        f32_exp_bias,
+        zero_bits_f32,
+        zero_point_five_bits_f32,
+        BLOCK_SIZE_IN,
+    ):
+        raise AssertionError("unsupported without triton")
+
+    def triton_f4_to_scaled_bf16_kernel(
+        x_ptr,
+        s_ptr,
+        output_ptr,
+        n_elements_in,
+        mx_block_size,
+        sign_mask_f4,
+        mantissa_mask_f4,
+        mbits_f4_e2m1,
+        ebits_f4_e2m1,
+        f4_e2m1_exp_bias,
+        mbits_f32,
+        ebits_f32,
+        f32_exp_bias,
+        zero_bits_f32,
+        zero_point_five_bits_f32,
+        e8m0_exponent_bias,
+        e8m0_exponent_nan_val,
+        BLOCK_SIZE_IN,
+    ):
+        raise AssertionError("unsupported without triton")
+
+    def triton_f6_to_bf16_kernel(
+        x_ptr,
+        output_ptr,
+        n_elements_in,
+        sign_mask_f6,
+        mbits_f6,
+        f6_exp_bias,
+        mbits_f32,
+        f32_exp_bias,
+        BLOCK_SIZE_IN,
+    ):
+        raise AssertionError("unsupported without triton")
+
+    def triton_f6_to_scaled_bf16_kernel(
+        x_ptr,
+        s_ptr,
+        output_ptr,
+        n_elements_in,
+        mx_block_size,
+        sign_mask_f6,
+        mbits_f6,
+        f6_exp_bias,
+        mbits_f32,
+        f32_exp_bias,
+        e8m0_exponent_bias,
+        e8m0_exponent_nan_val,
+        BLOCK_SIZE_IN,
+    ):
+        raise AssertionError("unsupported without triton")
+
+    def triton_pack_uint6_kernel(
+        input_ptr,
+        output_ptr,
+        n_mx_blocks,
+        MX_BLOCK_SIZE,
+        PACKED_MX_BLOCK_SIZE,
+        BLOCK_SIZE,
+    ):
+        raise AssertionError("unsupported without triton")
+
+
+def triton_f4_to_bf16(x: torch.Tensor):
+    """
+    Input: a tensor of packed fp4 values
+    Output: a tensor of bfloat16 values
+
+    Note: this function is only used in testing, so we can test
+      the numerical correctness of the cast without the scaling.
+    """
+    new_shape = (*x.shape[:-1], x.shape[-1] * 2)
+    output = torch.empty(*new_shape, device=x.device, dtype=torch.bfloat16)
+    assert x.is_contiguous()
+    assert x.is_cuda and output.is_cuda
+    n_elements_in = x.numel()
+    grid = lambda meta: (  # noqa: E731
+        triton.cdiv(n_elements_in, meta["BLOCK_SIZE_IN"]),
+    )  # noqa: E731,E501
+    triton_f4_to_bf16_kernel[grid](
+        x,
+        output,
+        n_elements_in,
+        sign_mask_f4=SIGN_MASK_F4,
+        mantissa_mask_f4=MANTISSA_MASK_F4,
+        mbits_f4_e2m1=MBITS_F4_E2M1,
+        ebits_f4_e2m1=EBITS_F4_E2M1,
+        f4_e2m1_exp_bias=F4_E2M1_EXP_BIAS,
+        mbits_f32=MBITS_F32,
+        ebits_f32=EBITS_F32,
+        f32_exp_bias=F32_EXP_BIAS,
+        zero_bits_f32=ZERO_BITS_F32,
+        zero_point_five_bits_f32=ZERO_POINT_FIVE_BITS_F32,
+        BLOCK_SIZE_IN=512,
+    )
+    return output
+
+
+def triton_f4_to_scaled_bf16(
+    x: torch.Tensor,
+    s_e8m0: torch.Tensor,
+    mx_block_size: int,
+):
+    """
+    Input: a tensor of packed fp4 values, and a scale in e8m0 format. The block
+      size is currently assumed to be 32.
+    Output: a tensor of bfloat16 values, multiplied by the encoded scale
+    """
+    s_e8m0 = s_e8m0.view(torch.uint8)
+    assert TORCH_VERSION_AT_LEAST_2_4, "unsupported"
+    new_shape = (*x.shape[:-1], x.shape[-1] * 2)
+    output = torch.empty(*new_shape, device=x.device, dtype=torch.bfloat16)
+    assert x.is_contiguous()
+    assert x.is_cuda and output.is_cuda
+    n_elements_in = x.numel()
+    grid = lambda meta: (  # noqa: E731
+        triton.cdiv(n_elements_in, meta["BLOCK_SIZE_IN"]),
+    )
+    triton_f4_to_scaled_bf16_kernel[grid](
+        x,
+        s_e8m0,
+        output,
+        n_elements_in,
+        mx_block_size,
+        sign_mask_f4=SIGN_MASK_F4,
+        mantissa_mask_f4=MANTISSA_MASK_F4,
+        mbits_f4_e2m1=MBITS_F4_E2M1,
+        ebits_f4_e2m1=EBITS_F4_E2M1,
+        f4_e2m1_exp_bias=F4_E2M1_EXP_BIAS,
+        mbits_f32=MBITS_F32,
+        ebits_f32=EBITS_F32,
+        f32_exp_bias=F32_EXP_BIAS,
+        zero_bits_f32=ZERO_BITS_F32,
+        zero_point_five_bits_f32=ZERO_POINT_FIVE_BITS_F32,
+        e8m0_exponent_bias=E8M0_EXPONENT_BIAS,
+        e8m0_exponent_nan_val=E8M0_EXPONENT_NAN_VAL,
+    )
+    return output
+
+
+def triton_f6_e2m3_to_bf16(x: torch.Tensor) -> torch.Tensor:
+    """
+    Input: a tensor of packed fp6 values
+    Output: a tensor of bfloat16 values
+
+    Note: this function is only used in testing, so we can test
+      the numerical correctness of the cast without the scaling.
+    """
+    packed_mx_block_size = x.shape[-1]
+    mx_block_size = 4 * packed_mx_block_size // 3
+
+    x = x.view(-1, packed_mx_block_size)
+    new_shape = (x.shape[0], mx_block_size)
+
+    output = torch.empty(*new_shape, device=x.device, dtype=torch.bfloat16)
+
+    assert x.is_contiguous()
+    assert x.is_cuda and output.is_cuda
+
+    n_mx_blocks = x.shape[0]
+    grid = lambda meta: (triton.cdiv(n_mx_blocks, meta["BLOCK_SIZE_IN"]),)
+    triton_f6_to_bf16_kernel[grid](
+        x,
+        output,
+        n_mx_blocks,
+        mx_block_size,
+        packed_mx_block_size,
+        sign_mask_f6=SIGN_MASK_F6_E2M3,
+        mbits_f6=MBITS_F6_E2M3,
+        f6_exp_bias=F6_E2M3_EXP_BIAS,
+        mbits_f32=MBITS_F32,
+        f32_exp_bias=F32_EXP_BIAS,
+    )
+    return output
+
+
+def triton_f6_e3m2_to_bf16(x: torch.Tensor) -> torch.Tensor:
+    """
+    Input: a tensor of packed fp6 values
+    Output: a tensor of bfloat16 values
+
+    Note: this function is only used in testing, so we can test
+      the numerical correctness of the cast without the scaling.
+    """
+    packed_mx_block_size = x.shape[-1]
+    mx_block_size = 4 * packed_mx_block_size // 3
+
+    x = x.view(-1, packed_mx_block_size)
+    new_shape = (x.numel() // packed_mx_block_size, mx_block_size)
+
+    output = torch.empty(*new_shape, device=x.device, dtype=torch.bfloat16)
+
+    assert x.is_contiguous()
+    assert x.is_cuda and output.is_cuda
+
+    n_mx_blocks = x.shape[0]
+    grid = lambda meta: (triton.cdiv(n_mx_blocks, meta["BLOCK_SIZE_IN"]),)
+    triton_f6_to_bf16_kernel[grid](
+        x,
+        output,
+        n_mx_blocks,
+        mx_block_size,
+        packed_mx_block_size,
+        sign_mask_f6=SIGN_MASK_F6_E3M2,
+        mbits_f6=MBITS_F6_E3M2,
+        f6_exp_bias=F6_E3M2_EXP_BIAS,
+        mbits_f32=MBITS_F32,
+        f32_exp_bias=F32_EXP_BIAS,
+    )
+    return output
+
+
+if TORCH_VERSION_AT_LEAST_2_4:
+
+    @torch.library.custom_op("ao::triton_f6_e2m3_to_scaled_bf16", mutates_args=())
+    def triton_f6_e2m3_to_scaled_bf16(
+        x: torch.Tensor,
+        s_e8m0: torch.Tensor,
+        mx_block_size: int,
+    ) -> torch.Tensor:
+        """
+        Input: a tensor of packed fp6 values, and a scale in e8m0 format. The block
+        size is currently assumed to be 32.
+        Output: a tensor of bfloat16 values, multiplied by the encoded scale
+        """
+        s_e8m0 = s_e8m0.view(torch.uint8)
+
+        packed_mx_block_size = 3 * mx_block_size // 4
+
+        x = x.view(-1, packed_mx_block_size)
+        new_shape = (x.numel() // packed_mx_block_size, mx_block_size)
+
+        output = torch.empty(*new_shape, device=x.device, dtype=torch.bfloat16)
+
+        assert x.is_contiguous()
+        assert x.is_cuda and output.is_cuda
+
+        n_mx_blocks = x.shape[0]
+        grid = lambda meta: (triton.cdiv(n_mx_blocks, meta["BLOCK_SIZE_IN"]),)
+        triton_f6_to_scaled_bf16_kernel[grid](
+            x,
+            s_e8m0,
+            output,
+            n_mx_blocks,
+            mx_block_size,
+            packed_mx_block_size,
+            sign_mask_f6=SIGN_MASK_F6_E2M3,
+            mbits_f6=MBITS_F6_E2M3,
+            f6_exp_bias=F6_E2M3_EXP_BIAS,
+            mbits_f32=MBITS_F32,
+            f32_exp_bias=F32_EXP_BIAS,
+            e8m0_exponent_bias=E8M0_EXPONENT_BIAS,
+            e8m0_exponent_nan_val=E8M0_EXPONENT_NAN_VAL,
+        )
+        return output
+
+    @torch.library.custom_op("ao::triton_f6_e3m2_to_scaled_bf16", mutates_args=())
+    def triton_f6_e3m2_to_scaled_bf16(
+        x: torch.Tensor,
+        s_e8m0: torch.Tensor,
+        mx_block_size: int,
+    ) -> torch.Tensor:
+        """
+        Input: a tensor of packed fp6 values, and a scale in e8m0 format. The block
+        size is currently assumed to be 32.
+        Output: a tensor of bfloat16 values, multiplied by the encoded scale
+        """
+        s_e8m0 = s_e8m0.view(torch.uint8)
+
+        packed_mx_block_size = 3 * mx_block_size // 4
+
+        x = x.view(-1, packed_mx_block_size)
+        new_shape = (x.numel() // packed_mx_block_size, mx_block_size)
+
+        output = torch.empty(*new_shape, device=x.device, dtype=torch.bfloat16)
+
+        assert x.is_contiguous()
+        assert x.is_cuda and output.is_cuda
+
+        n_mx_blocks = x.numel() // packed_mx_block_size
+        grid = lambda meta: (triton.cdiv(n_mx_blocks, meta["BLOCK_SIZE_IN"]),)
+        triton_f6_to_scaled_bf16_kernel[grid](
+            x,
+            s_e8m0,
+            output,
+            n_mx_blocks,
+            mx_block_size,
+            packed_mx_block_size,
+            sign_mask_f6=SIGN_MASK_F6_E3M2,
+            mbits_f6=MBITS_F6_E3M2,
+            f6_exp_bias=F6_E3M2_EXP_BIAS,
+            mbits_f32=MBITS_F32,
+            f32_exp_bias=F32_EXP_BIAS,
+            e8m0_exponent_bias=E8M0_EXPONENT_BIAS,
+            e8m0_exponent_nan_val=E8M0_EXPONENT_NAN_VAL,
+        )
+        return output
+
+    @triton_f6_e3m2_to_scaled_bf16.register_fake
+    def _(x, s_e8m0, mx_block_size):
+        _padded_mx_block_size = 3 * mx_block_size // 4
+        out_shape = (x.numel() // _padded_mx_block_size, mx_block_size)
+        return torch.empty(*out_shape, device=x.device, dtype=torch.bfloat16)
+
+    @triton_f6_e2m3_to_scaled_bf16.register_fake
+    def _(x, s_e8m0, mx_block_size):
+        _padded_mx_block_size = 3 * mx_block_size // 4
+        out_shape = (x.numel() // _padded_mx_block_size, mx_block_size)
+        return torch.empty(*out_shape, device=x.device, dtype=torch.bfloat16)
+
+else:
+
+    def triton_f6_e2m3_to_scaled_bf16(
+        x: torch.Tensor,
+        s_e8m0: torch.Tensor,
+        mx_block_size: int,
+    ) -> torch.Tensor:
+        raise AssertionError("unsupported without torch >= 2.4")
+
+    def triton_f6_e3m2_to_scaled_bf16(
+        x: torch.Tensor,
+        s_e8m0: torch.Tensor,
+        mx_block_size: int,
+    ) -> torch.Tensor:
+        raise AssertionError("unsupported without torch >= 2.4")
+
+
+# pack/unpack code copy-pasted from
+# https://github.com/pytorch-labs/ao/blob/main/torchao/dtypes/uint4.py
+
+
+def down_size(size):
+    assert size[-1] % 2 == 0, f"{size} last dim not divisible by two"
+    return (*size[:-1], size[-1] // 2)
+
+
+def up_size(size):
+    return (*size[:-1], size[-1] * 2)
+
+
+def unpack_uint4(uint8_data) -> torch.Tensor:
+    """Get the original weight from the normalized float weight format"""
+    assert uint8_data.is_contiguous()
+
+    shape = uint8_data.shape
+
+    # since we are using uint8 we will decode 2 entries per byte
+    # Shift elements down 4 and select out the bottom 4 bits
+    #
+    # Note: known slow with triton
+    # * currently generates two kernels with a cat in between
+    # * after https://github.com/pytorch/pytorch/pull/123278 lands I
+    #   verified that we get a single triton kernel, but that is even slower
+    #   than the two kernels before this PR
+    # * TODO add a microbenchmark of just the cast and profile this
+    first_elements = (uint8_data >> 4).to(torch.uint8)
+    second_elements = (uint8_data & 0b1111).to(torch.uint8)
+    unpacked = torch.stack([first_elements, second_elements], dim=-1).view(
+        up_size(shape)
+    )
+
+    # trying Bert Maher's suggestion
+    # 2024-04-04: this works in unit tests but is broken on LLaMa 7B FFN with
+    #   ptxas /tmp/tmp84wp7lea.ptx, line 227; error   : Unexpected instruction types specified for 'sub'  # noqa: E501
+    # which seems to be the same issue as https://github.com/pytorch/pytorch/issues/118589  # noqa: E501
+    # TODO(later): try removing subtractions from our cast to see if we can work around  # noqa: E501
+    # shift_tensor = torch.tensor([4, 0], dtype=torch.uint8, device=uint8_data.device)  # noqa: E501
+    # unpacked = (uint8_data.reshape(-1)[::, None] >> shift_tensor) & 0b1111
+    # unpacked = unpacked.view(up_size(shape))
+
+    return unpacked
+
+
+def pack_uint4(uint8_data: torch.Tensor) -> torch.Tensor:
+    # converting to uint8 for operations
+    shape = uint8_data.shape
+    assert shape[-1] % 2 == 0
+    uint8_data = uint8_data.contiguous().view(-1)
+    return (uint8_data[::2] << 4 | uint8_data[1::2]).view(down_size(shape))
+
+
+# PyTorch implementation of fp6 packing for reference purposes
+def pack_uint6_pytorch(uint8_data: torch.Tensor) -> torch.Tensor:
+    # check shape is divisible by 4 along packing axis
+    shape = uint8_data.shape
+    assert shape[-1] % 4 == 0
+
+    packed_shape = [*shape[:-1], 3 * shape[-1] // 4]
+
+    uint8_data = uint8_data.contiguous().view(-1)
+
+    # pack 4 bits of each of 4 numbers into 2xuint8, remaining 2 bits into 1xuint8
+    bits_packed_4_a = (uint8_data[1::4] >> 2) | ((uint8_data[::4] << 2) & 0xF0)
+    bits_packed_4_b = (uint8_data[2::4] >> 2) | ((uint8_data[3::4] << 2) & 0xF0)
+    bits_packed_2 = (
+        (uint8_data[::4] << 6)
+        | ((uint8_data[1::4] << 4) & 0x30)
+        | ((uint8_data[3::4] << 2) & 0xC)
+        | (uint8_data[2::4] & 0x3)
+    )
+
+    return (
+        torch.stack((bits_packed_4_a, bits_packed_4_b, bits_packed_2), dim=-1)
+    ).view(packed_shape)
+
+
+if TORCH_VERSION_AT_LEAST_2_4:
+
+    @torch.library.custom_op("ao::pack_uint6", mutates_args=())
+    def pack_uint6(uint8_data: torch.Tensor) -> torch.Tensor:
+        # ensure input data is contiguous before passing to kernel
+        assert uint8_data.is_contiguous()
+
+        # tensor should already be of shape [..., mx_block_size]
+        mx_block_size = uint8_data.shape[-1]
+        assert mx_block_size % 4 == 0
+
+        # effective mx block size since we're packing 2 fp4 into 1 uint8
+        packed_mx_block_size = 3 * mx_block_size // 4
+        packed_shape = [uint8_data.shape[0], packed_mx_block_size]
+        n_mx_blocks = uint8_data.numel() // mx_block_size
+
+        grid = lambda meta: (triton.cdiv(n_mx_blocks, meta["BLOCK_SIZE_IN"]),)
+
+        # contiguous uint8 container in which we can store the unpacked tensor
+        packed_uint8_data = torch.empty(
+            packed_shape, dtype=torch.uint8, device=uint8_data.device
+        )
+
+        triton_pack_uint6_kernel[grid](
+            uint8_data,
+            packed_uint8_data,
+            n_mx_blocks,
+            MX_BLOCK_SIZE=mx_block_size,
+            PACKED_MX_BLOCK_SIZE=packed_mx_block_size,
+        )
+
+        return packed_uint8_data
+
+    @pack_uint6.register_fake
+    def _(uint8_data):
+        out_shape = (*uint8_data.shape[:-1], 3 * uint8_data.shape[-1] // 4)
+        return torch.empty(*out_shape, device=uint8_data.device, dtype=torch.uint8)
+else:
+
+    def pack_uint6(uint8_data: torch.Tensor) -> torch.Tensor:
+        # Dummy placeholder op for torch < 2.4
+        raise AssertionError("fp6 packing unsupported without torch >= 2.4")
+
+
+if TORCH_VERSION_AT_LEAST_2_7 and has_triton():
+    import triton
+    import triton.language as tl
+    from torch.library import triton_op, wrap_triton
+
+    @triton.jit
+    def _triton_calculate_scale(x, axis):
+        # There is no good support for accessing globals from a jit'ed triton
+        # function, so we redefine them here. Since this is prototype code which
+        # we plan to remove after torch.compile catches up, this is fine.
+        target_max_pow2 = 8
+        e8m0_exponent_bias = 127
+        bf16_mbits = 7
+        bf16_exp_bias = 127
+        fp32_mbits = 23
+        # We use a small epsilon to avoid division by zero
+        epsilon = 1e-10
+
+        # Find the maximum absolute value for each row
+        max_abs = tl.max(x, axis=axis)
+
+        # Calculate the e8m0 scale by extracting the exponent (floor)
+        # TODO(future PR): support other exponent extraction types (ceil, RNE)
+        max_abs = max_abs + epsilon
+        max_abs = max_abs.to(tl.bfloat16)
+        max_abs_int16 = max_abs.to(tl.int16, bitcast=True)
+        extracted_pow2 = ((max_abs_int16 >> bf16_mbits) & 0b11111111) - bf16_exp_bias
+        extracted_pow2 = extracted_pow2 - target_max_pow2
+        scale_e8m0_unbiased = extracted_pow2.to(tl.bfloat16)
+
+        # Clamp to exponents that can be represented in e8m0
+        scale_e8m0_unbiased = tl.clamp(
+            scale_e8m0_unbiased, -1 * e8m0_exponent_bias, e8m0_exponent_bias
+        )
+
+        # Create the biased e8m0 representation and cast it to 8 bits
+        scale_e8m0_biased = scale_e8m0_unbiased + e8m0_exponent_bias
+        scale_e8m0_biased = scale_e8m0_biased.to(tl.uint8)
+
+        # TODO(future PR): add NaN handling here,
+        # https://github.com/pytorch/pytorch/pull/100572 will likely be useful to
+        # get proper NaN propagation working
+
+        # Calculate the scale in floating point.
+        scale_fp = (scale_e8m0_biased.to(tl.int32) << fp32_mbits).to(
+            tl.float32, bitcast=True
+        )
+
+        return scale_fp, scale_e8m0_biased
+
+    def _get_mxfp8_dim1_kernel_autotune_configs():
+        # Values to sweep over here were determined by a manual
+        # sweep over a small set of shapes, it's likely that this
+        # can be improved in the future.
+        results = []
+        for ROW_TILE_SIZE in (64, 128):
+            for COL_TILE_SIZE in (64, 128):
+                for num_warps in (1, 2, 4):
+                    config = triton.Config(
+                        {
+                            "ROW_TILE_SIZE": ROW_TILE_SIZE,
+                            "COL_TILE_SIZE": COL_TILE_SIZE,
+                        },
+                        num_warps=num_warps,
+                    )
+                    results.append(config)
+        return results
+
+    @triton.autotune(
+        configs=_get_mxfp8_dim1_kernel_autotune_configs(),
+        key=["n_rows", "n_cols", "INNER_BLOCK_SIZE"],
+    )
+    @triton.jit
+    def to_mxfp8_dim1_kernel(
+        x_ptr,  # pointer to input tensor
+        output_col_major_ptr,  # pointer to column-major output tensor (column-normalized)
+        col_scale_ptr,  # pointer to store column-wise maximum absolute values
+        n_rows,  # number of rows in the tensor
+        n_cols,  # number of columns in the tensor
+        ROW_TILE_SIZE: tl.constexpr,
+        COL_TILE_SIZE: tl.constexpr,
+        INNER_BLOCK_SIZE: tl.constexpr,  # should be 32 for MX
+    ):
+        """
+        Example tiling for n_rows==8, n_cols=8, ROW_TILE_SIZE=4, COL_TILE_SIZE=4, INNER_BLOCK_SIZE=2,
+        pid_row=0, pid_col=0:
+
+        Input (row-major)
+
+        cols      0  1  2  3  4  5  6  7
+        --------------------------------
+        rows 0 |  0  1  2  3
+             1 |  8  9 10 11
+             2 | 16 17 18 19
+             3 | 24 25 26 27
+             4 |
+             5 |
+             6 |
+             7 |
+
+        Output (row-major of transpose), ids are from input
+
+        cols      0  1  2  3  4  5  6  7
+        --------------------------------
+        rows 0 |  0  8 16 24
+             1 |  1  9 17 25
+             2 |  2 10 18 26
+             3 |  3 11 19 27
+             4 |
+             5 |
+             6 |
+             7 |
+
+        Output (scales), s(0, 8) means the scale used to cast elements 0 and 8
+
+        rows           0          1  ...      4  ...       31
+        ------------------------------------------------------
+                  s(0, 8)  s(16, 24) ... s(1, 9) ... s(19, 27)
+        """
+
+        BLOCKS_PER_ROW_TILE: tl.constexpr = ROW_TILE_SIZE // INNER_BLOCK_SIZE
+
+        # Get program ID
+        pid_row = tl.program_id(0)
+        pid_col = tl.program_id(1)
+
+        # Calculate starting row and column for this tile
+        start_row = pid_row * ROW_TILE_SIZE
+        start_col = pid_col * COL_TILE_SIZE
+
+        # Create offsets for the block
+        row_offsets = tl.arange(0, ROW_TILE_SIZE)
+        col_offsets = tl.arange(0, COL_TILE_SIZE)
+
+        # Compute global row/col positions
+        rows = start_row + row_offsets[:, None]  # Convert to 2D for proper broadcasting
+        cols = start_col + col_offsets[None, :]
+
+        # Create masks for out-of-bounds accesses
+        row_mask = rows < n_rows
+        col_mask = cols < n_cols
+        mask = row_mask & col_mask
+
+        # Compute memory offsets for row-major layout (rows, cols)
+        row_major_offsets = (rows * n_cols + cols).to(tl.int32)
+
+        # Compute memory offsets for column-major layout (cols, rows)
+        col_major_offsets = (cols * n_rows + rows).to(tl.int32)
+
+        # Load the entire block in a single operation
+        # shape: (ROW_TILE_SIZE, COL_TILE_SIZE)
+        x_block = tl.load(x_ptr + row_major_offsets, mask=mask)
+
+        # Transpose dim0 and dim1
+        # shape: (COL_TILE_SIZE, ROW_TILE_SIZE)
+        x_block_t = tl.trans(x_block)
+
+        # Reshape to inner tile size
+        # shape: (COL_TILE_SIZE, ROW_TILE_SIZE) -> (COL_TILE_SIZE * BLOCKS_PER_ROW_TILE, INNER_BLOCK_SIZE)
+        x_block_t_r = x_block_t.reshape(
+            COL_TILE_SIZE * BLOCKS_PER_ROW_TILE, INNER_BLOCK_SIZE
+        )
+
+        # Calculate the absolute values of elements in the block
+        x_block_abs_t_r = tl.abs(x_block_t_r)
+
+        # Find the maximum absolute value for each column
+        # shape: (COL_TILE_SIZE * BLOCKS_PER_ROW_TILE,)
+        col_scale_r, col_scale_e8m0_r = _triton_calculate_scale(x_block_abs_t_r, axis=1)
+
+        # Divide each column by scale
+        # Broadcasting col_scale to match x_block's shape
+        # x_block_t_r shape (COL_TILE_SIZE * BLOCKS_PER_ROW_TILE, INNER_BLOCK_SIZE)
+        # col_scale shape (COL_TILE_SIZE * BLOCKS_PER_ROW_TILE,) -> (COL_TILE_SIZE * BLOCKS_PER_ROW_TILE, 1)
+        col_normalized_t_r = x_block_t_r / col_scale_r[:, None]
+
+        # Reshape back to original tile size
+        col_normalized_t = tl.reshape(col_normalized_t_r, COL_TILE_SIZE, ROW_TILE_SIZE)
+
+        # Undo the transpose
+        col_normalized = tl.trans(col_normalized_t)
+
+        # Quantize to float8
+        col_normalized = col_normalized.to(tl.float8e4nv)
+
+        # Store the column-normalized result in column-major format
+        # TODO(future): this mask is for row-major likely need to transpose it for col-major
+        tl.store(output_col_major_ptr + col_major_offsets, col_normalized, mask=mask)
+
+        # reshape col_scale_e8m0_r to col_scale_e8m0
+        # shape: (COL_TILE_SIZE * BLOCKS_PER_ROW_TILE,) -> (COL_TILE_SIZE, BLOCKS_PER_ROW_TILE,)
+        col_scale_e8m0 = col_scale_e8m0_r.reshape(COL_TILE_SIZE * BLOCKS_PER_ROW_TILE)
+
+        col_scale_start_offsets = (
+            (pid_col * COL_TILE_SIZE * (n_rows // ROW_TILE_SIZE))
+            * BLOCKS_PER_ROW_TILE  # number of blocks seen so far
+            + pid_row * BLOCKS_PER_ROW_TILE  # increment BLOCKS_PER_ROW_TILE
+        )
+
+        col_scale_start_ptr = col_scale_ptr + col_scale_start_offsets
+
+        # calculate col_scale_indices
+        col_scale_indices = tl.arange(0, COL_TILE_SIZE * BLOCKS_PER_ROW_TILE)
+
+        # How many values are in all the other columns for this row_pid, need to jump
+        # over them for every BLOCKS_PER_ROW_TILE values
+        jump_vals_per_col = (n_rows - ROW_TILE_SIZE) // INNER_BLOCK_SIZE
+
+        # example transformation (specifics depend on tile sizes):
+        # [0, 1, 2, 3, 4, 5, 6, 7] -> [0, 1, 4, 5, 8, 9, 12, 13]
+        col_scale_indices = col_scale_indices + (
+            (col_scale_indices // BLOCKS_PER_ROW_TILE) * jump_vals_per_col
+        )
+
+        # TODO(future): mask this store
+        tl.store(col_scale_start_ptr + col_scale_indices, col_scale_e8m0)
+
+    @triton_op("torchao::triton_to_mxfp8_dim1", mutates_args={})
+    def triton_to_mxfp8_dim1(
+        x: torch.Tensor, inner_block_size: int = 32
+    ) -> Tuple[torch.Tensor, torch.Tensor]:
+        """
+        Input:
+        * `x` - input tensor, in row major memory layout
+        * `inner_block_size` - size of tiles to scale across, default is 32 for MX recipes
+
+        Output:
+        * `output_col_major`: the `float8_e4m3fn` values of `x` cast to mxfp8 across dim1
+        * `col_scale`: the `e8m0` values of `x_scale` used to cast `x` to mxfp8 across dim1
+        """
+        assert x.is_contiguous(), "`x` must be contiguous"
+        assert x.dtype == torch.bfloat16
+        assert inner_block_size <= 32
+
+        # Get tensor shape
+        n_rows, n_cols = x.shape
+
+        # Masking of loads and stores is not well tested yet, so for now enforce
+        # shapes which do not need masking. Note that this condition depends on max values of
+        # ROW_TILE_SIZE and COL_TILE_SIZE, which are autotuned above.
+        # TODO(future): implement and test masking and remove this restriction
+        max_row_tile_size = 128
+        max_col_tile_size = 128
+        assert n_rows % max_row_tile_size == 0, "unsupported"
+        assert n_cols % max_col_tile_size == 0, "unsupported"
+
+        # Create output tensors
+        output_col_major = torch.empty(
+            (n_cols, n_rows), dtype=torch.float8_e4m3fn, device=x.device
+        )
+
+        # Create scale tensors
+        col_scale = torch.empty(
+            (n_cols * n_rows // inner_block_size, 1), dtype=torch.uint8, device=x.device
+        )
+
+        # Calculate grid dimensions based on tile size
+        grid = lambda META: (
+            triton.cdiv(n_rows, META["ROW_TILE_SIZE"]),
+            triton.cdiv(n_cols, META["COL_TILE_SIZE"]),
+        )
+
+        # Launch the kernel
+        wrap_triton(to_mxfp8_dim1_kernel)[grid](
+            x_ptr=x,
+            output_col_major_ptr=output_col_major,
+            col_scale_ptr=col_scale,
+            n_rows=n_rows,
+            n_cols=n_cols,
+            INNER_BLOCK_SIZE=inner_block_size,
+        )
+
+        return (
+            output_col_major.t(),
+            col_scale.view(torch.float8_e8m0fnu),
+        )
+
+    def triton_to_mxfp8_dim1_reference(
+        x_hp: torch.Tensor, block_size
+    ) -> Tuple[torch.Tensor, torch.Tensor]:
+        """
+        A reference version of `to_mxfp8_dim1`.
+        """
+        from torchao.prototype.mx_formats.mx_tensor import to_mx
+
+        # cast across dim1
+        x_hp_d1 = x_hp.t().contiguous()
+        scale_e8m0_dim1, x_hp_d1_normalized = to_mx(
+            x_hp_d1, torch.float8_e4m3fn, block_size
+        )
+        scale_e8m0_dim1 = scale_e8m0_dim1.unsqueeze(1).view(torch.float8_e8m0fnu)
+        return (
+            x_hp_d1_normalized.t(),
+            scale_e8m0_dim1,
+        )
+
+else:
+
+    def triton_to_mxfp8_dim1(
+        x, inner_block_size=32
+    ) -> Tuple[torch.Tensor, torch.Tensor]:
+        raise AssertionError("needs torch version 2.8+ and triton")
+
+    def triton_to_mxfp8_dim1_reference(
+        x_hp: torch.Tensor, block_size
+    ) -> Tuple[torch.Tensor, torch.Tensor]:
+        raise AssertionError("needs torch version 2.8+ and triton")
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/fp_format_spec.py b/lib/python3.12/site-packages/torchao/prototype/mx_formats/fp_format_spec.py
new file mode 100644
index 0000000000000000000000000000000000000000..bdc0cc4dfdf178c1e1bc62c503c542f808c22363
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/mx_formats/fp_format_spec.py
@@ -0,0 +1,544 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""
+A helper script to summarize the key numerical values of various floating
+point formats relevant to the MX spec.
+"""
+
+import math
+from typing import Tuple
+
+import tabulate
+import torch
+
+from torchao.prototype.mx_formats.constants import (
+    DTYPE_FP4,
+    DTYPE_FP6_E2M3,
+    DTYPE_FP6_E3M2,
+)
+from torchao.prototype.mx_formats.custom_cast import get_bits
+
+dtype_to_bitwidth = {
+    torch.float: 32,
+    torch.bfloat16: 16,
+    torch.float16: 16,
+    torch.float8_e4m3fn: 8,
+    torch.float8_e5m2: 8,
+    DTYPE_FP6_E3M2: 6,
+    DTYPE_FP6_E2M3: 6,
+}
+dtype_to_sem_len = {
+    torch.float: (1, 8, 23),
+    torch.bfloat16: (1, 8, 7),
+    torch.float16: (1, 5, 10),
+    torch.float8_e4m3fn: (1, 4, 3),
+    torch.float8_e5m2: (1, 5, 2),
+    # the line below is currently representing fp4 with bits 0:3 empty and
+    # bits 4:7 containing the fp4 encoding
+    # TODO(future): clean this up
+    torch.uint8: (1, 2, 1),
+}
+# bias = 2 ** (exp_bitwidth - 1) - 1
+dtype_to_exp_bias = {
+    torch.float: 127,
+    torch.bfloat16: 127,
+    torch.float16: 15,
+    torch.float8_e4m3fn: 7,
+    torch.float8_e5m2: 15,
+    DTYPE_FP6_E2M3: 1,
+    DTYPE_FP6_E3M2: 3,
+}
+dtype_to_int_dtype = {
+    torch.float: torch.int32,
+    torch.float16: torch.int16,
+    torch.bfloat16: torch.int16,
+    torch.float8_e4m3fn: torch.int8,
+    torch.float8_e5m2: torch.int8,
+    # for fp4
+    # TODO(future): clean it up
+    torch.uint8: torch.uint8,
+}
+
+# format:
+# {
+#   dtype: [
+#     [
+#       ref_f32_value, sign_encoding, exp_encoding, mantissa_encoding,
+#       description,
+#     ],
+#     ...,
+#   ],
+#   ...,
+# }
+dtype_to_interesting_values = {
+    torch.float: [
+        # zero and neg zero
+        (0.0, "0", "0" * 8, "0" * 23, "zero"),
+        (-0.0, "1", "0" * 8, "0" * 23, "zero_neg"),
+        # special values
+        (float("nan"), "0", "1" * 8, "1" + "0" * 22, "nan"),
+        (float("inf"), "0", "1" * 8, "0" * 23, "inf"),
+        (float("-inf"), "1", "1" * 8, "0" * 23, "inf_neg"),
+        # values below verified with from https://www.h-schmidt.net/FloatConverter/IEEE754.html  # noqa: E501
+        # largest normal
+        (
+            3.402823466385288598117042e38,
+            "0",
+            "1" * 7 + "0",
+            "1" * 23,
+            "largest_norm",
+        ),  # noqa: E501
+        (
+            -3.402823466385288598117042e38,
+            "1",
+            "1" * 7 + "0",
+            "1" * 23,
+            "largest_norm_neg",
+        ),
+        # smallest normal
+        (
+            1.175494350822287507968737e-38,
+            "0",
+            "0" * 7 + "1",
+            "0" * 23,
+            "smallest_norm",
+        ),  # noqa: E501
+        (
+            -1.175494350822287507968737e-38,
+            "1",
+            "0" * 7 + "1",
+            "0" * 23,
+            "smallest_norm_neg",
+        ),
+        # largest denormal
+        (
+            1.175494210692441075487029e-38,
+            "0",
+            "0" * 8,
+            "1" * 23,
+            "largest_denorm",
+        ),  # noqa: E501
+        (
+            -1.175494210692441075487029e-38,
+            "1",
+            "0" * 8,
+            "1" * 23,
+            "largest_denorm_neg",
+        ),  # noqa: E501
+        # smallest denormal
+        (
+            1.401298464324817070923730e-45,
+            "0",
+            "0" * 8,
+            "0" * 22 + "1",
+            "smallest_denorm",
+        ),
+        (
+            -1.401298464324817070923730e-45,
+            "1",
+            "0" * 8,
+            "0" * 22 + "1",
+            "smallest_denorm_neg",
+        ),
+        # positive and negative value
+        (30.0, "0", "10000011", "1" * 3 + "0" * 20, "random_pos"),
+        (-24.0, "1", "10000011", "1" + "0" * 22, "random_neg"),
+    ],
+    torch.bfloat16: [
+        # zero and neg zero
+        (0.0, "0", "0" * 8, "0" * 7, "zero"),
+        (-0.0, "1", "0" * 8, "0" * 7, "zero_neg"),
+        # special values
+        (float("nan"), "0", "1" * 8, "1" + "0" * 6, "nan"),
+        (float("inf"), "0", "1" * 8, "0" * 7, "inf"),
+        (float("-inf"), "1", "1" * 8, "0" * 7, "inf_neg"),
+        # values below checked with TODO
+        # largest normal
+        (3.38953e38, "0", "1" * 7 + "0", "1" * 7, "largest_norm"),
+        (-3.38953e38, "1", "1" * 7 + "0", "1" * 7, "largest_norm_neg"),
+        # smallest normal
+        (1.17549e-38, "0", "0" * 7 + "1", "0" * 7, "smallest_norm"),
+        (-1.17549e-38, "1", "0" * 7 + "1", "0" * 7, "smallest_norm_neg"),
+        # largest denormal
+        (1.16631e-38, "0", "0" * 8, "1" * 7, "largest_denorm"),
+        (-1.16631e-38, "1", "0" * 8, "1" * 7, "largest_denorm_neg"),
+        # smallest denormal
+        (9.18355e-41, "0", "0" * 8, "0" * 6 + "1", "smallest_denorm"),
+        (-9.18355e-41, "1", "0" * 8, "0" * 6 + "1", "smallest_denorm_neg"),
+        # positive and negative value
+        (30.0, "0", "10000011", "1" * 3 + "0" * 4, "random_pos"),
+        (-24.0, "1", "10000011", "1" + "0" * 6, "random_neg"),
+    ],
+    torch.float16: [
+        # zero and neg zero
+        (0.0, "0", "0" * 5, "0" * 10, "zero"),
+        (-0.0, "1", "0" * 5, "0" * 10, "zero_neg"),
+        # special values
+        (float("nan"), "0", "1" * 5, "1" + "0" * 9, "nan"),
+        (float("inf"), "0", "1" * 5, "0" * 10, "inf"),
+        (float("-inf"), "1", "1" * 5, "0" * 10, "inf_neg"),
+        # values below checked with https://en.wikipedia.org/wiki/Half-precision_floating-point_format  # noqa: E501
+        # largest normal
+        (65504, "0", "1" * 4 + "0", "1" * 10, "largest_normal"),
+        (-65504, "1", "1" * 4 + "0", "1" * 10, "largest_normal_neg"),
+        # smallest normal
+        (0.00006103515625, "0", "0" * 4 + "1", "0" * 10, "smallest_normal"),
+        (
+            -0.00006103515625,
+            "1",
+            "0" * 4 + "1",
+            "0" * 10,
+            "smallest_normal_neg",
+        ),  # noqa: E501
+        # largest denormal
+        (0.000060975552, "0", "0" * 5, "1" * 10, "largest_denorm"),
+        (-0.000060975552, "1", "0" * 5, "1" * 10, "largest_denorm_neg"),
+        # smallest denormal
+        (0.000000059604645, "0", "0" * 5, "0" * 9 + "1", "smallest_denorm"),
+        (
+            -0.000000059604645,
+            "1",
+            "0" * 5,
+            "0" * 9 + "1",
+            "smallest_denorm_neg",
+        ),  # noqa: E501
+        # positive and negative value
+        (30.0, "0", "10011", "1" * 3 + "0" * 7, "random_pos"),
+        (-24.0, "1", "10011", "1" + "0" * 9, "random_neg"),
+    ],
+    torch.float8_e4m3fn: [
+        # zero and neg zero
+        (0.0, "0", "0000", "000", "zero"),
+        (-0.0, "1", "0000", "000", "zero_neg"),
+        # special values
+        # note: no pos or neg inf
+        (float("nan"), "0", "1111", "111", "nan"),
+        # values below checked with https://arxiv.org/pdf/2209.05433.pdf, Table 1  # noqa: E501
+        # largest normal
+        (448.0, "0", "1111", "110", "largest_normal"),
+        (-448.0, "1", "1111", "110", "largest_normal_neg"),
+        # smallest normal
+        (2**-6, "0", "0001", "000", "smallest_normal"),
+        (-(2**-6), "1", "0001", "000", "smallest_normal_neg"),
+        # largest denormal
+        (0.875 * 2**-6, "0", "0000", "111", "largest_denormal"),
+        (-0.875 * 2**-6, "1", "0000", "111", "largest_denormal_neg"),
+        # smallest denormal
+        (2**-9, "0", "0000", "001", "smallest_denormal"),
+        (-(2**-9), "1", "0000", "001", "smallest_denormal_neg"),
+        # positive and negative value
+        (30.0, "0", "1011", "111", "random_pos"),
+        (-24.0, "1", "1011", "100", "random_neg"),
+    ],
+    torch.float8_e5m2: [
+        # zero and neg zero
+        (0.0, "0", "00000", "00", "zero"),
+        (-0.0, "1", "00000", "00", "zero_neg"),
+        # special values
+        (float("nan"), "0", "11111", "11", "nan"),
+        (float("inf"), "0", "11111", "00", "inf"),
+        (float("-inf"), "1", "11111", "00", "inf_neg"),
+        # values below checked with https://arxiv.org/pdf/2209.05433.pdf, Table 1  # noqa: E501
+        # largest normal
+        (57344.0, "0", "11110", "11", "largest_normal"),
+        (-57344.0, "1", "11110", "11", "largest_normal_neg"),
+        # smallest normal
+        (2**-14, "0", "00001", "00", "smallest_normal"),
+        (-(2**-14), "1", "00001", "00", "smallest_normal_neg"),
+        # largest denormal
+        (0.75 * 2**-14, "0", "00000", "11", "largest_denormal"),
+        (-0.75 * 2**-14, "1", "00000", "11", "largest_denormal_neg"),
+        # smallest denormal
+        (2**-16, "0", "00000", "01", "smallest_denormal"),
+        (-(2**-16), "1", "00000", "01", "smallest_denormal_neg"),
+        # positive and negative value
+        (32.0, "0", "10100", "00", "random_pos"),
+        (-24.0, "1", "10011", "10", "random_neg"),
+    ],
+}
+
+# values for fp4_e2m1, as defined in the OCP spec for MXFP4
+# other than the sign, there are only 8 values, so just create
+# the table by hand
+# formula norm: sign * (2 ** (exp - 1)) * 1.x
+# formula denorm: sign * (2 ** (exp - 1 + 1)) * 0.x
+# format: val, formula, s, e, m, val, note
+float4_e2m1_interesting_values = [
+    (0, "1.0 * 2^0 * 0.0", "0", "00", "0", "zero"),
+    # same as largest denormal, there is only one
+    (
+        0.5,
+        "1.0 * 2^0 * 0.5",
+        "0",
+        "00",
+        "1",
+        "smallest_denormal",
+    ),  # 2**0 * 0.5  # noqa: E501
+    (1.0, "1.0 * 2^0 * 1.0", "0", "01", "0", "smallest_normal"),  # 2**0 * 1.0
+    (1.5, "1.0 * 2^0 * 1.5", "0", "01", "1", "val3"),  # 2**0 * 1.5
+    (2.0, "1.0 * 2^1 * 1.0", "0", "10", "0", "val4"),  # 2**1 * 1.0
+    (3.0, "1.0 * 2^1 * 1.5", "0", "10", "1", "val5"),  # 2**1 * 1.5
+    (4.0, "1.0 * 2^2 * 1.0", "0", "11", "0", "val6"),  # 2**2 * 1.0
+    (6.0, "1.0 * 2^2 * 1.5", "0", "11", "1", "largest_normal"),  # 2**2 * 1.5
+]
+float4_e2m1_neg = []
+for fp32_ref, formula, _s, e, m, label in float4_e2m1_interesting_values:
+    float4_e2m1_neg.append([-1 * fp32_ref, "-" + formula, "1", e, m, label + "_neg"])  # noqa: E501
+float4_e2m1_interesting_values.extend(float4_e2m1_neg)
+del float4_e2m1_neg
+
+# https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf, section 5.3.2  # noqa: E501
+float6_e3m2_interesting_values = [
+    (0, "1.0 * 2^-2 * 0.0", "0", "000", "00", "zero"),
+    (0.0625, "1.0 * 2^-2 * 0.25", "0", "000", "01", "smallest_denormal"),
+    (0.1875, "1.0 * 2^-2 * 0.75", "0", "000", "11", "largest_denormal"),
+    (0.25, "1.0 * 2^-2 * 1.0", "0", "001", "00", "smallest_normal"),
+    (28.0, "1.0 * 2^4 * 1.75", "0", "111", "11", "largest_normal"),
+]
+float6_e3m2_neg = []
+for fp32_ref, formula, _s, e, m, label in float6_e3m2_interesting_values:
+    float6_e3m2_neg.append([-1 * fp32_ref, "-" + formula, "1", e, m, label + "_neg"])  # noqa: E501
+float6_e3m2_interesting_values.extend(float6_e3m2_neg)
+del float6_e3m2_neg
+
+# https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf, section 5.3.2  # noqa: E501
+float6_e2m3_interesting_values = [
+    (0, "1.0 * 2^0 * 0.0", "0", "00", "000", "zero"),
+    (0.125, "1.0 * 2^0 * 0.125", "0", "00", "001", "smallest_denormal"),
+    (0.875, "1.0 * 2^0 * 0.875", "0", "00", "111", "largest_denormal"),
+    (1.0, "1.0 * 2^0 * 1.0", "0", "01", "000", "smallest_normal"),
+    (7.5, "1.0 * 2^2 * 1.875", "0", "11", "111", "largest_normal"),
+]
+float6_e2m3_neg = []
+for fp32_ref, formula, _s, e, m, label in float6_e2m3_interesting_values:
+    float6_e2m3_neg.append(
+        [
+            -1 * fp32_ref,
+            "-" + formula,
+            "1",
+            e,
+            m,
+            label + "_neg",
+        ]
+    )
+float6_e2m3_interesting_values.extend(float6_e2m3_neg)
+del float6_e2m3_neg
+
+
+def _assert_equals(fp_ref, s_enc_ref, e_enc_ref, m_enc_ref, dtype):
+    # test going from float to encoding
+    x = torch.tensor(fp_ref, dtype=dtype)
+    bitwidth = dtype_to_bitwidth[dtype]
+    s_enc, e_enc, m_enc = get_sem_bits(x, bitwidth=bitwidth)
+    assert s_enc_ref == s_enc
+    assert e_enc_ref == e_enc, f"{e_enc_ref} != {e_enc}"
+    assert m_enc_ref == m_enc, f"{m_enc_ref} != {m_enc}"
+
+    # test going from encoding to float
+    s_i, e_i, m_f, special_value = sem_bits_to_sem_vals(
+        s_enc,
+        e_enc,
+        m_enc,
+        dtype,
+    )
+    fp = sem_vals_to_f32(s_i, e_i, m_f, special_value)
+    assert_same(fp_ref, fp)
+
+
+def get_sem_bits(x: torch.Tensor, bitwidth: int) -> Tuple[str, str, str]:
+    """
+    Input: a tensor with a single element of the target element dtype
+    - for PT core dtypes, that dtype (fp32, fp16, fp8_e4m3, etc)
+    - for fp4_e2m1, fp6_e3m2, fp6_e2m3, not supported in this function
+    Output: bit strings for sign, exponent, mantissa encodings of the input
+    """
+    assert x.numel() == 1
+    s_len, e_len, m_len = dtype_to_sem_len[x.dtype]
+
+    new_dtype = dtype_to_int_dtype[x.dtype]
+    x = x.view(new_dtype)
+    np_res = get_bits(x)
+    if bitwidth == 4:
+        # TODO(future): clean up this fp4 codepath
+        offset = 4
+        s, e, m = (
+            np_res[offset],
+            np_res[offset + s_len : (offset + s_len + e_len)],  # noqa: E203
+            np_res[(offset + s_len + e_len) :],  # noqa: E203
+        )
+    else:
+        s, e, m = (
+            np_res[0],
+            np_res[s_len : (s_len + e_len)],  # noqa: E203
+            np_res[(s_len + e_len) :],  # noqa: E203
+        )
+    assert len(s) == s_len
+    assert len(e) == e_len
+    assert len(m) == m_len
+    return s, e, m
+
+
+def exp_encoding_to_exp(exp_bit_str: str, dtype):
+    """
+    Input: bit string of exponent for dtype
+    Output: integer representation of exponent
+    """
+    exp_biased = int(exp_bit_str, 2)
+    exp_bias = dtype_to_exp_bias[dtype]
+    exp_unbiased = exp_biased - exp_bias
+
+    # for denormalized values, increment exponent back
+    # up by one
+    if all(b == "0" for b in exp_bit_str):
+        exp_unbiased += 1
+
+    return exp_unbiased
+
+
+def sem_bits_to_sem_vals(s_enc, e_enc, m_enc, dtype):
+    """
+    Input: encodings of sign, exponent, mantissa for dtype
+    Output: integer sign, integer exponent, float32 mantissa, special value
+
+    Supported dtypes: PT core dtypes and fp6_e3m2 and fp6_e2m3
+    Not supported dtypes: fp4
+
+    If special value is filled out, sem are none
+    If sem are filled out, special value is none
+    """
+    sign = 1 if s_enc == "0" else -1
+
+    # handle special values
+    if all(bit == "1" for bit in e_enc):
+        dtypes = (
+            torch.float32,
+            torch.bfloat16,
+            torch.float16,
+            torch.float8_e5m2,
+        )
+        if dtype in dtypes:
+            if all(bit == "0" for bit in m_enc):
+                if s_enc == "0":
+                    return None, None, None, float("inf")
+                else:
+                    return None, None, None, float("-inf")
+            else:
+                return None, None, None, float("nan")
+        elif dtype in (DTYPE_FP6_E2M3, DTYPE_FP6_E3M2):
+            # no special values in f6 dtypes
+            pass
+        else:
+            assert dtype is torch.float8_e4m3fn
+            # 1. float8_e4m3fn does not have infinity
+            # 2. float8_e4m3fn only sets {s}.{1111}.{111} for nan
+            if all(b == "1" for b in e_enc + m_enc):
+                return None, None, None, float("nan")
+
+    exponent = exp_encoding_to_exp(e_enc, dtype)
+
+    is_zero = all(b == "0" for b in e_enc + m_enc)
+    is_denormal = (not is_zero) and all(b == "0" for b in e_enc)
+    is_normal = not is_zero and not is_denormal
+
+    if is_zero:
+        return sign, exponent, 0.0, None
+
+    mantissa = 1.0 if is_normal else 0.0
+    cur_pow_2 = -1
+    for m_bit in m_enc:
+        mantissa += int(m_bit) * pow(2, cur_pow_2)
+        cur_pow_2 -= 1
+    return sign, exponent, mantissa, None
+
+
+def sem_vals_to_f32(s_i, e_i, m_f, special_value):
+    """
+    Input: integer sign, integer exponent, float32 mantissa, special value
+    Output: float32 value
+    """
+    if special_value is not None:
+        return special_value
+    f = s_i * pow(2, e_i) * m_f
+    return f
+
+
+def sem_vals_to_formula(s_i, e_i, m_f, special_value):
+    """
+    Input: integer sign, integer exponent, float32 mantissa, special value
+    Output: formula to get the float32 value
+    """
+    if special_value is not None:
+        return special_value
+    return f"{s_i} * 2^{e_i} * {m_f}"
+
+
+def assert_same(fp1, fp2):
+    if math.isnan(fp1):
+        assert math.isnan(fp2)
+    elif math.isinf(fp1):
+        if fp1 > 0:
+            assert math.isinf(fp2) and fp2 > 0
+        else:
+            assert math.isinf(fp2) and fp2 < 0
+    else:
+        assert (abs(fp2 - fp1) / (fp1 + 1e-20)) - 1 < 1e-12, f"{fp2} != {fp1}"
+
+
+def run(dtype):
+    print("dtype", dtype)
+
+    headers = ["orig_val", "formula", "s_enc", "e_enc", "m_enc", "note"]
+    results = []
+
+    if dtype == DTYPE_FP4:
+        results = float4_e2m1_interesting_values
+    elif dtype == DTYPE_FP6_E3M2:
+        results = float6_e3m2_interesting_values
+    elif dtype == DTYPE_FP6_E2M3:
+        results = float6_e2m3_interesting_values
+    else:
+        interesting_values = dtype_to_interesting_values[dtype]
+        for row in interesting_values:
+            fp_ref, s_enc_ref, e_enc_ref, m_enc_ref, notes = row
+
+            # test that things still work
+            _assert_equals(fp_ref, s_enc_ref, e_enc_ref, m_enc_ref, dtype)
+
+            # create the formula
+            s_i, e_i, m_f, special_value = sem_bits_to_sem_vals(
+                s_enc_ref, e_enc_ref, m_enc_ref, dtype
+            )
+            formula = sem_vals_to_formula(s_i, e_i, m_f, special_value)
+
+            # create the table row
+            results.append(
+                [
+                    fp_ref,
+                    formula,
+                    s_enc_ref,
+                    e_enc_ref,
+                    m_enc_ref,
+                    notes,
+                ]
+            )
+
+    print(tabulate.tabulate(results, headers=headers))
+    print("\n")
+
+
+if __name__ == "__main__":
+    for dtype in (
+        torch.float,
+        torch.bfloat16,
+        torch.float16,
+        torch.float8_e4m3fn,
+        torch.float8_e5m2,
+        DTYPE_FP6_E3M2,
+        DTYPE_FP6_E2M3,
+        DTYPE_FP4,
+    ):
+        run(dtype)
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/mx_linear.py b/lib/python3.12/site-packages/torchao/prototype/mx_formats/mx_linear.py
new file mode 100644
index 0000000000000000000000000000000000000000..067613afb7cfd52496980654a372fa472f1fdac9
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/mx_formats/mx_linear.py
@@ -0,0 +1,283 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""
+Defines the prototype UX for converting a model to use mx weights
+"""
+
+from typing import Any, Optional
+
+import torch
+import torch.nn.functional as F
+
+from torchao.prototype.mx_formats.config import (
+    MXGemmKernelChoice,
+    MXInferenceLinearConfig,
+    MXLinearConfig,
+)
+from torchao.prototype.mx_formats.custom_cast import triton_to_mxfp8_dim1
+from torchao.prototype.mx_formats.mx_tensor import MXTensor
+from torchao.quantization.transform_module import (
+    register_quantize_module_handler,
+)
+
+
+@torch._dynamo.allow_in_graph
+class mx_mm(torch.autograd.Function):
+    # There are three gemms in a forward + backward of a Linear layer:
+    #
+    # 1.       input @ weight_t    = output     (forward pass)
+    # 2. grad_output @ weight      = grad_input (backward pass)
+    # 3.     input_t @ grad_output = grad_weight (backward pass)
+    #
+    # input, weight and grad_output can have each their own MX element dtype.
+
+    @staticmethod
+    def forward(
+        ctx,
+        input_hp: torch.Tensor,
+        weight_hp: torch.Tensor,
+        in_elem_dtype: Any,
+        w_elem_dtype: Any,
+        grad_elem_dtype: Any,
+        block_size: int,
+        gemm_kernel_choice: MXGemmKernelChoice,
+        use_fp8_dim1_cast_triton_kernel: bool,
+    ):
+        ctx.save_for_backward(input_hp, weight_hp)
+        ctx.in_elem_dtype = in_elem_dtype
+        ctx.w_elem_dtype = w_elem_dtype
+        ctx.grad_elem_dtype = grad_elem_dtype
+        ctx.block_size = block_size
+        ctx.gemm_kernel_choice = gemm_kernel_choice
+        ctx.use_fp8_dim1_cast_triton_kernel = use_fp8_dim1_cast_triton_kernel
+
+        # input @ weight_t = output
+        input_orig_shape = input_hp.shape
+        input_hp_r = input_hp.reshape(-1, input_orig_shape[-1])
+
+        input_mx_r_dim0 = MXTensor.to_mx(
+            input_hp_r, in_elem_dtype, block_size, gemm_kernel_choice=gemm_kernel_choice
+        )
+        weight_mx_dim0 = MXTensor.to_mx(
+            weight_hp, w_elem_dtype, block_size, gemm_kernel_choice=gemm_kernel_choice
+        )
+        output = torch.mm(input_mx_r_dim0, weight_mx_dim0.t())
+        output = output.reshape(*input_orig_shape[:-1], output.shape[-1])
+
+        return output
+
+    @staticmethod
+    def backward(ctx, grad_output_hp: torch.Tensor):
+        input_hp, weight_hp = ctx.saved_tensors
+        in_elem_dtype = ctx.in_elem_dtype
+        w_elem_dtype = ctx.w_elem_dtype
+        grad_elem_dtype = ctx.grad_elem_dtype
+        block_size = ctx.block_size
+        gemm_kernel_choice = ctx.gemm_kernel_choice
+        use_fp8_dim1_cast_triton_kernel = ctx.use_fp8_dim1_cast_triton_kernel
+
+        grad_output_orig_shape = grad_output_hp.shape
+        grad_output_hp_r = grad_output_hp.reshape(-1, grad_output_orig_shape[-1])
+
+        input_hp_orig_shape = input_hp.shape
+        input_hp_r = input_hp.reshape(-1, input_hp_orig_shape[-1])
+
+        # grad_output @ weight = grad_input
+        grad_output_mx_dim0 = MXTensor.to_mx(
+            grad_output_hp_r,
+            grad_elem_dtype,
+            block_size,
+            gemm_kernel_choice=gemm_kernel_choice,
+        )
+
+        if use_fp8_dim1_cast_triton_kernel:
+            weight_mx_dim1_data, weight_mx_dim1_scale = triton_to_mxfp8_dim1(
+                weight_hp, block_size
+            )
+            weight_mx_dim1 = MXTensor(
+                weight_mx_dim1_scale.reshape(-1),
+                weight_mx_dim1_data.t(),
+                w_elem_dtype,
+                block_size,
+                weight_hp.dtype,
+                False,
+                gemm_kernel_choice,
+                False,
+            )
+
+        else:
+            weight_hp_t_c = weight_hp.t().contiguous()
+            weight_mx_dim1 = MXTensor.to_mx(
+                weight_hp_t_c,
+                w_elem_dtype,
+                block_size,
+                gemm_kernel_choice=gemm_kernel_choice,
+            )
+        grad_input = torch.mm(grad_output_mx_dim0, weight_mx_dim1.t())
+        grad_input = grad_input.reshape(
+            *grad_output_orig_shape[:-1], grad_input.shape[-1]
+        )
+
+        # input_t @ grad_output = grad_weight
+        if use_fp8_dim1_cast_triton_kernel:
+            grad_output_mx_dim1_data, grad_output_mx_dim1_scale = triton_to_mxfp8_dim1(
+                grad_output_hp_r, block_size
+            )
+            grad_output_mx_dim1 = MXTensor(
+                grad_output_mx_dim1_scale.reshape(-1),
+                grad_output_mx_dim1_data.t(),
+                grad_elem_dtype,
+                block_size,
+                grad_output_hp_r.dtype,
+                False,
+                gemm_kernel_choice,
+                False,
+            )
+        else:
+            grad_output_mx_dim1 = MXTensor.to_mx(
+                grad_output_hp_r.t().contiguous(),
+                grad_elem_dtype,
+                block_size,
+                gemm_kernel_choice=gemm_kernel_choice,
+            )
+
+        if use_fp8_dim1_cast_triton_kernel:
+            input_t_mx_dim0_tmp_data, input_t_mx_dim0_tmp_scale = triton_to_mxfp8_dim1(
+                input_hp_r, block_size
+            )
+            input_t_mx_dim0_tmp = MXTensor(
+                input_t_mx_dim0_tmp_scale.reshape(-1),
+                input_t_mx_dim0_tmp_data.t(),
+                in_elem_dtype,
+                block_size,
+                input_hp_r.dtype,
+                False,
+                gemm_kernel_choice,
+                False,
+            )
+            input_t_mx_dim0 = input_t_mx_dim0_tmp.t()
+        else:
+            input_t_mx_dim0_tmp = MXTensor.to_mx(
+                input_hp_r.t().contiguous(),
+                in_elem_dtype,
+                block_size,
+                gemm_kernel_choice=gemm_kernel_choice,
+            )
+            input_t_mx_dim0 = input_t_mx_dim0_tmp.t()
+        grad_weight = torch.mm(grad_output_mx_dim1, input_t_mx_dim0)
+
+        return grad_input, grad_weight, None, None, None, None, None, None
+
+
+class MXLinear(torch.nn.Linear):
+    """
+    Linear layer with the compute happening in emulate MX. Currently the MX
+    matmul is emulated since there is no hardware support yet. Activations,
+    weights and grads are casted to MX and back to high precision for each
+    matmul.
+
+    Input, weight and grad_output can have each their own MX element dtype.
+    """
+
+    @classmethod
+    @torch.no_grad()
+    def from_float(
+        cls,
+        mod,
+        config: Optional[MXLinearConfig] = MXLinearConfig(),
+    ):
+        assert isinstance(mod, torch.nn.Linear), f"unsupported type(mod) {type(mod)}"
+        assert isinstance(config, MXLinearConfig)
+        mod.__class__ = MXLinear
+        mod.config = config
+        return mod
+
+    def forward(self, x):
+        if torch.is_autocast_enabled():
+            # special case autocast
+            autocast_dtype = torch.get_autocast_dtype("cuda")
+            x = x.to(autocast_dtype)
+            w = self.weight.to(autocast_dtype)
+        else:
+            w = self.weight
+
+        config = self.config
+        y = mx_mm.apply(
+            x,
+            w,
+            config.elem_dtype,
+            config.elem_dtype_weight_override or config.elem_dtype,
+            config.elem_dtype_grad_output_override or config.elem_dtype,
+            config.block_size,
+            config.gemm_kernel_choice,
+            config.use_fp8_dim1_cast_triton_kernel,
+        )
+        if self.bias is not None:
+            y = y + self.bias
+        return y
+
+    def extra_repr(self):
+        s = f"{super().extra_repr()}, {self.config.short_str()}"
+        return s
+
+
+class MXInferenceLinear(torch.nn.Linear):
+    """
+    Inference version of MXLinear, with the weight pre-quantized to MX.
+
+    Note: this is weight-only quantization, with the gemm being executed
+    in high precision.
+    """
+
+    @classmethod
+    @torch.no_grad()
+    def from_float(
+        cls,
+        mod,
+        config: Optional[MXInferenceLinearConfig] = MXInferenceLinearConfig(),
+    ):
+        with torch.device("meta"):
+            super_kwargs = {
+                "in_features": mod.in_features,
+                "out_features": mod.out_features,
+                "bias": False,
+            }
+            new_mod = cls(**super_kwargs)
+        # TODO(future PR): set to new_mod.weight directly, will need to work
+        # through some errors
+        new_mod.weight_mx = MXTensor.to_mx(
+            mod.weight,
+            config.elem_dtype,
+            block_size=config.block_size,
+            gemm_kernel_choice=config.gemm_kernel_choice,
+            pack_fp6=config.pack_fp6,
+        )
+        new_mod.bias = mod.bias
+        new_mod.config = config
+        return new_mod
+
+    @torch.no_grad()
+    def forward(self, x):
+        w_hp = self.weight_mx.to_dtype(x.dtype)
+        y = F.linear(x, w_hp, self.bias)
+        return y
+
+    def extra_repr(self):
+        s = f"{super().extra_repr()}, {self.config.short_str()}"
+        return s
+
+
+@register_quantize_module_handler(MXLinearConfig)
+def _mx_linear_transform(module: torch.nn.Module, config: MXLinearConfig):
+    return MXLinear.from_float(module, config=config)
+
+
+@register_quantize_module_handler(MXInferenceLinearConfig)
+def _mx_inference_linear_transform(
+    module: torch.nn.Module, config: MXInferenceLinearConfig
+):
+    return MXInferenceLinear.from_float(module, config=config)
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/mx_ops.py b/lib/python3.12/site-packages/torchao/prototype/mx_formats/mx_ops.py
new file mode 100644
index 0000000000000000000000000000000000000000..af2d89c11288d5529d05b7cbca3dc5046771ed91
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/mx_formats/mx_ops.py
@@ -0,0 +1,203 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""
+This file defines the ops needed for our tensor subclass implementation
+of `MXTensor` to work naturally in PyTorch programs.  For example, if
+the modeling code is written as
+
+  x_mx = MXTensor.to_mx(x, torch.float8_e4m3fn)
+  w_mx = MXTensor.to_mx(w, torch.float8_e4m3fn)
+  y = F.linear(x_mx, w_mx)
+
+then the ops in this file are used under the hood to properly route
+the underlying data fields to the MX matmul.
+"""
+
+from typing import Any, Dict
+
+import torch
+from torch.utils._pytree import tree_map
+
+import torchao.ops
+from torchao.prototype.mx_formats.config import MXGemmKernelChoice
+from torchao.prototype.mx_formats.constants import (
+    DTYPE_FP4,
+    DTYPE_FP6_E2M3,
+    DTYPE_FP6_E3M2,
+)
+from torchao.prototype.mx_formats.mx_tensor import (  # noqa: E501
+    MXTensor,
+    tensor_size_hp_to_fp4x2,
+    tensor_size_hpx3_to_fp6x4,
+)
+from torchao.prototype.mx_formats.utils import to_blocked
+
+aten = torch.ops.aten
+
+MX_OPS_TABLE: Dict[Any, Any] = {}
+
+
+def implements(aten_ops):
+    """Register aten ops to the mx op table"""
+
+    def decorator(func):
+        for op in aten_ops:
+            MX_OPS_TABLE[op] = func
+        return func
+
+    return decorator
+
+
+@implements([aten.detach.default])
+def mx_desugar_op(aten_op, args, kwargs=None):
+    old = args[0]
+    new_data = aten_op(old._data, *args[1:], **kwargs)
+    new = MXTensor(
+        old._scale_e8m0,
+        new_data,
+        old._elem_dtype,
+        old._block_size,
+        old._orig_dtype,
+        old._use_fp4_custom_triton_dequant_kernel,
+        old._gemm_kernel_choice,
+        old._pack_fp6,
+    )
+    return new
+
+
+@implements([aten.mm.default, aten.matmul.default])
+def mx_mm(aten_op, args, kwargs=None):
+    a = args[0]
+    b = args[1]
+    assert isinstance(a, MXTensor) and isinstance(b, MXTensor)
+    assert a._gemm_kernel_choice == b._gemm_kernel_choice, "unsupported"
+    if a._gemm_kernel_choice in (MXGemmKernelChoice.CUBLAS, MXGemmKernelChoice.CUTLASS):
+        # real MX gemm backed by torchao's CUTLASS kernels
+        M, K, N = a.shape[0], a.shape[1], b.shape[1]
+        assert a._data.is_contiguous()
+        assert b._data.t().is_contiguous()
+
+        # TODO(future PR): use block_size instead of hardcoding 32
+        a_scale = a._scale_e8m0.view(M, K // 32)
+        b_scale = b._scale_e8m0.view(N, K // 32)
+        a_scale_block = to_blocked(a_scale)
+        b_scale_block = to_blocked(b_scale)
+        if a._elem_dtype == torch.float8_e4m3fn:
+            assert b._elem_dtype == torch.float8_e4m3fn
+            assert a._gemm_kernel_choice is MXGemmKernelChoice.CUBLAS, (
+                "CUBLAS is the only supported kernel choice for MX FP8 operations"
+            )
+            res = torch._scaled_mm(
+                a._data,
+                b._data,
+                a_scale_block.view(torch.float8_e8m0fnu),
+                b_scale_block.view(torch.float8_e8m0fnu),
+                out_dtype=torch.bfloat16,
+            )
+        else:
+            assert a._elem_dtype == DTYPE_FP4
+            assert b._elem_dtype == DTYPE_FP4
+            assert a._gemm_kernel_choice is MXGemmKernelChoice.CUTLASS, "unsupported"
+            res = torchao.ops.mx_fp4_bf16(
+                a._data, b._data, a_scale_block, b_scale_block
+            )
+    else:
+        # emulated MX gemm
+        a_hp = a.to_dtype(a._orig_dtype)
+        b_hp = b.to_dtype(b._orig_dtype)
+        # assert memory layout we expect to be required in hardware
+        assert a_hp.is_contiguous()
+        assert b_hp.t().is_contiguous()
+        res = aten_op(a_hp, b_hp)
+    return res
+
+
+@implements([aten.t.default])
+def mx_t(aten_op, args, kwargs=None):
+    # For now, only transpose(input, 0, 1) is supported.
+    old = args[0]
+    new = MXTensor(
+        old._scale_e8m0,
+        old._data.t(),
+        old._elem_dtype,
+        old._block_size,
+        old._orig_dtype,
+        old._use_fp4_custom_triton_dequant_kernel,
+        old._gemm_kernel_choice,
+        old._pack_fp6,
+    )
+    return new
+
+
+@implements([aten.sum.dim_IntList])
+def mx_cast_up_op(aten_op, args, kwargs=None):
+    """Be careful with this function, this is a "fallback" op that
+    casts the output of the op to the original precision. And performs the op.
+
+    We currently need this to support the backward for admmm bias.
+    "addmm" -> out
+    "hp_gradBias" <-"sum" <- "identity" <- gradOut <- "hp_gradOut"
+    """
+
+    def unwrap(x):
+        if isinstance(x, MXTensor):
+            return x.to_dtype(x._orig_dtype)
+        return x
+
+    new_args = tree_map(unwrap, args)
+    new_kwargs = tree_map(unwrap, kwargs)
+    return aten_op(*new_args, **new_kwargs)
+
+
+@implements([aten.view.default])
+def mx_view_op(aten_op, args, kwargs=None):
+    data = args[0]._data
+    new_size = args[1]
+    if args[0]._elem_dtype == DTYPE_FP4:
+        # special case fp4 as we pack two elements per byte
+        new_size = tensor_size_hp_to_fp4x2(new_size, data.is_contiguous())
+    elif args[0]._elem_dtype in [DTYPE_FP6_E3M2, DTYPE_FP6_E2M3] and args[0]._pack_fp6:
+        # special case fp6 as we pack 4 elements in 3 bytes
+        new_size = tensor_size_hpx3_to_fp6x4(new_size, data.is_contiguous())
+    new_data = aten_op(data, new_size, *args[2:], **kwargs)
+    return MXTensor(
+        args[0]._scale_e8m0,
+        new_data,
+        args[0]._elem_dtype,
+        args[0]._block_size,
+        args[0]._orig_dtype,
+        args[0]._use_fp4_custom_triton_dequant_kernel,
+        args[0]._gemm_kernel_choice,
+        args[0]._pack_fp6,
+    )
+
+
+@implements([aten._to_copy.default])
+def autocast_to_copy(aten_op, args, kwargs=None):
+    """This gets called when running matmul under autocast
+    when the input is a MXTensor, presenting as a fp32
+    tensor.
+    """
+    assert isinstance(args[0], MXTensor)
+    assert len(kwargs) == 1 and "dtype" in kwargs, (
+        "Only support dtype kwarg for autocast"
+    )
+    assert kwargs["dtype"] in {
+        torch.float16,
+        torch.bfloat16,
+    }, "Only support floating point conversion for autocast w/ MXTensor"
+    res = MXTensor(
+        args[0]._scale_e8m0,
+        args[0]._data,
+        args[0]._elem_dtype,
+        args[0]._block_size,
+        kwargs["dtype"],
+        args[0]._use_fp4_custom_triton_dequant_kernel,
+        args[0]._gemm_kernel_choice,
+        args[0]._pack_fp6,
+    )
+    return res
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/mx_tensor.py b/lib/python3.12/site-packages/torchao/prototype/mx_formats/mx_tensor.py
new file mode 100644
index 0000000000000000000000000000000000000000..f3aca15a73e1ea3cb1f7a43aabeaaaf9f1f41072
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/mx_formats/mx_tensor.py
@@ -0,0 +1,635 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# Copyright (c) 2025, NVIDIA CORPORATION.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+"""
+Defines the tensor subclasses to represent the MX format spec from
+https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
+
+Exponent E8M0 encoding details (OCP spec section 5.4.1):
+  * bias: 127
+  * supported exponent range: -127 to 127
+  * infinities: N/A
+  * NaN: 11111111
+  * Zeros: N/A
+"""
+
+from enum import Enum, auto
+from typing import Dict, Union
+
+import torch
+
+from torchao.prototype.mx_formats.config import MXGemmKernelChoice
+from torchao.prototype.mx_formats.constants import (
+    BF16_EXP_BIAS,
+    BLOCK_SIZE_DEFAULT,
+    DTYPE_FP4,
+    DTYPE_FP6_E2M3,
+    DTYPE_FP6_E3M2,
+    E8M0_EXPONENT_BIAS,
+    E8M0_EXPONENT_NAN_VAL,
+    F4_E2M1_MAX,
+    F4_E2M1_MAX_POW2,
+    F6_E2M3_MAX,
+    F6_E2M3_MAX_POW2,
+    F6_E3M2_MAX,
+    F6_E3M2_MAX_POW2,
+    F8E4M3_MAX,
+    F8E4M3_MAX_POW2,
+    F8E5M2_MAX,
+    F8E5M2_MAX_POW2,
+    F32_EXP_BIAS,
+    F32_MIN_NORMAL,
+    SUPPORTED_ELEM_DTYPES,
+)
+from torchao.prototype.mx_formats.custom_cast import (
+    f4_unpacked_to_f32,
+    f6_e2m3_unpacked_to_f32,
+    f6_e3m2_unpacked_to_f32,
+    f32_to_f4_unpacked,
+    f32_to_f6_e2m3_unpacked,
+    f32_to_f6_e3m2_unpacked,
+    pack_uint4,
+    pack_uint6,
+    triton_f4_to_scaled_bf16,
+    triton_f6_e2m3_to_scaled_bf16,
+    triton_f6_e3m2_to_scaled_bf16,
+    unpack_uint4,
+)
+
+# TODO(later): read from somewhere else?
+SBITS, EBITS_F32, MBITS_F32 = 1, 8, 23
+EBITS_BF16, MBITS_BF16 = 8, 7
+EBITS_F4_E2M1, MBITS_F4_E2M1 = 2, 1
+EBITS_F6_E2M3, MBITS_F6_E2M3 = 2, 3
+EBITS_F6_E3M2, MBITS_F6_E3M2 = 3, 2
+EBITS_F8_E4M3, MBITS_F8_E4M3 = 4, 3
+EBITS_F8_E5M2, MBITS_F8_E5M2 = 5, 2
+
+
+class ScaleCalculationMode(Enum):
+    """
+    Enum representing the different methods for calculating MX block scaling.
+    There are three methods available:
+    FLOOR: This method is recommended by the OCP MX Spec 1.0 and uses X = 2^floor(log2(max_abs(v))-max_exp).
+           It result in overflow issues for large values and bad for gradient quantization.
+    CEIL: This method avoids overflow issues, but small values may shift to 0 due to a large scaling factor.
+           It uses X = 2^ceil(log2(max_abs(v))-max_exp).
+    EVEN: This method is a trade-off between Option 1 and Option 2. It uses X = 2^(floor(log2(rounding(max_abs(v)))-max_exp)).
+           It provides better accuracy for MX4 training compared to FLOOR and CEIL.
+    RCEIL: The method is to apply ceil to the ratio of max_abs(v) and max_pos.
+           This method's detail is described in https://docs.nvidia.com/cuda/cublas/index.html#d-block-quantization
+           Section "Computing scaling and conversion factors for FP8 with UE8M0 scales"
+
+    By default, we use the EVEN method for better accuracy.
+    """
+
+    FLOOR = auto()
+    CEIL = auto()
+    EVEN = auto()
+    RCEIL = auto()
+
+
+def _to_mx_rceil(
+    data_hp: torch.Tensor,
+    max_abs: torch.Tensor,
+    max_pos: float,
+) -> tuple[torch.Tensor, torch.Tensor]:
+    """
+    A prototype implementation of MXFP scale factor derivation method described in
+    https://docs.nvidia.com/cuda/cublas/#d-block-quantization
+
+    For Nvidia GPU with Blackwell+ architecture, the scale factor derivation method
+    could be accelerated by the `cvt.rp.satfinite.ue8m0x2.f32` instruction.
+
+    Args:
+        data_hp: High precision data.
+        max_abs: Maximum absolute value for data_hp along specified dimension/block_size.
+        max_pos: The maximum value of the low precision data type.
+
+    Returns:
+        exponent: The biased exponent with dtype E8M0 in uint8 container.
+        data_lp: The targeted low precision data, in high precision container
+            (requires cast to low precision data type).
+    """
+    descale = max_abs / max_pos
+    # TODO: nan/inf needs to be set for any value
+    # of nan/inf in input not just amax.
+    exponent = torch.where(
+        torch.isnan(descale),
+        0xFF,  # Handle biased exponent for nan
+        # NOTE: descale < (torch.finfo(torch.float32).smallest_normal / 2) is handled through clamping
+        (
+            torch.clamp(
+                torch.ceil(torch.log2(descale)),
+                min=-E8M0_EXPONENT_BIAS,
+                max=E8M0_EXPONENT_BIAS,
+            )
+            + E8M0_EXPONENT_BIAS
+        ).to(torch.uint8),
+    )
+
+    descale_fp = torch.where(
+        exponent == 0, 1.0, torch.exp2(E8M0_EXPONENT_BIAS - exponent.to(torch.float32))
+    )
+
+    # scale and saturated cast the data elements to max of target dtype
+    data_lp = torch.clamp(
+        data_hp * descale_fp.unsqueeze(1), min=-1 * max_pos, max=max_pos
+    )
+    return exponent, data_lp
+
+
+def to_mx(
+    data_hp: torch.Tensor,
+    elem_dtype: Union[torch.dtype, str],
+    block_size: int,
+    scaling_mode: ScaleCalculationMode = ScaleCalculationMode.FLOOR,
+    pack_fp6: bool = False,
+):
+    """
+    Takes a high precision tensor and converts to MX scale and raw data, in
+    naive layout (scale and raw data are separate tensors).
+    """
+
+    assert data_hp.dtype in (
+        torch.bfloat16,
+        torch.float,
+    ), f"{data_hp.dtype} is not supported yet"
+    # TODO(future PR): consider supporting padding
+    assert data_hp.numel() % block_size == 0, "unsupported"
+    assert data_hp.is_contiguous(), "unsupported"
+    assert elem_dtype in SUPPORTED_ELEM_DTYPES, "unsupported"
+
+    # calculate the scale in e8m0 format
+
+    orig_shape = data_hp.shape
+    data_hp = data_hp.reshape(-1, block_size)
+
+    # find max value of the data
+    # Note: this only implements the `minimally supported` version of
+    # https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
+    # section 6.3.
+    max_abs = torch.amax(torch.abs(data_hp), 1)
+
+    # Add an epsilon to prevent the log2 function call for returning -inf
+    # where the values are zero.
+    eps = F32_MIN_NORMAL * (max_abs == 0).type(max_abs.dtype)
+
+    # Set X to be the largest power-of-two less than or equal to
+    # max_abs(v), divided by the largest power of two representable
+    # in the element data type, and get the mbits at the same time
+    if elem_dtype == torch.float8_e4m3fn:
+        target_max_pow2 = F8E4M3_MAX_POW2
+        mbits = MBITS_F8_E4M3
+        max_pos = F8E4M3_MAX
+    elif elem_dtype == torch.float8_e5m2:
+        target_max_pow2 = F8E5M2_MAX_POW2
+        mbits = MBITS_F8_E5M2
+        max_pos = F8E5M2_MAX
+    elif elem_dtype == DTYPE_FP6_E2M3:
+        target_max_pow2 = F6_E2M3_MAX_POW2
+        mbits = MBITS_F6_E2M3
+        max_pos = F6_E2M3_MAX
+    elif elem_dtype == DTYPE_FP6_E3M2:
+        target_max_pow2 = F6_E3M2_MAX_POW2
+        mbits = MBITS_F6_E3M2
+        max_pos = F6_E3M2_MAX
+    elif elem_dtype == DTYPE_FP4:
+        target_max_pow2 = F4_E2M1_MAX_POW2
+        mbits = MBITS_F4_E2M1
+        max_pos = F4_E2M1_MAX
+    else:
+        raise AssertionError("unsupported element dtype")
+
+    if scaling_mode == ScaleCalculationMode.RCEIL:
+        scale_e8m0_biased, data_lp = _to_mx_rceil(data_hp, max_abs, max_pos)
+    else:
+        if data_hp.dtype is torch.float32:
+            hp_int_dtype = torch.int32
+            hp_mbits = MBITS_F32
+            hp_ebits = EBITS_F32
+            hp_exp_bias = F32_EXP_BIAS
+        else:
+            assert data_hp.dtype is torch.bfloat16
+            hp_int_dtype = torch.int16
+            hp_mbits = MBITS_BF16
+            hp_ebits = EBITS_BF16
+            hp_exp_bias = BF16_EXP_BIAS
+
+        # rounding before calculating the largest power of 2
+        # X = 2^(floor(log2(rounding(max_abs(v)))-max_exp))
+        if scaling_mode == ScaleCalculationMode.EVEN:
+            nan_mask = torch.isnan(max_abs)
+            max_abs = max_abs.view(hp_int_dtype)
+            val_to_add = 1 << (hp_mbits - mbits - 1)
+            mask = ((1 << (hp_ebits + SBITS)) - 1) << hp_mbits
+            max_abs = (max_abs + val_to_add) & mask
+            max_abs = max_abs.view(data_hp.dtype)
+            max_abs[nan_mask] = torch.tensor(
+                float("nan"), device=max_abs.device, dtype=max_abs.dtype
+            )
+
+        # Calculate the scale for different modes
+        max_abs_int32 = (max_abs + eps).view(hp_int_dtype)
+        extracted_pow2 = ((max_abs_int32 >> hp_mbits) & 0b11111111) - hp_exp_bias
+
+        if scaling_mode in (ScaleCalculationMode.FLOOR, ScaleCalculationMode.EVEN):
+            scale_e8m0_unbiased = extracted_pow2 - target_max_pow2
+        elif scaling_mode == ScaleCalculationMode.CEIL:
+            # round up: add one to scale if the mantissa is larger than 0
+            # 0x7FFFFF is equal to 23 ones
+            mantissa_gt_one = (max_abs_int32 & 0x7FFFFF) > 0
+            extracted_pow2 += mantissa_gt_one
+            scale_e8m0_unbiased = extracted_pow2 - target_max_pow2
+        else:
+            raise AssertionError("unsupported scaling calculation mode")
+
+        # Clamp to exponents that can be represented in e8m0
+        # add one to positive range to capture NaNs
+        scale_e8m0_unbiased = torch.clamp(
+            scale_e8m0_unbiased, min=-E8M0_EXPONENT_BIAS, max=E8M0_EXPONENT_BIAS + 1
+        )
+
+        # Create the biased e8m0 representation and cast it to 8 bits
+        scale_e8m0_biased = scale_e8m0_unbiased + E8M0_EXPONENT_BIAS
+        scale_e8m0_biased = scale_e8m0_biased.to(torch.uint8)
+
+        # Conversion to torch.uint8 sets NaN values to 0, fix this by
+        # explicitly setting known NaN values to 255
+        scale_e8m0_biased = torch.where(
+            torch.isnan(max_abs),
+            E8M0_EXPONENT_NAN_VAL,
+            scale_e8m0_biased,
+        )
+
+        # For now, calculate the scale in floating point.
+        scale_fp32 = (scale_e8m0_biased.to(torch.int32) << MBITS_F32).view(
+            torch.float32
+        )
+
+        # Today, 2**-127 returns 0 in compile+inductor+triton because it is in the
+        # float32 denormal range. For now, manually adjust the fp scale. This is
+        # relevant if all of the incoming block values are zeroes.
+        # See https://github.com/pytorch/pytorch/issues/125557 for details.
+        # Note: it would be more correct to set the minimum to 2**-127, but this
+        # does not work in triton either as it looks like subnormal value handling
+        # has some gaps.  So, for now just set to the minimum normal value.
+        scale_fp32 = torch.clamp(scale_fp32, min=F32_MIN_NORMAL)
+
+        # scale and saturated cast the data elements to max of target dtype
+        data_lp = data_hp / scale_fp32.unsqueeze(1)
+
+        if (
+            elem_dtype in (torch.float8_e4m3fn, torch.float8_e5m2)
+            and not torch._dynamo.is_compiling()
+        ):
+            # As of 20250317, the Pytorch eager mode cast to `torch.float8_e4m3fn`
+            # is unsaturated. This cast is saturated in triton. If we are compute bound,
+            # we see a speedup if we remove this redundant clamp if we are compiling
+            # to triton.
+            # TODO(#1912): make the saturated cast work in eager mode and remove this
+            # workaround.
+            data_lp = torch.clamp(data_lp, min=-1 * max_pos, max=max_pos)
+
+    # cast to target dtype
+    if elem_dtype in (torch.float8_e4m3fn, torch.float8_e5m2):
+        data_lp = data_lp.to(elem_dtype)
+        # need to reshape at the end to help inductor fuse things
+        data_lp = data_lp.reshape(orig_shape)
+    elif elem_dtype == DTYPE_FP6_E2M3:
+        data_lp = f32_to_f6_e2m3_unpacked(data_lp)
+        if pack_fp6:
+            orig_shape = [*orig_shape[:-1], 3 * orig_shape[-1] // 4]
+            data_lp = pack_uint6(data_lp)
+        # need to reshape at the end to help inductor fuse things
+        data_lp = data_lp.reshape(orig_shape)
+    elif elem_dtype == DTYPE_FP6_E3M2:
+        data_lp = f32_to_f6_e3m2_unpacked(data_lp)
+        if pack_fp6:
+            orig_shape = [*orig_shape[:-1], 3 * orig_shape[-1] // 4]
+            data_lp = pack_uint6(data_lp)
+        # need to reshape at the end to help inductor fuse things
+        data_lp = data_lp.reshape(orig_shape)
+    elif elem_dtype == DTYPE_FP4:
+        # can't reshape at the end without handling it in the packing code,
+        # punt until later since we'll need to rethink the torch.compile
+        # approach for fp4x2 in any case
+        data_lp = data_lp.reshape(orig_shape)
+        data_lp = f32_to_f4_unpacked(data_lp)
+        orig_shape = [*orig_shape[:-1], orig_shape[-1] // 2]
+        data_lp = pack_uint4(data_lp)
+    else:
+        raise AssertionError("unsupported")
+
+    scale_e8m0_biased = scale_e8m0_biased.view(torch.float8_e8m0fnu)
+    return scale_e8m0_biased, data_lp
+
+
+def get_fp_scale(scale_e8m0):
+    scale_e8m0 = scale_e8m0.view(torch.uint8)
+    s_offset = scale_e8m0.to(torch.int16) - E8M0_EXPONENT_BIAS
+    # TODO(later): it would be nice if there was a way to do the 2^x operation
+    # in PyTorch without creating a tensor of twos
+    two = torch.full(s_offset.size(), 2.0, device=scale_e8m0.device)
+    # pow(two, s_offset) can be out of range of floating point formats.
+    # TODO(later): handle this for float16 if we decide to support float16
+    # scales.
+    s_fp = torch.pow(two, s_offset)
+
+    # If a block exponent was 255, set values of that block to NaN
+    s_fp = torch.where(scale_e8m0 != E8M0_EXPONENT_NAN_VAL, s_fp, float("nan"))
+
+    return s_fp
+
+
+def to_dtype(
+    data_lp,
+    scale_e8m0,
+    elem_dtype,
+    block_size,
+    target_dtype,
+    use_fp4_custom_triton_dequant_kernel,
+    pack_fp6,
+):
+    orig_shape = data_lp.shape
+    is_transposed = not data_lp.is_contiguous()
+    # if the underlying data is transposed, convert to row major before
+    # unpacking and unscaling
+    if is_transposed:
+        data_lp = data_lp.t()
+        assert data_lp.is_contiguous()
+        orig_shape = (orig_shape[1], orig_shape[0])
+
+    if elem_dtype in (torch.float8_e4m3fn, torch.float8_e5m2):
+        data_hp = data_lp.to(target_dtype)
+    elif elem_dtype == DTYPE_FP6_E2M3:
+        if pack_fp6:
+            orig_shape = (*orig_shape[:-1], 4 * orig_shape[-1] // 3)
+            data_hp_rescaled = triton_f6_e2m3_to_scaled_bf16(
+                data_lp,
+                scale_e8m0,
+                block_size,
+            ).reshape(orig_shape)
+            if is_transposed:
+                data_hp_rescaled = data_hp_rescaled.t()
+            return data_hp_rescaled.to(target_dtype)
+        else:
+            data_hp = f6_e2m3_unpacked_to_f32(data_lp)
+            data_hp = data_hp.to(target_dtype).reshape(orig_shape)
+    elif elem_dtype == DTYPE_FP6_E3M2:
+        if pack_fp6:
+            orig_shape = (*orig_shape[:-1], 4 * orig_shape[-1] // 3)
+            data_hp_rescaled = triton_f6_e3m2_to_scaled_bf16(
+                data_lp,
+                scale_e8m0,
+                block_size,
+            ).reshape(orig_shape)
+            if is_transposed:
+                data_hp_rescaled = data_hp_rescaled.t()
+            return data_hp_rescaled.to(target_dtype)
+        else:
+            data_hp = f6_e3m2_unpacked_to_f32(data_lp)
+            data_hp = data_hp.to(target_dtype).reshape(orig_shape)
+    elif elem_dtype == DTYPE_FP4:
+        if use_fp4_custom_triton_dequant_kernel:
+            data_hp_rescaled = triton_f4_to_scaled_bf16(
+                data_lp,
+                scale_e8m0,
+                block_size,
+            )
+            if is_transposed:
+                data_hp_rescaled = data_hp_rescaled.t()
+            return data_hp_rescaled.to(target_dtype)
+        else:
+            # fp4
+            f4_unpacked = unpack_uint4(data_lp)
+            # for now we only have a cast to f32
+            # TODO(future PR): add cast directly to bf16
+            f32 = f4_unpacked_to_f32(f4_unpacked)
+            data_hp = f32.to(target_dtype)
+            # manually adjust shape to account for the unpacking
+            # TODO(future PR): clean up the shape code and remove the hack
+            # below
+        orig_shape = (*orig_shape[:-1], orig_shape[-1] * 2)
+    else:
+        raise AssertionError("unsupported")
+
+    data_hp = data_hp.reshape(-1, block_size)
+    s_fp = get_fp_scale(scale_e8m0).reshape(-1, 1).to(target_dtype)
+    data_hp = data_hp * s_fp
+    data_hp = data_hp.reshape(orig_shape)
+
+    # if we converted to row-major before unscaling convert back
+    if is_transposed:
+        data_hp = data_hp.t()
+
+    return data_hp
+
+
+def tensor_size_hp_to_fp4x2(orig_size, is_contiguous):
+    new_size = orig_size
+    if is_contiguous:
+        new_size = [*list(new_size[:-1]), new_size[-1] // 2]
+    else:
+        new_size = [new_size[0] // 2, *list(new_size[1:])]
+    return new_size
+
+
+def tensor_size_fp4x2_to_hp(orig_size, is_contiguous):
+    new_size = orig_size
+    if is_contiguous:
+        new_size = [*list(new_size[:-1]), new_size[-1] * 2]
+    else:
+        new_size = [new_size[0] * 2, *list(new_size[1:])]
+    return new_size
+
+
+def tensor_size_hpx3_to_fp6x4(orig_size, is_contiguous):
+    new_size = orig_size
+    if is_contiguous:
+        new_size = [*list(new_size[:-1]), 3 * new_size[-1] // 4]
+    else:
+        new_size = [3 * new_size[0] // 4, *list(new_size[1:])]
+    return new_size
+
+
+def tensor_size_fp6x4_to_hpx3(orig_size, is_contiguous):
+    new_size = orig_size
+    if is_contiguous:
+        new_size = [*list(new_size[:-1]), 4 * new_size[-1] // 3]
+    else:
+        new_size = [4 * new_size[0] // 3, *list(new_size[1:])]
+    return new_size
+
+
+class MXTensor(torch.Tensor):
+    def __new__(
+        cls,
+        scale_e8m0_bits,
+        data_bits,
+        elem_dtype,
+        block_size,
+        orig_dtype,
+        use_fp4_custom_triton_dequant_kernel,
+        gemm_kernel_choice,
+        pack_fp6,
+    ):
+        new_size = data_bits.size()
+        if elem_dtype == DTYPE_FP4:
+            # set the tensor size to what it would be without 2x4 packing
+            # Note: `is_contiguous` is going to return True for a tensor of size
+            # (M, 1) regardless or the order of dims, so this logic is currently
+            # broken for tensors of size (M, 1) or (1, M). Leaving broken until
+            # a time when fixing this becomes important.
+            new_size = tensor_size_fp4x2_to_hp(
+                new_size,
+                data_bits.is_contiguous(),
+            )
+        elif pack_fp6 and elem_dtype in [DTYPE_FP6_E2M3, DTYPE_FP6_E3M2]:
+            # set the tensor size to what it would be without fp6 packing
+            new_size = tensor_size_fp6x4_to_hpx3(
+                new_size,
+                data_bits.is_contiguous(),
+            )
+        self = torch.Tensor._make_wrapper_subclass(
+            cls,
+            new_size,
+            strides=data_bits.stride(),
+            storage_offset=data_bits.storage_offset(),
+            layout=data_bits.layout,
+            dtype=orig_dtype,
+            device=data_bits.device,
+        )
+        assert scale_e8m0_bits.dtype == torch.float8_e8m0fnu, (
+            f"scale_e8m0_bits.dtype must be `torch.float8_e8m0fnu`, got {scale_e8m0_bits.dtype}"
+        )
+        assert len(scale_e8m0_bits.shape) == 1, "unsupported"
+        assert data_bits.dtype in (
+            torch.float8_e4m3fn,
+            torch.float8_e5m2,
+            torch.uint8,
+        ), "unsupported"
+        if elem_dtype in (
+            torch.float8_e4m3fn,
+            torch.float8_e5m2,
+        ):
+            target_numel = scale_e8m0_bits.numel() * block_size
+        elif elem_dtype == DTYPE_FP4:
+            assert data_bits.dtype is torch.uint8  # fp4
+            target_numel = scale_e8m0_bits.numel() * block_size / 2
+        elif elem_dtype in [DTYPE_FP6_E2M3, DTYPE_FP6_E3M2]:
+            assert data_bits.dtype is torch.uint8  # fp4
+            target_numel = scale_e8m0_bits.numel() * block_size
+            if pack_fp6:
+                target_numel = 3 * target_numel // 4
+        else:
+            raise AssertionError("unsupported")
+        if not issubclass(
+            torch._subclasses.fake_tensor.FakeTensor,
+            type(data_bits),
+        ):
+            # this check is sometimes broken for FakeTensor
+            # TODO investigate
+            assert target_numel == data_bits.numel(), (
+                f"{target_numel} != {data_bits.numel()}"
+            )
+
+        # `_scale_e8m0` has rank 1 and applies to a row-major memory layout of
+        # `_data`
+        self._scale_e8m0 = scale_e8m0_bits
+        self._data = data_bits
+        self._elem_dtype = elem_dtype
+        self._block_size = block_size
+        self._orig_dtype = orig_dtype
+        self._use_fp4_custom_triton_dequant_kernel = (
+            use_fp4_custom_triton_dequant_kernel
+        )
+        self._gemm_kernel_choice = gemm_kernel_choice
+        self._pack_fp6 = pack_fp6
+        return self
+
+    def __repr__(self):
+        # TODO better elem dtype print for fp4
+        return f"MXTensor: elem_dtype: {self._elem_dtype}, s_e8m0: {self._scale_e8m0}, d: {self._data}, d_hp: {self.to_dtype(self._orig_dtype)}"  # noqa: E501
+
+    @classmethod
+    def __torch_dispatch__(cls, func, types, args, kwargs=None):
+        # avoid circular dependency
+        from torchao.prototype.mx_formats.mx_ops import MX_OPS_TABLE
+
+        if func in MX_OPS_TABLE:
+            return MX_OPS_TABLE[func](func, args, kwargs)
+
+        raise NotImplementedError(f"{func} not implemented")
+
+    def to_dtype(self, target_dtype):
+        return to_dtype(
+            self._data,
+            self._scale_e8m0,
+            self._elem_dtype,
+            self._block_size,
+            target_dtype,
+            self._use_fp4_custom_triton_dequant_kernel,
+            self._pack_fp6,
+        )
+
+    @staticmethod
+    @torch._dynamo.allow_in_graph
+    def to_mx(
+        data_hp: torch.Tensor,
+        elem_dtype: Union[torch.dtype, str],
+        block_size: int = BLOCK_SIZE_DEFAULT,
+        scaling_mode: ScaleCalculationMode = ScaleCalculationMode.FLOOR,
+        use_fp4_custom_triton_dequant_kernel: bool = False,
+        gemm_kernel_choice: MXGemmKernelChoice = MXGemmKernelChoice.EMULATED,
+        pack_fp6: bool = False,
+    ):
+        scale_e8m0_biased, data_lp = to_mx(
+            data_hp, elem_dtype, block_size, scaling_mode, pack_fp6
+        )
+        return MXTensor(
+            scale_e8m0_biased,
+            data_lp,
+            elem_dtype,
+            block_size,
+            data_hp.dtype,
+            use_fp4_custom_triton_dequant_kernel,
+            gemm_kernel_choice,
+            pack_fp6,
+        )
+
+    def __tensor_flatten__(self):
+        ctx = {
+            "_elem_dtype": self._elem_dtype,
+            "_block_size": self._block_size,
+            "_orig_dtype": self._orig_dtype,
+            "_use_fp4_custom_triton_dequant_kernel": self._use_fp4_custom_triton_dequant_kernel,
+            "_gemm_kernel_choice": self._gemm_kernel_choice,
+            "_pack_fp6": self._pack_fp6,
+        }
+        return ["_scale_e8m0", "_data"], ctx
+
+    @staticmethod
+    def __tensor_unflatten__(
+        inner_tensors: Dict,
+        metadata,
+        outer_size,
+        outer_stride,
+    ):
+        return MXTensor(
+            inner_tensors["_scale_e8m0"],
+            inner_tensors["_data"],
+            metadata["_elem_dtype"],
+            metadata["_block_size"],
+            metadata["_orig_dtype"],
+            metadata["_use_fp4_custom_triton_dequant_kernel"],
+            metadata["_gemm_kernel_choice"],
+            metadata["_pack_fp6"],
+        )
+
+    # Do not force the MXTensor type on the returned tensor
+    __torch_function__ = torch._C._disabled_torch_function_impl
diff --git a/lib/python3.12/site-packages/torchao/prototype/mx_formats/utils.py b/lib/python3.12/site-packages/torchao/prototype/mx_formats/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b186f82d6550a97c84d4eb902698af2f83a696d
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/mx_formats/utils.py
@@ -0,0 +1,61 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+import torch
+
+Tensor = torch.Tensor
+
+
+def ceil_div(a, b):
+    return (a + b - 1) // b
+
+
+def to_blocked(input_matrix) -> Tensor:
+    """
+    Rearrange a large matrix by breaking it into blocks and applying the rearrangement pattern.
+
+    See:
+        https://docs.nvidia.com/cuda/cublas/index.html#d-block-scaling-factors-layout
+
+    Args:
+        input_matrix: Input tensor of shape (H, W)
+
+    Returns:
+        Rearranged tensor of shape (32*ceil_div(H,128), 16*ceil_div(W,4))
+    """
+    rows, cols = input_matrix.shape
+    n_row_blocks = ceil_div(rows, 128)
+    n_col_blocks = ceil_div(cols, 4)
+
+    # Calculate the padded shape
+    padded_rows = n_row_blocks * 128
+    padded_cols = n_col_blocks * 4
+
+    padded = input_matrix
+    if (rows, cols) != (padded_rows, padded_cols):
+        padded = torch.zeros(
+            (padded_rows, padded_cols),
+            device=input_matrix.device,
+            dtype=input_matrix.dtype,
+        )
+        padded[:rows, :cols] = input_matrix
+
+    # Rearrange the blocks
+    blocks = padded.view(n_row_blocks, 128, n_col_blocks, 4).permute(0, 2, 1, 3)
+    rearranged = blocks.reshape(-1, 4, 32, 4).transpose(1, 2).reshape(-1, 32, 16)
+
+    return rearranged.flatten()
+
+
+def _to_blocked_single(scales: Tensor) -> Tensor:
+    """Assume that we have a 128x4 block of scales in K Major order
+
+    To see more information on the individual tile layout:
+    https://docs.nvidia.com/cuda/cublas/index.html#d-block-scaling-factors-layout
+    """
+    assert scales.shape == (128, 4)
+    scales_tiled = scales.view(4, 32, 4)  # view as 4 - (32, 4) tiles
+    return scales_tiled.transpose(0, 1).reshape(32, 16)  # Interleave tiles
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/__init__.py b/lib/python3.12/site-packages/torchao/prototype/paretoq/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/paretoq/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a9d8d346ec30612beed1cb1a7891a554105c1597
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/paretoq/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/__pycache__/train.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/paretoq/__pycache__/train.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..38e4a401340475f0682b7f50ad1a1129a4763aca
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/paretoq/__pycache__/train.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__init__.py b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..61fdffe4601d1fd8810272c3a755faec4f4f1706
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/configuration_llama.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/configuration_llama.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d92fe79303bd12d989142990af122895552a058d
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/configuration_llama.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/modeling_llama_quant.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/modeling_llama_quant.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..895e50a98b6896d18c2db43e4b9be4ce97ef32b7
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/modeling_llama_quant.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/utils_quant.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/utils_quant.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..fdd633e238fed3d5df3617f8e9af0416726e9bb8
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/__pycache__/utils_quant.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/models/configuration_llama.py b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/configuration_llama.py
new file mode 100644
index 0000000000000000000000000000000000000000..b9a763d8c080493a9ee24af5eb2c54902e3d63ff
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/configuration_llama.py
@@ -0,0 +1,231 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree.
+
+# coding=utf-8
+# Copyright 2022 EleutherAI and the HuggingFace Inc. team. All rights reserved.
+#
+# This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX
+# and OPT implementations in this library. It has been modified from its
+# original forms to accommodate minor architectural differences compared
+# to GPT-NeoX and OPT used by the Meta AI team that trained the model.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""LLaMA model configuration"""
+
+from transformers.configuration_utils import PretrainedConfig
+from transformers.modeling_rope_utils import rope_config_validation
+
+
+class LlamaConfig(PretrainedConfig):
+    r"""
+    This is the configuration class to store the configuration of a [`LlamaModel`]. It is used to instantiate an LLaMA
+    model according to the specified arguments, defining the model architecture. Instantiating a configuration with the
+    defaults will yield a similar configuration to that of the LLaMA-7B.
+
+    Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
+    documentation from [`PretrainedConfig`] for more information.
+
+
+    Args:
+        vocab_size (`int`, *optional*, defaults to 32000):
+            Vocabulary size of the LLaMA model. Defines the number of different tokens that can be represented by the
+            `inputs_ids` passed when calling [`LlamaModel`]
+        hidden_size (`int`, *optional*, defaults to 4096):
+            Dimension of the hidden representations.
+        intermediate_size (`int`, *optional*, defaults to 11008):
+            Dimension of the MLP representations.
+        num_hidden_layers (`int`, *optional*, defaults to 32):
+            Number of hidden layers in the Transformer decoder.
+        num_attention_heads (`int`, *optional*, defaults to 32):
+            Number of attention heads for each attention layer in the Transformer decoder.
+        num_key_value_heads (`int`, *optional*):
+            This is the number of key_value heads that should be used to implement Grouped Query Attention. If
+            `num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
+            `num_key_value_heads=1` the model will use Multi Query Attention (MQA) otherwise GQA is used. When
+            converting a multi-head checkpoint to a GQA checkpoint, each group key and value head should be constructed
+            by meanpooling all the original heads within that group. For more details checkout [this
+            paper](https://arxiv.org/pdf/2305.13245.pdf). If it is not specified, will default to
+            `num_attention_heads`.
+        hidden_act (`str` or `function`, *optional*, defaults to `"silu"`):
+            The non-linear activation function (function or string) in the decoder.
+        max_position_embeddings (`int`, *optional*, defaults to 2048):
+            The maximum sequence length that this model might ever be used with. Llama 1 supports up to 2048 tokens,
+            Llama 2 up to 4096, CodeLlama up to 16384.
+        initializer_range (`float`, *optional*, defaults to 0.02):
+            The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
+        rms_norm_eps (`float`, *optional*, defaults to 1e-06):
+            The epsilon used by the rms normalization layers.
+        use_cache (`bool`, *optional*, defaults to `True`):
+            Whether or not the model should return the last key/values attentions (not used by all models). Only
+            relevant if `config.is_decoder=True`.
+        pad_token_id (`int`, *optional*):
+            Padding token id.
+        bos_token_id (`int`, *optional*, defaults to 1):
+            Beginning of stream token id.
+        eos_token_id (`int`, *optional*, defaults to 2):
+            End of stream token id.
+        pretraining_tp (`int`, *optional*, defaults to 1):
+            Experimental feature. Tensor parallelism rank used during pretraining. Please refer to [this
+            document](https://huggingface.co/docs/transformers/main/perf_train_gpu_many#tensor-parallelism) to
+            understand more about it. This value is necessary to ensure exact reproducibility of the pretraining
+            results. Please refer to [this issue](https://github.com/pytorch/pytorch/issues/76232).
+        tie_word_embeddings (`bool`, *optional*, defaults to `False`):
+            Whether to tie weight embeddings
+        rope_theta (`float`, *optional*, defaults to 10000.0):
+            The base period of the RoPE embeddings.
+        rope_scaling (`Dict`, *optional*):
+            Dictionary containing the scaling configuration for the RoPE embeddings. NOTE: if you apply new rope type
+            and you expect the model to work on longer `max_position_embeddings`, we recommend you to update this value
+            accordingly.
+            Expected contents:
+                `rope_type` (`str`):
+                    The sub-variant of RoPE to use. Can be one of ['default', 'linear', 'dynamic', 'yarn', 'longrope',
+                    'llama3'], with 'default' being the original RoPE implementation.
+                `factor` (`float`, *optional*):
+                    Used with all rope types except 'default'. The scaling factor to apply to the RoPE embeddings. In
+                    most scaling types, a `factor` of x will enable the model to handle sequences of length x *
+                    original maximum pre-trained length.
+                `original_max_position_embeddings` (`int`, *optional*):
+                    Used with 'dynamic', 'longrope' and 'llama3'. The original max position embeddings used during
+                    pretraining.
+                `attention_factor` (`float`, *optional*):
+                    Used with 'yarn' and 'longrope'. The scaling factor to be applied on the attention
+                    computation. If unspecified, it defaults to value recommended by the implementation, using the
+                    `factor` field to infer the suggested value.
+                `beta_fast` (`float`, *optional*):
+                    Only used with 'yarn'. Parameter to set the boundary for extrapolation (only) in the linear
+                    ramp function. If unspecified, it defaults to 32.
+                `beta_slow` (`float`, *optional*):
+                    Only used with 'yarn'. Parameter to set the boundary for interpolation (only) in the linear
+                    ramp function. If unspecified, it defaults to 1.
+                `short_factor` (`List[float]`, *optional*):
+                    Only used with 'longrope'. The scaling factor to be applied to short contexts (<
+                    `original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
+                    size divided by the number of attention heads divided by 2
+                `long_factor` (`List[float]`, *optional*):
+                    Only used with 'longrope'. The scaling factor to be applied to long contexts (<
+                    `original_max_position_embeddings`). Must be a list of numbers with the same length as the hidden
+                    size divided by the number of attention heads divided by 2
+                `low_freq_factor` (`float`, *optional*):
+                    Only used with 'llama3'. Scaling factor applied to low frequency components of the RoPE
+                `high_freq_factor` (`float`, *optional*):
+                    Only used with 'llama3'. Scaling factor applied to high frequency components of the RoPE
+        attention_bias (`bool`, *optional*, defaults to `False`):
+            Whether to use a bias in the query, key, value and output projection layers during self-attention.
+        attention_dropout (`float`, *optional*, defaults to 0.0):
+            The dropout ratio for the attention probabilities.
+        mlp_bias (`bool`, *optional*, defaults to `False`):
+            Whether to use a bias in up_proj, down_proj and gate_proj layers in the MLP layers.
+        head_dim (`int`, *optional*):
+            The attention head dimension. If None, it will default to hidden_size // num_attention_heads
+
+    ```python
+    >>> from transformers import LlamaModel, LlamaConfig
+
+    >>> # Initializing a LLaMA llama-7b style configuration
+    >>> configuration = LlamaConfig()
+
+    >>> # Initializing a model from the llama-7b style configuration
+    >>> model = LlamaModel(configuration)
+
+    >>> # Accessing the model configuration
+    >>> configuration = model.config
+    ```"""
+
+    model_type = "llama"
+    keys_to_ignore_at_inference = ["past_key_values"]
+    # Default tensor parallel plan for base model `LlamaModel`
+    base_model_tp_plan = {
+        "layers.*.self_attn.q_proj": "colwise",
+        "layers.*.self_attn.k_proj": "colwise",
+        "layers.*.self_attn.v_proj": "colwise",
+        "layers.*.self_attn.o_proj": "rowwise",
+        "layers.*.mlp.gate_proj": "colwise",
+        "layers.*.mlp.up_proj": "colwise",
+        "layers.*.mlp.down_proj": "rowwise",
+    }
+    base_model_pp_plan = {
+        "embed_tokens": (["input_ids"], ["inputs_embeds"]),
+        "layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
+        "norm": (["hidden_states"], ["hidden_states"]),
+    }
+
+    def __init__(
+        self,
+        vocab_size=32000,
+        hidden_size=4096,
+        intermediate_size=11008,
+        num_hidden_layers=32,
+        num_attention_heads=32,
+        num_key_value_heads=None,
+        hidden_act="silu",
+        max_position_embeddings=2048,
+        initializer_range=0.02,
+        rms_norm_eps=1e-6,
+        use_cache=True,
+        pad_token_id=None,
+        bos_token_id=1,
+        eos_token_id=2,
+        pretraining_tp=1,
+        tie_word_embeddings=False,
+        rope_theta=10000.0,
+        rope_scaling=None,
+        attention_bias=False,
+        attention_dropout=0.0,
+        mlp_bias=False,
+        head_dim=None,
+        w_bits=32,
+        **kwargs,
+    ):
+        self.vocab_size = vocab_size
+        self.max_position_embeddings = max_position_embeddings
+        self.hidden_size = hidden_size
+        self.intermediate_size = intermediate_size
+        self.num_hidden_layers = num_hidden_layers
+        self.num_attention_heads = num_attention_heads
+
+        # for backward compatibility
+        if num_key_value_heads is None:
+            num_key_value_heads = num_attention_heads
+
+        self.num_key_value_heads = num_key_value_heads
+        self.hidden_act = hidden_act
+        self.initializer_range = initializer_range
+        self.rms_norm_eps = rms_norm_eps
+        self.pretraining_tp = pretraining_tp
+        self.use_cache = use_cache
+        self.rope_theta = rope_theta
+        self.rope_scaling = rope_scaling
+        self.attention_bias = attention_bias
+        self.attention_dropout = attention_dropout
+        self.mlp_bias = mlp_bias
+        self.head_dim = head_dim if head_dim is not None else self.hidden_size // self.num_attention_heads
+        # Validate the correctness of rotary position embeddings parameters
+        # BC: if there is a 'type' field, copy it it to 'rope_type'.
+        if self.rope_scaling is not None and "type" in self.rope_scaling:
+            self.rope_scaling["rope_type"] = self.rope_scaling["type"]
+        rope_config_validation(self)
+        self.w_bits = w_bits
+
+        super().__init__(
+            pad_token_id=pad_token_id,
+            bos_token_id=bos_token_id,
+            eos_token_id=eos_token_id,
+            tie_word_embeddings=tie_word_embeddings,
+            **kwargs,
+        )
+
+
+__all__ = ["LlamaConfig"]
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/models/modeling_llama_quant.py b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/modeling_llama_quant.py
new file mode 100644
index 0000000000000000000000000000000000000000..b2d9e82a11318b551ad8a3b833ce813cb25edf56
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/modeling_llama_quant.py
@@ -0,0 +1,1173 @@
+# coding=utf-8
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree.
+
+# coding=utf-8
+# Copyright 2022 EleutherAI and the HuggingFace Inc. team. All rights reserved.
+#
+# This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX
+# and OPT implementations in this library. It has been modified from its
+# original forms to accommodate minor architectural differences compared
+# to GPT-NeoX and OPT used by the Meta AI team that trained the model.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from typing import Callable, List, Optional, Tuple, Union
+
+import torch
+import torch.utils.checkpoint
+from torch import nn
+
+from transformers.activations import ACT2FN
+from transformers.cache_utils import Cache, DynamicCache, StaticCache
+from transformers.generation import GenerationMixin
+from transformers.modeling_attn_mask_utils import AttentionMaskConverter
+from transformers.modeling_flash_attention_utils import FlashAttentionKwargs
+from transformers.modeling_outputs import (
+    BaseModelOutputWithPast,
+    CausalLMOutputWithPast,
+    QuestionAnsweringModelOutput,
+    SequenceClassifierOutputWithPast,
+    TokenClassifierOutput,
+)
+from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS
+from transformers.modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
+from transformers.processing_utils import Unpack
+from transformers.pytorch_utils import ALL_LAYERNORM_LAYERS
+from transformers.utils import (
+    LossKwargs,
+    add_code_sample_docstrings,
+    add_start_docstrings,
+    add_start_docstrings_to_model_forward,
+    logging,
+    replace_return_docstrings,
+)
+from transformers.utils.deprecation import deprecate_kwarg
+from .configuration_llama import LlamaConfig
+from .utils_quant import QuantizeLinear
+
+logger = logging.get_logger(__name__)
+
+_CHECKPOINT_FOR_DOC = "meta-llama/Llama-2-7b-hf"
+_CONFIG_FOR_DOC = "LlamaConfig"
+
+
+class LlamaRMSNorm(nn.Module):
+    def __init__(self, hidden_size, eps=1e-6):
+        """
+        LlamaRMSNorm is equivalent to T5LayerNorm
+        """
+        super().__init__()
+        self.weight = nn.Parameter(torch.ones(hidden_size))
+        self.variance_epsilon = eps
+
+    def forward(self, hidden_states):
+        input_dtype = hidden_states.dtype
+        hidden_states = hidden_states.to(torch.float32)
+        variance = hidden_states.pow(2).mean(-1, keepdim=True)
+        hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
+        return self.weight * hidden_states.to(input_dtype)
+
+    def extra_repr(self):
+        return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
+
+
+ALL_LAYERNORM_LAYERS.append(LlamaRMSNorm)
+
+
+class LlamaRotaryEmbedding(nn.Module):
+    def __init__(self, config: LlamaConfig, device=None):
+        super().__init__()
+        # BC: "rope_type" was originally "type"
+        if hasattr(config, "rope_scaling") and config.rope_scaling is not None:
+            self.rope_type = config.rope_scaling.get("rope_type", config.rope_scaling.get("type"))
+        else:
+            self.rope_type = "default"
+        self.max_seq_len_cached = config.max_position_embeddings
+        self.original_max_seq_len = config.max_position_embeddings
+
+        self.config = config
+        self.rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
+
+        inv_freq, self.attention_scaling = self.rope_init_fn(self.config, device)
+        self.register_buffer("inv_freq", inv_freq, persistent=False)
+        self.original_inv_freq = self.inv_freq
+
+    def _dynamic_frequency_update(self, position_ids, device):
+        """
+        dynamic RoPE layers should recompute `inv_freq` in the following situations:
+        1 - growing beyond the cached sequence length (allow scaling)
+        2 - the current sequence length is in the original scale (avoid losing precision with small sequences)
+        """
+        seq_len = torch.max(position_ids) + 1
+        if seq_len > self.max_seq_len_cached:  # growth
+            inv_freq, self.attention_scaling = self.rope_init_fn(self.config, device, seq_len=seq_len)
+            self.register_buffer("inv_freq", inv_freq, persistent=False)  # TODO joao: may break with compilation
+            self.max_seq_len_cached = seq_len
+
+        if seq_len < self.original_max_seq_len and self.max_seq_len_cached > self.original_max_seq_len:  # reset
+            # This .to() is needed if the model has been moved to a device after being initialized (because
+            # the buffer is automatically moved, but not the original copy)
+            self.original_inv_freq = self.original_inv_freq.to(device)
+            self.register_buffer("inv_freq", self.original_inv_freq, persistent=False)
+            self.max_seq_len_cached = self.original_max_seq_len
+
+    @torch.no_grad()
+    def forward(self, x, position_ids):
+        if "dynamic" in self.rope_type:
+            self._dynamic_frequency_update(position_ids, device=x.device)
+
+        # Core RoPE block
+        inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1)
+        position_ids_expanded = position_ids[:, None, :].float()
+        # Force float32 (see https://github.com/huggingface/transformers/pull/29285)
+        device_type = x.device.type
+        device_type = device_type if isinstance(device_type, str) and device_type != "mps" else "cpu"
+        with torch.autocast(device_type=device_type, enabled=False):
+            freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
+            emb = torch.cat((freqs, freqs), dim=-1)
+            cos = emb.cos()
+            sin = emb.sin()
+
+        # Advanced RoPE types (e.g. yarn) apply a post-processing scaling factor, equivalent to scaling attention
+        cos = cos * self.attention_scaling
+        sin = sin * self.attention_scaling
+
+        return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
+
+
+def rotate_half(x):
+    """Rotates half the hidden dims of the input."""
+    x1 = x[..., : x.shape[-1] // 2]
+    x2 = x[..., x.shape[-1] // 2 :]
+    return torch.cat((-x2, x1), dim=-1)
+
+
+def apply_rotary_pos_emb(q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
+    """Applies Rotary Position Embedding to the query and key tensors.
+
+    Args:
+        q (`torch.Tensor`): The query tensor.
+        k (`torch.Tensor`): The key tensor.
+        cos (`torch.Tensor`): The cosine part of the rotary embedding.
+        sin (`torch.Tensor`): The sine part of the rotary embedding.
+        position_ids (`torch.Tensor`, *optional*):
+            Deprecated and unused.
+        unsqueeze_dim (`int`, *optional*, defaults to 1):
+            The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
+            sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
+            that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
+            k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
+            cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
+            the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
+    Returns:
+        `tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
+    """
+    cos = cos.unsqueeze(unsqueeze_dim)
+    sin = sin.unsqueeze(unsqueeze_dim)
+    q_embed = (q * cos) + (rotate_half(q) * sin)
+    k_embed = (k * cos) + (rotate_half(k) * sin)
+    return q_embed, k_embed
+
+
+class LlamaMLP(nn.Module):
+    def __init__(self, config):
+        super().__init__()
+        self.config = config
+        self.hidden_size = config.hidden_size
+        self.intermediate_size = config.intermediate_size
+        self.gate_proj = QuantizeLinear(self.hidden_size, self.intermediate_size, bias=config.mlp_bias, w_bits=config.w_bits)
+        self.up_proj = QuantizeLinear(self.hidden_size, self.intermediate_size, bias=config.mlp_bias, w_bits=config.w_bits)
+        self.down_proj = QuantizeLinear(self.intermediate_size, self.hidden_size, bias=config.mlp_bias, w_bits=config.w_bits)
+        self.act_fn = ACT2FN[config.hidden_act]
+
+    def forward(self, x):
+        down_proj = self.down_proj(self.act_fn(self.gate_proj(x)) * self.up_proj(x))
+        return down_proj
+
+
+def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
+    """
+    This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
+    num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
+    """
+    batch, num_key_value_heads, slen, head_dim = hidden_states.shape
+    if n_rep == 1:
+        return hidden_states
+    hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
+    return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
+
+
+def eager_attention_forward(
+    module: nn.Module,
+    query: torch.Tensor,
+    key: torch.Tensor,
+    value: torch.Tensor,
+    attention_mask: Optional[torch.Tensor],
+    scaling: float,
+    dropout: float = 0.0,
+    **kwargs,
+):
+    key_states = repeat_kv(key, module.num_key_value_groups)
+    value_states = repeat_kv(value, module.num_key_value_groups)
+
+    attn_weights = torch.matmul(query, key_states.transpose(2, 3)) * scaling
+    if attention_mask is not None:
+        causal_mask = attention_mask[:, :, :, : key_states.shape[-2]]
+        attn_weights = attn_weights + causal_mask
+
+    attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(query.dtype)
+    attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)
+    attn_output = torch.matmul(attn_weights, value_states)
+    attn_output = attn_output.transpose(1, 2).contiguous()
+
+    return attn_output, attn_weights
+
+
+class LlamaAttention(nn.Module):
+    """Multi-headed attention from 'Attention Is All You Need' paper"""
+
+    def __init__(self, config: LlamaConfig, layer_idx: int):
+        super().__init__()
+        self.config = config
+        self.layer_idx = layer_idx
+        self.head_dim = getattr(config, "head_dim", config.hidden_size // config.num_attention_heads)
+        self.num_key_value_groups = config.num_attention_heads // config.num_key_value_heads
+        self.scaling = self.head_dim**-0.5
+        self.attention_dropout = config.attention_dropout
+        self.is_causal = True
+
+        self.q_proj = QuantizeLinear(
+            config.hidden_size, config.num_attention_heads * self.head_dim, bias=config.attention_bias, w_bits=config.w_bits
+        )
+        self.k_proj = QuantizeLinear(
+            config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias, w_bits=config.w_bits
+        )
+        self.v_proj = QuantizeLinear(
+            config.hidden_size, config.num_key_value_heads * self.head_dim, bias=config.attention_bias, w_bits=config.w_bits
+        )
+        self.o_proj = QuantizeLinear(
+            config.num_attention_heads * self.head_dim, config.hidden_size, bias=config.attention_bias, w_bits=config.w_bits
+        )
+
+    def forward(
+        self,
+        hidden_states: torch.Tensor,
+        position_embeddings: Tuple[torch.Tensor, torch.Tensor],
+        attention_mask: Optional[torch.Tensor],
+        past_key_value: Optional[Cache] = None,
+        cache_position: Optional[torch.LongTensor] = None,
+        **kwargs: Unpack[FlashAttentionKwargs],
+    ) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
+        input_shape = hidden_states.shape[:-1]
+        hidden_shape = (*input_shape, -1, self.head_dim)
+
+        query_states = self.q_proj(hidden_states).view(hidden_shape).transpose(1, 2)
+        key_states = self.k_proj(hidden_states).view(hidden_shape).transpose(1, 2)
+        value_states = self.v_proj(hidden_states).view(hidden_shape).transpose(1, 2)
+
+        cos, sin = position_embeddings
+        query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin)
+
+        if past_key_value is not None:
+            # sin and cos are specific to RoPE models; cache_position needed for the static cache
+            cache_kwargs = {"sin": sin, "cos": cos, "cache_position": cache_position}
+            key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
+
+        attention_interface: Callable = eager_attention_forward
+        if self.config._attn_implementation != "eager":
+            if self.config._attn_implementation == "sdpa" and kwargs.get("output_attentions", False):
+                logger.warning_once(
+                    "`torch.nn.functional.scaled_dot_product_attention` does not support `output_attentions=True`. Falling back to "
+                    'eager attention. This warning can be removed using the argument `attn_implementation="eager"` when loading the model.'
+                )
+            else:
+                attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]
+
+        attn_output, attn_weights = attention_interface(
+            self,
+            query_states,
+            key_states,
+            value_states,
+            attention_mask,
+            dropout=0.0 if not self.training else self.attention_dropout,
+            scaling=self.scaling,
+            **kwargs,
+        )
+
+        attn_output = attn_output.reshape(*input_shape, -1).contiguous()
+        attn_output = self.o_proj(attn_output)
+        return attn_output, attn_weights
+
+
+class LlamaDecoderLayer(nn.Module):
+    def __init__(self, config: LlamaConfig, layer_idx: int):
+        super().__init__()
+        self.hidden_size = config.hidden_size
+
+        self.self_attn = LlamaAttention(config=config, layer_idx=layer_idx)
+
+        self.mlp = LlamaMLP(config)
+        self.input_layernorm = LlamaRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
+        self.post_attention_layernorm = LlamaRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
+
+    def forward(
+        self,
+        hidden_states: torch.Tensor,
+        attention_mask: Optional[torch.Tensor] = None,
+        position_ids: Optional[torch.LongTensor] = None,
+        past_key_value: Optional[Cache] = None,
+        output_attentions: Optional[bool] = False,
+        use_cache: Optional[bool] = False,
+        cache_position: Optional[torch.LongTensor] = None,
+        position_embeddings: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,  # necessary, but kept here for BC
+        **kwargs: Unpack[FlashAttentionKwargs],
+    ) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
+        residual = hidden_states
+
+        hidden_states = self.input_layernorm(hidden_states)
+
+        # Self Attention
+        hidden_states, self_attn_weights = self.self_attn(
+            hidden_states=hidden_states,
+            attention_mask=attention_mask,
+            position_ids=position_ids,
+            past_key_value=past_key_value,
+            output_attentions=output_attentions,
+            use_cache=use_cache,
+            cache_position=cache_position,
+            position_embeddings=position_embeddings,
+            **kwargs,
+        )
+        hidden_states = residual + hidden_states
+
+        # Fully Connected
+        residual = hidden_states
+        hidden_states = self.post_attention_layernorm(hidden_states)
+        hidden_states = self.mlp(hidden_states)
+        hidden_states = residual + hidden_states
+
+        outputs = (hidden_states,)
+        if output_attentions:
+            outputs += (self_attn_weights,)
+
+        return outputs
+
+
+LLAMA_START_DOCSTRING = r"""
+    This model inherits from [`PreTrainedModel`]. Check the superclass documentation for the generic methods the
+    library implements for all its model (such as downloading or saving, resizing the input embeddings, pruning heads
+    etc.)
+
+    This model is also a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) subclass.
+    Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage
+    and behavior.
+
+    Parameters:
+        config ([`LlamaConfig`]):
+            Model configuration class with all the parameters of the model. Initializing with a config file does not
+            load the weights associated with the model, only the configuration. Check out the
+            [`~PreTrainedModel.from_pretrained`] method to load the model weights.
+"""
+
+
+@add_start_docstrings(
+    "The bare LLaMA Model outputting raw hidden-states without any specific head on top.",
+    LLAMA_START_DOCSTRING,
+)
+class LlamaPreTrainedModel(PreTrainedModel):
+    config_class = LlamaConfig
+    base_model_prefix = "model"
+    supports_gradient_checkpointing = True
+    _no_split_modules = ["LlamaDecoderLayer"]
+    _skip_keys_device_placement = ["past_key_values"]
+    _supports_flash_attn_2 = True
+    _supports_sdpa = True
+    _supports_flex_attn = True
+    _supports_cache_class = True
+    _supports_quantized_cache = True
+    _supports_static_cache = True
+    _supports_attention_backend = True
+
+    def _init_weights(self, module):
+        std = self.config.initializer_range
+        if isinstance(module, nn.Linear):
+            module.weight.data.normal_(mean=0.0, std=std)
+            if module.bias is not None:
+                module.bias.data.zero_()
+        elif isinstance(module, nn.Embedding):
+            module.weight.data.normal_(mean=0.0, std=std)
+            if module.padding_idx is not None:
+                module.weight.data[module.padding_idx].zero_()
+
+
+LLAMA_INPUTS_DOCSTRING = r"""
+    Args:
+        input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`):
+            Indices of input sequence tokens in the vocabulary. Padding will be ignored by default should you provide
+            it.
+
+            Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and
+            [`PreTrainedTokenizer.__call__`] for details.
+
+            [What are input IDs?](../glossary#input-ids)
+        attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
+            Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`:
+
+            - 1 for tokens that are **not masked**,
+            - 0 for tokens that are **masked**.
+
+            [What are attention masks?](../glossary#attention-mask)
+
+            Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and
+            [`PreTrainedTokenizer.__call__`] for details.
+
+            If `past_key_values` is used, optionally only the last `input_ids` have to be input (see
+            `past_key_values`).
+
+            If you want to change padding behavior, you should read [`modeling_opt._prepare_decoder_attention_mask`]
+            and modify to your needs. See diagram 1 in [the paper](https://arxiv.org/abs/1910.13461) for more
+            information on the default strategy.
+
+            - 1 indicates the head is **not masked**,
+            - 0 indicates the head is **masked**.
+        position_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
+            Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0,
+            config.n_positions - 1]`.
+
+            [What are position IDs?](../glossary#position-ids)
+        past_key_values (`Cache` or `tuple(tuple(torch.FloatTensor))`, *optional*):
+            Pre-computed hidden-states (key and values in the self-attention blocks and in the cross-attention
+            blocks) that can be used to speed up sequential decoding. This typically consists in the `past_key_values`
+            returned by the model at a previous stage of decoding, when `use_cache=True` or `config.use_cache=True`.
+
+            Two formats are allowed:
+            - a [`~cache_utils.Cache`] instance, see our
+            [kv cache guide](https://huggingface.co/docs/transformers/en/kv_cache);
+            - Tuple of `tuple(torch.FloatTensor)` of length `config.n_layers`, with each tuple having 2 tensors of
+            shape `(batch_size, num_heads, sequence_length, embed_size_per_head)`). This is also known as the legacy
+            cache format.
+
+            The model will output the same cache format that is fed as input. If no `past_key_values` are passed, the
+            legacy cache format will be returned.
+
+            If `past_key_values` are used, the user can optionally input only the last `input_ids` (those that don't
+            have their past key value states given to this model) of shape `(batch_size, 1)` instead of all `input_ids`
+            of shape `(batch_size, sequence_length)`.
+        inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
+            Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This
+            is useful if you want more control over how to convert `input_ids` indices into associated vectors than the
+            model's internal embedding lookup matrix.
+        use_cache (`bool`, *optional*):
+            If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding (see
+            `past_key_values`).
+        output_attentions (`bool`, *optional*):
+            Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned
+            tensors for more detail.
+        output_hidden_states (`bool`, *optional*):
+            Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for
+            more detail.
+        return_dict (`bool`, *optional*):
+            Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple.
+        cache_position (`torch.LongTensor` of shape `(sequence_length)`, *optional*):
+            Indices depicting the position of the input sequence tokens in the sequence. Contrarily to `position_ids`,
+            this tensor is not affected by padding. It is used to update the cache in the correct position and to infer
+            the complete sequence length.
+"""
+
+
+@add_start_docstrings(
+    "The bare LLaMA Model outputting raw hidden-states without any specific head on top.",
+    LLAMA_START_DOCSTRING,
+)
+class LlamaModel(LlamaPreTrainedModel):
+    """
+    Transformer decoder consisting of *config.num_hidden_layers* layers. Each layer is a [`LlamaDecoderLayer`]
+
+    Args:
+        config: LlamaConfig
+    """
+
+    def __init__(self, config: LlamaConfig):
+        super().__init__(config)
+        self.padding_idx = config.pad_token_id
+        self.vocab_size = config.vocab_size
+
+        self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
+        self.layers = nn.ModuleList(
+            [LlamaDecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
+        )
+        self.norm = LlamaRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
+        self.rotary_emb = LlamaRotaryEmbedding(config=config)
+        self.gradient_checkpointing = False
+
+        # Initialize weights and apply final processing
+        self.post_init()
+
+    def get_input_embeddings(self):
+        return self.embed_tokens
+
+    def set_input_embeddings(self, value):
+        self.embed_tokens = value
+
+    @add_start_docstrings_to_model_forward(LLAMA_INPUTS_DOCSTRING)
+    def forward(
+        self,
+        input_ids: torch.LongTensor = None,
+        attention_mask: Optional[torch.Tensor] = None,
+        position_ids: Optional[torch.LongTensor] = None,
+        past_key_values: Optional[Cache] = None,
+        inputs_embeds: Optional[torch.FloatTensor] = None,
+        use_cache: Optional[bool] = None,
+        output_attentions: Optional[bool] = None,
+        output_hidden_states: Optional[bool] = None,
+        return_dict: Optional[bool] = None,
+        cache_position: Optional[torch.LongTensor] = None,
+        **flash_attn_kwargs: Unpack[FlashAttentionKwargs],
+    ) -> Union[Tuple, BaseModelOutputWithPast]:
+        output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
+        output_hidden_states = (
+            output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
+        )
+        use_cache = use_cache if use_cache is not None else self.config.use_cache
+        return_dict = return_dict if return_dict is not None else self.config.use_return_dict
+
+        if (input_ids is None) ^ (inputs_embeds is not None):
+            raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
+
+        if self.gradient_checkpointing and self.training and use_cache:
+            logger.warning_once(
+                "`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`."
+            )
+            use_cache = False
+
+        if inputs_embeds is None:
+            inputs_embeds = self.embed_tokens(input_ids)
+
+        if use_cache and past_key_values is None:
+            past_key_values = DynamicCache()
+
+        if cache_position is None:
+            past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
+            cache_position = torch.arange(
+                past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device
+            )
+
+        if position_ids is None:
+            position_ids = cache_position.unsqueeze(0)
+
+        causal_mask = self._update_causal_mask(
+            attention_mask, inputs_embeds, cache_position, past_key_values, output_attentions
+        )
+
+        hidden_states = inputs_embeds
+
+        # create position embeddings to be shared across the decoder layers
+        position_embeddings = self.rotary_emb(hidden_states, position_ids)
+
+        # decoder layers
+        all_hidden_states = () if output_hidden_states else None
+        all_self_attns = () if output_attentions else None
+
+        for decoder_layer in self.layers[: self.config.num_hidden_layers]:
+            if output_hidden_states:
+                all_hidden_states += (hidden_states,)
+
+            if self.gradient_checkpointing and self.training:
+                layer_outputs = self._gradient_checkpointing_func(
+                    decoder_layer.__call__,
+                    hidden_states,
+                    causal_mask,
+                    position_ids,
+                    past_key_values,
+                    output_attentions,
+                    use_cache,
+                    cache_position,
+                    position_embeddings,
+                )
+            else:
+                layer_outputs = decoder_layer(
+                    hidden_states,
+                    attention_mask=causal_mask,
+                    position_ids=position_ids,
+                    past_key_value=past_key_values,
+                    output_attentions=output_attentions,
+                    use_cache=use_cache,
+                    cache_position=cache_position,
+                    position_embeddings=position_embeddings,
+                    **flash_attn_kwargs,
+                )
+
+            hidden_states = layer_outputs[0]
+
+            if output_attentions:
+                all_self_attns += (layer_outputs[1],)
+
+        hidden_states = self.norm(hidden_states)
+
+        # add hidden states from the last decoder layer
+        if output_hidden_states:
+            all_hidden_states += (hidden_states,)
+
+        output = BaseModelOutputWithPast(
+            last_hidden_state=hidden_states,
+            past_key_values=past_key_values if use_cache else None,
+            hidden_states=all_hidden_states,
+            attentions=all_self_attns,
+        )
+        return output if return_dict else output.to_tuple()
+
+    def _update_causal_mask(
+        self,
+        attention_mask: torch.Tensor,
+        input_tensor: torch.Tensor,
+        cache_position: torch.Tensor,
+        past_key_values: Cache,
+        output_attentions: bool,
+    ):
+        if self.config._attn_implementation == "flash_attention_2":
+            if attention_mask is not None and (attention_mask == 0.0).any():
+                return attention_mask
+            return None
+
+        # For SDPA, when possible, we will rely on its `is_causal` argument instead of its `attn_mask` argument, in
+        # order to dispatch on Flash Attention 2. This feature is not compatible with static cache, as SDPA will fail
+        # to infer the attention mask.
+        past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
+        using_static_cache = isinstance(past_key_values, StaticCache)
+
+        # When output attentions is True, sdpa implementation's forward method calls the eager implementation's forward
+        if self.config._attn_implementation == "sdpa" and not using_static_cache and not output_attentions:
+            if AttentionMaskConverter._ignore_causal_mask_sdpa(
+                attention_mask,
+                inputs_embeds=input_tensor,
+                past_key_values_length=past_seen_tokens,
+                is_training=self.training,
+            ):
+                return None
+
+        dtype, device = input_tensor.dtype, input_tensor.device
+        sequence_length = input_tensor.shape[1]
+        if using_static_cache:
+            target_length = past_key_values.get_max_cache_shape()
+        else:
+            target_length = (
+                attention_mask.shape[-1]
+                if isinstance(attention_mask, torch.Tensor)
+                else past_seen_tokens + sequence_length + 1
+            )
+
+        # In case the provided `attention` mask is 2D, we generate a causal mask here (4D).
+        causal_mask = self._prepare_4d_causal_attention_mask_with_cache_position(
+            attention_mask,
+            sequence_length=sequence_length,
+            target_length=target_length,
+            dtype=dtype,
+            device=device,
+            cache_position=cache_position,
+            batch_size=input_tensor.shape[0],
+        )
+
+        if (
+            self.config._attn_implementation == "sdpa"
+            and attention_mask is not None
+            and attention_mask.device.type in ["cuda", "xpu"]
+            and not output_attentions
+        ):
+            # Attend to all tokens in fully masked rows in the causal_mask, for example the relevant first rows when
+            # using left padding. This is required by F.scaled_dot_product_attention memory-efficient attention path.
+            # Details: https://github.com/pytorch/pytorch/issues/110213
+            min_dtype = torch.finfo(dtype).min
+            causal_mask = AttentionMaskConverter._unmask_unattended(causal_mask, min_dtype)
+
+        return causal_mask
+
+    @staticmethod
+    def _prepare_4d_causal_attention_mask_with_cache_position(
+        attention_mask: torch.Tensor,
+        sequence_length: int,
+        target_length: int,
+        dtype: torch.dtype,
+        device: torch.device,
+        cache_position: torch.Tensor,
+        batch_size: int,
+        **kwargs,
+    ):
+        """
+        Creates a causal 4D mask of shape `(batch_size, 1, query_length, key_value_length)` from a 2D mask of shape
+        `(batch_size, key_value_length)`, or if the input `attention_mask` is already 4D, do nothing.
+
+        Args:
+            attention_mask (`torch.Tensor`):
+                A 2D attention mask of shape `(batch_size, key_value_length)` or a 4D attention mask of shape
+                `(batch_size, 1, query_length, key_value_length)`.
+            sequence_length (`int`):
+                The sequence length being processed.
+            target_length (`int`):
+                The target length: when generating with static cache, the mask should be as long as the static cache,
+                to account for the 0 padding, the part of the cache that is not filled yet.
+            dtype (`torch.dtype`):
+                The dtype to use for the 4D attention mask.
+            device (`torch.device`):
+                The device to plcae the 4D attention mask on.
+            cache_position (`torch.Tensor`):
+                Indices depicting the position of the input sequence tokens in the sequence.
+            batch_size (`torch.Tensor`):
+                Batch size.
+        """
+        if attention_mask is not None and attention_mask.dim() == 4:
+            # In this case we assume that the mask comes already in inverted form and requires no inversion or slicing.
+            causal_mask = attention_mask
+        else:
+            min_dtype = torch.finfo(dtype).min
+            causal_mask = torch.full(
+                (sequence_length, target_length), fill_value=min_dtype, dtype=dtype, device=device
+            )
+            if sequence_length != 1:
+                causal_mask = torch.triu(causal_mask, diagonal=1)
+            causal_mask *= torch.arange(target_length, device=device) > cache_position.reshape(-1, 1)
+            causal_mask = causal_mask[None, None, :, :].expand(batch_size, 1, -1, -1)
+            if attention_mask is not None:
+                causal_mask = causal_mask.clone()  # copy to contiguous memory for in-place edit
+                mask_length = attention_mask.shape[-1]
+                padding_mask = causal_mask[:, :, :, :mask_length] + attention_mask[:, None, None, :].to(
+                    causal_mask.device
+                )
+                padding_mask = padding_mask == 0
+                causal_mask[:, :, :, :mask_length] = causal_mask[:, :, :, :mask_length].masked_fill(
+                    padding_mask, min_dtype
+                )
+
+        return causal_mask
+
+
+class KwargsForCausalLM(FlashAttentionKwargs, LossKwargs): ...
+
+
+class LlamaForCausalLM(LlamaPreTrainedModel, GenerationMixin):
+    _tied_weights_keys = ["lm_head.weight"]
+    _tp_plan = {"lm_head": "colwise_rep"}
+    _pp_plan = {"lm_head": (["hidden_states"], ["logits"])}
+
+    def __init__(self, config):
+        super().__init__(config)
+        self.model = LlamaModel(config)
+        self.vocab_size = config.vocab_size
+        self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
+
+        # Initialize weights and apply final processing
+        self.post_init()
+
+    def get_input_embeddings(self):
+        return self.model.embed_tokens
+
+    def set_input_embeddings(self, value):
+        self.model.embed_tokens = value
+
+    def get_output_embeddings(self):
+        return self.lm_head
+
+    def set_output_embeddings(self, new_embeddings):
+        self.lm_head = new_embeddings
+
+    def set_decoder(self, decoder):
+        self.model = decoder
+
+    def get_decoder(self):
+        return self.model
+
+    @deprecate_kwarg("num_logits_to_keep", version="4.50", new_name="logits_to_keep")
+    @add_start_docstrings_to_model_forward(LLAMA_INPUTS_DOCSTRING)
+    @replace_return_docstrings(output_type=CausalLMOutputWithPast, config_class=_CONFIG_FOR_DOC)
+    def forward(
+        self,
+        input_ids: torch.LongTensor = None,
+        attention_mask: Optional[torch.Tensor] = None,
+        position_ids: Optional[torch.LongTensor] = None,
+        past_key_values: Optional[Union[Cache, List[torch.FloatTensor]]] = None,
+        inputs_embeds: Optional[torch.FloatTensor] = None,
+        labels: Optional[torch.LongTensor] = None,
+        use_cache: Optional[bool] = None,
+        output_attentions: Optional[bool] = None,
+        output_hidden_states: Optional[bool] = None,
+        return_dict: Optional[bool] = None,
+        cache_position: Optional[torch.LongTensor] = None,
+        logits_to_keep: Union[int, torch.Tensor] = 0,
+        **kwargs: Unpack[KwargsForCausalLM],
+    ) -> Union[Tuple, CausalLMOutputWithPast]:
+        r"""
+        Args:
+            labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
+                Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
+                config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
+                (masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
+
+            logits_to_keep (`int` or `torch.Tensor`, *optional*):
+                If an `int`, compute logits for the last `logits_to_keep` tokens. If `0`, calculate logits for all
+                `input_ids` (special case). Only last token logits are needed for generation, and calculating them only for that
+                token can save memory, which becomes pretty significant for long sequences or large vocabulary size.
+                If a `torch.Tensor`, must be 1D corresponding to the indices to keep in the sequence length dimension.
+                This is useful when using packed tensor format (single dimension for batch and sequence length).
+
+        Returns:
+
+        Example:
+
+        ```python
+        >>> from transformers import AutoTokenizer, LlamaForCausalLM
+
+        >>> model = LlamaForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
+        >>> tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
+
+        >>> prompt = "Hey, are you conscious? Can you talk to me?"
+        >>> inputs = tokenizer(prompt, return_tensors="pt")
+
+        >>> # Generate
+        >>> generate_ids = model.generate(inputs.input_ids, max_length=30)
+        >>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
+        "Hey, are you conscious? Can you talk to me?\nI'm not conscious, but I can talk to you."
+        ```"""
+        output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
+        output_hidden_states = (
+            output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
+        )
+        return_dict = return_dict if return_dict is not None else self.config.use_return_dict
+
+        # decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
+        outputs = self.model(
+            input_ids=input_ids,
+            attention_mask=attention_mask,
+            position_ids=position_ids,
+            past_key_values=past_key_values,
+            inputs_embeds=inputs_embeds,
+            use_cache=use_cache,
+            output_attentions=output_attentions,
+            output_hidden_states=output_hidden_states,
+            return_dict=return_dict,
+            cache_position=cache_position,
+            **kwargs,
+        )
+
+        hidden_states = outputs[0]
+        # Only compute necessary logits, and do not upcast them to float if we are not computing the loss
+        slice_indices = slice(-logits_to_keep, None) if isinstance(logits_to_keep, int) else logits_to_keep
+        logits = self.lm_head(hidden_states[:, slice_indices, :])
+
+        loss = None
+        if labels is not None:
+            loss = self.loss_function(logits=logits, labels=labels, vocab_size=self.config.vocab_size, **kwargs)
+
+        if not return_dict:
+            output = (logits,) + outputs[1:]
+            return (loss,) + output if loss is not None else output
+
+        return CausalLMOutputWithPast(
+            loss=loss,
+            logits=logits,
+            past_key_values=outputs.past_key_values,
+            hidden_states=outputs.hidden_states,
+            attentions=outputs.attentions,
+        )
+
+
+@add_start_docstrings(
+    """
+    The LLaMa Model transformer with a sequence classification head on top (linear layer).
+
+    [`LlamaForSequenceClassification`] uses the last token in order to do the classification, as other causal models
+    (e.g. GPT-2) do.
+
+    Since it does classification on the last token, it requires to know the position of the last token. If a
+    `pad_token_id` is defined in the configuration, it finds the last token that is not a padding token in each row. If
+    no `pad_token_id` is defined, it simply takes the last value in each row of the batch. Since it cannot guess the
+    padding tokens when `inputs_embeds` are passed instead of `input_ids`, it does the same (take the last value in
+    each row of the batch).
+    """,
+    LLAMA_START_DOCSTRING,
+)
+class LlamaForSequenceClassification(LlamaPreTrainedModel):
+    def __init__(self, config):
+        super().__init__(config)
+        self.num_labels = config.num_labels
+        self.model = LlamaModel(config)
+        self.score = nn.Linear(config.hidden_size, self.num_labels, bias=False)
+
+        # Initialize weights and apply final processing
+        self.post_init()
+
+    def get_input_embeddings(self):
+        return self.model.embed_tokens
+
+    def set_input_embeddings(self, value):
+        self.model.embed_tokens = value
+
+    @add_start_docstrings_to_model_forward(LLAMA_INPUTS_DOCSTRING)
+    def forward(
+        self,
+        input_ids: Optional[torch.LongTensor] = None,
+        attention_mask: Optional[torch.Tensor] = None,
+        position_ids: Optional[torch.LongTensor] = None,
+        past_key_values: Optional[Union[Cache, List[torch.FloatTensor]]] = None,
+        inputs_embeds: Optional[torch.FloatTensor] = None,
+        labels: Optional[torch.LongTensor] = None,
+        use_cache: Optional[bool] = None,
+        output_attentions: Optional[bool] = None,
+        output_hidden_states: Optional[bool] = None,
+        return_dict: Optional[bool] = None,
+    ) -> Union[Tuple, SequenceClassifierOutputWithPast]:
+        r"""
+        labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
+            Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
+            config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
+            `config.num_labels > 1` a classification loss is computed (Cross-Entropy).
+        """
+        return_dict = return_dict if return_dict is not None else self.config.use_return_dict
+
+        transformer_outputs = self.model(
+            input_ids,
+            attention_mask=attention_mask,
+            position_ids=position_ids,
+            past_key_values=past_key_values,
+            inputs_embeds=inputs_embeds,
+            use_cache=use_cache,
+            output_attentions=output_attentions,
+            output_hidden_states=output_hidden_states,
+            return_dict=return_dict,
+        )
+        hidden_states = transformer_outputs[0]
+        logits = self.score(hidden_states)
+
+        if input_ids is not None:
+            batch_size = input_ids.shape[0]
+        else:
+            batch_size = inputs_embeds.shape[0]
+
+        if self.config.pad_token_id is None and batch_size != 1:
+            raise ValueError("Cannot handle batch sizes > 1 if no padding token is defined.")
+        if self.config.pad_token_id is None:
+            last_non_pad_token = -1
+        elif input_ids is not None:
+            # To handle both left- and right- padding, we take the rightmost token that is not equal to pad_token_id
+            non_pad_mask = (input_ids != self.config.pad_token_id).to(logits.device, torch.int32)
+            token_indices = torch.arange(input_ids.shape[-1], device=logits.device)
+            last_non_pad_token = (token_indices * non_pad_mask).argmax(-1)
+        else:
+            last_non_pad_token = -1
+            logger.warning_once(
+                f"{self.__class__.__name__} will not detect padding tokens in `inputs_embeds`. Results may be "
+                "unexpected if using padding tokens in conjunction with `inputs_embeds.`"
+            )
+
+        pooled_logits = logits[torch.arange(batch_size, device=logits.device), last_non_pad_token]
+
+        loss = None
+        if labels is not None:
+            loss = self.loss_function(logits=logits, labels=labels, pooled_logits=pooled_logits, config=self.config)
+
+        if not return_dict:
+            output = (pooled_logits,) + transformer_outputs[1:]
+            return ((loss,) + output) if loss is not None else output
+
+        return SequenceClassifierOutputWithPast(
+            loss=loss,
+            logits=pooled_logits,
+            past_key_values=transformer_outputs.past_key_values,
+            hidden_states=transformer_outputs.hidden_states,
+            attentions=transformer_outputs.attentions,
+        )
+
+
+@add_start_docstrings(
+    """
+The Llama Model transformer with a span classification head on top for extractive question-answering tasks like
+SQuAD (a linear layer on top of the hidden-states output to compute `span start logits` and `span end logits`).
+    """,
+    LLAMA_START_DOCSTRING,
+)
+class LlamaForQuestionAnswering(LlamaPreTrainedModel):
+    base_model_prefix = "transformer"
+
+    # Copied from transformers.models.bloom.modeling_bloom.BloomForQuestionAnswering.__init__ with Bloom->Llama
+    def __init__(self, config):
+        super().__init__(config)
+        self.transformer = LlamaModel(config)
+        self.qa_outputs = nn.Linear(config.hidden_size, 2)
+
+        # Initialize weights and apply final processing
+        self.post_init()
+
+    def get_input_embeddings(self):
+        return self.transformer.embed_tokens
+
+    def set_input_embeddings(self, value):
+        self.transformer.embed_tokens = value
+
+    @add_start_docstrings_to_model_forward(LLAMA_INPUTS_DOCSTRING)
+    def forward(
+        self,
+        input_ids: Optional[torch.LongTensor] = None,
+        attention_mask: Optional[torch.FloatTensor] = None,
+        position_ids: Optional[torch.LongTensor] = None,
+        past_key_values: Optional[Union[Cache, List[torch.FloatTensor]]] = None,
+        inputs_embeds: Optional[torch.FloatTensor] = None,
+        start_positions: Optional[torch.LongTensor] = None,
+        end_positions: Optional[torch.LongTensor] = None,
+        output_attentions: Optional[bool] = None,
+        output_hidden_states: Optional[bool] = None,
+        return_dict: Optional[bool] = None,
+        **kwargs,
+    ) -> Union[Tuple, QuestionAnsweringModelOutput]:
+        r"""
+        start_positions (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
+            Labels for position (index) of the start of the labelled span for computing the token classification loss.
+            Positions are clamped to the length of the sequence (`sequence_length`). Position outside of the sequence
+            are not taken into account for computing the loss.
+        end_positions (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
+            Labels for position (index) of the end of the labelled span for computing the token classification loss.
+            Positions are clamped to the length of the sequence (`sequence_length`). Position outside of the sequence
+            are not taken into account for computing the loss.
+        """
+        return_dict = return_dict if return_dict is not None else self.config.use_return_dict
+
+        outputs = self.transformer(
+            input_ids,
+            attention_mask=attention_mask,
+            position_ids=position_ids,
+            past_key_values=past_key_values,
+            inputs_embeds=inputs_embeds,
+            output_attentions=output_attentions,
+            output_hidden_states=output_hidden_states,
+            return_dict=return_dict,
+        )
+
+        sequence_output = outputs[0]
+
+        logits = self.qa_outputs(sequence_output)
+        start_logits, end_logits = logits.split(1, dim=-1)
+        start_logits = start_logits.squeeze(-1).contiguous()
+        end_logits = end_logits.squeeze(-1).contiguous()
+
+        loss = None
+        if start_positions is not None and end_positions is not None:
+            loss = self.loss_function(start_logits, end_logits, start_positions, end_positions, **kwargs)
+
+        if not return_dict:
+            output = (start_logits, end_logits) + outputs[2:]
+            return ((loss,) + output) if loss is not None else output
+
+        return QuestionAnsweringModelOutput(
+            loss=loss,
+            start_logits=start_logits,
+            end_logits=end_logits,
+            hidden_states=outputs.hidden_states,
+            attentions=outputs.attentions,
+        )
+
+
+@add_start_docstrings(
+    """
+    The Llama Model transformer with a token classification head on top (a linear layer on top of the hidden-states
+    output) e.g. for Named-Entity-Recognition (NER) tasks.
+    """,
+    LLAMA_START_DOCSTRING,
+)
+class LlamaForTokenClassification(LlamaPreTrainedModel):
+    def __init__(self, config):
+        super().__init__(config)
+        self.num_labels = config.num_labels
+        self.model = LlamaModel(config)
+        if getattr(config, "classifier_dropout", None) is not None:
+            classifier_dropout = config.classifier_dropout
+        elif getattr(config, "hidden_dropout", None) is not None:
+            classifier_dropout = config.hidden_dropout
+        else:
+            classifier_dropout = 0.1
+        self.dropout = nn.Dropout(classifier_dropout)
+        self.score = nn.Linear(config.hidden_size, config.num_labels)
+
+        # Initialize weights and apply final processing
+        self.post_init()
+
+    def get_input_embeddings(self):
+        return self.model.embed_tokens
+
+    def set_input_embeddings(self, value):
+        self.model.embed_tokens = value
+
+    @add_start_docstrings_to_model_forward(LLAMA_INPUTS_DOCSTRING)
+    @add_code_sample_docstrings(
+        checkpoint=_CHECKPOINT_FOR_DOC,
+        output_type=TokenClassifierOutput,
+        config_class=_CONFIG_FOR_DOC,
+    )
+    def forward(
+        self,
+        input_ids: Optional[torch.LongTensor] = None,
+        attention_mask: Optional[torch.Tensor] = None,
+        position_ids: Optional[torch.LongTensor] = None,
+        past_key_values: Optional[List[torch.FloatTensor]] = None,
+        inputs_embeds: Optional[torch.FloatTensor] = None,
+        labels: Optional[torch.LongTensor] = None,
+        use_cache: Optional[bool] = None,
+        output_attentions: Optional[bool] = None,
+        output_hidden_states: Optional[bool] = None,
+        return_dict: Optional[bool] = None,
+    ) -> Union[Tuple, TokenClassifierOutput]:
+        r"""
+        labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
+            Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
+            config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
+            `config.num_labels > 1` a classification loss is computed (Cross-Entropy).
+        """
+        return_dict = return_dict if return_dict is not None else self.config.use_return_dict
+
+        outputs = self.model(
+            input_ids,
+            attention_mask=attention_mask,
+            position_ids=position_ids,
+            past_key_values=past_key_values,
+            inputs_embeds=inputs_embeds,
+            use_cache=use_cache,
+            output_attentions=output_attentions,
+            output_hidden_states=output_hidden_states,
+            return_dict=return_dict,
+        )
+        sequence_output = outputs[0]
+        sequence_output = self.dropout(sequence_output)
+        logits = self.score(sequence_output)
+
+        loss = None
+        if labels is not None:
+            loss = self.loss_function(logits, labels, self.config)
+
+        if not return_dict:
+            output = (logits,) + outputs[2:]
+            return ((loss,) + output) if loss is not None else output
+
+        return TokenClassifierOutput(
+            loss=loss,
+            logits=logits,
+            hidden_states=outputs.hidden_states,
+            attentions=outputs.attentions,
+        )
+
+
+__all__ = [
+    "LlamaForCausalLM",
+    "LlamaModel",
+    "LlamaPreTrainedModel",
+    "LlamaForSequenceClassification",
+    "LlamaForQuestionAnswering",
+    "LlamaForTokenClassification",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/models/utils_quant.py b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/utils_quant.py
new file mode 100644
index 0000000000000000000000000000000000000000..cae2c7d0fb9e05137f4fe2ba8629d0efea4dfb30
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/paretoq/models/utils_quant.py
@@ -0,0 +1,289 @@
+# coding=utf-8
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree.
+
+import math
+
+import torch
+import torch.nn as nn
+
+class LsqBinaryTernaryExtension(torch.autograd.Function):
+    """
+    Modified from Learned Step-size Quantization.
+    https://arxiv.org/abs/1902.08153
+    """
+
+    @staticmethod
+    def forward(ctx, input, alpha, num_bits, layerwise):
+        """
+        :param input: input to be quantized
+        :param alpha: the step size
+        :param num_bits: quantization bits
+        :param layerwise: rowwise quant
+        :return: quantized output
+        """
+        ctx.num_bits = num_bits
+        if num_bits >= 16:
+            return input
+        if num_bits == 1 or num_bits == 0:
+            Qn = -1
+            Qp = 1
+        else:
+            Qn = -(2 ** (num_bits - 1))
+            Qp = 2 ** (num_bits - 1) - 1
+
+        eps = torch.tensor(0.00001, device=alpha.device).float()
+
+        alpha = torch.where(alpha > eps, alpha, eps)
+
+        grad_scale = (
+            1.0 / math.sqrt(input.numel())
+            if not Qp
+            else 1.0 / math.sqrt(input.numel() * Qp)
+        )
+        ctx.save_for_backward(input, alpha)
+        ctx.other = grad_scale, Qn, Qp, layerwise
+        if num_bits == 1:
+            q_w = input.sign()
+        else:
+            q_w = (input / alpha).round().clamp(Qn, Qp)
+        w_q = q_w * alpha
+        return w_q
+
+    @staticmethod
+    def backward(ctx, grad_output):
+        if ctx.num_bits >= 16:
+            return grad_output, None, None, None
+
+        input_, alpha = ctx.saved_tensors
+        grad_scale, Qn, Qp, layerwise = ctx.other
+        q_w = input_ / alpha
+        indicate_small = (q_w < Qn).float()
+        indicate_big = (q_w > Qp).float()
+        indicate_middle = (
+            1.0 - indicate_small - indicate_big
+        )  # this is more cpu-friendly than torch.ones(input_.shape)
+        if ctx.num_bits == 1:
+            if layerwise:
+                grad_alpha = (
+                    ((input_.sign()) * grad_output * grad_scale).sum().unsqueeze(dim=0)
+                )
+            else:
+                grad_alpha = (input_.sign()) * grad_output * grad_scale
+                grad_alpha = torch.sum(grad_alpha, dim=-1, keepdim=True)
+        else:
+            if layerwise:
+                grad_alpha = (
+                    (
+                        (
+                            indicate_small * Qn
+                            + indicate_big * Qp
+                            + indicate_middle * (-q_w + q_w.round())
+                        )
+                        * grad_output
+                        * grad_scale
+                    )
+                    .sum()
+                    .unsqueeze(dim=0)
+                )
+            else:
+                grad_alpha = (
+                    (
+                        indicate_small * Qn
+                        + indicate_big * Qp
+                        + indicate_middle * (-q_w + q_w.round())
+                    )
+                    * grad_output
+                    * grad_scale
+                )
+                grad_alpha = torch.sum(grad_alpha, dim=-1, keepdim=True)
+
+        grad_input = indicate_middle * grad_output
+        return grad_input, grad_alpha, None, None
+
+
+class StretchedElasticQuant(torch.autograd.Function):
+    """
+    Modified from Learned Step-size Quantization.
+    https://arxiv.org/abs/1902.08153
+    """
+
+    @staticmethod
+    def forward(ctx, input, alpha, num_bits, layerwise):
+        """
+        :param input: input to be quantized
+        :param alpha: the step size
+        :param num_bits: quantization bits
+        :param layerwise: rowwise quant
+        :return: quantized output
+        """
+        ctx.num_bits = num_bits
+        if num_bits >= 16:
+            return input
+        if num_bits == 1 or num_bits == 0:
+            Qn = -1
+            Qp = 1
+        else:
+            Qn = -(2 ** (num_bits - 1))
+            Qp = 2 ** (num_bits - 1) - 1
+
+        eps = torch.tensor(0.00001, device=alpha.device).float()
+        alpha = torch.where(alpha > eps, alpha, eps)
+
+        grad_scale = (
+            1.0 / math.sqrt(input.numel())
+            if not Qp
+            else 1.0 / math.sqrt(input.numel() * Qp)
+        )
+        ctx.save_for_backward(input, alpha)
+        clip_val = 1 - 1e-2
+        if num_bits == 0:
+            n_levels = 1.5
+            shift = 0
+        else:
+            n_levels = 2 ** (num_bits - 1)
+            shift = 0.5
+        Qp = (n_levels - shift) / n_levels
+        Qn = -Qp
+        ctx.other = grad_scale, Qn, Qp, layerwise
+        if num_bits == 1:
+            q_w = input.sign()
+        else:
+            q_w = (
+                torch.round(
+                    torch.clamp(input / alpha, -clip_val, clip_val) * n_levels - shift
+                )
+                + shift
+            ) / n_levels
+        w_q = q_w * alpha
+        return w_q
+
+    @staticmethod
+    def backward(ctx, grad_output):
+        if ctx.num_bits >= 16:
+            return grad_output, None, None, None
+
+        input_, alpha = ctx.saved_tensors
+        grad_scale, Qn, Qp, layerwise = ctx.other
+        q_w = input_ / alpha
+        clip_val = 1 - 1e-2
+        if ctx.num_bits == 0:
+            n_levels = 1.5
+            shift = 0
+        else:
+            n_levels = 2 ** (ctx.num_bits - 1)
+            shift = 0.5
+        indicate_small = (q_w < -clip_val).float()
+        indicate_big = (q_w > clip_val).float()
+        indicate_middle = (
+            1.0 - indicate_small - indicate_big
+        )
+        if ctx.num_bits == 1:
+            if layerwise:
+                grad_alpha = (
+                    ((input_.sign()) * grad_output * grad_scale).sum().unsqueeze(dim=0)
+                )
+            else:
+                grad_alpha = (input_.sign()) * grad_output * grad_scale
+                grad_alpha = torch.sum(grad_alpha, dim=-1, keepdim=True)
+        else:
+            if layerwise:
+                grad_alpha = (
+                    (
+                        (
+                            indicate_small * Qn
+                            + indicate_big * Qp
+                            + indicate_middle
+                            * (
+                                -q_w
+                                + (
+                                    torch.round(
+                                        torch.clamp(q_w, -clip_val, clip_val) * n_levels
+                                        - shift
+                                    )
+                                    + shift
+                                )
+                                / n_levels
+                            )
+                        )
+                        * grad_output
+                        * grad_scale
+                    )
+                    .sum()
+                    .unsqueeze(dim=0)
+                )
+            else:
+                grad_alpha = (
+                    (
+                        indicate_small * Qn
+                        + indicate_big * Qp
+                        + indicate_middle
+                        * (
+                            -q_w
+                            + (
+                                torch.round(
+                                    torch.clamp(q_w, -clip_val, clip_val) * n_levels
+                                    - shift
+                                )
+                                + shift
+                            )
+                            / n_levels
+                        )
+                    )
+                    * grad_output
+                    * grad_scale
+                )
+                grad_alpha = torch.sum(grad_alpha, dim=-1, keepdim=True)
+
+        grad_input = indicate_middle * grad_output
+        return grad_input, grad_alpha, None, None
+
+
+
+class QuantizeLinear(nn.Linear):
+    def __init__(
+        self,
+        *kargs,
+        symmetric=True,
+        bias=False,
+        w_bits=16,
+        weight_layerwise=False,
+    ):
+        super(QuantizeLinear, self).__init__(*kargs, bias=False)
+        self.w_bits = w_bits
+        self.weight_layerwise = weight_layerwise
+        # params for weight quant
+        if self.w_bits < 16:
+            self.weight_clip_val = nn.Parameter(torch.Tensor(self.weight.shape[0], 1))
+
+    def forward(self, input_):
+        # quantize weight
+        assert len(self.weight.size()) == 2
+        real_weights = self.weight
+
+        if self.w_bits >= 16:
+            weight = self.weight
+        elif self.w_bits == 2 or self.w_bits == 0:
+            weight = StretchedElasticQuant.apply(
+                real_weights,
+                self.weight_clip_val,
+                self.w_bits,
+                self.weight_layerwise,
+            ).to(input_.dtype)
+        elif self.w_bits <= 4:
+            weight = LsqBinaryTernaryExtension.apply(
+                real_weights,
+                self.weight_clip_val,
+                self.w_bits,
+                self.weight_layerwise,
+            ).to(input_.dtype)
+        else:
+            raise NotImplementedError
+
+        out = nn.functional.linear(input_, weight)
+        if self.bias is not None:
+            out += self.bias.view(1, -1).expand_as(out)
+
+        return out
diff --git a/lib/python3.12/site-packages/torchao/prototype/paretoq/train.py b/lib/python3.12/site-packages/torchao/prototype/paretoq/train.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe52f4c187a7365af1275bbaa5303698a9d2eebe
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/paretoq/train.py
@@ -0,0 +1,122 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree.
+
+import math
+from models.configuration_llama import LlamaConfig
+from models.modeling_llama_quant import (
+    LlamaForCausalLM as LlamaForCausalLMQuant,
+)
+import copy
+import torch
+import transformers
+from utils import utils
+from utils import datautils
+
+from utils.process_args import process_args
+from torch import distributed as dist
+from transformers import default_data_collator, Trainer
+
+log = utils.get_logger("clm")
+
+
+def train():
+    dist.init_process_group(backend="nccl")
+    model_args, data_args, training_args = process_args()
+
+    log.info("Start to load model...")
+    dtype = torch.bfloat16 if training_args.bf16 else torch.float
+
+    config = LlamaConfig.from_pretrained(model_args.input_model_filename)
+    config.w_bits = model_args.w_bits
+    model = LlamaForCausalLMQuant.from_pretrained(
+        pretrained_model_name_or_path=model_args.input_model_filename,
+        config=config,
+        cache_dir=training_args.cache_dir,
+        torch_dtype=dtype,
+        low_cpu_mem_usage=True,
+        device_map='cpu',
+    )
+
+    if not model_args.contain_weight_clip_val:
+        for name, param in model.named_parameters():
+            if "weight_clip_val" in name:
+                weight_name = name.replace("weight_clip_val", "weight")
+                weight_param = dict(model.named_parameters()).get(weight_name, None)
+
+                if model_args.w_bits == 1:
+                    scale = torch.mean(weight_param.abs(), dim=-1, keepdim=True).detach()
+                elif model_args.w_bits == 0 or model_args.w_bits == 2:
+                    scale, _ = torch.max(torch.abs(weight_param), dim=-1, keepdim=True)
+                elif model_args.w_bits == 3 or model_args.w_bits == 4:
+                    xmax, _ = torch.max(torch.abs(weight_param), dim=-1, keepdim=True)
+                    maxq = 2 ** (model_args.w_bits - 1) - 1
+                    scale = xmax / maxq
+                else:
+                    raise NotImplementedError
+
+                param.data.copy_(scale)
+
+    model.cuda()
+    log.info("Complete model loading...")
+
+    log.info("Start to load tokenizer...")
+    tokenizer = transformers.LlamaTokenizerFast.from_pretrained(
+        pretrained_model_name_or_path=model_args.input_model_filename,
+        cache_dir=training_args.cache_dir,
+        model_max_length=training_args.model_max_length,
+        padding_side="right",
+        add_bos_token=False,
+        add_eos_token=False,
+    )
+    log.info("Complete tokenizer loading...")
+
+    train_dataset, valid_dataset = datautils.get_train_val_dataset(
+        train_path=data_args.train_data_local_path,
+        valid_path=data_args.eval_data_local_path
+        if data_args.eval_data_local_path is not None
+        else None,
+    )
+    train_data = datautils.CustomJsonDataset(
+        train_dataset, tokenizer, block_size=training_args.model_max_length
+    )
+    valid_data = datautils.CustomJsonDataset(
+        valid_dataset, tokenizer, block_size=min(training_args.model_max_length, 1024)
+    )
+    model.config.use_cache = False
+    myTrainer = Trainer
+    trainer = myTrainer(
+        model=model,
+        tokenizer=tokenizer,
+        args=training_args,
+        train_dataset=train_data if training_args.do_train else None,
+        eval_dataset=valid_data if training_args.do_eval else None,
+        data_collator=default_data_collator,
+    )
+
+    if training_args.do_train:
+        train_result = trainer.train()
+        trainer.save_state()
+        utils.safe_save_model_for_hf_trainer(trainer, model_args.output_model_local_path)
+
+    # Evaluation
+    if training_args.do_eval:
+        model.to("cuda")
+        metrics = trainer.evaluate()
+        max_eval_samples = len(valid_data)
+        metrics["eval_samples"] = min(max_eval_samples, len(valid_data))
+        try:
+            perplexity = math.exp(metrics["eval_loss"])
+        except OverflowError:
+            perplexity = float("inf")
+        metrics["perplexity"] = perplexity
+
+        trainer.log_metrics("eval", metrics)
+        trainer.save_metrics("eval", metrics)
+
+    torch.distributed.barrier()
+
+
+if __name__ == "__main__":
+    train()
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantization/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..bf49e2717b0b4c1573cae525c58c80c737a1299f
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/__init__.py
@@ -0,0 +1,5 @@
+from .gguf import GGUFWeightOnlyConfig
+
+__all__ = [
+    "GGUFWeightOnlyConfig",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a4752875c41025fbfc3a76460e9b66a3000d9828
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/__pycache__/autoquant_v2.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/__pycache__/autoquant_v2.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b12ba53cb86e5edfe88cc79b22d1e7cef6433ee8
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/__pycache__/autoquant_v2.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/autoquant_v2.py b/lib/python3.12/site-packages/torchao/prototype/quantization/autoquant_v2.py
new file mode 100644
index 0000000000000000000000000000000000000000..8966bd52268253fd76abe121a4eea90c82dbc835
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/autoquant_v2.py
@@ -0,0 +1,1457 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import copy
+import csv
+import logging
+import os
+import re
+from itertools import chain
+
+import torch
+import torch.nn.functional as F
+from torch.utils._python_dispatch import return_and_correct_aliasing
+from torch.utils._pytree import tree_map
+
+import torchao
+from torchao.dtypes import (
+    AffineQuantizedTensor,
+    Float8Layout,
+    PlainLayout,
+    TensorCoreTiledLayout,
+)
+from torchao.float8.inference import Float8MMConfig
+from torchao.kernel import safe_int_mm
+from torchao.prototype.quantization.subgraph_utils.extract_subgraphs import (
+    debug_linears_for_float8,
+    prepare_target_folder,
+)
+from torchao.quantization import LinearActivationQuantizedTensor
+from torchao.quantization.autoquant import (
+    AutoQuantizableLinearWeight as AutoQuantizableLinearWeightV1,
+)
+from torchao.quantization.granularity import (
+    PerRow,
+    PerTensor,
+)
+from torchao.quantization.quant_primitives import (
+    MappingType,
+    ZeroPointDomain,
+)
+from torchao.quantization.subclass import (  # noqa
+    Int8DynamicallyQuantizedLinearWeight,
+    Int8WeightOnlyQuantizedLinearWeight,
+    QuantizedLinearWeightBase,
+)
+from torchao.quantization.utils import quantize_activation_per_token_absmax
+from torchao.utils import (
+    TORCH_VERSION_AT_LEAST_2_3,
+    TORCH_VERSION_AT_LEAST_2_5,
+    TorchAOBaseTensor,
+    is_sm_at_least_89,
+    is_sm_at_least_90,
+)
+
+logging.basicConfig(level=logging.ERROR)  # Set the root logger level to ERROR
+
+
+target_folder = "/home/jerryzh/local/tmp/20241104_dynamo_test"
+
+__all__ = [
+    "AutoQuantizableLinearWeight",
+    "autoquant_v2",
+    "DEFAULT_AUTOQUANT_CLASS_LIST",
+    "DEFAULT_INT4_AUTOQUANT_CLASS_LIST",
+    "DEFAULT_FLOAT_AUTOQUANT_CLASS_LIST",
+    "OTHER_AUTOQUANT_CLASS_LIST",
+    "ALL_AUTOQUANT_CLASS_LIST",
+    "_is_linear",
+]
+
+
+def _is_linear(mod, *args):
+    # avoid circular dependencies
+    from torchao.quantization.qat.affine_fake_quantized_tensor import (
+        AffineFakeQuantizedTensor,
+    )
+
+    # adding weight tensor subclass isinstance check to make sure the weight is only quantized once
+    # when it is shared by multiple linear modules
+    return (
+        isinstance(mod, torch.nn.Linear)
+        and hasattr(mod, "weight")
+        and not isinstance(mod.weight, QuantizedLinearWeightBase)
+        and not isinstance(mod.weight, AutoQuantizableLinearWeightV1)
+        and not isinstance(mod.weight, AffineQuantizedTensor)
+        and not isinstance(mod.weight, LinearActivationQuantizedTensor)
+        and not isinstance(mod.weight, AffineFakeQuantizedTensor)
+        and not isinstance(mod, torch.nn.modules.linear.NonDynamicallyQuantizableLinear)
+    )
+
+
+# TODO: use SubgraphMatcher
+def _graph_equals(g1, g2):
+    if len(g1.nodes) != len(g2.nodes):
+        return False
+
+    for n1, n2 in zip(g1.nodes, g2.nodes):
+        if n1.op != n2.op:
+            return False
+
+        if n1.op in ["call_function", "call_method"] and n1.target != n2.target:
+            return False
+
+        if len(n1.args) != len(n2.args):
+            return False
+    return True
+
+
+aten = torch.ops.aten
+
+AUTOQUANT_CACHE = {}
+
+# This is a flag to control whether we do some rewrite for graph
+# to account for different batch sizes, it's a temporary solution for llama model
+# we'll need to think about how to support this more generally
+LLAMA = True
+
+
+def check_cache(gm, cls, shapes_and_dtype):
+    for gm_, cls_, shapes_and_dtype_ in AUTOQUANT_CACHE.keys():
+        graph_equals = _graph_equals(gm_.graph, gm.graph)
+        if graph_equals and cls_ is cls and shapes_and_dtype_ == shapes_and_dtype:
+            return AUTOQUANT_CACHE[(gm_, cls_, shapes_and_dtype_)]
+    return None
+
+
+def update_cache(gm, cls, shapes_and_dtype, res):
+    AUTOQUANT_CACHE[(gm, cls, shapes_and_dtype)] = res
+
+
+# adjust each input's bsz to target_bsz
+# enable grad
+# a hacky solution but should work in the use cases we are testing now
+# we went through the list of sizes and swap the dimension that matches extracted_bsz to target_bsz
+def resize_input(t, extracted_bsz, target_bsz):
+    if len(t.shape) > 1:
+        new_shape = []
+        for i in range(len(t.size())):
+            if t.size(i) == extracted_bsz:
+                new_shape.append(target_bsz)
+            else:
+                new_shape.append(t.size(i))
+        t = torch.randn(*new_shape, dtype=t.dtype, device=t.device)
+    return t
+
+
+# a hacky solution but should work in the use cases we are testing now
+# we went through the list of sizes and swap the dimension that matches extracted_bsz to target_bsz
+def maybe_adjust_model_bsz(m, extracted_bsz, target_bsz):
+    """
+    Makes guesses on how to adjust the model graph to account for the
+    fact that we changed the batch size. Note: this is very brittle
+    """
+    for n in m.graph.nodes:
+        if n.op == "call_method" and n.target == "view":
+            new_args = []
+            for arg in n.args:
+                if arg == extracted_bsz:
+                    new_args.append(target_bsz)
+                else:
+                    new_args.append(arg)
+            n.args = tuple(new_args)
+
+    m.recompile()
+
+
+# TODO: Document the methods
+class AutoQuantizableLinearWeight(torch.Tensor):
+    """
+    A subclass of torch.Tensor that, when run, finds the best type of quantization for itself and swaps
+    its data with the quantized version.
+
+    Args:
+        weight (torch.Tensor): The initial weight tensor.
+        qtensor_class_list (list): A list of tensor classes to be considered for quantization.
+        *args: Additional positional arguments.
+        mode (list, optional): A list containing mode settings for quantization. The first element is the mode type
+                               (e.g., "relu"), and the second element is the mode value (e.g., None). Defaults to ["relu", None].
+        **kwargs: Additional keyword arguments.
+    """
+
+    @staticmethod
+    def __new__(
+        cls,
+        weight,
+        qtensor_class_list,
+        *args,
+        mode=["relu", None],
+        model=None,
+        fqn=None,
+        example_inputs=None,
+        fqn_to_submodule=None,
+        batch_size=None,
+        **kwargs,
+    ):
+        kwargs["device"] = weight.device
+        kwargs["layout"] = (
+            kwargs.get("layout") if kwargs.get("layout", False) else weight.layout
+        )
+        kwargs["dtype"] = (
+            kwargs.get("dtype") if kwargs.get("dtype", False) else weight.dtype
+        )
+        kwargs["requires_grad"] = False
+        shape = kwargs.pop("shape", weight.shape)
+        return torch.Tensor._make_wrapper_subclass(cls, shape, **kwargs)  # type: ignore[attr-defined]
+
+    def __init__(
+        self,
+        weight,
+        qtensor_class_list,
+        *args,
+        mode=["relu", None],
+        model=None,
+        fqn=None,
+        example_inputs=None,
+        fqn_to_submodule=None,
+        batch_size=None,
+        **kwargs,
+    ):
+        self.weight = weight
+        self.qtensor_class_list = qtensor_class_list
+        self.logged_data = {}
+        self.mode = mode
+        self.model = model
+        self.fqn = fqn
+        self.example_inputs = example_inputs
+        self.fqn_to_submodule = fqn_to_submodule
+        self.batch_size = batch_size
+
+    def __repr__(self):
+        return (
+            f"{self.__class__.__name__}(data={self.weight}, shape={self.shape}, "
+            f"device={self.device}, dtype={self.dtype}, qtensor_class_list={self.qtensor_class_list})"
+        )
+
+    @staticmethod
+    def log_shape(act_mat, w_autoquant, bias):
+        act_mat = act_mat.reshape(-1, act_mat.shape[-1])
+        logged_dtype = act_mat.dtype
+        logged_shapes = (
+            act_mat.shape,
+            w_autoquant.shape,
+            None if bias is None else bias.shape,
+        )
+        shapes_and_dtype = logged_shapes + (logged_dtype,)
+        w_autoquant.logged_data[shapes_and_dtype] = 1 + w_autoquant.logged_data.get(
+            shapes_and_dtype, 0
+        )
+
+    def tune_autoquant2(
+        self, fqn, m, batch_size, inputs, q_cls, shapes_and_dtype, time_for_best_shape
+    ):
+        act_shape, w_shape, bias_shape, act_dtype = shapes_and_dtype
+
+        with torch.no_grad():
+            try:
+                m_copy = copy.deepcopy(m)
+                for name, module in m_copy.named_modules():
+                    if isinstance(module, torch.nn.Linear):
+                        linear_module = module
+                weight = q_cls.from_float(linear_module.weight)
+                linear_module.weight = torch.nn.Parameter(weight, requires_grad=False)
+                if batch_size is not None:
+                    extracted_bsz = batch_size
+                    target_bsz = act_shape[0]
+                    inputs = tree_map(
+                        lambda t: resize_input(t, extracted_bsz, target_bsz), inputs
+                    )
+                    maybe_adjust_model_bsz(m_copy, extracted_bsz, target_bsz)
+
+                m_copy = torch.compile(m_copy, mode="max-autotune-no-cudagraphs")
+
+                if isinstance(inputs, (list, tuple)):
+                    cur_time = do_autoquant_bench(m_copy, *inputs, warmup=25, rep=100)
+                else:
+                    cur_time = do_autoquant_bench(m_copy, **inputs, warmup=25, rep=100)
+                print(
+                    f">>time: {cur_time:0.3f}ms for {q_cls}, to_beat: {time_for_best_shape}"
+                )
+                if cur_time < time_for_best_shape:
+                    update_cache(m, q_cls, shapes_and_dtype, cur_time)
+                res = cur_time
+                return res
+            except Exception as e:
+                print(f"warning: failed to autoquant {q_cls.__name__} due to {e}")
+                return None
+
+    @torch.no_grad()
+    def to_quantized(self, error_on_unseen, **kwargs):
+        if error_on_unseen and self.logged_data == {}:
+            raise RuntimeError(
+                "must run module normally to get shape, dtype info for autoquant"
+            )
+        elif (self.logged_data == {}) and not error_on_unseen:
+            # default back to non-quantized weight if not seen
+            self = AQDefaultLinearWeight.from_float(self.weight)
+            return self
+
+        # only want to print shape (at start) and final result (at end)
+        # once per shape+quantization subclass combination.
+        ran_new_benchmarks = False
+        print_shape_once = True
+
+        def count_shapes(self, do_print=True):
+            differe_shape_count = 0
+            for shapes_and_dtype, times_seen in self.logged_data.items():
+                differe_shape_count += 1
+                if do_print:
+                    act_shape, weight_shape, bias_shape, dtype = shapes_and_dtype
+                    print(f"activation_shapes: {act_shape}, times_seen: {times_seen}")
+            if do_print:
+                print(
+                    f"weight_shape: {weight_shape}, dtype: {dtype}, bias_shape: {bias_shape}"
+                )
+            return differe_shape_count
+
+        # check each class
+        best_time = torch.inf
+        best_cls = None
+        fqn = self.fqn
+        print(f"autoquant for {fqn}")
+        for q_cls in self.qtensor_class_list:
+            # for each logged shape+dtype, benchmark
+            cur_time = 0
+            total_seen = 0
+            shape_count = count_shapes(self, do_print=False)
+            # copied from https://github.com/pytorch/pytorch/blob/75eeefbfab3862abe887e1d85a0b1b18c227d9f3/torch/_dynamo/variables/builder.py#L963
+            modified_fqn = "L__self___" + re.sub(r"[^a-zA-Z0-9]+", "_", fqn)
+            m, inputs = self.fqn_to_submodule[modified_fqn]
+            for shapes_and_dtype, times_seen in self.logged_data.items():
+                if check_cache(m, q_cls, shapes_and_dtype) is None:
+                    # only print shapes once
+                    if print_shape_once is True:
+                        print_shape_once = False
+                        count_shapes(self, do_print=True)
+
+                    time_for_best_shape = check_cache(m, q_cls, shapes_and_dtype)
+                    time_for_best_shape = (
+                        torch.inf
+                        if time_for_best_shape is None
+                        else time_for_best_shape
+                    )
+                    self.tune_autoquant2(
+                        fqn,
+                        m,
+                        self.batch_size,
+                        inputs,
+                        q_cls,
+                        shapes_and_dtype,
+                        time_for_best_shape,
+                    )
+                    ran_new_benchmarks = True
+                    torch._dynamo.reset()
+                if check_cache(m, q_cls, shapes_and_dtype) is not None:
+                    cur_time += check_cache(m, q_cls, shapes_and_dtype) * times_seen
+                    total_seen += times_seen
+
+            if total_seen != 0:
+                cur_time = cur_time / total_seen
+
+                # print aggregated time if there were multiple shapes to aggregate and some new benchmarking was done
+                if shape_count is not None and shape_count > 1 and ran_new_benchmarks:
+                    print(
+                        f">time (all shapes): {cur_time:0.4f}ms for {q_cls}, prev_best: {best_time:0.4f}ms"
+                    )
+                if best_time >= cur_time:
+                    best_time = cur_time
+                    best_cls = q_cls
+        # if no new benchmarking was done, don't print the final result, it will be the same as for another layer
+        if ran_new_benchmarks:
+            print(f"best_cls={best_cls}\n")
+        # TODO handle random cls args/kwargs? or should they be curried?
+        if best_cls is None:
+            best_cls = AQDefaultLinearWeight
+
+        self = best_cls.from_float(self.weight)
+        return self
+
+    def _apply_fn_to_data(self, fn):
+        return self.__class__(
+            fn(self.weight),
+            self.qtensor_class_list,
+            dtype=self.dtype,
+            mode=self.mode,
+            model=self.model,
+            fqn=self.fqn,
+            example_inputs=self.example_inputs,
+            fqn_to_submodule=self.fqn_to_submodule,
+            batch_size=self.batch_size,
+        )
+
+    def __tensor_flatten__(self):
+        return ["weight"], [
+            self.qtensor_class_list,
+            self.mode,
+            self.model,
+            self.fqn,
+            self.example_inputs,
+            self.fqn_to_submodule,
+            self.batch_size,
+            self.dtype,
+            self.shape,
+        ]
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls, tensor_data_dict, tensor_attributes, outer_size=None, outer_stride=None
+    ):
+        weight = tensor_data_dict["weight"]
+        (
+            qtensor_class_list,
+            mode,
+            model,
+            fqn,
+            example_inputs,
+            fqn_to_submodule,
+            batch_size,
+            dtype,
+            shape,
+        ) = tensor_attributes
+        return cls(
+            weight,
+            qtensor_class_list,
+            mode,
+            model=model,
+            fqn=fqn,
+            example_inputs=example_inputs,
+            fqn_to_submodule=fqn_to_submodule,
+            batch_size=batch_size,
+            shape=shape if outer_size is None else outer_size,
+            dtype=dtype,
+            strides=outer_stride,
+        )
+
+    @classmethod
+    def from_float(cls, weight, qtensor_class_list, **kwargs):
+        return cls(weight, qtensor_class_list, **kwargs)
+
+    @classmethod
+    def __torch_function__(cls, func, types, args=(), kwargs=None):
+        kwargs = {} if kwargs is None else kwargs
+
+        if func is torch.nn.functional.linear:
+            mat1, w_autoquant, bias = (
+                args[0],
+                args[1],
+                args[2] if len(args) > 2 else None,
+            )
+            cls.log_shape(mat1, w_autoquant, bias)
+            return func(mat1, w_autoquant.weight, bias)
+        try:
+            with torch._C.DisableTorchFunctionSubclass():
+                return func(*args, **kwargs)
+        except Exception:
+            print(f"ERR: subclass doesn't implement {func}")
+
+    @classmethod
+    def __torch_dispatch__(cls, func, types, args, kwargs):
+        if func is aten.detach.default:
+            return return_and_correct_aliasing(
+                func, args, kwargs, args[0]._apply_fn_to_data(torch.detach)
+            )
+
+
+@torch.no_grad()
+def do_autoquant_bench(op, *args, **kwargs):
+    """
+    runs benchmark op(*args, **kwargs) avoiding torch.compile overhead
+    """
+    rep = kwargs.pop("rep", 100)
+    warmup = kwargs.pop("warmup", 25)
+    with torch.no_grad():
+        torch.cuda.synchronize()
+        stream = torch.cuda.Stream()
+        stream.wait_stream(torch.cuda.current_stream())
+        with torch.cuda.stream(stream):
+            op(*args, **kwargs)
+        stream.synchronize()
+        torch.cuda.current_stream().wait_stream(stream)
+        torch.cuda.synchronize()
+        graph = torch.cuda.CUDAGraph()
+        with torch.cuda.graph(graph, stream=stream):
+            op(*args, **kwargs)
+        if TORCH_VERSION_AT_LEAST_2_5:
+            from torch._inductor.runtime.benchmarking import benchmarker
+
+            res = benchmarker.benchmark_gpu(
+                lambda: graph.replay(), warmup=warmup, rep=rep, return_mode="median"
+            )
+        elif TORCH_VERSION_AT_LEAST_2_3:
+            from torch._inductor.runtime.runtime_utils import do_bench_gpu
+
+            res = do_bench_gpu(
+                lambda: graph.replay(), warmup=warmup, rep=rep, return_mode="median"
+            )
+        else:
+            from torch._inductor.utils import do_bench
+
+            res = do_bench(
+                lambda: graph.replay(), warmup=warmup, rep=rep, return_mode="median"
+            )
+    return res
+
+
+def _is_interpolate_mode(mode):
+    if (
+        isinstance(mode, list)
+        and mode[0] == "interpolate"
+        and len(mode) == 2
+        and isinstance(mode[1], float)
+    ):
+        return True
+    return False
+
+
+class AQMixin:
+    """
+    Tests and benchmarks the autoquantization process for the given activation matrix, weight, and bias.
+
+    Args:
+        act_mat (torch.Tensor): The activation matrix.
+        weight (torch.Tensor): The weight tensor.
+        bias (torch.Tensor or None): The bias tensor.
+        best_time (float): The best time to beat for the quantization process.
+        mode (list, optional): A list containing mode settings for quantization. The first element is the mode type
+                                (e.g., "relu"), and the second element is the mode value (e.g., None). Defaults to ["relu", None].
+
+    Returns:
+        float: The benchmarked time for the autoquantization process.
+    """
+
+    @classmethod
+    def _autoquant_test(cls, act_mat, weight, bias, best_time, mode=["relu", None]):
+        w_qtensor = cls.from_float(weight)
+        if _is_interpolate_mode(mode):
+            q_c_op = torch.compile(
+                cls._quantized_linear_op, mode="max-autotune-no-cudagraphs"
+            )
+        else:
+            func = lambda a, b, c: F.relu(cls._quantized_linear_op(F.relu(a), b, c))
+            q_c_op = torch.compile(func, mode="max-autotune-no-cudagraphs")
+        res = do_autoquant_bench(q_c_op, act_mat, w_qtensor, bias, warmup=25, rep=100)
+        if res < best_time * 1.1:
+            res2 = do_autoquant_bench(
+                q_c_op, act_mat, w_qtensor, bias, warmup=25, rep=900
+            )
+            res = res2 * 0.9 + res * 0.1
+        print(f">>time: {res:0.3f}ms for {cls}, to_beat: {best_time:0.3f}ms ")
+        return res
+
+
+class AQInt8DynamicallyQuantizedLinearWeight(AQMixin, LinearActivationQuantizedTensor):
+    """
+    AutoQuantizable version of Int8DynamicallyQuantizedLinearWeight
+    """
+
+    @classmethod
+    def from_float(cls, weight):
+        # TODO test if this is valid
+        # in_features = weight.shape[1]
+        # int8 dynamic quantization only has benefit when in_feature > 16
+        # if in_features <= 16:
+        # return weight
+
+        # avoid circular dep
+        from torchao.dtypes import to_affine_quantized_intx
+
+        # weight settings
+        mapping_type = MappingType.SYMMETRIC
+
+        def get_weight_block_size(x):
+            return (1, x.shape[1])
+
+        target_dtype = torch.int8
+        eps = torch.finfo(torch.float32).eps
+        zero_point_dtype = torch.int64
+
+        # input settings
+        def get_per_token_block_size(x):
+            block_size = list(x.shape)
+            for i in range(len(block_size) - 1):
+                block_size[i] = 1
+            return block_size
+
+        input_mapping_type = MappingType.SYMMETRIC
+        input_target_dtype = torch.int8
+        input_eps = 1e-5
+        input_quant_min = -127
+        input_quant_max = 127
+        _layout = PlainLayout()
+        input_quant_func = lambda x: to_affine_quantized_intx(
+            x,
+            input_mapping_type,
+            get_per_token_block_size(x),
+            input_target_dtype,
+            eps=input_eps,
+            quant_min=input_quant_min,
+            quant_max=input_quant_max,
+            scale_dtype=torch.float32 if x.dtype == torch.float16 else None,
+        )
+
+        block_size = get_weight_block_size(weight)
+        weight = to_affine_quantized_intx(
+            weight,
+            mapping_type,
+            block_size,
+            target_dtype,
+            eps=eps,
+            zero_point_dtype=zero_point_dtype,
+            _layout=_layout,
+        )
+        weight = super(AQInt8DynamicallyQuantizedLinearWeight, cls).from_float(
+            weight, input_quant_func
+        )
+        return weight
+
+    @classmethod
+    def _autoquant_test(cls, act_mat, weight, bias, best_time, mode=["relu", None]):
+        """
+        Tests and benchmarks the autoquantization process with special handling for interpolate mode.
+
+        Args:
+            act_mat (torch.Tensor): The activation matrix.
+            weight (torch.Tensor): The weight tensor.
+            bias (torch.Tensor or None): The bias tensor.
+            best_time (float): The best time to beat for the quantization process.
+            mode (list, optional): A list containing mode settings for quantization. The first element is the mode type
+                                   (e.g., "relu"), and the second element is the mode value (e.g., None). Defaults to ["relu", None].
+
+        Returns:
+            float: The benchmarked time for the autoquantization process.
+        """
+        if not _is_interpolate_mode(mode):
+            return super()._autoquant_test(act_mat, weight, bias, best_time, mode)
+
+        # SAM best is between .8 and 1, SDXL also performs best in this range
+        INTERPOLATION_CONSTANT = mode[1]
+        w_qtensor = cls.from_float(weight)
+        x_vals_int8, x_scales = quantize_activation_per_token_absmax(
+            act_mat.reshape(-1, act_mat.shape[-1])
+        )
+        quantized_matmul = (
+            lambda x_vals_int8, x_scales, w_vals_int8: safe_int_mm(
+                x_vals_int8, w_vals_int8
+            )
+            * x_scales
+        )
+        q_c_matmul = torch.compile(quantized_matmul, mode="max-autotune-no-cudagraphs")
+        with torch.no_grad():
+            w_vals_int8 = (
+                w_qtensor.original_weight_tensor.tensor_impl.int_data.contiguous().t()
+            )
+            res_matmul = do_autoquant_bench(
+                q_c_matmul, x_vals_int8, x_scales.reshape(-1, 1), w_vals_int8
+            )
+        print(
+            f">>time: {res_matmul:0.3f}ms for {cls} matmul, to_beat: {best_time:0.3f}ms"
+        )
+
+        # if the (much faster) matmul kernel is already beat, don't bother benchmarking full op
+        if res_matmul >= best_time:
+            return res_matmul
+
+        # calculate what time full op needs to beat for dynamic quant to be best given INTERPOLATION_CONSTANT
+        to_beat = best_time + INTERPOLATION_CONSTANT / (1 - INTERPOLATION_CONSTANT) * (
+            best_time - res_matmul
+        )
+        res = super()._autoquant_test(act_mat, weight, bias, to_beat)
+        max_int_const_win = (best_time - res_matmul) / (res - res_matmul)
+        res_f = INTERPOLATION_CONSTANT * res + (1 - INTERPOLATION_CONSTANT) * res_matmul
+        print(
+            f">>time: {res_f:0.3f}ms for {cls} interpolated, breakeven constant: {max_int_const_win:0.2f}"
+        )
+        return res_f
+
+
+class AQInt8WeightOnlyQuantizedLinearWeight(AffineQuantizedTensor, AQMixin):
+    """
+    AutoQuantizable version of Int8WeightOnlyQuantizedLinearWeight
+    """
+
+    @classmethod
+    def from_float(cls, weight):
+        mapping_type = MappingType.SYMMETRIC
+        target_dtype = torch.int8
+        eps = torch.finfo(torch.float32).eps
+        zero_point_dtype = torch.int64
+        block_size = (1, weight.shape[1])
+        return super(AQInt8WeightOnlyQuantizedLinearWeight, cls).from_hp_to_intx(
+            weight,
+            mapping_type,
+            block_size,
+            target_dtype,
+            eps=eps,
+            zero_point_dtype=zero_point_dtype,
+        )
+
+
+class AQInt8WeightOnlyQuantizedLinearWeight2(
+    AQInt8WeightOnlyQuantizedLinearWeight, AQMixin
+):
+    """
+    AutoQuantizable version of Int8WeightOnlyQuantizedLinearWeight that
+    uses a different kernel
+    """
+
+    @staticmethod
+    def _quantized_linear_op(act_mat, w_qtensor, bias):
+        """
+        Performs the quantized linear operations
+
+        Args:
+            act_mat (torch.Tensor): The activation matrix.
+            w_qtensor (torch.Tensor): The quantized weight tensor.
+            bias (torch.Tensor or None): The bias tensor.
+
+        Returns:
+            torch.Tensor: The result of the quantized operation.
+        """
+        orig_dtype = act_mat.dtype
+        orig_shape = act_mat.shape
+        act_mat = act_mat.reshape(-1, act_mat.shape[-1], 1)
+        y = (act_mat * w_qtensor.tensor_impl.int_data.t().unsqueeze(0)).sum(dim=-2)
+        y = y.reshape(*orig_shape[:-1], y.shape[-1]) * w_qtensor.tensor_impl.scale
+        if bias is not None:
+            y += bias
+        return y.to(orig_dtype)
+
+    @classmethod
+    def _autoquant_test(cls, act_mat, *args):
+        # if act_mat has batchsize>2 don't use this kernel
+        if act_mat.reshape(-1, act_mat.shape[-1]).shape[0] > 32:
+            return torch.inf
+        return super()._autoquant_test(act_mat, *args)
+
+
+class AQInt8WeightOnlyQuantizedLinearWeight3(
+    AQInt8WeightOnlyQuantizedLinearWeight, AQMixin
+):
+    """
+    AutoQuantizable version of Int8WeightOnlyQuantizedLinearWeight that
+    uses a different kernel
+    """
+
+    @staticmethod
+    def _quantized_linear_op(act_mat, w_qtensor, bias):
+        orig_shape = act_mat.shape
+        y = torch.mm(
+            act_mat.reshape(-1, orig_shape[-1]),
+            w_qtensor.tensor_impl.int_data.t() * w_qtensor.tensor_impl.scale,
+        )
+        y = y.reshape(*orig_shape[:-1], y.shape[-1])
+        if bias is not None:
+            y += bias
+        return y
+
+
+class AQInt4G32WeightOnlyQuantizedLinearWeight(AffineQuantizedTensor, AQMixin):
+    """
+    AutoQuantizable version of Int4WeightOnlyQuantizedLinearWeight
+    """
+
+    group_size: int = 32
+
+    @classmethod
+    def from_float(cls, weight):
+        group_size = cls.group_size
+        _layout = TensorCoreTiledLayout(inner_k_tiles=8)
+
+        if weight.shape[-1] % group_size != 0:
+            return weight
+        use_hqq = True
+        mapping_type = MappingType.ASYMMETRIC
+        block_size = (1, group_size)
+        target_dtype = torch.int32
+        quant_min = 0
+        quant_max = 15
+        eps = 1e-6
+        preserve_zero = False
+        zero_point_dtype = torch.bfloat16
+        zero_point_domain = ZeroPointDomain.FLOAT
+        return super(AQInt4G32WeightOnlyQuantizedLinearWeight, cls).from_hp_to_intx(
+            weight,
+            mapping_type,
+            block_size,
+            target_dtype,
+            quant_min,
+            quant_max,
+            eps,
+            zero_point_dtype=zero_point_dtype,
+            preserve_zero=preserve_zero,
+            zero_point_domain=zero_point_domain,
+            _layout=_layout,
+            use_hqq=use_hqq,
+        )
+
+
+class AQInt4G64WeightOnlyQuantizedLinearWeight(
+    AQInt4G32WeightOnlyQuantizedLinearWeight
+):
+    group_size: int = 64
+
+
+class AQInt4G128WeightOnlyQuantizedLinearWeight(
+    AQInt4G32WeightOnlyQuantizedLinearWeight
+):
+    group_size: int = 128
+
+
+class AQInt4G256WeightOnlyQuantizedLinearWeight(
+    AQInt4G32WeightOnlyQuantizedLinearWeight
+):
+    group_size: int = 256
+
+
+class AQDefaultLinearWeight(torch.Tensor, AQMixin):
+    """
+    A class to be used in concert with AutoQuantizableLinearWeight to provide a
+    default/non-quantized option. Only implements the bare minimum needed to work with the
+    AutoQuantizableLinearWeight class using the same interfaces that would normally be
+    used by QTensor subclasses but for a default linear op instead. Result of from_float
+    is not a tensor subclass, but rather the float tensor.
+    """
+
+    def __init__(self):
+        super().__init__()
+
+    @staticmethod
+    def _quantized_linear_op(act_mat, w_qtensor, bias):
+        return torch.nn.functional.linear(act_mat, w_qtensor, bias)
+
+    @classmethod
+    def from_float(cls, weight):
+        return weight
+
+
+class Float32Tensor(TorchAOBaseTensor):
+    """Tensor subclass tensor for fp32 dtype"""
+
+    def __init__(self, weight):
+        self.weight = weight.to(torch.float32)
+
+    @staticmethod
+    def _quantized_linear_op(act_mat, w_qtensor, bias):
+        _DTYPE = torch.float32
+        orig_dtype = act_mat.dtype
+        return torch.nn.functional.linear(
+            act_mat.to(_DTYPE),
+            w_qtensor.weight,
+            bias.to(_DTYPE) if bias is not None else bias,
+        ).to(dtype=orig_dtype)
+
+    def _apply_fn_to_data(self, fn):
+        return self.__class__(
+            fn(self.weight),
+        )
+
+    @classmethod
+    def from_float(cls, weight):
+        return cls(weight)
+
+
+@Float32Tensor.implements([torch.nn.functional.linear, aten.linear.default])
+def _(func, types, args, kwargs):
+    input_tensor, weight_tensor, bias = (
+        args[0],
+        args[1],
+        args[2] if len(args) > 2 else None,
+    )
+    return weight_tensor._quantized_linear_op(input_tensor, weight_tensor, bias)
+
+
+@Float32Tensor.implements(aten.detach.default)
+def _(func, types, args, kwargs):
+    return return_and_correct_aliasing(
+        func, args, kwargs, args[0]._apply_fn_to_data(torch.detach)
+    )
+
+
+@Float32Tensor.implements(aten.clone.default)
+def _(func, types, args, kwargs):
+    return return_and_correct_aliasing(
+        func, args, kwargs, args[0]._apply_fn_to_data(torch.clone)
+    )
+
+
+@Float32Tensor.implements(aten._to_copy.default)
+def _(func, types, args, kwargs):
+    return return_and_correct_aliasing(
+        func,
+        args,
+        kwargs,
+        args[0].to(*args[1:], **kwargs)._apply_fn_to_data(torch.clone),
+    )
+
+
+class BFloat16Tensor(Float32Tensor):
+    def __init__(self, weight):
+        self.weight = weight.to(torch.bfloat16)
+
+    @staticmethod
+    def _quantized_linear_op(act_mat, w_qtensor, bias):
+        _DTYPE = torch.bfloat16
+        orig_dtype = act_mat.dtype
+        return torch.nn.functional.linear(
+            act_mat.to(_DTYPE),
+            w_qtensor.weight,
+            bias.to(_DTYPE) if bias is not None else bias,
+        ).to(dtype=orig_dtype)
+
+
+class Float16Tensor(Float32Tensor):
+    def __init__(self, weight):
+        self.weight = weight.to(torch.float16)
+
+    @staticmethod
+    def _quantized_linear_op(act_mat, w_qtensor, bias):
+        _DTYPE = torch.float16
+        orig_dtype = act_mat.dtype
+        return torch.nn.functional.linear(
+            act_mat.to(_DTYPE),
+            w_qtensor.weight,
+            bias.to(_DTYPE) if bias is not None else bias,
+        ).to(dtype=orig_dtype)
+
+
+class AQFloat32LinearWeight(Float32Tensor, AQMixin):
+    """
+    AutoQuantizable version for float32 precision weight
+
+    (also converts input activation and bias to float32, and restores the original precision after
+    linear)
+    """
+
+    @classmethod
+    def from_float(cls, weight):
+        return super(AQFloat32LinearWeight, cls).from_float(weight)
+
+
+class AQBFloat16LinearWeight(BFloat16Tensor, AQMixin):
+    """
+    AutoQuantizable version for bfloat16 precision weight
+
+    (also converts input activation and bias to bfloat16, and restores the original precision after
+    linear)
+    """
+
+    @classmethod
+    def from_float(cls, weight):
+        return super(AQBFloat16LinearWeight, cls).from_float(weight)
+
+
+class AQFloat16LinearWeight(Float16Tensor, AQMixin):
+    """
+    AutoQuantizable version for float16 precision weight
+
+    (also converts input activation and bias to float16, and restores the original precision after
+    linear)
+    """
+
+    @classmethod
+    def from_float(cls, weight):
+        return super(AQFloat16LinearWeight, cls).from_float(weight)
+
+
+class AQFloat8WeightOnlyQuantizedLinearWeight(AffineQuantizedTensor, AQMixin):
+    """
+    AutoQuantizable version of Float8WeightOnlyQuantizedLinearWeight for target_dtype=torch.float8_e4m3fn
+    """
+
+    target_dtype: torch.dtype = torch.float8_e4m3fn
+
+    @staticmethod
+    def _quantized_linear_op(act_mat, w_qtensor, bias):
+        return torch.nn.functional.linear(act_mat, w_qtensor.dequantize(), bias)
+
+    @classmethod
+    def from_float(cls, weight):
+        block_size = (1, weight.shape[1])
+        return super(AQFloat8WeightOnlyQuantizedLinearWeight, cls).from_hp_to_floatx(
+            weight, block_size, target_dtype=cls.target_dtype, _layout=Float8Layout()
+        )
+
+
+class AQFloat8PerRowScalingDynamicallyQuantizedLinearWeight(
+    AQMixin, LinearActivationQuantizedTensor
+):
+    """
+    AutoQuantizable version of Float8DynamicallyQuantizedLinearWeight using per row scaling
+    """
+
+    activation_granularity = PerRow()
+
+    @classmethod
+    def from_float(cls, weight):
+        # avoid circular dep
+        from torchao.dtypes import to_affine_quantized_floatx
+        from torchao.quantization.quant_api import _input_activation_quant_func_fp8
+
+        # weight settings
+        def get_weight_block_size(x):
+            return (1, x.shape[1])
+
+        target_dtype = torch.float8_e4m3fn
+
+        # input settings
+        def get_per_token_block_size(x):
+            block_size = list(x.shape)
+            for i in range(len(block_size) - 1):
+                block_size[i] = 1
+            return block_size
+
+        input_target_dtype = torch.float8_e4m3fn
+        _layout = Float8Layout(mm_config=Float8MMConfig(use_fast_accum=True))
+        input_quant_func = lambda x: _input_activation_quant_func_fp8(
+            x=x,
+            activation_granularity=cls.activation_granularity,
+            activation_dtype=input_target_dtype,
+        )
+        block_size = get_weight_block_size(weight)
+        weight = to_affine_quantized_floatx(
+            input_float=weight,
+            block_size=block_size,
+            target_dtype=target_dtype,
+            _layout=_layout,
+            scale_dtype=torch.float32,
+        )
+        weight = super(
+            AQFloat8PerRowScalingDynamicallyQuantizedLinearWeight, cls
+        ).from_float(weight, input_quant_func)
+        return weight
+
+
+class AQFloat8PerTensorScalingDynamicallyQuantizedLinearWeight(
+    AQMixin, LinearActivationQuantizedTensor
+):
+    """
+    AutoQuantizable version of Float8DynamicallyQuantizedLinearWeight using per tensor scaling
+    """
+
+    activation_granularity = PerTensor()
+
+    @classmethod
+    def from_float(cls, weight):
+        # avoid circular dep
+        from torchao.dtypes import to_affine_quantized_floatx
+        from torchao.quantization.quant_api import _input_activation_quant_func_fp8
+
+        # weight settings
+        def get_weight_block_size(x):
+            assert x.ndim == 2, "Only works for 2D tensors"
+            return x.shape
+
+        target_dtype = torch.float8_e4m3fn
+
+        input_target_dtype = torch.float8_e4m3fn
+        _layout = Float8Layout(mm_config=Float8MMConfig(use_fast_accum=True))
+        input_quant_func = lambda x: _input_activation_quant_func_fp8(
+            x=x,
+            activation_granularity=cls.activation_granularity,
+            activation_dtype=input_target_dtype,
+        )
+        block_size = get_weight_block_size(weight)
+        weight = to_affine_quantized_floatx(
+            input_float=weight,
+            block_size=block_size,
+            target_dtype=target_dtype,
+            _layout=_layout,
+            scale_dtype=torch.float32,
+        )
+        weight = super(
+            AQFloat8PerTensorScalingDynamicallyQuantizedLinearWeight, cls
+        ).from_float(weight, input_quant_func)
+        return weight
+
+
+# here we don't include int4 quantization in since int8 tends to be a better apples to apples comparison
+DEFAULT_AUTOQUANT_CLASS_LIST = [
+    AQDefaultLinearWeight,
+    AQInt8WeightOnlyQuantizedLinearWeight,
+    AQInt8WeightOnlyQuantizedLinearWeight2,
+    # AQInt8WeightOnlyQuantizedLinearWeight3,
+    # TODO this gets picked in places where it makes perf worse, why?
+    AQInt8DynamicallyQuantizedLinearWeight,
+]
+
+DEFAULT_INT4_AUTOQUANT_CLASS_LIST = [
+    AQDefaultLinearWeight,
+    AQInt8DynamicallyQuantizedLinearWeight,
+    AQInt4G64WeightOnlyQuantizedLinearWeight,
+]
+
+DEFAULT_FLOAT_AUTOQUANT_CLASS_LIST = [
+    AQFloat32LinearWeight,
+    AQBFloat16LinearWeight,
+    AQFloat16LinearWeight,
+]
+
+OTHER_AUTOQUANT_CLASS_LIST = [
+    AQFloat8WeightOnlyQuantizedLinearWeight,
+    AQFloat8PerRowScalingDynamicallyQuantizedLinearWeight,
+    AQFloat8PerTensorScalingDynamicallyQuantizedLinearWeight,
+]
+
+ALL_AUTOQUANT_CLASS_LIST = list(
+    set(
+        DEFAULT_AUTOQUANT_CLASS_LIST
+        + DEFAULT_INT4_AUTOQUANT_CLASS_LIST
+        + DEFAULT_FLOAT_AUTOQUANT_CLASS_LIST
+    )
+)
+if is_sm_at_least_89():
+    ALL_AUTOQUANT_CLASS_LIST += [
+        AQFloat8WeightOnlyQuantizedLinearWeight,
+        AQFloat8PerTensorScalingDynamicallyQuantizedLinearWeight,
+    ]
+
+if is_sm_at_least_90():
+    ALL_AUTOQUANT_CLASS_LIST += [AQFloat8PerRowScalingDynamicallyQuantizedLinearWeight]
+
+
+def _replace_with_custom_fn_if_matches_filter(
+    model,
+    replacement_fn,
+    filter_fn,
+    cur_fqn="",
+    device=None,
+) -> None:
+    """
+    Recursively replaces each child module in `model` with the result of `replacement_fn(child)`
+    if `filter_fn(child)` returns `True`.
+    Args:
+        model (torch.nn.Module): The model containing modules to be replaced.
+        replacement_fn (Callable[[torch.nn.Module], torch.nn.Module]): The function to replace matching modules.
+        filter_fn (Callable[[torch.nn.Module], bool]): The filter function to determine which modules to replace.
+        cur_fqn (str, optional): The current fully qualified name of the module being processed. Defaults to "".
+        device (device, optional): Device to move the model to before applying `filter_fn`. Defaults to None.
+    Returns:
+        None
+    """
+    if filter_fn(model, cur_fqn[:-1]):
+        if device is not None:
+            model.to(device=device)  # move to device before quantization
+        model = replacement_fn(model, cur_fqn[:-1])
+        return model
+    else:
+        for name, child in model.named_children():
+            new_child = _replace_with_custom_fn_if_matches_filter(
+                child, replacement_fn, filter_fn, f"{cur_fqn}{name}.", device
+            )
+            if new_child is not child:
+                setattr(model, name, new_child)
+        if device is not None:
+            model.to(device=device)  # move parent module to device
+        return model
+
+
+def dict_union(*args):
+    return dict(chain.from_iterable(d.items() for d in args))
+
+
+def _change_linears_to_autoquantizable(
+    model, example_input, fqn_to_submodule, batch_size, **kwargs
+):
+    """
+    Converts all linear weight tensors to the
+    AutoQuantizableLinearWeight tensor subclass. Expectation is that this is followed
+    by running the model and then calling _change_autoquantizable_to_quantized
+    """
+    # from torchao.quantization.quant_api import _is_linear
+
+    filter_fn = kwargs.pop("filter_fn", _is_linear)
+    _ = kwargs.pop(
+        "error_on_unseen", True
+    )  # same kwargs used for this and to_quantized
+    kwargs["qtensor_class_list"] = kwargs.get(
+        "qtensor_class_list", DEFAULT_AUTOQUANT_CLASS_LIST
+    )
+    kwargs["mode"] = kwargs.get("mode", ["relu", None])
+    kwargs["model"] = model
+    kwargs["example_inputs"] = example_input
+    kwargs["fqn_to_submodule"] = fqn_to_submodule
+    kwargs["batch_size"] = batch_size
+    from torchao.quantization.quant_api import _get_subclass_inserter
+
+    _replace_with_custom_fn_if_matches_filter(
+        model,
+        lambda model, fqn: _get_subclass_inserter(
+            AutoQuantizableLinearWeight, **dict_union(kwargs, {"fqn": fqn})
+        )(model),
+        filter_fn if filter_fn is not None else _is_linear,
+    )
+
+
+def _change_autoquantizable_to_quantized(
+    model, supress_autoquant_errors=True, **kwargs
+):
+    """
+    Converts AutoQuantizableLinearWeight tensor subclasses
+    to various quantized/non-quantized tensor subclasses depending
+    on benchmark results. Expectation is that these modules are
+    torch.compiled afterwards.
+    """
+    hold_automatic_dynamic_shapes = torch._dynamo.config.automatic_dynamic_shapes
+    torch._dynamo.config.automatic_dynamic_shapes = False
+
+    if supress_autoquant_errors:
+        hold_supress_errors = torch._dynamo.config.suppress_errors
+        torch._dynamo.config.suppress_errors = True
+        import logging
+
+        torch._logging.set_logs(inductor=logging.CRITICAL, dynamo=logging.CRITICAL)
+    filter_fn = kwargs.pop(
+        "filter_fn",
+        lambda mod, *args: hasattr(mod, "weight")
+        and isinstance(mod.weight, AutoQuantizableLinearWeight),
+    )
+    error_on_unseen = kwargs.pop("error_on_unseen", True)
+    from torchao.quantization.quant_api import (
+        _get_subclass_inserter,
+        _replace_with_custom_fn_if_matches_filter,
+    )
+
+    _replace_with_custom_fn_if_matches_filter(
+        model,
+        _get_subclass_inserter(
+            AutoQuantizableLinearWeight,
+            method="to_quantized",
+            error_on_unseen=error_on_unseen,
+            **kwargs,
+        ),
+        filter_fn,
+    )
+    # undo dynamic shape change
+    torch._dynamo.config.automatic_dynamic_shapes = hold_automatic_dynamic_shapes
+
+    # undo error supression
+    if supress_autoquant_errors:
+        torch._dynamo.config.suppress_errors = hold_supress_errors
+        torch._logging.set_logs()
+    torch._dynamo.reset()
+
+
+# TODO: example_input seems weird to include in the API
+# TODO: Document all the modes
+# TODO: Mode being a list is weird, should be a string or some object
+@torch.no_grad()
+def autoquant_v2(
+    model,
+    example_input=None,
+    qtensor_class_list=DEFAULT_AUTOQUANT_CLASS_LIST,
+    filter_fn=None,
+    mode=["interpolate", 0.85],
+    manual=False,
+    set_inductor_config=True,
+    supress_autoquant_errors=True,
+    batch_size=None,
+    **aq_kwargs,
+):
+    """
+    Autoquantization is a process which identifies the fastest way to quantize each layer of a model over some set of potential
+    qtensor subclasses.
+
+    Autoquantization happens in three steps:
+
+    1-Prepare Model: the model is searched for Linear layers whose weights are exchanged for AutoQuantizableLinearWeight.
+    2-Shape Calibration: the user runs the model on one or more inputs, the details of the activation shape/dtype seen by
+        the AutoQuantizableLinearWeight are recorded so we know what shapes/dtypes to use in order to optimize the quantized op in step 3
+    3-Finalize Autoquantization: for each AutoQuantizableLinearWeight, benchmarks are run for each shape/dtype on each member of the qtensor_class_list.
+        the fastest option is picked, resulting in a highly performant model
+
+    This autoquant function performs step 1. Steps 2 and 3 can be completed by simply running the model.
+    If `example_input` is provided, this function also runs the model (which completes steps 2 and 3).
+    This autoquant api can handle models which have already had torch.compile applied to them, in which case, once the model is run and quantized,
+    the torch.compile process normally proceeds as well.
+
+    To optimize over a combination of input shapes/dtypes, the user can set manual=True, run the model with all desired shapes/dtypes, then
+    call model.finalize_autoquant to finalize the quantization once the desired set of inputs have been logged.
+
+    Args:
+        model (torch.nn.Module): The model to be autoquantized.
+        example_input (Any, optional): An example input for the model. If provided, the function performs a forward pass
+                                       on this input (which fully autoquantizes the model unless manual=True). Defaults to None.
+        qtensor_class_list (list, optional): A list of tensor classes to be used for quantization. Defaults to DEFAULT_AUTOQUANT_CLASS_LIST.
+        filter_fn (callable, optional): A filter function to apply to the model parameters. Defaults to None.
+        mode (list, optional): A list containing mode settings for quantization. The first element is the mode type (e.g., "interpolate"),
+                               and the second element is the mode value (e.g., 0.85). Defaults to ["interpolate", .85].
+        manual (bool, optional): Whether to stop shape calibration and do autoquant after a single run (default, False) or to wait for
+                                the user to call model.finalize_autoquant (True) so inputs with several shapes/dtypes can be logged.
+        set_inductor_config (bool, optional): Whether to automatically use recommended inductor config settings (defaults to True)
+        supress_autoquant_errors (bool, optional): Whether to suppress errors during autoquantization. (defaults to True)
+        **aq_kwargs: Additional keyword arguments for the autoquantization process.
+
+    Returns:
+        torch.nn.Module: The autoquantized and wrapped model. If `example_input` is provided, the function performs a forward pass
+                         on the input and returns the result of the forward pass.
+
+    Example usage:
+        torchao.autoquant(torch.compile(model))
+        model(*example_input)
+
+        # multiple input shapes
+        torchao.autoquant(model, manual=True)
+        model(*example_input1)
+        model(*example_input2)
+        model.finalize_autoquant()
+    """
+    if set_inductor_config:
+        torchao.quantization.utils.recommended_inductor_config_setter()
+
+    if qtensor_class_list is OTHER_AUTOQUANT_CLASS_LIST:
+        assert torch.cuda.is_available() and torch.cuda.get_device_capability() >= (
+            8,
+            9,
+        ), "float8 requires CUDA arch >= 8.9"
+
+    assert example_input is not None
+
+    prepare_target_folder(target_folder)
+    torch._dynamo.reset()
+    # TODO: explore using node.meta to retrieve the subgraph and fqn information
+    # disable nn module inlining, our subgraph extraction logic depends on this
+    torch._dynamo.config.inline_inbuilt_nn_modules = False
+    torch._inductor.config.pre_grad_custom_pass = lambda g: debug_linears_for_float8(
+        g, target_folder
+    )
+    model = torch.compile(model)
+    if isinstance(example_input, torch.Tensor):
+        example_input = [example_input]
+    if isinstance(example_input, (list, tuple)):
+        model(*example_input)
+    elif isinstance(example_input, dict):
+        model(**example_input)
+    else:
+        raise Exception("Unexpected example_input:", example_input)
+
+    torch._inductor.config.pre_grad_custom_pass = None
+
+    # verify debug logs and summary got saved
+    assert os.path.isfile(os.path.join(target_folder, "debug_logs_0.txt")), (
+        "No debug log saved, autoquant_v2 can't work for this model right now"
+    )
+    assert os.path.isfile(os.path.join(target_folder, "summary_0.csv")), (
+        "No debug log saved, autoquant_v2 can't work for this model right now"
+    )
+
+    # first, find how many torch.compile'd regions we have
+    extraction_idxs = []
+    for f in os.listdir(target_folder):
+        match = re.match(r"summary_([0-9]+).csv", f)
+        if match:
+            extraction_idxs.append(int(match.group(1)))
+    extraction_idxs.sort()
+
+    fqn_to_submodule = {}
+
+    for extraction_idx in extraction_idxs:
+        summary_filename = os.path.join(target_folder, f"summary_{extraction_idx}.csv")
+        summary_rows = []
+        with open(summary_filename, "r") as f:
+            reader = csv.reader(f)
+            for row in reader:
+                summary_rows.append(row)
+
+        # [1:] to skip header row
+        for row_idx, row in enumerate(summary_rows[1:]):
+            subgraph_idx = row[2]
+            fqn = row[-1]
+            subgraph_fname = f"subgraph_with_inputs_{extraction_idx}_{subgraph_idx}.pt"
+            print(f"loading {subgraph_fname} fqn {fqn}")
+            subgraph_fname = os.path.join(target_folder, subgraph_fname)
+            m, inputs = torch.load(subgraph_fname, weights_only=False)
+
+            # for now, force cast to bf16
+            # TODO(future): configure this
+            m = m.to(torch.bfloat16)
+            inputs = tree_map(lambda x: x.to(torch.bfloat16), inputs)
+
+            m = m.to(torch.bfloat16)
+            inputs = tree_map(lambda x: x.to(torch.bfloat16), inputs)
+
+            fqn_to_submodule[fqn] = m, inputs
+
+    model = model._orig_mod
+
+    # perform initial swap from linear weights
+    # to AutoQuantizableLinearWeight
+    _change_linears_to_autoquantizable(
+        model,
+        example_input,
+        fqn_to_submodule,
+        batch_size,
+        filter_fn=filter_fn,
+        qtensor_class_list=qtensor_class_list,
+        mode=mode,
+        **aq_kwargs,
+    )
+
+    # access actual model of torch.compile wrapper if needed
+    is_compiled = isinstance(model, torch._dynamo.eval_frame.OptimizedModule)
+    if is_compiled:
+        real_model = model._orig_mod
+    else:
+        real_model = model
+
+    if manual:
+        # we don't want model.forward to trigger
+        # torch.compilation
+        if is_compiled:
+            real_model.old_forward = model.forward
+            model.forward = real_model.forward
+
+    # we want to automatically do autoquant after a single model run
+    # and have it occur before torch.compilation if applicable
+    else:
+        # the hook we will use to intercept the model forward and perform
+        # autoquantization
+        def autoquant_prehook(module, args, kwargs):
+            real_model.forward(*args, **kwargs)
+            module.finalize_autoquant()
+            return args, kwargs
+
+        # the autoquant_prehook intercepts the forward call, performs logging then
+        # does autoquantization. if model is a torch.compile wrapper, it then
+        # does the tracing/compile since the prehook is naturally followed by the normal.
+        # model run.
+        handle = model.register_forward_pre_hook(autoquant_prehook, with_kwargs=True)
+
+    # note the torch.compile wrapper (eval_frame) moves the assignment of any assigned
+    # attributes to the inner model that didn't exist before, so we have to call delattr on the inner model
+    def finalize_autoquant():
+        _change_autoquantizable_to_quantized(
+            real_model,
+            supress_autoquant_errors,
+            **aq_kwargs,
+        )
+        if hasattr(real_model, "old_forward"):
+            model.forward = real_model.old_forward
+            delattr(real_model, "old_forward")
+        if hasattr(real_model, "finalize_autoquant"):
+            delattr(real_model, "finalize_autoquant")
+        if not manual:
+            handle.remove()
+
+    real_model.finalize_autoquant = finalize_autoquant
+
+    # if example input was provided, check it and run it
+    if isinstance(example_input, torch.Tensor):
+        example_input = [example_input]
+    if isinstance(example_input, (tuple, list)):
+        model(*example_input)
+    elif isinstance(example_input, dict):
+        model(**example_input)
+
+    return model
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3fba2beedd30c6749278e6a37313998979e48bd9
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__init__.py
@@ -0,0 +1,14 @@
+from .codebook_ops import (
+    choose_qparams_codebook,
+    dequantize_codebook,
+    quantize_codebook,
+)
+from .codebook_quantized_tensor import CodebookQuantizedTensor, codebook_weight_only
+
+__all__ = [
+    "CodebookQuantizedTensor",
+    "codebook_weight_only",
+    "quantize_codebook",
+    "dequantize_codebook",
+    "choose_qparams_codebook",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f505b44b414c86c9eebd1d66a4d732bfe12acf3d
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__pycache__/codebook_ops.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__pycache__/codebook_ops.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3631a39c6cbad0f55d69fe38299bd20b7320e4f5
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__pycache__/codebook_ops.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__pycache__/codebook_quantized_tensor.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__pycache__/codebook_quantized_tensor.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b11ee397f44e970c9a3f5ffe329ef3c0e047e335
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/__pycache__/codebook_quantized_tensor.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/codebook_ops.py b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/codebook_ops.py
new file mode 100644
index 0000000000000000000000000000000000000000..ca81ce045338183b4cb9d6f7e8fabaf832987089
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/codebook_ops.py
@@ -0,0 +1,443 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+from typing import List, Optional, Tuple
+
+import torch
+
+from torchao.quantization.quant_primitives import (
+    _DTYPE_TO_QVALUE_BOUNDS,
+    _SUB_BYTE_UINT_BOUNDS,
+)
+
+
+def quantize_codebook(
+    input: torch.Tensor,
+    codebook: torch.Tensor,
+    scales: torch.Tensor,
+    chunk_size: int = 1024,
+    code_dtype: torch.dtype = torch.uint4,
+) -> torch.Tensor:
+    """
+    code modified from: https://github.com/Vahe1994/AQLM/blob/main/src/kmeans.py
+
+    Args:
+        input (torch.Tensor): Input tensor to quantize, shape (d1, d2, ..., dN).
+        codebook (torch.Tensor): Codebook tensor for quantization, shape (k, b1, b2, ..., bN) where b_i are block sizes.
+        scales (torch.Tensor): Scales, shape (d1, d2, ..., dN // scale_block_size, 1).
+        chunk_size (int): Number of elements to process per chunk to control memory usage.
+        code_dtype (torch.dtype): dtype for the codes.
+
+    Output:
+        codes (torch.Tensor): indices of the closest codebook entries for each block, shape (d1//b1, d2//b2, ..., dN//bN).
+    """
+    if code_dtype in _SUB_BYTE_UINT_BOUNDS:
+        code_dtype = torch.uint8
+    assert input.dtype in [
+        torch.float32,
+        torch.float16,
+        torch.bfloat16,
+    ], f"Unsupported input dtype: {input.dtype}"
+    assert codebook.dim() == input.dim() + 1, (
+        f"codebook dim ({codebook.dim()}) must be input dim + 1 ({input.dim() + 1})"
+    )
+
+    k = codebook.shape[0]
+    block_size = codebook.shape[1:]
+    input_size = input.shape
+    D = input.dim()
+    for i in range(D):
+        assert (input_size[i] % block_size[i]) == 0, (
+            f"dimension {i} of input ({input_size[i]}) must be divisible by block_size ({block_size[i]})."
+        )
+
+    num_scale_blocks = scales.shape[-2]
+
+    new_shape = input_size[:-1] + (num_scale_blocks, -1)
+    input_reshaped = input.view(
+        *new_shape
+    )  # shape: (d1, d2, ..., num_scale_blocks, scale_block_size)
+    input_reshaped = input_reshaped / scales
+
+    input = input_reshaped.view(*input_size)
+    input_flat = _reshape_into_blocks(
+        input, block_size
+    )  # shape: (num_blocks, block_vector_size)
+
+    codebook_flat = codebook.reshape(k, -1)
+
+    codes = torch.empty(input_flat.size(0), dtype=torch.int64, device=input.device)
+
+    # Process in chunks to avoid memory spikes
+    for chunk_start in range(0, input_flat.size(0), chunk_size):
+        chunk_end = min(chunk_start + chunk_size, input_flat.size(0))
+
+        input_chunk = input_flat[chunk_start:chunk_end]
+        input_chunk = input_chunk
+
+        # Compute distances and find nearest codebook entries for the chunk
+        distances = torch.addmm(
+            torch.bmm(codebook_flat[:, None, :], codebook_flat[:, :, None]).flatten(),
+            input_chunk,
+            codebook_flat.T,
+            beta=-0.5,
+        )
+        # distance = || input_chunk[:, None, :] - codebook_flat[None, :, :] ||^2 = || input_chunk ||^2 + || codebook_flat ||^2 - 2 * input_chunk @ codebook_flat.T
+        # don't need to compute input_chunk squared norm as it's constant during argmax
+
+        codes[chunk_start:chunk_end] = distances.argmax(dim=1)
+
+    block_grid_shape = [input_size[i] // block_size[i] for i in range(D)]
+    codes = codes.view(*block_grid_shape)  # shape: (d1//b1, d2//b2, ..., dN//bN)
+
+    return codes.to(code_dtype)
+
+
+def dequantize_codebook(
+    codes: torch.Tensor,
+    codebook: torch.Tensor,
+    scales: torch.Tensor,
+    output_dtype: torch.dtype = torch.float32,
+) -> torch.Tensor:
+    """
+    Reconstructs the original tensor from codes and the codebook.
+
+    Args:
+        codes (torch.Tensor): Indices of codebook entries for each block,
+                                          shape (d1//b1, d2//b2, ..., dN//bN).
+        codebook (torch.Tensor): Codebook tensor used for quantization,
+                                 shape (k, b1, b2, ..., bN) where b_i are block sizes.
+        scales (torch.Tensor): Scales, shape (d1, d2, ..., dN // scale_block_size, 1).
+        output_dtype (torch.dtype): dtype for the output tensor.
+
+    Returns:
+        dequant (torch.Tensor): Reconstructed tensor, shape (out_features, in_features)
+    """
+    assert output_dtype in [
+        torch.float32,
+        torch.float16,
+        torch.bfloat16,
+    ], f"Unsupported output dtype: {output_dtype}"
+
+    block_size = codebook.shape[1:]
+    block_grid_shape = codes.shape
+    D = codebook.dim() - 1
+    original_shape = [block_grid_shape[i] * block_size[i] for i in range(D)]
+
+    # Use codes to lookup corresponding codebook entries and reshape
+    dequant = codebook[codes]  # shape: (*block_grid_shape, *block_size)
+
+    # probably can make this simpler
+    dequant = _reshape_from_blocks(
+        dequant.view(-1, int(torch.prod(torch.tensor(block_size)))),
+        block_size,
+        tuple(original_shape),
+    )
+
+    num_scale_blocks = scales.shape[-2]
+
+    new_shape = dequant.shape[:-1] + (num_scale_blocks, -1)
+    dequant = dequant.view(
+        *new_shape
+    )  # (d1, d2, ..., num_scale_blocks, scale_block_size)
+    dequant.mul_(scales)
+
+    dequant = dequant.view(*original_shape)
+
+    return dequant.to(output_dtype)
+
+
+@torch.no_grad()
+def choose_qparams_codebook(
+    input_tensor: torch.Tensor,
+    block_size: Tuple[int, ...],
+    scale_block_size: int,
+    code_dtype: torch.dtype,
+    max_iter: int = 200,
+    devices: Optional[List[torch.device]] = None,
+) -> torch.Tensor:
+    """
+    Initialize the codebook using k-means clustering on blocks of the input tensor.
+
+    Args:
+        input_tensor (torch.Tensor): The input tensor to be quantized.
+        block_size (Tuple[int, ...],): The size of the blocks for k-means clustering.
+        scale_block_size (int): The size of the blocks that share a scale
+        code_dtype (torch.dtype): The dtype for the codes.
+        max_iter (int): Maximum number of k-means iterations.
+        devices (List[torch.device]): Devices to run k-means on.
+
+    Returns:
+        torch.Tensor: The codebook tensor, shape (codebook_size, *block_size).
+    """
+    if code_dtype == torch.int32:
+        codebook_size = 2**16
+    else:
+        codebook_size = _DTYPE_TO_QVALUE_BOUNDS[code_dtype][1] + 1
+
+    input_size = input_tensor.shape
+    D = input_tensor.dim()
+    for i in range(D):
+        assert input_size[i] % block_size[i] == 0, (
+            f"Dimension {i} must be divisible by block_size {block_size[i]}."
+        )
+
+    assert input_tensor.shape[-1] % scale_block_size == 0, (
+        f"input_features ({input_tensor.shape[-1]}) must be divisible by scale_block_size ({scale_block_size})."
+    )
+    num_scale_blocks = input_tensor.shape[-1] // scale_block_size
+
+    new_shape = list(input_size[:-1]) + [num_scale_blocks, scale_block_size]
+    input = input_tensor.view(*new_shape)
+
+    # Not sure if I should make scales max only when block_size is (1, 1)
+    if block_size == (1, 1):
+        scales = input.max(
+            dim=(-1), keepdim=True
+        ).values  # Shape: [*input_size[:-1], num_scale_blocks, 1]
+    else:
+        scales = input.norm(
+            dim=(-1), keepdim=True
+        )  # Shape: [*input_size[:-1], num_scale_blocks, 1]
+    scales = torch.clamp(scales, min=1e-9)
+
+    input = input / scales
+
+    input = input.view(*input_size)
+
+    input = _reshape_into_blocks(
+        input, block_size
+    )  # Shape: (num_blocks, block_vector_size)
+
+    codebook, _, _ = fit_kmeans(
+        input,
+        k=codebook_size,
+        max_iter=max_iter,
+        devices=devices,
+    )
+
+    return codebook.view(codebook_size, *block_size), scales
+
+
+@torch.jit.script
+def _kmeans_greedy_init(data: torch.Tensor, k: int) -> torch.Tensor:
+    # code modified from: https://github.com/Vahe1994/AQLM/blob/main/src/kmeans.py not sure if I should modify for
+    clusters = torch.zeros(k, data.shape[1], device=data.device)
+    running_min_distances = torch.full(
+        (data.shape[0],), torch.inf, device=data.device, dtype=data.dtype
+    )
+    data_norm_squared = data.norm(p=2, dim=1).square()
+
+    for i in range(k):
+        clusters[i] = data[running_min_distances.argmax()]
+        distances_to_cluster_i = (
+            data_norm_squared - 2 * data @ clusters[i] + clusters[i].norm().square()
+        )
+        running_min_distances = torch.minimum(
+            running_min_distances, distances_to_cluster_i, out=running_min_distances
+        )
+    return clusters
+
+
+@torch.jit.script
+def fit_kmeans(
+    data: torch.Tensor,
+    k: int,
+    max_iter: int = 200,
+    check_every: int = 10,
+    rtol: float = 1e-06,
+    atol: float = 1e-08,
+    greedy_init: bool = True,
+    block_size_vals: int = 2**30,
+    devices: Optional[List[torch.device]] = None,
+):
+    """
+    code modified from: https://github.com/Vahe1994/AQLM/blob/main/src/kmeans.py not sure if I should modify for
+    :param data: [nsamples, dim]
+    :param k: number of centroids
+    :param max_iter: run at most this many iterations
+    :param check_every: check for convergence (allclose(new_centroids, old_centroids)) once in this many steps
+    :param rtol: early stopping relative tolerance for centroids
+    :param atol: early stopping absolute tolerance for centroids
+    :param block_size_vals: how many dot products to compute at a time
+    :param devices: if specified, run kmeans in data-parallel mode across these devices
+    :return: (clusters float[k, dim], data_indices int[nsamples], reconstructed_data: float[nsamples, dim])
+    """
+    if devices is None:
+        devices = [data.device]
+
+    if greedy_init:
+        clusters = _kmeans_greedy_init(data, k)
+    else:
+        clusters = data[torch.randperm(data.shape[0])[:k], :]  # [k, dim]
+
+    block_size = block_size_vals // k
+    shard_size = (len(data) - 1) // len(devices) + 1
+    data = [
+        data[gi * shard_size : (gi + 1) * shard_size].to(devices[gi], non_blocking=True)
+        for gi in range(len(devices))
+    ]
+    nearest_indices = [
+        torch.empty(len(data[gi]), dtype=torch.int64, device=devices[gi])
+        for gi in range(len(devices))
+    ]
+    clusters = [clusters.to(device, non_blocking=True) for device in devices]
+
+    for i in range(max_iter):
+        for block_start in range(0, shard_size, block_size):
+            for gi in range(len(devices)):
+                nearest_indices[gi][block_start : block_start + block_size] = (
+                    torch.addmm(
+                        torch.bmm(
+                            clusters[gi][:, None, :], clusters[gi][:, :, None]
+                        ).flatten(),
+                        data[gi][block_start : block_start + block_size],
+                        clusters[gi].T,
+                        beta=-0.5,
+                    ).argmax(1)
+                )
+            # note: the above formula equals to - 0.5 || data[:, None, :] - clusters[None, :, :] || ^ 2 + const
+
+        if len(devices) == 1:
+            new_clusters = [
+                clusters[0]
+                .clone()
+                .index_reduce_(
+                    dim=0,
+                    index=nearest_indices[0],
+                    source=data[0],
+                    reduce="mean",
+                    include_self=False,
+                )
+            ]
+        else:
+            cluster_sums = [
+                torch.zeros_like(clusters[gi])
+                .index_add(dim=0, index=nearest_indices[gi], source=data[gi])
+                .to(devices[0], non_blocking=True)
+                for gi in range(len(devices))
+            ]
+            cluster_counts = [
+                torch.bincount(nearest_indices[gi], minlength=k).to(
+                    devices[0], non_blocking=True
+                )
+                for gi in range(len(devices))
+            ]
+            for gi in range(1, len(devices)):
+                cluster_sums[0] += cluster_sums[gi]
+                cluster_counts[0] += cluster_counts[gi]
+
+            new_clusters = [
+                cluster_sums[0] / cluster_counts[0].unsqueeze(1).clamp_min(1)
+            ]
+            new_clusters[0] += (cluster_counts[0].unsqueeze(1) == 0) * clusters[0]
+            for gi in range(1, len(devices)):
+                new_clusters.append(new_clusters[0].to(devices[gi], non_blocking=True))
+
+        if i % check_every == 0:
+            if torch.allclose(new_clusters[0], clusters[0], rtol=rtol, atol=atol):
+                break
+        clusters = new_clusters
+    for block_start in range(0, shard_size, block_size):
+        for gi in range(len(devices)):
+            nearest_indices[gi][block_start : block_start + block_size] = torch.addmm(
+                torch.bmm(clusters[gi][:, None, :], clusters[gi][:, :, None]).flatten(),
+                data[gi][block_start : block_start + block_size],
+                clusters[gi].T,
+                beta=-0.5,
+            ).argmax(1)
+
+    clusters = clusters[0]
+    nearest_indices = torch.cat(
+        [nearest_indices[gi].to(devices[0]) for gi in range(len(devices))], dim=0
+    )
+    reconstructed_data = clusters[nearest_indices]
+    return clusters, nearest_indices, reconstructed_data
+
+
+def _reshape_into_blocks(
+    input: torch.Tensor, block_size: Tuple[int, ...]
+) -> torch.Tensor:
+    """
+    Reshape an N-D input tensor into a 2D tensor where each row corresponds to one block.
+    """
+    assert len(block_size) == input.dim(), (
+        f"block_size {block_size} must match the input dimension {input.dim()}"
+    )
+    input_size = input.shape
+
+    # Create shape with alternating (num_blocks_along_dim, block_size_dim)
+    reshaped_dims = []
+    for i in range(input.dim()):
+        assert input_size[i] % block_size[i] == 0, (
+            f"Input size at dim {i} ({input_size[i]}) must be divisible by block_size[i] ({block_size[i]})."
+        )
+        reshaped_dims.extend([input_size[i] // block_size[i], block_size[i]])
+
+    input_reshaped = input.view(*reshaped_dims)  # Shape: [g1, b1, g2, b2, ..., gD, bD]
+
+    D = input.dim()
+    perm_order = list(range(2 * D))
+    grid_dims = perm_order[0::2]
+    block_dims = perm_order[1::2]
+    perm_order = grid_dims + block_dims
+
+    input_reshaped = input_reshaped.permute(
+        *perm_order
+    )  # Shape: [g1, g2, ..., gD, b1, b2, ..., bD]
+
+    num_blocks = 1
+    for i in range(D):
+        num_blocks *= input_size[i] // block_size[i]
+    block_vector_size = 1
+    for b in block_size:
+        block_vector_size *= b
+
+    input_flat = input_reshaped.reshape(num_blocks, block_vector_size)
+    return input_flat
+
+
+def _reshape_from_blocks(
+    blocks: torch.Tensor, block_size: Tuple[int, ...], original_shape: Tuple[int, ...]
+) -> torch.Tensor:
+    """
+    Reshape from the 2D block form (num_blocks, block_vector_size) back to the original N-D shape.
+    """
+    D = len(block_size)
+
+    reshaped_dims = []
+    num_blocks = 1
+    for i in range(D):
+        reshaped_dims.extend([original_shape[i] // block_size[i], block_size[i]])
+        num_blocks *= original_shape[i] // block_size[i]
+    block_vector_size = 1
+    for b in block_size:
+        block_vector_size *= b
+
+    perm_order = []
+    for i in range(D):
+        perm_order.append(i * 2)  # grid dim indices first
+    for i in range(D):
+        perm_order.append(i * 2 + 1)  # block dim indices after
+
+    perm_inverse = [0] * (2 * D)
+    for idx, val in enumerate(perm_order):
+        perm_inverse[val] = idx
+
+    input_permuted_shape = []
+    for i in range(D):
+        input_permuted_shape.append(original_shape[i] // block_size[i])
+    for i in range(D):
+        input_permuted_shape.append(block_size[i])
+
+    blocks_permuted = blocks.view(
+        *input_permuted_shape
+    )  # Shape: [g1, g2, ..., gD, b1, b2, ..., bD]
+
+    blocks_unpermuted = blocks_permuted.permute(
+        *perm_inverse
+    )  # Shape: [g1, b1, g2, b2, ..., gD, bD]
+
+    return blocks_unpermuted.reshape(*original_shape)
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/codebook_quantized_tensor.py b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/codebook_quantized_tensor.py
new file mode 100644
index 0000000000000000000000000000000000000000..e16a339e82de899a7a03feb2eeb9968c596484e6
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/codebook/codebook_quantized_tensor.py
@@ -0,0 +1,308 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+from dataclasses import dataclass
+from typing import Optional, Tuple
+
+import torch
+
+from torchao.core.config import AOBaseConfig
+from torchao.dtypes.uintx.uintx_layout import _DTYPE_TO_BIT_WIDTH, UintxTensor
+from torchao.prototype.quantization.codebook.codebook_ops import (
+    choose_qparams_codebook,
+    dequantize_codebook,
+    quantize_codebook,
+)
+from torchao.quantization.transform_module import (
+    register_quantize_module_handler,
+)
+from torchao.utils import TorchAOBaseTensor
+
+aten = torch.ops.aten
+
+
+class CodebookQuantizedTensor(TorchAOBaseTensor):
+    """
+    Codebook quantized tensor subclass.
+
+    Codebook (lookup table) quantization involves partitioning the input tensor into blocks, and replacing each block
+    with the index of the closest entry in a predefined codebook.
+
+    Fields:
+      codes (torch.Tensor): Tensor of indices representing blocks in the original tensor. Each index
+         maps to a corresponding codebook entry.
+      codebook (torch.Tensor): Tensor representing the quantization codebook, where each entry
+         corresponds to a block in the original tensor. Shape is `(codebook_size, out_block_size, in_block_size)`.
+      block_size (Tuple[int, ...]): Granularity of quantization, specifying the dimensions of tensor
+         blocks that share the same quantization parameters.
+      shape (torch.Size): Shape of the original high-precision tensor.
+      dtype (torch.dtype): dtype of the original high-precision tensor.
+    """
+
+    @staticmethod
+    def __new__(
+        cls,
+        codes: torch.Tensor,
+        codebook: torch.Tensor,
+        block_size: Tuple[int, ...],
+        scales: torch.Tensor,
+        shape: torch.Size,
+        dtype=None,
+        strides=None,
+    ):
+        kwargs = {}
+        kwargs["device"] = codes.device
+        kwargs["layout"] = (
+            kwargs.get("layout") if kwargs.get("layout", False) else codes.layout
+        )
+        kwargs["dtype"] = dtype
+        if strides is not None:
+            kwargs["strides"] = strides
+        kwargs["requires_grad"] = False
+        return torch.Tensor._make_wrapper_subclass(cls, shape, **kwargs)  # type: ignore[attr-defined]
+
+    def __init__(
+        self,
+        codes: torch.Tensor,
+        codebook: torch.Tensor,
+        block_size: Tuple[int, ...],
+        scales: torch.Tensor,
+        shape: torch.Size,
+        dtype=None,
+        strides=None,
+    ):
+        self.codes = codes
+        self.codebook = codebook
+        self.block_size = block_size
+        self.scales = scales
+        self._dtype = dtype  # not sure this is right
+
+    def __repr__(self):
+        return (
+            f"{self.__class__.__name__}(codes={self.codes}, codebook={self.codebook}, block_size={self.block_size}, scales={self.scales}, "
+            f"shape={self.shape}, device={self.device}, dtype={self.dtype}, requires_grad={self.requires_grad})"
+        )
+
+    def _quantization_type(self):
+        return f"shape={self.shape}, block_size={self.block_size}, codebook_size={self.codebook.size(0)}, device={self.device}, code_dtype={self.codes.dtype}"
+
+    def dequantize(self, output_dtype: Optional[torch.dtype] = None) -> torch.Tensor:
+        if output_dtype is None:
+            output_dtype = self.dtype
+
+        if isinstance(self.codes, UintxTensor):
+            codes = self.codes.get_plain()
+        else:
+            codes = self.codes
+        if codes.dtype != torch.int32:
+            # TODO: Investigate and support not casting to torch.int32 for indexing to improve performance
+            codes = codes.to(torch.int32)
+        return dequantize_codebook(
+            codes,
+            self.codebook,
+            self.scales,
+            output_dtype=output_dtype,
+        )
+
+    def __tensor_flatten__(self):
+        return ["codes", "codebook", "scales"], [
+            self.block_size,
+            self.shape,
+            self.dtype,
+        ]
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls, tensor_data_dict, tensor_attributes, outer_size, outer_stride
+    ):
+        codes = tensor_data_dict["codes"]
+        codebook = tensor_data_dict["codebook"]
+        scales = tensor_data_dict["scales"]
+        block_size, shape, dtype = tensor_attributes
+        return cls(
+            codes,
+            codebook,
+            block_size,
+            scales,
+            shape if outer_size is None else outer_size,
+            dtype=dtype,
+            strides=outer_stride,
+        )
+
+    @classmethod
+    def from_float(
+        cls,
+        input_tensor: torch.Tensor,
+        block_size: Tuple[int, ...],
+        code_dtype: torch.dtype,
+        scale_block_size: int,
+        chunk_size: int = 1024,
+    ):
+        """
+        Creates a CodebookQuantizedTensor from a floating-point tensor by performing codebook quantization.
+
+        Args:
+            input_tensor (torch.Tensor): The input floating-point tensor to quantize.
+            block_size (Tuple[int, ...]): The size of the blocks for which codes are assigned.
+            code_dtype (torch.dtype): The dtype of the codes.
+            chunk_size (int): The chunk size to use during quantization (to control memory usage).
+        """
+
+        codebook, scales = choose_qparams_codebook(
+            input_tensor.to(torch.float32), block_size, scale_block_size, code_dtype
+        )  # .to(torch.float32) because I think k_means isn't numerically stable
+
+        codes = quantize_codebook(
+            input_tensor.to(torch.float32), codebook, scales, chunk_size, code_dtype
+        )
+        if code_dtype in _DTYPE_TO_BIT_WIDTH:
+            codes = UintxTensor.from_uint8(codes, dtype=code_dtype)
+
+        codebook = codebook.to(input_tensor.dtype)
+        scales = scales.to(input_tensor.dtype)
+
+        return cls(
+            codes,
+            codebook,
+            block_size,
+            scales,
+            input_tensor.shape,
+            dtype=input_tensor.dtype,
+        )
+
+    def to(self, *args, **kwargs):
+        # I'm not sure if this is right
+        kwargs = self._get_to_kwargs(*args, **kwargs)
+        device = kwargs.pop("device")
+        return self.__class__(
+            self.codes.to(device),
+            self.codebook.to(device),
+            self.block_size,
+            self.scales.to(device),
+            self.shape,
+            **kwargs,
+        )
+
+    def _apply_fn_to_data(self, fn):
+        # Apply function to only codes?
+        return self.__class__(
+            fn(self.codes),
+            self.codebook,
+            self.block_size,
+            self.scales,
+            self.shape,
+            dtype=self.dtype,
+        )
+
+    @classmethod
+    def __torch_function__(cls, func, types, args=(), kwargs=None):
+        if kwargs is None:
+            kwargs = {}
+
+        if func in CODEBOOK_TORCH_FUNCTIONS:
+            return CODEBOOK_TORCH_FUNCTIONS[func](*args, **kwargs)
+
+        if any(isinstance(arg, cls) for arg in args):
+            # Dequantize all instances of CodebookQuantizedTensor in args
+            new_args = tuple(
+                arg.dequantize() if isinstance(arg, cls) else arg for arg in args
+            )
+
+            return func(*new_args, **kwargs)
+        else:
+            return NotImplemented
+
+    def detach(self):
+        """
+        Returns a new `CodebookQuantizedTensor`.
+        """
+        return self.__class__(
+            self.codes.detach(),
+            self.codebook.detach(),
+            self.block_size,
+            self.scales.detach(),
+            self.shape,
+            dtype=self.dtype,
+        )
+
+    def requires_grad_(self, requires_grad=True):
+        """
+        Modifies the tensor's `requires_grad` status in-place.
+        """
+        self.codes.requires_grad_(requires_grad)
+        self.codebook.requires_grad_(requires_grad)
+        self.scales.requires_grad_(requires_grad)
+        return self
+
+    @property
+    def dtype(self):
+        # Hacky way to avoid recursion with __torch_function__
+        return self._dtype
+
+
+CODEBOOK_TORCH_FUNCTIONS = {}
+
+
+def implements_torch_function(torch_function):
+    def decorator(func):
+        CODEBOOK_TORCH_FUNCTIONS[torch_function] = func
+        return func
+
+    return decorator
+
+
+@implements_torch_function(torch.Tensor.detach)
+def function_detach(tensor, *args, **kwargs):
+    return tensor.detach()
+
+
+@implements_torch_function(torch.Tensor.requires_grad_)
+def function_requires_grad_(tensor, *args, **kwargs):
+    return tensor.requires_grad_(*args, **kwargs)
+
+
+@dataclass
+class CodebookWeightOnlyConfig(AOBaseConfig):
+    dtype: torch.dtype = torch.uint4
+    block_size: Tuple[int, int] = (1, 1)
+    scale_block_size: int = None
+
+
+# for bc
+codebook_weight_only = CodebookWeightOnlyConfig
+
+
+@register_quantize_module_handler(CodebookWeightOnlyConfig)
+def _codebook_weight_only_transform(
+    module: torch.nn.Module,
+    config: CodebookWeightOnlyConfig,
+):
+    """
+    Applies codebook weight-only quantization to linear layers.
+
+    Args:
+        dtype: torch.uint1 to torch.uint8, torch.int32 supported.
+        block_size: Tuple of (out_features, in_features) to control quantization granularity.
+        scale_block_size (int): The size of the blocks that share a scale
+    Returns:
+        Callable for quantization transformation.
+    """
+    dtype = config.dtype
+    block_size = config.block_size
+    scale_block_size = config.scale_block_size
+    weight = module.weight
+
+    if weight.numel() > 2**27:
+        return module  # k_means is too numerically unstable
+    if scale_block_size is None:
+        scale_block_size = weight.shape[1]
+    quantized_weight = CodebookQuantizedTensor.from_float(
+        weight,
+        block_size=block_size,
+        code_dtype=dtype,
+        scale_block_size=scale_block_size,
+    )
+    module.weight = torch.nn.Parameter(quantized_weight, requires_grad=False)
+    return module
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3e43e1f3dce547bbbf0f6e04f27e3a0a1eab3509
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__init__.py
@@ -0,0 +1,9 @@
+from .api import GGUFWeightOnlyConfig
+from .gguf_quantized_tensor import (
+    GGUFQuantizedTensor,
+)
+
+__all__ = [
+    "GGUFQuantizedTensor",
+    "GGUFWeightOnlyConfig",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b2f535411ce91866243c8470f148b1379aee1c24
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__pycache__/api.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__pycache__/api.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..974b64d44f07bc6ac76095d5567c836530589ecb
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__pycache__/api.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__pycache__/gguf_quantized_tensor.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__pycache__/gguf_quantized_tensor.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..04491483a2beb968a8ae0413eab8773909ce6a47
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/__pycache__/gguf_quantized_tensor.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/api.py b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/api.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc4b46992ad72f8808f3e68d79fc564e49810778
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/api.py
@@ -0,0 +1,52 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+
+from dataclasses import dataclass
+
+import torch
+
+from torchao.core.config import AOBaseConfig
+from torchao.quantization.transform_module import register_quantize_module_handler
+
+from .gguf_quantized_tensor import GGUFQuantizedTensor
+
+__all__ = [
+    "GGUFWeightOnlyConfig",
+]
+
+
+@dataclass
+class GGUFWeightOnlyConfig(AOBaseConfig):
+    dtype: torch.dtype = torch.uint4
+    n_blocks_per_superblock: int = 8
+
+
+@register_quantize_module_handler(GGUFWeightOnlyConfig)
+def _gguf_weight_only_transform(
+    module: torch.nn.Module,
+    config: GGUFWeightOnlyConfig,
+):
+    """
+    Applies gguf weight-only quantization to linear layers.
+
+    Args:
+        dtype: torch.uint1 to torch.uint8, torch.int32 supported.
+        n_blocks_per_superblock: the number of super blocks in a 256 element block for gguf, e.g. when it is 8
+            it means we have blocks of 32 and 8 blocks in a superblock of 256 elements.
+    Returns:
+        Callable for quantization transformation.
+    """
+    weight = module.weight
+    if (weight.ndim != 2) or (weight.shape[-1] % 256 != 0):
+        return module
+
+    quantized_weight = GGUFQuantizedTensor.from_float(
+        weight,
+        n_blocks_per_superblock=config.n_blocks_per_superblock,
+        target_dtype=config.dtype,
+    )
+    module.weight = torch.nn.Parameter(quantized_weight, requires_grad=False)
+    return module
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/gguf_quantized_tensor.py b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/gguf_quantized_tensor.py
new file mode 100644
index 0000000000000000000000000000000000000000..9757769d161aeda6d8c2f714dc5ea9476da2d50f
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/gguf/gguf_quantized_tensor.py
@@ -0,0 +1,272 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree.
+
+from typing import Optional
+
+import torch
+from torch.utils._python_dispatch import return_and_correct_aliasing
+
+from torchao.quantization.quant_primitives import (
+    choose_qparams_gguf,
+    dequantize_gguf,
+    quantize_gguf,
+)
+from torchao.utils import (
+    TORCH_VERSION_AT_LEAST_2_5,
+    TorchAOBaseTensor,
+)
+
+_QK_K = 256
+aten = torch.ops.aten
+
+__all__ = [
+    "GGUFQuantizedTensor",
+]
+
+
+class GGUFQuantizedTensor(TorchAOBaseTensor):
+    """
+    A Tensor subclass that when applied to a weight used in a linear op/module,
+    changes that linear op to a weight-only int4 quantized linear op with groupwise
+    affine quantization on the weight.
+    """
+
+    @staticmethod
+    def __new__(
+        cls,
+        n_blocks_per_superblock,
+        super_block_scale_scale,
+        super_block_min_scale,
+        quantized_block_scale,
+        quantized_block_min,
+        int_data,
+        shape,
+        **kwargs,
+    ):
+        kwargs["device"] = kwargs.get("device", super_block_scale_scale.device)
+        kwargs["dtype"] = kwargs.get("dtype", super_block_scale_scale.dtype)
+        kwargs["requires_grad"] = False
+        return torch.Tensor._make_wrapper_subclass(cls, shape, **kwargs)  # type: ignore[attr-defined]
+
+    def __init__(
+        self,
+        n_blocks_per_superblock,
+        super_block_scale_scale,
+        super_block_min_scale,
+        quantized_block_scale,
+        quantized_block_min,
+        int_data,
+        shape,
+        **kwargs,
+    ):
+        self.n_blocks_per_superblock = n_blocks_per_superblock
+        self.super_block_scale_scale = super_block_scale_scale
+        self.super_block_min_scale = super_block_min_scale
+        self.quantized_block_scale = quantized_block_scale
+        self.quantized_block_min = quantized_block_min
+        self.int_data = int_data
+
+    def _apply_fn_to_data(self, fn):
+        return self.__class__(
+            self.n_blocks_per_superblock,
+            fn(self.super_block_scale_scale),
+            fn(self.super_block_min_sclae),
+            fn(self.quantized_block_scale),
+            fn(self.quantized_block_min),
+            fn(self.int_data),
+            self.shape,
+            dtype=self.dtype,
+        )
+
+    def __tensor_flatten__(self):
+        return [
+            "super_block_scale_scale",
+            "super_block_min_scale",
+            "quantized_block_scale",
+            "quantized_block_min",
+            "int_data",
+        ], (
+            self.n_blocks_per_superblock,
+            self.dtype,
+            self.shape,
+        )
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls, tensor_data_dict, attributes, outer_size=None, outer_stride=None
+    ):
+        (
+            super_block_scale_scale,
+            super_block_min_scale,
+            quantized_block_scale,
+            quantized_block_min,
+            int_data,
+        ) = (
+            tensor_data_dict["super_block_scale_scale"],
+            tensor_data_dict["super_block_min_scale"],
+            tensor_data_dict["quantized_block_scale"],
+            tensor_data_dict["quantized_block_min"],
+            tensor_data_dict["int_data"],
+        )
+        n_blocks_per_superblock, dtype, shape = attributes
+        return cls(
+            n_blocks_per_superblock,
+            super_block_scale_scale,
+            super_block_min_scale,
+            quantized_block_scale,
+            quantized_block_min,
+            int_data,
+            shape if outer_size is None else outer_size,
+            dtype=dtype,
+        )
+
+    def dequantize(self, output_dtype: Optional[torch.dtype] = None) -> torch.Tensor:
+        if output_dtype is None:
+            output_dtype = self.dtype
+
+        block_size = tuple(
+            [1] * (self.int_data.ndim - 1) + [_QK_K // self.n_blocks_per_superblock]
+        )
+        return dequantize_gguf(
+            self.int_data,
+            block_size,
+            self.dtype,
+            self.super_block_scale_scale,
+            self.super_block_min_scale,
+            self.quantized_block_scale,
+            self.quantized_block_min,
+            output_dtype=output_dtype,
+        )
+
+    def to(self, *args, **kwargs):
+        kwargs = self._get_to_kwargs(*args, **kwargs)
+        device = kwargs.pop("device")
+        return self.__class__(
+            self.n_blocks_per_superblock,
+            self.super_block_scale_scale.to(device),
+            self.super_block_min_scale.to(device),
+            self.quantized_block_scale.to(device),
+            self.quantized_block_min.to(device),
+            self.int_data.to(device),
+            self.shape,
+            **kwargs,
+        )
+
+    def _apply_fn_to_data(self, fn):
+        """
+        Returns a new `CodebookQuantizedTensor`.
+        """
+        return self.__class__(
+            self.n_blocks_per_superblock,
+            fn(self.super_block_scale_scale),
+            fn(self.super_block_min_scale),
+            fn(self.quantized_block_scale),
+            fn(self.quantized_block_min),
+            fn(self.int_data),
+            self.shape,
+            dtype=self.dtype,
+        )
+
+    def requires_grad_(self, requires_grad=False):
+        """
+        Modifies the tensor's `requires_grad` status in-place.
+        """
+        assert not requires_grad, "Only requires_grad == False is supported"
+        return self
+
+    @classmethod
+    def from_float(cls, input_float, n_blocks_per_superblock, target_dtype):
+        """
+        Method used to convert a linear weight tensor to an instance of the
+        GGMLInt4LinearWeight subclass.
+
+        Example usage::
+
+            model.lin_mod.weight = (
+                GGMLInt4LinearWeight.from_float(model.lin_mod.weight)
+            )
+        """
+        assert target_dtype == torch.uint4, (
+            "only uint4 quantization is supported right now"
+        )
+        block_size = (1, _QK_K // n_blocks_per_superblock)
+        (
+            super_block_scale_scale,
+            super_block_min_scale,
+            quantized_block_scale,
+            quantized_block_min,
+        ) = choose_qparams_gguf(input_float, block_size, target_dtype)
+
+        int_data = quantize_gguf(
+            input_float,
+            block_size,
+            target_dtype,
+            super_block_scale_scale,
+            super_block_min_scale,
+            quantized_block_scale,
+            quantized_block_min,
+        )
+        return cls(
+            n_blocks_per_superblock,
+            super_block_scale_scale,
+            super_block_min_scale,
+            quantized_block_scale,
+            quantized_block_min,
+            int_data,
+            input_float.shape,
+        )
+
+
+implements = GGUFQuantizedTensor.implements
+
+
+@implements([aten.detach.default, aten.alias.default])
+def _(func, types, args, kwargs):
+    return return_and_correct_aliasing(
+        func, args, kwargs, args[0]._apply_fn_to_data(torch.detach)
+    )
+
+
+@implements(aten.clone.default)
+def _(func, types, args, kwargs):
+    return return_and_correct_aliasing(
+        func, args, kwargs, args[0]._apply_fn_to_data(torch.clone)
+    )
+
+
+@implements(aten._to_copy.default)
+def _(func, types, args, kwargs):
+    return return_and_correct_aliasing(
+        func,
+        args,
+        kwargs,
+        args[0].to(*args[1:], **kwargs)._apply_fn_to_data(torch.clone),
+    )
+
+
+@implements([torch.nn.functional.linear, aten.linear.default])
+def _(func, types, args, kwargs):
+    input_tensor, weight_tensor, bias = (
+        args[0],
+        args[1],
+        args[2] if len(args) > 2 else None,
+    )
+    if not input_tensor.is_floating_point():
+        raise NotImplementedError(
+            f"{func} is not implemented for non floating point input"
+        )
+
+    dtype = input_tensor.dtype
+
+    if hasattr(weight_tensor, "dequantize"):
+        weight_tensor = weight_tensor.dequantize(output_dtype=dtype)
+
+    return torch.nn.functional.linear(input_tensor, weight_tensor, bias)
+
+
+if TORCH_VERSION_AT_LEAST_2_5:
+    # Allow a model with GGUFQuantizedTensor weights to be loaded with `weights_only=True`
+    torch.serialization.add_safe_globals([GGUFQuantizedTensor])
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..09243f0785220abdf78df40661f4aef83cf23d2f
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/BO_acc_modelsize.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/BO_acc_modelsize.py
new file mode 100644
index 0000000000000000000000000000000000000000..68561408bd70c722b3c6a03ae967c0fe66cf1605
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/BO_acc_modelsize.py
@@ -0,0 +1,409 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import random
+
+import torch
+import torch.multiprocessing as mp
+from ax.service.ax_client import AxClient, ObjectiveProperties
+from utils import (
+    cal_model_size,
+    cal_wikitext_ppl,
+    load_initial_samples,
+    load_model,
+    load_parameters_from_json,
+    quantize_by_fqn_to_config,
+    write_history_to_csv,
+)
+
+
+# return evaluation results to complete BO trials
+def eval(model, tokenizer, num_PPL_eval_samples, fqn_to_config):
+    return {
+        "cal_PPL": (cal_wikitext_ppl(model, tokenizer, num_PPL_eval_samples), 0.0),
+        "model_size": (cal_model_size(model, fqn_to_config), 0.0),
+    }
+
+
+# add initial search points based on the sensitivity score
+# TODO: add random initial samples if no sensitivity prior
+def get_initial_samples(num_BO_initial_samples=10):
+    initial_points_set = []
+
+    # auto sample the bit choices with random choice probability positive correlated to FIT score
+    for _ in range(num_BO_initial_samples):
+        initial_points = {}
+        for i in range(0, 3):
+            initial_points["bitwidth." + str(i) + "."] = 5
+            initial_points["groupsize." + str(i) + "."] = 32
+
+        for i in range(3, 18):
+            if i in [5, 6, 7, 10, 11, 12, 16]:
+                initial_points["bitwidth." + str(i) + "."] = random.choices(
+                    [5, 4], [20, 80]
+                )[0]
+                initial_points["groupsize." + str(i) + "."] = random.choices(
+                    [32, 64], [30, 70]
+                )[0]
+            else:
+                initial_points["bitwidth." + str(i) + "."] = random.choices(
+                    [5, 4], [30, 70]
+                )[0]
+                initial_points["groupsize." + str(i) + "."] = random.choices(
+                    [32, 64], [40, 60]
+                )[0]
+
+        for i in range(18, 30):
+            if i in [22, 23, 24]:
+                initial_points["bitwidth." + str(i) + "."] = random.choices(
+                    [5, 4, 3, 2], [20, 55, 20, 5]
+                )[0]
+                initial_points["groupsize." + str(i) + "."] = random.choices(
+                    [32, 64, 128, 256], [30, 40, 25, 5]
+                )[0]
+            else:
+                initial_points["bitwidth." + str(i) + "."] = random.choices(
+                    [5, 4, 3, 2], [30, 55, 10, 5]
+                )[0]
+                initial_points["groupsize." + str(i) + "."] = random.choices(
+                    [32, 64, 128, 256], [40, 40, 15, 5]
+                )[0]
+
+        for i in range(30, 32):
+            initial_points["bitwidth." + str(i) + "."] = 5
+            initial_points["groupsize." + str(i) + "."] = 32
+
+        initial_points_set.append(initial_points)
+    return initial_points_set
+
+
+"""
+This function will run BO trials sequentially on a single GPU.
+Each time the BO gets one new trial, evaluates the trial on the GPU and return the evaluation results to update the BO.
+One trial, one BO update.
+TODO: refactor the sequential BO and parallel BO into a single function
+"""
+
+
+def run_sequential_BO(
+    device,
+    checkpoint,
+    num_PPL_eval_samples,
+    num_trials,
+    model_size_constraint,
+    history_output,
+    parameters_list,
+    initial_samples,
+):
+    # TODO: add default parameter list if not specified
+    parameters_list = load_parameters_from_json(parameters_list)
+    initial_points_set = load_initial_samples(initial_samples)
+    num_BO_initial_samples = len(initial_points_set)
+
+    # initialize ax_client
+    constraint = "model_size <= " + str(model_size_constraint)
+    ax_client = AxClient()
+    ax_client.create_experiment(
+        parameters=parameters_list,
+        name="test_quantize_BO",
+        objectives={"cal_PPL": ObjectiveProperties(minimize=True)},
+        choose_generation_strategy_kwargs={
+            "num_initialization_trials": num_BO_initial_samples,  # the number of trials to build generation strategy
+        },
+        outcome_constraints=[constraint],
+    )
+
+    history = []
+    trial_id = 0
+
+    # add initial points into the BO trials
+    for i in range(num_BO_initial_samples):
+        ax_client.attach_trial(parameters=initial_points_set[i])
+
+        m, tokenizer = load_model(checkpoint, device)
+        quantize_by_fqn_to_config(m, device, initial_points_set[i])
+
+        eval_results = eval(m, tokenizer, num_PPL_eval_samples, initial_points_set[i])
+
+        print("------------")
+        print(trial_id, initial_points_set[i], eval_results)
+
+        history.append((eval_results, initial_points_set[i]))
+        ax_client.complete_trial(
+            trial_index=trial_id,
+            raw_data=eval_results,
+        )
+        trial_id += 1
+        del m
+        torch.cuda.empty_cache()
+
+    # run new BO trials
+    for k_ in range(num_trials):
+        parameters, trial_idx = ax_client.get_next_trial()
+
+        m, tokenizer = load_model(checkpoint, device)
+
+        quantize_by_fqn_to_config(m, device, parameters)
+
+        eval_results = eval(m, tokenizer, num_PPL_eval_samples, parameters)
+
+        print("------------")
+        print(trial_idx, parameters, eval_results)
+        history.append((eval_results, parameters))
+
+        ax_client.complete_trial(
+            trial_index=trial_idx,
+            raw_data=eval_results,
+        )
+
+        del m
+        torch.cuda.empty_cache()
+
+    # write BO search trial history to csv file
+    write_history_to_csv(
+        history, history_output, ["cal_PPL", "model_size", "quant_config"]
+    )
+
+    print("------Best config------")
+    best_parameters, values = ax_client.get_best_parameters()
+    print(values, best_parameters)
+
+
+# Worker function to perform BO trials on a specific GPU
+def eval_in_parallel(
+    gpu_id, checkpoint, num_PPL_eval_samples, config, return_dict, proc_id, trial_id
+):
+    model, tokenizer = load_model(checkpoint, f"cuda:{gpu_id}")
+
+    print(f"Process {proc_id} on GPU {gpu_id} starts!")
+    dict_config = dict(config)
+    quantize_by_fqn_to_config(
+        model=model, device=f"cuda:{gpu_id}", fqn_to_config=dict_config
+    )
+
+    eval_results = eval(model, tokenizer, num_PPL_eval_samples, dict_config)
+
+    return_dict[proc_id] = (trial_id, config, eval_results)
+
+    del model
+    torch.cuda.empty_cache()
+
+
+"""
+This function will run BO trials in parallel on multiple GPUs.
+Each time the BO gets multiple new trials, evaluates the trials on the GPUs and return the evaluation results to update the BO.
+Multiple trials, one BO update.
+"""
+
+
+def run_parallel_BO(
+    device,
+    checkpoint,
+    num_PPL_eval_samples,
+    num_trials,
+    model_size_constraint,
+    gpu_list,
+    history_output,
+    parameters_list,
+    initial_samples,
+):
+    # TODO: add default parameter list if not specified
+    parameters_list = load_parameters_from_json(parameters_list)
+    initial_points_set = load_initial_samples(initial_samples)
+    num_BO_initial_samples = len(initial_points_set)
+
+    # initialize ax_client
+    constraint = "model_size <= " + str(model_size_constraint)
+    ax_client = AxClient()
+    ax_client.create_experiment(
+        parameters=parameters_list,
+        name="test_quantize_BO",
+        objectives={"cal_PPL": ObjectiveProperties(minimize=True)},
+        choose_generation_strategy_kwargs={
+            "num_initialization_trials": num_BO_initial_samples,  # the number of trials to build generation strategy
+        },
+        outcome_constraints=[constraint],
+    )
+
+    gpu_list = [int(i) for i in gpu_list.split(",")]
+
+    history = []
+    trial_id = 0
+
+    # Set the multiprocessing start method to 'spawn'
+    mp.set_start_method("spawn", force=True)
+
+    # add initial points into the BO trials
+    for id in range(num_BO_initial_samples // len(gpu_list)):
+        processes = []
+        manager = mp.Manager()
+        return_dict = manager.dict()
+
+        # Start the worker processes
+        for i, gpu_id in enumerate(gpu_list):
+            ax_client.attach_trial(
+                parameters=dict(initial_points_set[id * len(gpu_list) + i])
+            )
+            p = mp.Process(
+                target=eval_in_parallel,
+                args=(
+                    gpu_id,
+                    checkpoint,
+                    num_PPL_eval_samples,
+                    initial_points_set[id * len(gpu_list) + i],
+                    return_dict,
+                    i,
+                    trial_id,
+                ),
+            )
+            trial_id += 1
+            p.start()
+            processes.append(p)
+
+        # Wait for all processes to finish
+        for p in processes:
+            p.join()
+
+        # Print the results after all processes have finished
+        print(return_dict)
+        for i in range(len(gpu_list)):
+            current_trial_id, config, eval_results = return_dict[i]
+            history.append((eval_results, config))
+            ax_client.complete_trial(
+                trial_index=current_trial_id,
+                raw_data=eval_results,
+            )
+
+    # run new BO trials
+    for id in range(num_trials // len(gpu_list)):
+        processes = []
+        manager = mp.Manager()
+        return_dict = manager.dict()
+
+        # Start the worker processes
+        for i, gpu_id in enumerate(gpu_list):
+            parameters, trial_idx = ax_client.get_next_trial()
+            parameter_tuple = []
+            for k, v in parameters.items():
+                parameter_tuple.append((k, v))
+            p = mp.Process(
+                target=eval_in_parallel,
+                args=(
+                    gpu_id,
+                    checkpoint,
+                    num_PPL_eval_samples,
+                    parameter_tuple,
+                    return_dict,
+                    i,
+                    trial_idx,
+                ),
+            )
+            p.start()
+            processes.append(p)
+
+        # Wait for all processes to finish
+        for p in processes:
+            p.join()
+
+        # Print the results after all processes have finished
+        print(return_dict)
+        for i in range(len(gpu_list)):
+            current_trial_id, config, eval_results = return_dict[i]
+            history.append((eval_results, config))
+            ax_client.complete_trial(
+                trial_index=current_trial_id,
+                raw_data=eval_results,
+            )
+
+    # write BO search trial history to csv file
+    write_history_to_csv(
+        history, history_output, ["cal_PPL", "model_size", "quant_config"]
+    )
+
+    print("------Best config------")
+    best_parameters, values = ax_client.get_best_parameters()
+    print(values, best_parameters)
+
+
+if __name__ == "__main__":
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        description="Bayesian optimization for mixed-precision quantization to optimize accuracy under model size constraint."
+    )
+    parser.add_argument(
+        "--device", type=str, default="cuda", help="Device to use for evaluation"
+    )
+    parser.add_argument(
+        "--checkpoint",
+        type=str,
+        default="/tmp/Meta-Llama-3-8B",
+        help="Path to load model",
+    )
+    parser.add_argument(
+        "--num_PPL_eval_samples",
+        type=int,
+        default=None,
+        help="Number of samples to evaluate ppl",
+    )
+    parser.add_argument(
+        "--num_trials", type=int, default=200, help="Number of trials to run BO"
+    )
+    parser.add_argument(
+        "--model_size_constraint",
+        type=float,
+        default=6.0,
+        help="The model size (GB) constraint for BO",
+    )
+    parser.add_argument(
+        "--gpu_list",
+        type=str,
+        default="",
+        help="A list of gpus to run evaluation, separated by comma, e.g., --gpu_lists=0,1,2,3",
+    )
+    parser.add_argument(
+        "--history_output",
+        type=str,
+        default="BO_acc_modelsize_output.csv",
+        help="The csv file path to save the BO search trials",
+    )
+    parser.add_argument(
+        "--parameters_list",
+        type=str,
+        default="Llama3-8B_parameters.json",
+        help="The json file path to save the parameters list for BO",
+    )
+    parser.add_argument(
+        "--initial_samples",
+        type=str,
+        default="Llama3-8B_initial_samples.json",
+        help="The json file path to save the user-defined initial samples for BO",
+    )
+
+    args = parser.parse_args()
+
+    if args.gpu_list == "":
+        run_sequential_BO(
+            device=args.device,
+            checkpoint=args.checkpoint,
+            num_PPL_eval_samples=args.num_PPL_eval_samples,
+            num_trials=args.num_trials,
+            model_size_constraint=args.model_size_constraint,
+            history_output=args.history_output,
+            parameters_list=args.parameters_list,
+            initial_samples=args.initial_samples,
+        )
+    else:
+        run_parallel_BO(
+            device=args.device,
+            checkpoint=args.checkpoint,
+            num_PPL_eval_samples=args.num_PPL_eval_samples,
+            num_trials=args.num_trials,
+            model_size_constraint=args.model_size_constraint,
+            gpu_list=args.gpu_list,
+            history_output=args.history_output,
+            parameters_list=args.parameters_list,
+            initial_samples=args.initial_samples,
+        )
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/BO_acc_throughput.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/BO_acc_throughput.py
new file mode 100644
index 0000000000000000000000000000000000000000..b2277ef4e5d28f90f1ccafeafb938f98ff24e1f1
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/BO_acc_throughput.py
@@ -0,0 +1,598 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import random
+import time
+from pathlib import Path
+from typing import Optional
+
+import torch
+import torch._dynamo.config
+import torch._inductor.config
+from ax.service.ax_client import AxClient, ObjectiveProperties
+from transformers import AutoTokenizer
+from utils import (
+    cal_wikitext_ppl,
+    load_initial_samples,
+    load_model,
+    load_parameters_from_json,
+    quantize_by_fqn_to_config,
+    write_history_to_csv,
+)
+
+import torchao
+from torchao._models.llama.generate import (
+    _load_model,
+    decode_one_token,
+    device_sync,
+    encode_tokens,
+    prefill,
+)
+from torchao._models.llama.model import Transformer, prepare_inputs_for_model
+from torchao._models.llama.tokenizer import get_tokenizer
+
+default_device = "cuda" if torch.cuda.is_available() else "cpu"
+
+
+def decode_n_tokens(
+    model: Transformer,
+    cur_token: torch.Tensor,
+    input_pos: torch.Tensor,
+    num_new_tokens: int,
+    callback=lambda _: _,
+    **sampling_kwargs,
+):
+    new_tokens, new_probs = [], []
+    for i in range(num_new_tokens):
+        with torch.backends.cuda.sdp_kernel(
+            enable_flash=False, enable_mem_efficient=False, enable_math=True
+        ):  # Actually better for Inductor to codegen attention here
+            next_token, next_prob = decode_one_token(
+                model, cur_token, input_pos, **sampling_kwargs
+            )
+            next_token, next_prob = next_token.clone(), next_prob.clone()
+            input_pos += 1
+            new_tokens.append(next_token)
+            callback(new_tokens[-1])
+            new_probs.append(next_prob)
+            cur_token = next_token.view(1, -1)
+
+    return new_tokens, new_probs
+
+
+@torch.no_grad()
+def generate(
+    model: Transformer,
+    prompt: torch.Tensor,
+    max_new_tokens: int,
+    *,
+    interactive: bool,
+    callback=lambda x: x,
+    kv_cache_quantization: bool = False,
+    **sampling_kwargs,
+) -> torch.Tensor:
+    """
+    Takes a conditioning sequence (prompt) as input and continues to generate as many tokens as requested.
+    """
+
+    # create an empty tensor of the expected final shape and fill in the current tokens
+    device = prompt.device
+    T = prompt.numel()
+
+    # calculate how many tokens to generate based on max_new_tokens and model's upper bound (block_size)
+    max_seq_length = (
+        min(T + max_new_tokens, model.config.block_size) if not interactive else 350
+    )
+    new_tokens = max_seq_length - T
+
+    # full prompt+output will be stored in seq
+    seq = torch.empty(max_seq_length, dtype=prompt.dtype, device=device)
+    seq[:T] = prompt.view(-1)
+
+    # setup model caches
+    with torch.device(device):
+        model.setup_caches(max_batch_size=1, max_seq_length=max_seq_length)
+        if kv_cache_quantization:
+            from model import AffineQuantizedKVCache
+
+            from torchao.quantization.quant_api import (
+                _replace_with_custom_fn_if_matches_filter,
+            )
+
+            _replace_with_custom_fn_if_matches_filter(
+                model,
+                AffineQuantizedKVCache.from_float,
+                lambda x, y: isinstance(x, torchao._models.llama.model.KVCache),
+            )
+
+    # format model input
+    x, input_pos = prepare_inputs_for_model(prompt, max_new_tokens)
+
+    # execute prefill
+    next_token = prefill(model, x, input_pos, **sampling_kwargs).clone()
+    seq[T] = next_token
+
+    # execute token generation
+    input_pos = torch.tensor([T], device=device, dtype=torch.int)
+    generated_tokens, _ = decode_n_tokens(
+        model,
+        next_token.view(1, -1),
+        input_pos,
+        new_tokens - 1,
+        callback=callback,
+        **sampling_kwargs,
+    )
+    seq[T + 1 :] = torch.cat(generated_tokens)
+
+    return seq
+
+
+def cal_throughput(
+    model,
+    tokenizer,
+    device,
+    prompt: str = "Hello, my name is",
+    interactive: bool = False,
+    num_samples: int = 5,
+    max_new_tokens: int = 100,
+    top_k: int = 200,
+    temperature: float = 0.8,
+    checkpoint_path: Path = Path("/tmp/Meta-Llama-3-8B/model.pth"),
+    quantization: Optional[str] = None,
+    kv_cache_quantization: bool = False,
+    save: bool = False,
+    compile: bool = True,
+    compile_prefill: bool = False,
+    profile: Optional[Path] = None,
+    precision=torch.bfloat16,
+    write_result: Optional[Path] = None,
+) -> None:
+    """Generates text samples based on a pre-trained Transformer model and tokenizer."""
+    B_INST, E_INST = "[INST]", "[/INST]"
+
+    torchao.quantization.utils.recommended_inductor_config_setter()
+
+    is_chat = "chat" in str(checkpoint_path)
+
+    device_sync(device=device)  # MKG
+
+    encoded = encode_tokens(tokenizer, prompt, bos=True, device=device)
+    prompt_length = encoded.size(0)
+
+    torch.manual_seed(1234)
+
+    if compile:
+        print("Compiling Model")
+        global decode_one_token, prefill
+        decode_one_token = torch.compile(
+            decode_one_token, mode="reduce-overhead", fullgraph=True
+        )
+
+        if compile_prefill:
+            prefill = torch.compile(prefill, fullgraph=True, dynamic=True)
+
+    aggregate_metrics = {
+        "tokens_per_sec": [],
+    }
+    start = -1 if compile else 0
+
+    for i in range(start, num_samples):
+        if i == 0:
+            torch.cuda.reset_peak_memory_stats()
+        device_sync(device=device)  # MKG
+        if i >= 0 and interactive:
+            prompt = input("What is your prompt? ")
+            if is_chat:
+                prompt = f"{B_INST} {prompt.strip()} {E_INST}"
+            encoded = encode_tokens(tokenizer, prompt, bos=True, device=device)
+
+        if interactive and i >= 0:
+            buffer = []
+            period_id = tokenizer.encode(".")[0]
+            done_generating = False
+
+            def callback(x):
+                nonlocal done_generating
+                if done_generating:
+                    return
+                buffer.append(tokenizer.decode([period_id] + x.tolist())[1:])
+                if x.item() == tokenizer.eos_id():
+                    done_generating = True
+                if len(buffer) == 4 or done_generating:
+                    print("".join(buffer), end="", flush=True)
+                    buffer.clear()
+                # print(, end='', flush=True)
+        else:
+            callback = lambda x: x
+        t0 = time.perf_counter()
+        import contextlib
+
+        if i != num_samples - 1 or not profile:
+            prof = contextlib.nullcontext()
+        else:
+            torch.profiler._utils._init_for_cuda_graphs()
+            prof = torch.profiler.profile()
+        with prof:
+            y = generate(
+                model,
+                encoded,
+                max_new_tokens,
+                interactive=interactive,
+                callback=callback,
+                temperature=temperature,
+                top_k=top_k,
+                kv_cache_quantization=kv_cache_quantization,
+            )
+        if i == -1:
+            print(f"Compilation time: {time.perf_counter() - t0:.2f} seconds")
+            continue
+        if hasattr(prof, "export_chrome_trace"):
+            prof.export_chrome_trace(f"{profile}.json")
+        device_sync(device=device)  # MKG
+        t = time.perf_counter() - t0
+
+        if interactive:
+            print()
+        tokens_generated = y.size(0) - prompt_length
+        tokens_sec = tokens_generated / t
+        aggregate_metrics["tokens_per_sec"].append(tokens_sec)
+
+    tokpersec = torch.mean(torch.tensor(aggregate_metrics["tokens_per_sec"])).item()
+    print("tokpersec", tokpersec)
+    return tokpersec
+
+
+# return evaluation results to complete BO trials
+def eval(model4ppl, model4tp, tokenizer, device, num_PPL_eval_samples, fqn_to_config):
+    return {
+        "cal_PPL": (cal_wikitext_ppl(model4ppl, tokenizer, num_PPL_eval_samples), 0.0),
+        "cal_throughput": (
+            cal_throughput(model=model4tp, tokenizer=tokenizer, device=device),
+            0.0,
+        ),
+    }
+
+
+# TODO: make it into a yaml or json file to enable users specify their custom model formats
+def define_parameter_list():
+    # define the search space for all layers
+    parameters_list = []
+
+    for i in range(0, 3):
+        parameters_list.append(
+            {
+                "name": f"bitwidth.{i}.",
+                "type": "fixed",
+                "value_type": "int",
+                "value": 8,
+                "is_ordered": True,
+                "sort_values": True,
+            }
+        )
+
+        parameters_list.append(
+            {
+                "name": f"groupsize.{i}.",
+                "type": "fixed",
+                "value_type": "int",
+                "value": 32,
+                "is_ordered": True,
+                "sort_values": True,
+            }
+        )
+
+    for i in range(3, 30):
+        parameters_list.append(
+            {
+                "name": f"bitwidth.{i}.",
+                "type": "choice",
+                "value_type": "int",
+                "values": [2, 3, 4, 5, 6, 8],
+                "is_ordered": True,
+                "sort_values": True,
+            }
+        )
+
+        parameters_list.append(
+            {
+                "name": f"groupsize.{i}.",
+                "type": "choice",
+                "value_type": "int",
+                "values": [32, 64, 128, 256],
+                "is_ordered": True,
+                "sort_values": True,
+            }
+        )
+
+    for i in range(30, 32):
+        parameters_list.append(
+            {
+                "name": f"bitwidth.{i}.",
+                "type": "fixed",
+                "value_type": "int",
+                "value": 8,
+                "is_ordered": True,
+                "sort_values": True,
+            }
+        )
+        parameters_list.append(
+            {
+                "name": f"groupsize.{i}.",
+                "type": "fixed",
+                "value_type": "int",
+                "value": 32,
+                "is_ordered": True,
+                "sort_values": True,
+            }
+        )
+
+    return parameters_list
+
+
+# add initial search points based on the sensitivity score
+# TODO: add default parameter list if not specified
+def get_initial_samples(num_BO_initial_samples=10):
+    initial_points_set = []
+
+    # auto sample the bit choices with random choice probability positive correlated to FIT score
+    for _ in range(num_BO_initial_samples):
+        initial_points = {}
+        for i in range(0, 3):
+            initial_points["bitwidth." + str(i) + "."] = 8
+            initial_points["groupsize." + str(i) + "."] = 32
+
+        for i in range(3, 18):
+            if i in [5, 6, 7, 10, 11, 12, 16]:
+                initial_points["bitwidth." + str(i) + "."] = random.choices(
+                    [8, 6, 5, 4], [25, 2, 2, 71]
+                )[0]
+                initial_points["groupsize." + str(i) + "."] = random.choices(
+                    [32, 64], [40, 60]
+                )[0]
+            else:
+                initial_points["bitwidth." + str(i) + "."] = random.choices(
+                    [8, 6, 5, 4], [30, 2, 2, 66]
+                )[0]
+                initial_points["groupsize." + str(i) + "."] = random.choices(
+                    [32, 64], [50, 50]
+                )[0]
+
+        for i in range(18, 30):
+            if i in [22, 23, 24]:
+                initial_points["bitwidth." + str(i) + "."] = random.choices(
+                    [8, 6, 5, 4], [10, 2, 2, 86]
+                )[0]
+                initial_points["groupsize." + str(i) + "."] = random.choices(
+                    [32, 64, 128, 256], [35, 45, 10, 10]
+                )[0]
+            else:
+                initial_points["bitwidth." + str(i) + "."] = random.choices(
+                    [8, 6, 5, 4], [20, 2, 2, 76]
+                )[0]
+                initial_points["groupsize." + str(i) + "."] = random.choices(
+                    [32, 64, 128, 256], [30, 40, 25, 5]
+                )[0]
+
+        for i in range(30, 32):
+            initial_points["bitwidth." + str(i) + "."] = 8
+            initial_points["groupsize." + str(i) + "."] = 32
+
+        initial_points_set.append(initial_points)
+
+    return initial_points_set
+
+
+"""
+This function will run BO trials sequentially on a single GPU.
+Each time the BO gets one new trial, evaluates the trial on the GPU and return the evaluation results to update the BO.
+One trial, one BO update.
+"""
+
+
+def run_sequential_BO(
+    device,
+    checkpoint_path,
+    repo_id,
+    num_PPL_eval_samples,
+    num_trials,
+    ppl_constraint,
+    args,
+):
+    """
+    currently use the loader and benchmark code from torchao/_models/llama/generate,
+    and use lm_eval for ppl evaluation
+    """
+    # load tokenizers
+    assert checkpoint_path.is_file(), checkpoint_path
+    tokenizer_path = checkpoint_path.parent / "tokenizer.model"
+    assert tokenizer_path.is_file(), str(tokenizer_path)
+    device_sync(device=device)  # MKG
+    tokenizer4tp = get_tokenizer(tokenizer_path, checkpoint_path)
+    tokenizer4ppl = AutoTokenizer.from_pretrained(repo_id)
+
+    # initialize parameters
+    # TODO: add default parameter list if not specified
+    parameters_list = load_parameters_from_json(args.parameters_list)
+
+    # sample initial points
+    # TODO(future PR): fix me
+    initial_samples = []
+    initial_points_set = load_initial_samples(initial_samples)
+    num_BO_initial_samples = len(initial_points_set)
+
+    # initialize BO experiment
+    constraint = "cal_PPL <= " + str(ppl_constraint)
+    ax_client = AxClient()
+    ax_client.create_experiment(
+        parameters=parameters_list,
+        name="test_quantize_BO",
+        objectives={"cal_throughput": ObjectiveProperties(minimize=False)},
+        choose_generation_strategy_kwargs={
+            "num_initialization_trials": num_BO_initial_samples  # the number of trials to build generation strategy
+        },
+        outcome_constraints=[constraint],
+    )
+
+    history = []
+    trial_id = 0
+
+    # add initial points into the BO trials
+    for i in range(num_BO_initial_samples):
+        ax_client.attach_trial(parameters=initial_points_set[i])
+
+        # evaluate throuput of quantized model under torch.compile()
+        model4tp = _load_model(checkpoint_path, device, torch.bfloat16)
+        quantize_by_fqn_to_config(
+            model=model4tp, device=device, fqn_to_config=initial_points_set[i]
+        )
+        tp = cal_throughput(model=model4tp, tokenizer=tokenizer4tp, device=device)
+        del model4tp
+        torch.cuda.empty_cache()
+
+        # evaluate ppl of quantized model
+        model4ppl = load_model(repo_id, device)
+        quantize_by_fqn_to_config(
+            model=model4ppl, device=device, fqn_to_config=initial_points_set[i]
+        )
+        ppl = cal_wikitext_ppl(model4ppl, tokenizer4ppl, num_PPL_eval_samples)
+        del model4ppl
+        torch.cuda.empty_cache()
+
+        eval_results = {
+            "cal_PPL": (ppl, 0.0),
+            "cal_throughput": (tp, 0.0),
+        }
+
+        print("------------")
+        print(trial_id, initial_points_set[i], eval_results)
+
+        history.append((eval_results, initial_points_set[i]))
+        ax_client.complete_trial(
+            trial_index=trial_id,
+            raw_data=eval_results,
+        )
+        trial_id += 1
+
+    # run new BO trials
+    for k_ in range(num_trials):
+        parameters, trial_idx = ax_client.get_next_trial()
+
+        # evaluate throuput of quantized model under torch.compile()
+        model4tp = _load_model(checkpoint_path, device, torch.bfloat16)
+        quantize_by_fqn_to_config(
+            model=model4tp, device=device, fqn_to_config=initial_points_set[i]
+        )
+        tp = cal_throughput(model=model4tp, tokenizer=tokenizer4tp, device=device)
+        del model4tp
+        torch.cuda.empty_cache()
+
+        # evaluate ppl of quantized model
+        model4ppl = load_model(repo_id, device)
+        quantize_by_fqn_to_config(
+            model=model4ppl, device=device, fqn_to_config=initial_points_set[i]
+        )
+        ppl = cal_wikitext_ppl(model4ppl, tokenizer4ppl, num_PPL_eval_samples)
+        del model4ppl
+        torch.cuda.empty_cache()
+
+        eval_results = {
+            "cal_PPL": (ppl, 0.0),
+            "cal_throughput": (tp, 0.0),
+        }
+
+        print("------------")
+        print(trial_idx, parameters, eval_results)
+
+        history.append((eval_results, parameters))
+
+        ax_client.complete_trial(
+            trial_index=trial_idx,
+            raw_data=eval_results,
+        )
+
+    # write BO search trial history to csv file
+    write_history_to_csv(
+        history, args.history_output, ["cal_PPL", "cal_throughput", "quant_config"]
+    )
+
+    print("------Best config------")
+    best_parameters, values = ax_client.get_best_parameters()
+    print(values, best_parameters)
+
+
+if __name__ == "__main__":
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        description="Bayesian optimization for mixed-precision quantization to optimize inference speed under model accuracy constraint."
+    )
+
+    parser.add_argument(
+        "--device", type=str, default="cuda", help="Device to use for evaluation"
+    )
+    parser.add_argument(
+        "--checkpoint_path",
+        type=Path,
+        default=Path("/tmp/Meta-Llama-3-8B/model.pth"),
+        help="Model checkpoint path for model.pth.",
+    )
+    parser.add_argument(
+        "--repo_id",
+        type=str,
+        default=Path("/tmp/Meta-Llama-3-8B"),
+        help="Model repo id.",
+    )
+    parser.add_argument(
+        "--num_PPL_eval_samples",
+        type=int,
+        default=None,
+        help="Number of samples to evaluate ppl",
+    )
+    parser.add_argument(
+        "--num_trials", type=int, default=150, help="Number of trials to run BO"
+    )
+    parser.add_argument(
+        "--ppl_constraint", type=float, default=7.5, help="The ppl constraint for BO"
+    )
+    parser.add_argument(
+        "--multi_gpus",
+        action="store_true",
+        help="Use multi-processing to run evaluation on multi-gpus",
+    )
+    parser.add_argument(
+        "--gpu_list",
+        type=str,
+        default="",
+        help="A list of gpus to run evaluation, separated by comma, e.g., --gpu_lists=0,1,2,3",
+    )
+    parser.add_argument(
+        "--history_output",
+        type=str,
+        default="BO_acc_speed_output.csv",
+        help="The csv file path to save the BO search trials",
+    )
+    parser.add_argument(
+        "--parameters_list",
+        type=str,
+        default="Llama3-8B_parameters.json",
+        help="The json file path to save the parameters list for BO",
+    )
+    parser.add_argument(
+        "--initial_samples",
+        type=str,
+        default="Llama3-8B_initial_samples.json",
+        help="The json file path to save the user-defined initial samples for BO",
+    )
+
+    args = parser.parse_args()
+    run_sequential_BO(
+        device=args.device,
+        checkpoint_path=args.checkpoint_path,
+        repo_id=args.repo_id,
+        num_PPL_eval_samples=args.num_PPL_eval_samples,
+        num_trials=args.num_trials,
+        ppl_constraint=args.ppl_constraint,
+        args=args,
+    )
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d4e7e5acaef07c724c0a47da8578a520a84a18d8
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__init__.py
@@ -0,0 +1,5 @@
+from .naive_intNwo import intN_weight_only
+
+__all__ = [
+    "intN_weight_only",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/BO_acc_modelsize.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/BO_acc_modelsize.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9e7c5c7a6bc721839579f63b6762675e88b8b13a
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/BO_acc_modelsize.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/BO_acc_throughput.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/BO_acc_throughput.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6a2980aad3ef98d465a664eb75ff5879e7df9de9
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/BO_acc_throughput.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9ee3584efacf706a806a6380a6be3c2a34dd29f9
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/fit.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/fit.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..55a031e0c085d2f1da1adfb3ce3fae4c3201b43b
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/fit.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/hessian_grad.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/hessian_grad.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..6dca614a6e927295b07a970f82d8c5c31eb6db78
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/hessian_grad.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/hessian_vhp.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/hessian_vhp.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..bbaa8e7aa97e2db1dcdb556441ea85603a15d8b8
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/hessian_vhp.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/mp_quant_eval.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/mp_quant_eval.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..04181c76422c18f19e3361cd0047153d6e820c8f
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/mp_quant_eval.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/naive_intNwo.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/naive_intNwo.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cfcef342bea4fd565b4f44e16096cb09a5c30de8
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/naive_intNwo.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..81c623ba54de2b8d04648fa7949e287a165dbbad
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/__pycache__/utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/fit.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/fit.py
new file mode 100644
index 0000000000000000000000000000000000000000..d8e6be4550ee73316e54c0374f9f7a5409083bdc
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/fit.py
@@ -0,0 +1,151 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import random
+
+import numpy as np
+import torch
+import transformers
+from datasets import load_dataset
+from tqdm import tqdm
+
+
+def get_wikitext2(nsamples, seed, seqlen, tokenizer):
+    traindata = load_dataset("Salesforce/wikitext", "wikitext-2-raw-v1", split="train")
+    testdata = load_dataset("Salesforce/wikitext", "wikitext-2-raw-v1", split="test")
+
+    trainenc = tokenizer("\n\n".join(traindata["text"]), return_tensors="pt")
+    testenc = tokenizer("\n\n".join(testdata["text"]), return_tensors="pt")
+
+    random.seed(seed)
+    trainloader = []
+    for _ in range(nsamples):
+        i = random.randint(0, trainenc.input_ids.shape[1] - seqlen - 1)
+        j = i + seqlen
+        inp = trainenc.input_ids[:, i:j]
+        tar = inp.clone()
+        tar[:, :-1] = -100
+        trainloader.append((inp, tar))
+    return trainloader, testenc
+
+
+def cal_FIT(device, data, nsamples, model, max_iter, max_seqlen, criterion, num_layers):
+    # store the history of trace for each layer
+    estimated_history = []
+
+    # store the history of mean trace for each layer
+    estimated_mean = [[] for _ in range(num_layers)]
+    trace = [0.0] * num_layers
+
+    for iteration in range(max_iter):
+        print("iteration: ", iteration)
+        trace_tmp = [0.0] * num_layers
+
+        for i in tqdm(range(nsamples)):
+            inputs, targets = data[i]
+            inputs = inputs.to(device)
+            targets = targets.to(device)
+            model.zero_grad()
+            outputs = model(inputs)
+            logits = outputs.logits
+            loss = criterion(logits.view(-1, logits.size(-1)), targets.view(-1))
+
+            grads = torch.autograd.grad(loss, model.parameters())
+
+            # Trace(Fisher Information Matrix) is calculated by the sum of the square of the gradient
+            for layerid in range(num_layers):
+                for (name, _), grad in zip(model.named_parameters(), grads):
+                    if "." + str(layerid) + "." in name and (
+                        "self_attn" in name or "mlp" in name
+                    ):
+                        trace_tmp[layerid] += torch.sum(grad * grad).item()
+
+            # clean cache
+            model.zero_grad()
+            del grads
+            torch.cuda.empty_cache()
+
+        # calculate the mean of the trace on the calibration dataset
+        for t in range(num_layers):
+            trace[t] = trace_tmp[t] / float(nsamples)
+            estimated_mean[t].append(trace[t])
+
+        print("trace:", trace)
+        estimated_history.append(trace)
+
+    F_average = np.array([np.mean(i) for i in estimated_mean])
+    return F_average, estimated_mean, estimated_history
+
+
+def main(max_seqlen, checkpoint, nsamples, max_iter, num_layers):
+    device = "cuda" if torch.cuda.is_available() else "cpu"
+
+    # have been tested models Llama-3-8B, Llama-2-7B, Mistral-7B, and stories110M
+    model = transformers.AutoModelForCausalLM.from_pretrained(
+        checkpoint, torch_dtype=torch.bfloat16
+    )
+    tokenizer = transformers.AutoTokenizer.from_pretrained(checkpoint)
+    model = model.to(device)
+    model.eval()
+
+    criterion = torch.nn.CrossEntropyLoss()
+
+    # load calibration dataset
+    seed = 0
+    trainloader, testloader = get_wikitext2(nsamples, seed, max_seqlen, tokenizer)
+
+    F_average, estimated_mean, estimated_history = cal_FIT(
+        device=device,
+        data=trainloader,
+        nsamples=nsamples,
+        model=model,
+        max_iter=max_iter,
+        max_seqlen=max_seqlen,
+        criterion=criterion,
+        num_layers=num_layers,
+    )
+    print("Iteration Done")
+    print("FIT scores for", num_layers, "layers:\n", F_average)
+    print("estimated_mean:", estimated_mean)
+    print("estimated_history:", estimated_history)
+
+
+if __name__ == "__main__":
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        description="Calculate layer-wised fish information matrix trace."
+    )
+    parser.add_argument(
+        "--checkpoint",
+        type=str,
+        default="/tmp/Meta-Llama-3-8B",
+        help="Path to load model",
+    )
+    parser.add_argument(
+        "--max_seqlen", type=int, default=2048, help="Max sequence length"
+    )
+    parser.add_argument(
+        "--max_iter",
+        type=int,
+        default=100,
+        help="The number of iterations to calculate FIT",
+    )
+    parser.add_argument(
+        "--num_layers",
+        type=int,
+        default=32,
+        help="The number of layers to calculate FIT.",
+    )
+    parser.add_argument(
+        "--nsamples",
+        type=int,
+        default=128,
+        help="The number of samples in calibration dataset",
+    )
+    args = parser.parse_args()
+    main(
+        args.max_seqlen, args.checkpoint, args.nsamples, args.max_iter, args.num_layers
+    )
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/hessian_grad.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/hessian_grad.py
new file mode 100644
index 0000000000000000000000000000000000000000..1e7b403e3de4b16c5f4ad79ab15385cd13598159
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/hessian_grad.py
@@ -0,0 +1,201 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import random
+
+import numpy as np
+import torch
+import transformers
+from datasets import load_dataset
+from torch.nn.attention import SDPBackend, sdpa_kernel
+from tqdm import tqdm
+
+
+def group_product(xs, ys):
+    return [torch.sum(x * y) for (x, y) in zip(xs, ys)]
+
+
+def get_wikitext2(nsamples, seed, seqlen, tokenizer):
+    traindata = load_dataset("Salesforce/wikitext", "wikitext-2-raw-v1", split="train")
+    testdata = load_dataset("Salesforce/wikitext", "wikitext-2-raw-v1", split="test")
+
+    trainenc = tokenizer("\n\n".join(traindata["text"]), return_tensors="pt")
+    testenc = tokenizer("\n\n".join(testdata["text"]), return_tensors="pt")
+
+    random.seed(seed)
+    trainloader = []
+    for _ in range(nsamples):
+        i = random.randint(0, trainenc.input_ids.shape[1] - seqlen - 1)
+        j = i + seqlen
+        inp = trainenc.input_ids[:, i:j]
+        tar = inp.clone()
+        tar[:, :-1] = -100
+        trainloader.append((inp, tar))
+    return trainloader, testenc.input_ids
+
+
+def dataloader_hv_product(
+    layerid, params, device, v, data, nsamples, model, max_seqlen, criterion
+):
+    model.zero_grad()
+    THv = [torch.zeros(p.size()).to(device) for p in params]  # accumulate result
+
+    # Freeze all the parameters in the model
+    for param in model.parameters():
+        param.requires_grad = False
+
+    # Unfreeze the parameters of attention and MLP layers in layer 0
+    layer_ = model.model.layers[layerid]
+    for param in layer_.self_attn.parameters():
+        param.requires_grad = True
+    for param in layer_.mlp.parameters():
+        param.requires_grad = True
+
+    for i in tqdm(range(nsamples)):
+        torch.cuda.empty_cache()
+        inputs, labels = data[i]
+        inputs = inputs.to(device)
+        labels = labels.to(device)
+        # if use testloader:
+        # inputs = data[:, (i * max_seqlen) : ((i + 1) * max_seqlen)].to(device)
+        # labels = data[:, (i * max_seqlen) : ((i + 1) * max_seqlen)].to(device)
+        model.zero_grad()
+        outputs = model(inputs)
+        logits = outputs.logits
+        loss = criterion(logits.view(-1, logits.size(-1)), labels.view(-1))
+
+        # get the first order gradients
+        grads = torch.autograd.grad(loss, params, create_graph=True, only_inputs=True)
+
+        # calculate Hessian vector product via Jac-vector product
+        Hv = torch.autograd.grad(
+            grads, params, grad_outputs=v, only_inputs=True, retain_graph=False
+        )
+
+        THv = [THv1 + Hv1 + 0.0 for THv1, Hv1 in zip(THv, Hv)]
+
+        # clean cache
+        model.zero_grad()
+        del Hv
+        del grads
+        torch.cuda.empty_cache()
+
+    THv = [THv1 / float(nsamples) for THv1 in THv]
+    return THv
+
+
+def cal_trace(
+    layerid, params, device, data, nsamples, model, max_iter, max_seqlen, criterion
+):
+    vhv_c_history = []
+    trace_history = []
+    trace = 0.0
+
+    for i in range(max_iter):
+        print("iteration: ", i)
+
+        # generate Rademacher random variables
+        v = [torch.randint_like(p, high=2, device=device) for p in params]
+
+        for v_i in v:
+            v_i[v_i == 0] = -1
+
+        # calculate Hessian vector product
+        Hv = dataloader_hv_product(
+            layerid, params, device, v, data, nsamples, model, max_seqlen, criterion
+        )
+
+        vHv = group_product(Hv, v)
+
+        vHv_c = np.array([i.cpu().numpy() for i in vHv])
+
+        vhv_c_history.append(vHv_c)
+
+        trace = np.sum(vHv_c)
+
+        trace_history.append(trace)
+        print("trace,", trace)
+        print("trace_history,", trace_history)
+        print("vhv_c_history,", vhv_c_history)
+
+    return np.mean(trace_history)
+
+
+def main(layer_id, checkpoint, max_seqlen, max_iter, nsamples):
+    device = "cuda" if torch.cuda.is_available() else "cpu"
+
+    # to avoid aten::_scaled_dot_product_flash_attention_backward not implemented error
+    with sdpa_kernel(SDPBackend.MATH):
+        # have been tested models Llama-3-8B, Llama-2-7B, Mistral-7B, and stories110M
+        model = transformers.AutoModelForCausalLM.from_pretrained(
+            checkpoint, torch_dtype=torch.bfloat16
+        )
+        tokenizer = transformers.AutoTokenizer.from_pretrained(checkpoint)
+        model = model.cuda()
+        model.eval()
+
+        criterion = torch.nn.CrossEntropyLoss()
+
+        # load calibration dataset
+        seed = 0
+        trainloader, testloader = get_wikitext2(128, seed, 2048, tokenizer)
+
+        # calculate Hessian for only one layer each time
+        params = []
+        layer_ = model.model.layers[layer_id]
+        for param in layer_.self_attn.parameters():
+            params.append(param)
+        for param in layer_.mlp.parameters():
+            params.append(param)
+
+        trace = cal_trace(
+            layerid=layer_id,
+            params=params,
+            device=device,
+            data=trainloader,
+            nsamples=nsamples,
+            model=model,
+            max_iter=max_iter,
+            max_seqlen=max_seqlen,
+            criterion=criterion,
+        )
+        print("The trace of layer " + str(layer_id) + " is", trace)
+
+
+if __name__ == "__main__":
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        description="Calculate layer-wised Hessian trace leveraging autograd."
+    )
+    parser.add_argument(
+        "--layer_id",
+        type=int,
+        default=0,
+        help="Which layer to compute the trace and hessian",
+    )
+    parser.add_argument(
+        "--checkpoint",
+        type=str,
+        default="/tmp/Meta-Llama-3-8B",
+        help="Path to load model",
+    )
+    parser.add_argument(
+        "--max_seqlen", type=int, default=2048, help="Max sequence length"
+    )
+    parser.add_argument(
+        "--max_iter",
+        type=int,
+        default=100,
+        help="The number of iterations to calculate Hessian trace",
+    )
+    parser.add_argument(
+        "--nsamples",
+        type=int,
+        default=128,
+        help="The number of samples in calibration dataset",
+    )
+    args = parser.parse_args()
+    main(args.layer_id, args.checkpoint, args.max_seqlen, args.max_iter, args.nsamples)
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/hessian_vhp.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/hessian_vhp.py
new file mode 100644
index 0000000000000000000000000000000000000000..faf46b01ebd924603328f25862c644c7de0778b7
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/hessian_vhp.py
@@ -0,0 +1,204 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import random
+
+import numpy as np
+import torch
+import transformers
+from datasets import load_dataset
+from torch.autograd.functional import vhp
+from torch.nn.attention import SDPBackend, sdpa_kernel
+from tqdm import tqdm
+
+
+def group_product(xs, ys):
+    return [torch.sum(x * y) for (x, y) in zip(xs, ys)]
+
+
+def get_wikitext2(nsamples, seed, seqlen, tokenizer):
+    traindata = load_dataset("Salesforce/wikitext", "wikitext-2-raw-v1", split="train")
+    testdata = load_dataset("Salesforce/wikitext", "wikitext-2-raw-v1", split="test")
+
+    trainenc = tokenizer("\n\n".join(traindata["text"]), return_tensors="pt")
+    testenc = tokenizer("\n\n".join(testdata["text"]), return_tensors="pt")
+
+    random.seed(seed)
+    trainloader = []
+    for _ in range(nsamples):
+        i = random.randint(0, trainenc.input_ids.shape[1] - seqlen - 1)
+        j = i + seqlen
+        inp = trainenc.input_ids[:, i:j]
+        tar = inp.clone()
+        tar[:, :-1] = -100
+        trainloader.append((inp, tar))
+    return trainloader, testenc.input_ids
+
+
+# utilities to make nn.Module functional
+def del_attr(obj, names):
+    if len(names) == 1:
+        delattr(obj, names[0])
+    else:
+        del_attr(getattr(obj, names[0]), names[1:])
+
+
+def set_attr(obj, names, val):
+    if len(names) == 1:
+        setattr(obj, names[0], val)
+    else:
+        set_attr(getattr(obj, names[0]), names[1:], val)
+
+
+def make_functional(mod, layer_id):
+    orig_params = tuple(mod.parameters())
+    # remove all the parameters in the model
+    selected_params = []
+    selected_params_names = []
+
+    names = []
+    for name, p in list(mod.named_parameters()):
+        if name.startswith(
+            "model.layers." + str(layer_id) + ".self_attn."
+        ) or name.startswith("model.layers." + str(layer_id) + ".mlp."):
+            selected_params.append(p)
+            selected_params_names.append(name)
+        del_attr(mod, name.split("."))
+        names.append(name)
+    return orig_params, names, selected_params, selected_params_names
+
+
+def main(layer_id, checkpoint, max_seqlen, max_iter, nsamples):
+    # use the functional model to load the weights back
+    def load_weights(mod, names, params, selected_params, selected_params_names):
+        for name, p in zip(names, params):
+            if name.startswith(
+                "model.layers." + str(layer_id) + ".self_attn."
+            ) or name.startswith("model.layers." + str(layer_id) + ".mlp."):
+                idx = selected_params_names.index(name)
+                set_attr(mod, name.split("."), selected_params[idx])
+            else:
+                set_attr(mod, name.split("."), p)
+        for name, param in mod.named_parameters():
+            if param.requires_grad:
+                print(f"Parameter {name} requires gradients.")
+
+    # define the function to calculate the vhp
+    def f(*new_params):
+        load_weights(model, names, params, new_params, selected_params_names)
+        model.zero_grad()
+        outputs = model(inputs)
+        logits = outputs.logits
+        loss = criterion(logits.view(-1, logits.size(-1)), labels.view(-1))
+        return loss
+
+    device = "cuda" if torch.cuda.is_available() else "cpu"
+
+    # to avoid aten::_scaled_dot_product_flash_attention_backward not implemented error
+    with sdpa_kernel(SDPBackend.MATH):
+        # have been tested models Llama-3-8B, Llama-2-7B, Mistral-7B, and stories110M
+        model = transformers.AutoModelForCausalLM.from_pretrained(
+            checkpoint, torch_dtype=torch.bfloat16
+        )
+        tokenizer = transformers.AutoTokenizer.from_pretrained(checkpoint)
+        model = model.to(device)
+        model.eval()
+
+        criterion = torch.nn.CrossEntropyLoss()
+
+        # load calibration dataset
+        trainloader, _ = get_wikitext2(128, 0, 2048, tokenizer)
+
+        # make the model functional
+        params, names, selected_params, selected_params_names = make_functional(
+            model, layer_id
+        )
+
+        # make params regular Tensors instead of nn.Parameter
+        params = tuple(p.detach() for p in params)
+
+        # set requires_grad to True for the selected parameters
+        selected_params_tuple = tuple(
+            p.detach().requires_grad_() for p in selected_params
+        )
+
+        trace_history = []
+        vhv_c_history = []
+
+        for iteration in range(max_iter):
+            print("iteration: ", iteration)
+
+            # generate Rademacher random variables
+            v = [torch.randint_like(p, high=2) for p in selected_params_tuple]
+            for v_i in v:
+                v_i[v_i == 0] = -1
+
+            for i in tqdm(range(nsamples)):
+                inputs, labels = trainloader[i]
+                inputs = inputs.to(device)
+                labels = labels.to(device)
+                # if use testloader:
+                # inputs = testloader[:, (i * max_seqlen) : ((i + 1) * max_seqlen)].to(device)
+                # labels = testloader[:, (i * max_seqlen) : ((i + 1) * max_seqlen)].to(device)
+
+                # get vector-Hessian product
+                _, vH = vhp(f, selected_params_tuple, tuple(v))
+
+                if i == 0:
+                    TvH = [
+                        torch.zeros(p.size()).to(device) for p in selected_params_tuple
+                    ]
+                TvH = [TvH1 + vH1 + 0.0 for TvH1, vH1 in zip(TvH, vH)]
+
+            TvH = [TvH1 / float(nsamples) for TvH1 in TvH]
+            # get vHv
+            vHv = group_product(TvH, v)
+            vHv_c = np.array([i.to(torch.float32).cpu().numpy() for i in vHv])
+            vhv_c_history.append(vHv_c)
+            trace = np.sum(np.abs(vHv_c))
+            print("trace", trace)
+            trace_history.append(trace)
+
+        print("Iteration Done")
+        print("Avg Hessian trace for layer", layer_id, "is:", np.mean(trace_history))
+        print("trace_history,", trace_history)
+
+
+if __name__ == "__main__":
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        description="Calculate layer-wised Hessian trace leveraging torch's vhp function."
+    )
+    # TODO: make it a for loop for all the layer_ids to automatically calculate the Hessian trace for all the layers of a model
+    parser.add_argument(
+        "--layer_id",
+        type=int,
+        default=0,
+        help="Which layer to compute the Hessian trace",
+    )
+    parser.add_argument(
+        "--checkpoint",
+        type=str,
+        default="/tmp/Meta-Llama-3-8B",
+        help="Path to load model",
+    )
+    parser.add_argument(
+        "--max_seqlen", type=int, default=2048, help="Max sequence length"
+    )
+    parser.add_argument(
+        "--max_iter",
+        type=int,
+        default=100,
+        help="The number of iterations to calculate Hessian trace",
+    )
+    parser.add_argument(
+        "--nsamples",
+        type=int,
+        default=128,
+        help="The number of samples in calibration dataset",
+    )
+    args = parser.parse_args()
+    main(args.layer_id, args.checkpoint, args.max_seqlen, args.max_iter, args.nsamples)
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/mp_quant_eval.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/mp_quant_eval.py
new file mode 100644
index 0000000000000000000000000000000000000000..e10b10ffb29edee1d97a6152508dcf7f630a9df8
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/mp_quant_eval.py
@@ -0,0 +1,214 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import torch
+import torch.nn as nn
+from lm_eval.evaluator import evaluate
+from lm_eval.models.huggingface import HFLM
+from lm_eval.tasks import get_task_dict
+from naive_intNwo import intN_weight_only
+from transformers import AutoModelForCausalLM, AutoTokenizer
+
+from torchao.quantization import (
+    quantize_,
+)
+from torchao.quantization.quant_api import autoquant
+
+torch._inductor.config.force_fuse_int_mm_with_mul = True
+torch._inductor.config.fx_graph_cache = True
+
+
+def run_evaluation(
+    repo_id,
+    tasks,
+    limit,
+    device,
+    precision,
+    quantization,
+    compile,
+    batch_size,
+    max_length,
+    sensi_bit,
+    non_sensi_bit,
+    quant_sym,
+    group_size,
+):
+    tokenizer = AutoTokenizer.from_pretrained(repo_id)
+    model = AutoModelForCausalLM.from_pretrained(repo_id).to(
+        device="cpu", dtype=precision
+    )
+
+    if quantization == "autoquant":
+        model = autoquant(model.to(device=device))
+
+    # naive implementation of uniform precision quantization all layers
+    elif quantization in ["2", "3", "4", "5", "6", "8"]:
+        quantize_(
+            model.to(device=device),
+            intN_weight_only(
+                n=int(quantization), group_size=group_size, symmetric=quant_sym
+            ),
+        )
+
+    # mix precision quantization for Llama3
+    elif quantization == "MP_llama3":
+        # filter for sensitive layers (the first 3 and last 2 layers for Llama3)
+        def filter_fn_sen(child: torch.nn.Module, cur_fqn: str) -> bool:
+            return isinstance(child, nn.Linear) and any(
+                skiplayer in cur_fqn
+                for skiplayer in [".0.", ".1.", ".2.", ".30.", ".31."]
+            )
+
+        # filter for non-sensitive layers (other 27 layers for Llama3)
+        def filter_fn_nonsen(child: torch.nn.Module, cur_fqn: str) -> bool:
+            return isinstance(child, nn.Linear) and not (
+                any(
+                    skiplayer in cur_fqn
+                    for skiplayer in [".0.", ".1.", ".2.", ".30.", ".31."]
+                )
+            )
+
+        # quantize the sensitive layers
+        if sensi_bit != 16:
+            quantize_(
+                model.to(device=device),
+                intN_weight_only(
+                    n=sensi_bit, group_size=group_size, symmetric=quant_sym
+                ),
+                filter_fn_sen,
+            )
+
+        # quantize the less-sensitive layers
+        if sensi_bit == 4:
+            quantize_(
+                model,
+                intN_weight_only(
+                    n=non_sensi_bit, group_size=group_size, symmetric=quant_sym
+                ),
+                filter_fn_nonsen,
+            )
+        else:
+            quantize_(
+                model.to(device=device),
+                intN_weight_only(
+                    n=non_sensi_bit, group_size=group_size, symmetric=quant_sym
+                ),
+                filter_fn_nonsen,
+            )
+
+    if compile:
+        model = torch.compile(model, mode="max-autotune", fullgraph=True)
+
+    with torch.no_grad():
+        result = evaluate(
+            HFLM(
+                pretrained=model,
+                tokenizer=tokenizer,
+                batch_size=batch_size,
+                max_length=max_length,
+            ),
+            get_task_dict(tasks),
+            limit=limit,
+        )
+
+    for task, res in result["results"].items():
+        print(f"{task}: {res}")
+
+
+if __name__ == "__main__":
+    import argparse
+
+    parser = argparse.ArgumentParser(
+        description="Run evaluation for uniform or mixed-precision quantization."
+    )
+    parser.add_argument(
+        "--repo_id",
+        type=str,
+        default="checkpoints/meta-llama/Meta-Llama-3-8B",
+        help="Repository ID to download from HF.",
+    )
+    parser.add_argument(
+        "--tasks",
+        nargs="+",
+        type=str,
+        default=["wikitext"],
+        help="List of lm-eluther tasks to evaluate usage: --tasks task1 task2",
+    )
+    parser.add_argument(
+        "--limit", type=int, default=None, help="Number of eval samples to evaluate"
+    )
+    parser.add_argument(
+        "--precision",
+        type=lambda x: getattr(torch, x.split(".")[-1]),
+        default=torch.bfloat16,
+        help="dtype precision to use",
+    )
+    parser.add_argument(
+        "--device", type=str, default="cuda", help="Device to use for evaluation"
+    )
+    parser.add_argument(
+        "-q",
+        "--quantization",
+        default="None",
+        choices=["2", "3", "4", "5", "6", "8", "MP_llama3", "None"],
+        help='Which quantization technique to apply, choose from ["2", "3", "4", "5", "6", "8"] for uniform quantizatoin, choose "MP_llama3" for mixed-precision for Llama3 and need to set corresponding sensi_bit and non_sensi_bit, choose "None" for no quantization',
+    )
+    parser.add_argument(
+        "--compile", action="store_true", help="Whether to compile the model."
+    )
+    parser.add_argument(
+        "--batch_size",
+        type=int,
+        default=1,
+        help="Batch size to use for evaluation, note int8wo and int4wo work best with small batchsizes, int8dq works better with large batchsizes",
+    )
+    parser.add_argument(
+        "--max_length",
+        type=int,
+        default=None,
+        help="Length of text to process at one time",
+    )
+    parser.add_argument(
+        "--sensi_bit",
+        type=int,
+        default=16,
+        choices=[16, 8, 6, 5, 4, 3],
+        help="Bit setting for sensitive layers",
+    )
+    parser.add_argument(
+        "--non_sensi_bit",
+        type=int,
+        default=8,
+        choices=[8, 6, 5, 4, 3, 2],
+        help="Bit setting for non-sensitive layers",
+    )
+    parser.add_argument(
+        "--quant_sym",
+        type=bool,
+        default=False,
+        help="Symmetric or asymmetric quantization, asymmetric by default",
+    )
+    parser.add_argument(
+        "--group_size",
+        type=int,
+        default=32,
+        help="Group size to perform quantization on",
+    )
+    args = parser.parse_args()
+    run_evaluation(
+        args.repo_id,
+        args.tasks,
+        args.limit,
+        args.device,
+        args.precision,
+        args.quantization,
+        args.compile,
+        args.batch_size,
+        args.max_length,
+        args.sensi_bit,
+        args.non_sensi_bit,
+        args.quant_sym,
+        args.group_size,
+    )
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/naive_intNwo.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/naive_intNwo.py
new file mode 100644
index 0000000000000000000000000000000000000000..016b6c9eef27bf9cd4cb4a1f5570e1972cf36ced
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/naive_intNwo.py
@@ -0,0 +1,116 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+from dataclasses import dataclass
+
+import torch
+
+import torchao
+from torchao.core.config import AOBaseConfig
+from torchao.quantization.quant_primitives import (
+    MappingType,
+)
+from torchao.quantization.transform_module import (
+    register_quantize_module_handler,
+)
+
+
+@dataclass
+class IntNWeightOnlyConfig(AOBaseConfig):
+    """
+    Configuration for applying int N-bit weight only quantization to a linear layer.
+    Args:
+        `group_size`: parameter for quantization, controls the granularity of quantization, smaller size is more fine grained, choices are [512, 256, 128, 64, 32]
+        `n`: number of bits to quantize to, choices are [8, 6, 5, 4, 3, 2]
+        `set_inductor_config`: if True, adjusts `torchinductor` settings to recommended values.
+    Usage:
+        from torchao.quantization import quantize_
+        quantize_(model, intN_weight_only(n=your_bit_choice, group_size=group_size), optional_filter_func_for_desired_layers_to_quantize)
+    """
+
+    group_size: int = 32
+    n: int = 8
+    symmetric: bool = False
+    set_inductor_config: bool = True
+
+
+# for bc
+intN_weight_only = IntNWeightOnlyConfig
+
+
+@register_quantize_module_handler(IntNWeightOnlyConfig)
+def _intN_weight_only_transform(
+    module: torch.nn.Module,
+    config: IntNWeightOnlyConfig,
+) -> torch.nn.Module:
+    group_size = config.group_size
+    n = config.n
+    symmetric = config.symmetric
+    weight = module.weight
+    if config.set_inductor_config:
+        torchao.quantization.utils.recommended_inductor_config_setter()
+
+    # for asymmetric quantization
+    def apply_intN_weight_only_quant_asym(weight):
+        # avoid circular dependency
+        from torchao.dtypes import to_affine_quantized_intx
+
+        mapping_type = MappingType.ASYMMETRIC
+        block_size = (1, group_size)
+        target_dtype = torch.uint8
+        quant_min = 0
+        quant_max = 2**n - 1
+        eps = 1e-6
+        zero_point_dtype = torch.int64
+        return to_affine_quantized_intx(
+            weight,
+            mapping_type,
+            block_size,
+            target_dtype,
+            quant_min,
+            quant_max,
+            eps,
+            zero_point_dtype=zero_point_dtype,
+        )  # , preserve_zero=preserve_zero,zero_point_domain=zero_point_domain)
+
+    # for symmetric quantization
+    def apply_intN_weight_only_quant_sym(weight):
+        # avoid circular dependency
+        from torchao.dtypes import to_affine_quantized_intx
+
+        mapping_type = MappingType.SYMMETRIC
+        block_size = (1, group_size)
+        target_dtype = torch.int8
+        quant_min = -(2 ** (n - 1))
+        quant_max = 2 ** (n - 1) - 1
+        eps = 1e-6
+        zero_point_dtype = torch.int64
+        return to_affine_quantized_intx(
+            weight,
+            mapping_type,
+            block_size,
+            target_dtype,
+            quant_min,
+            quant_max,
+            eps=eps,
+            zero_point_dtype=zero_point_dtype,
+        )
+
+    assert n in [8, 6, 5, 4, 3, 2], "n must be one of [8, 6, 5, 4, 3, 2]"
+    if n == 8:
+        raise AssertionError(
+            "Someone needs to refactor this code to handle int8_weight_only again"
+        )
+    elif n == 4:
+        raise AssertionError(
+            "Someone needs to refactor this code to handle int4_weight_only again"
+        )
+    else:
+        if symmetric:
+            new_weight = apply_intN_weight_only_quant_sym(weight)
+        else:
+            new_weight = apply_intN_weight_only_quant_asym(weight)
+        module.weight = torch.nn.Parameter(new_weight, requires_grad=False)
+    return module
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/utils.py b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a476642006b6d3060f318c17daa42d4863ad160
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/mixed_precision/scripts/utils.py
@@ -0,0 +1,167 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import csv
+import json
+
+import torch
+from lm_eval.evaluator import evaluate
+from lm_eval.models.huggingface import HFLM
+from lm_eval.tasks import get_task_dict
+from naive_intNwo import intN_weight_only
+from transformers import AutoModelForCausalLM, AutoTokenizer
+
+from torchao.quantization import quantize_
+
+
+def write_history_to_csv(history, output_file, keyword):
+    # keyword example: ['cal_PPL', 'cal_throughput', 'config']
+
+    with open(output_file, mode="w", newline="") as file:
+        writer = csv.writer(file)
+
+        # Write the header row
+        writer.writerow(keyword)
+
+        for eval_results, config in history:
+            obj1 = eval_results[keyword[0]][0]
+            obj2 = eval_results[keyword[1]][0]
+
+            writer.writerow([obj1, obj2, config])
+
+
+# quantize a model based on a given quantization configuration
+def quantize_by_fqn_to_config(model, device, fqn_to_config):
+    it = iter(fqn_to_config.items())
+    while True:
+        try:
+            k1, v1 = next(it)
+            k2, v2 = next(it)
+            fqn = k1[8:]
+            bit_width, groupsize = v1, v2
+
+            def filter_fn_sen(child: torch.nn.Module, cur_fqn: str) -> bool:
+                return isinstance(child, torch.nn.Linear) and (fqn in cur_fqn)
+
+            quantize_(
+                model.to(device=device),
+                intN_weight_only(n=bit_width, group_size=groupsize),
+                filter_fn_sen,
+            )
+        except StopIteration:
+            break
+
+
+# calculate perplexity on wikitext-document, need to support more tasks
+def cal_wikitext_ppl(model, tokenizer, limit=62):
+    with torch.no_grad():
+        result = evaluate(
+            HFLM(pretrained=model, tokenizer=tokenizer, batch_size=1),
+            get_task_dict("wikitext"),
+            limit=limit,
+        )
+
+    return result["results"]["wikitext"]["word_perplexity,none"]
+
+
+# TODO: make it generalize to more models
+def cal_model_size(model, fqn_to_config):
+    _sum = 0
+    fqn_cofg_dict = dict()
+
+    it = iter(fqn_to_config.items())
+    while True:
+        try:
+            k1, v1 = next(it)
+            k2, v2 = next(it)
+            bit_width, groupsize = v1, v2
+            bit_zeropoint = 32
+            bit_scale = 8
+            fqn = k1[8:]
+            fqn_cofg_dict[fqn] = (bit_width, groupsize, bit_zeropoint, bit_scale)
+        except StopIteration:
+            break
+
+    for name, parameter in model.named_parameters():
+        flag = 0
+        for fqn in fqn_cofg_dict:
+            if fqn in name:
+                flag = 1
+                if "self_attn" in name or "mlp" in name:
+                    _sum += parameter.numel() * fqn_cofg_dict[fqn][
+                        0
+                    ] + parameter.numel() // fqn_cofg_dict[fqn][1] * (
+                        fqn_cofg_dict[fqn][2] + fqn_cofg_dict[fqn][3]
+                    )
+        if flag == 0:
+            _sum += parameter.numel() * 16
+
+    _sum_in_byte = _sum / 8.0
+    _sum_in_GB = _sum_in_byte / (1024**3) / 1.0
+    return _sum_in_GB
+
+
+def load_model(repo_id, device):
+    tokenizer = AutoTokenizer.from_pretrained(repo_id)
+    model = AutoModelForCausalLM.from_pretrained(
+        repo_id, torch_dtype=torch.bfloat16
+    ).to(device=device)
+    return model, tokenizer
+
+
+def load_parameters_from_json(json_path):
+    with open(json_path, "r") as f:
+        config = json.load(f)
+
+    bitwidth_config = next(
+        param for param in config["parameters"] if param["name"] == "bitwidth"
+    )
+    groupsize_config = next(
+        param for param in config["parameters"] if param["name"] == "groupsize"
+    )
+
+    parameters_list = []
+
+    # Ensure that we are interleaving bitwidth and groupsize for each layer
+    for bw_layer, gs_layer in zip(
+        bitwidth_config["layers"], groupsize_config["layers"]
+    ):
+        start, end = bw_layer["range"]
+        for i in range(start, end):
+            # Add bitwidth parameter
+            bitwidth_param = {
+                "name": bitwidth_config["name_format"].format(i=i),
+                "type": bw_layer["type"],
+                "value_type": "int",
+                "is_ordered": True,
+                "sort_values": True,
+            }
+            if bw_layer["type"] == "fixed":
+                bitwidth_param["value"] = bw_layer["value"]
+            elif bw_layer["type"] == "choice":
+                bitwidth_param["values"] = bw_layer["values"]
+            parameters_list.append(bitwidth_param)
+
+            # Add groupsize parameter
+            groupsize_param = {
+                "name": groupsize_config["name_format"].format(i=i),
+                "type": gs_layer["type"],
+                "value_type": "int",
+                "is_ordered": True,
+                "sort_values": True,
+            }
+            if gs_layer["type"] == "fixed":
+                groupsize_param["value"] = gs_layer["value"]
+            elif gs_layer["type"] == "choice":
+                groupsize_param["values"] = gs_layer["values"]
+            parameters_list.append(groupsize_param)
+
+    return parameters_list
+
+
+def load_initial_samples(json_path):
+    with open(json_path, "r") as f:
+        config = json.load(f)
+    return config["initial_samples"]
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..af62c3899ff6fb1540e28f4ad5be4d59ad0e3f87
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__init__.py
@@ -0,0 +1,21 @@
+from .module_swap import (
+    QuantizationRecipe,
+    quantize_module_swap,
+)
+from .quantized_modules import (
+    QuantizedEmbedding,
+    QuantizedLinear,
+)
+from .quantizers import (
+    CodeBookQuantizer,
+    IntQuantizer,
+)
+
+__all__ = [
+    "CodeBookQuantizer",
+    "IntQuantizer",
+    "QuantizedEmbedding",
+    "QuantizedLinear",
+    "QuantizationRecipe",
+    "quantize_module_swap",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9305633fbca8519acad39fc1451a29c8c708bb0d
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/module_swap.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/module_swap.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ccd49e4789a3b96fa214d98a61d02bff5f5aa9f7
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/module_swap.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/quantized_modules.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/quantized_modules.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7e7cfb39935f777c3a090aee919ef4ec05f69ff2
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/quantized_modules.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/quantizers.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/quantizers.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e20f9be9fad41e8bf414c827d613b6837d4dad08
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/quantizers.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/range_setting_methods.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/range_setting_methods.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0aea85ec5feb07b619451bafcddca1e5de5058ca
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/range_setting_methods.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/utils.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..10ea7c26c9cf79ff1d3c163214959217593a1a6f
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/__pycache__/utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..f5e61235c7c7a7af66b70904ee3c0a8db2ade3e1
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/__init__.py
@@ -0,0 +1,5 @@
+from .kmeans_codebook import kmeans_codebook
+
+__all__ = [
+    "kmeans_codebook",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9a6537d6150e619bdbe2e149b014a39168b6a929
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/__pycache__/kmeans_codebook.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/__pycache__/kmeans_codebook.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..57627f3106c4cba462426023189060e1f74bf3c1
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/__pycache__/kmeans_codebook.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/kmeans_codebook.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/kmeans_codebook.py
new file mode 100644
index 0000000000000000000000000000000000000000..7a47f7420027bd85664e92d1aaea653e9097dccf
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/algorithms/kmeans_codebook.py
@@ -0,0 +1,40 @@
+import torch
+import torch.nn as nn
+
+from torchao.prototype.quantization.module_swap.quantized_modules import QuantizedLinear
+from torchao.prototype.quantization.module_swap.quantizers import CodeBookQuantizer
+
+
+def kmeans_codebook(
+    model: nn.Module,
+    niter: int = 30,
+    nredo: int = 1,
+    dtype: torch.dtype = torch.float32,
+) -> None:
+    import faiss
+
+    with torch.no_grad():
+        for layer in model.modules():
+            if isinstance(layer, QuantizedLinear):
+                if isinstance(layer.weight_quantizer, CodeBookQuantizer):
+                    weight = layer.weight
+                    codebook_dim = layer.weight_quantizer.codebook_dim
+                    weight = weight.reshape(
+                        weight.shape[0] * (weight.shape[1] // codebook_dim),
+                        codebook_dim,
+                    )
+                    num_centroids = layer.weight_quantizer.codebook.shape[0]
+                    kmeans = faiss.Kmeans(
+                        weight.shape[1],
+                        num_centroids,
+                        niter=niter,
+                        nredo=nredo,
+                        verbose=True,
+                        gpu=True if torch.cuda.is_available() else False,
+                    )
+                    kmeans.train(weight.to(device="cpu", dtype=dtype))
+                    C = kmeans.centroids
+
+                    layer.weight_quantizer.codebook.data = torch.FloatTensor(C).to(
+                        weight.dtype
+                    )
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..75b8cfba71bff35b37f8422a68fa3bec1f1a314c
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__init__.py
@@ -0,0 +1,13 @@
+from .llm_ptq_data_getter import (
+    LLMPTQDataGetter,
+)
+from .ptq_data_getter import (
+    DataGetter,
+    get_module_input_data,
+)
+
+__all__ = [
+    "DataGetter",
+    "get_module_input_data",
+    "LLMPTQDataGetter",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..433113d11ee4a2c1855ab1912fece7115b0c6404
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__pycache__/llm_ptq_data_getter.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__pycache__/llm_ptq_data_getter.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..24c0eb01488913836c231ee201a91d3ea35fdbdb
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__pycache__/llm_ptq_data_getter.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__pycache__/ptq_data_getter.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__pycache__/ptq_data_getter.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d2ea83886ebb807012b4deb2326ca3ca42826660
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/__pycache__/ptq_data_getter.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/llm_ptq_data_getter.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/llm_ptq_data_getter.py
new file mode 100644
index 0000000000000000000000000000000000000000..476f1876987a62a0b8e14e2b8b2a47951499e794
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/llm_ptq_data_getter.py
@@ -0,0 +1,133 @@
+from typing import Dict
+
+import torch
+import torch.nn as nn
+from transformers.models.llama.modeling_llama import LlamaForCausalLM
+
+from torchao.prototype.quantization.module_swap.data_getters.ptq_data_getter import (
+    DataGetter,
+    get_module_input_data,
+)
+from torchao.prototype.quantization.module_swap.utils import (
+    get_layer_by_name,
+)
+
+
+class LLMPTQDataGetter(DataGetter):
+    """
+    This datagetter can be used to efficiently retrieve layer-wise input data from a LlamaForCausalLM model
+    The two benefits are
+    1) It caches the data in between layer's residuals, so previous layers dont have to be computed
+    2) Layers with the same input have their input cached and returned
+
+    Usage is simple, give it a model, and data
+    then data_getter.pop(model, layer_name) for each batch of data you require
+
+    the actual model passed is used to get the data, so if you want to e.g. quantize
+    the entire network with weight quantizers, it uses that data
+    The datagetter has to be called in-order of the layer's occurence in the network, otherwise it will fail
+
+    """
+
+    def __init__(
+        self, model: LlamaForCausalLM, data: torch.Tensor, batch_size: int
+    ) -> None:
+        super().__init__()
+        self.initialize(model, data, batch_size)
+
+    def initialize(self, model: nn.Module, data: torch.Tensor, batch_size: int) -> None:
+        assert isinstance(model, LlamaForCausalLM)
+        assert isinstance(data, torch.Tensor)
+
+        # set attention_mask and/or position_ids
+        self.layer_kwargs: Dict[str, torch.Tensor] = self.get_layer_kwargs(model, data)
+
+        self.input_data_cache: torch.Tensor = get_module_input_data(
+            model, data, model.model.layers[0], batch_size
+        )
+        self.current_layer_idx = 0
+        self.previously_called_name: str = ""
+        self.batch_size = batch_size
+        self.output_data_cache: torch.Tensor = torch.zeros_like(data)
+        self.matched_input_layers = [
+            ["q_proj", "k_proj", "v_proj"],
+            ["up_proj", "gate_proj"],
+        ]
+
+    def pop(self, model: nn.Module, name: str) -> torch.Tensor:
+        assert isinstance(model, LlamaForCausalLM)
+        with torch.no_grad():
+            # special case for the last layer
+            if name != "lm_head":
+                query_layer_idx = int(name.split(".")[2])
+            else:
+                query_layer_idx = len(model.model.layers)
+
+            assert query_layer_idx >= self.current_layer_idx, (
+                "pop() called out of order, layers have to be called in order"
+            )
+
+            # TODO: batch the next two parts
+
+            # progress the progress over layers
+            while query_layer_idx > self.current_layer_idx:
+                self.input_data_cache = model.model.layers[self.current_layer_idx](
+                    self.input_data_cache, **self.layer_kwargs
+                )[0]
+                self.current_layer_idx += 1
+
+            # special case for the final layer
+            if name == "lm_head":
+                return self.input_data_cache
+
+            # use cached output data if the outputs are matching
+            base_name = self.get_base_name(name)
+            for matching_list in self.matched_input_layers:
+                if base_name in matching_list:
+                    previous_base_name = self.get_base_name(self.previously_called_name)
+                    if previous_base_name in matching_list:
+                        self.previously_called_name = name
+                        return self.output_data_cache
+
+            # get data from current requested layer
+            query_layer = get_layer_by_name(model, name)
+            layer_output_data = get_module_input_data(
+                model.model.layers[self.current_layer_idx],
+                self.input_data_cache,
+                query_layer,
+                self.batch_size,
+                self.layer_kwargs,
+            )
+
+            # cache the data for next call
+            self.output_data_cache = layer_output_data
+            self.previously_called_name = name
+            return layer_output_data
+
+    def get_layer_kwargs(
+        self, model: LlamaForCausalLM, data: torch.Tensor
+    ) -> Dict[str, torch.Tensor]:
+        # get used attention_mask and position_ids
+        layer_kwargs: Dict[str, torch.Tensor] = {}
+
+        class Catcher(nn.Module):
+            def __init__(self, module):
+                super().__init__()
+                self.module = module
+
+            def forward(self, inp, **kwargs):
+                if kwargs["attention_mask"] is not None:
+                    layer_kwargs["attention_mask"] = kwargs["attention_mask"]
+                if kwargs["position_ids"] is not None:
+                    layer_kwargs["position_ids"] = kwargs["position_ids"]
+                raise ValueError
+
+        device = model.parameters().__next__().device
+        model.model.layers[0] = Catcher(model.model.layers[0])
+        try:
+            model(data[0:2].to(device))
+        except ValueError:
+            pass
+        model.model.layers[0] = model.model.layers[0].module
+
+        return layer_kwargs
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/ptq_data_getter.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/ptq_data_getter.py
new file mode 100644
index 0000000000000000000000000000000000000000..6f17ebdc490250461a872ecf4c619278bbfc9685
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/data_getters/ptq_data_getter.py
@@ -0,0 +1,67 @@
+from typing import Dict, List
+
+import torch
+import torch.nn as nn
+
+
+class ExpectedError(Exception):
+    pass
+
+
+class DataGetter:
+    def __init__(self) -> None:
+        return
+
+    def pop(self, model: nn.Module, name: str) -> torch.Tensor:
+        raise NotImplementedError()
+
+    def get_base_name(self, name: str) -> str:
+        base_name = name.split(".")[-1]
+        if base_name.isnumeric():
+            base_name = name.split(".")[-2]
+        return base_name
+
+    def initialize(self, model: nn.Module, data: torch.Tensor, batch_size: int) -> None:
+        raise NotImplementedError()
+
+
+def get_module_input_data(
+    model: nn.Module,
+    data: torch.Tensor,
+    module: nn.Module,
+    batch_size: int,
+    layer_kwargs: Dict[str, torch.Tensor] = {},  # noqa
+) -> torch.Tensor:
+    with torch.no_grad():
+        if isinstance(data, list):
+            num_data = len(data)
+        else:
+            num_data = data.shape[0]
+        num_batches = num_data // batch_size
+        assert num_data % batch_size == 0
+
+        input_data: List[torch.Tensor] = []
+
+        def _input_data_hook(
+            module: nn.Module, input: List[torch.Tensor], output: List[torch.Tensor]
+        ) -> None:
+            input_data.append(input[0].detach())
+            assert len(input) == 1
+            raise ExpectedError
+
+        hook = module.register_forward_hook(_input_data_hook)
+
+        for i in range(num_batches):
+            try:
+                this_batch = data[i * batch_size : (i + 1) * batch_size]
+                this_batch = this_batch.to(next(model.parameters()).device)
+                if layer_kwargs:
+                    model(this_batch, **layer_kwargs)
+                else:
+                    model(this_batch)
+            except ExpectedError:
+                pass
+
+        hook.remove()
+        return_data = torch.cat(input_data, dim=0)
+        return return_data
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/module_swap.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/module_swap.py
new file mode 100644
index 0000000000000000000000000000000000000000..e56965c8d21f4c616d87ef870ca66feaf5f59b39
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/module_swap.py
@@ -0,0 +1,167 @@
+import logging
+from dataclasses import dataclass, field
+from typing import List, Union
+
+import torch
+import torch.nn as nn
+
+from torchao.prototype.quantization.module_swap.algorithms import (
+    kmeans_codebook,
+)
+from torchao.prototype.quantization.module_swap.quantized_modules import (
+    QuantizedEmbedding,
+    QuantizedLinear,
+)
+from torchao.prototype.quantization.module_swap.quantizers import (
+    CodeBookQuantizer,
+    IntQuantizer,
+)
+from torchao.prototype.quantization.module_swap.range_setting_methods import (
+    set_weight_min_max,
+)
+
+logger: logging.Logger = logging.getLogger(__name__)
+
+
+# TODO: express this using AOBaseConfig
+@dataclass
+class QuantizationRecipe:
+    # weights
+    weight_bits: int = 4
+    weight_group_size: Union[int, str] = 32
+    weight_quantization: bool = True
+    dynamic_weights: bool = False
+
+    # weight codebooking settings
+    weight_codebook: bool = False  # if we're using weight codebooks
+    codebook_dim: int = 1
+
+    # activations
+    activation_bits: int = 8
+    activation_group_size: Union[int, str] = "per_token"
+    activation_quantization: bool = False
+    input_quantization: bool = False
+    output_quantization: bool = False
+    dynamic_activations: bool = True
+
+    # general
+    range_learning: bool = False
+    embedding_quantization: bool = True
+    embedding_bits: int = 4
+    embedding_group_size: Union[int, str] = 32
+    exclude_layers: List[str] = field(default_factory=lambda: ["lm_head"])
+
+
+def get_layer_parent_by_name(model: nn.Module, input_name: str) -> nn.Module:
+    parent_name = input_name.rsplit(".", 1)[:-1]
+    if len(parent_name) == 0:  # parent is model itself
+        return model
+    else:
+        parent_name = parent_name[0]
+
+    for name, module in model.named_modules():
+        if parent_name == name:
+            return module
+    raise ValueError(f"Layer {input_name} not found in model")
+
+
+# TODO: delete this, use quantize_ instead
+def quantize_module_swap(
+    model: nn.Module, recipe: QuantizationRecipe, dtype: torch.dtype = torch.float32
+) -> nn.Module:
+    model = replace_all_linear_with_quantized_linear(model, recipe)
+    if recipe.embedding_quantization:
+        model = replace_all_embedding_with_quantized(model, recipe)
+    initialize_model_parameters(model, recipe, dtype)
+    return model
+
+
+def replace_all_embedding_with_quantized(
+    model: nn.Module, recipe: QuantizationRecipe
+) -> nn.Module:
+    for name, module in model.named_modules():
+        if isinstance(module, nn.Embedding):
+            if name in recipe.exclude_layers:
+                logger.info(f"skip layer {name} in exclude list")
+            else:
+                quantized_embedding = QuantizedEmbedding(
+                    num_embeddings=module.num_embeddings,
+                    embedding_dim=module.embedding_dim,
+                    padding_idx=module.padding_idx,
+                    max_norm=module.max_norm,
+                    norm_type=module.norm_type,
+                    scale_grad_by_freq=module.scale_grad_by_freq,
+                    sparse=module.sparse,
+                    _weight=module.weight,
+                    num_bits=recipe.embedding_bits,
+                    group_size=recipe.embedding_group_size,
+                    quantization_mode="symmetric",
+                    range_learning=recipe.range_learning,
+                    dynamic_weights=recipe.dynamic_weights,
+                )
+                attribute_name = name.rsplit(".", 1)[-1]
+                parent_of_module = get_layer_parent_by_name(model, name)
+                setattr(parent_of_module, attribute_name, quantized_embedding)
+
+                logger.info(f"replaced {name} with quantized embedding")
+    return model
+
+
+def replace_all_linear_with_quantized_linear(
+    model: nn.Module, recipe: QuantizationRecipe
+) -> nn.Module:
+    for name, module in model.named_modules():
+        if isinstance(module, nn.Linear):
+            if name in recipe.exclude_layers:
+                logger.info(f"skip layer {name} in exclude list")
+            else:
+                if recipe.weight_codebook:
+                    weight_quantizer = CodeBookQuantizer(
+                        n_bits=recipe.weight_bits,
+                        features=module.out_features,
+                        codebook_dim=recipe.codebook_dim,
+                    )
+                else:
+                    weight_quantizer = IntQuantizer(
+                        num_bits=recipe.weight_bits,
+                        group_size=recipe.weight_group_size,
+                        dynamic=recipe.dynamic_weights,
+                        quantization_mode="symmetric",
+                        range_learning=recipe.range_learning,
+                    )
+                quantized_linear = QuantizedLinear(
+                    in_features=module.in_features,
+                    out_features=module.out_features,
+                    bias=module.bias is not None,
+                    weight_quantizer=weight_quantizer,
+                    weight_quantization=recipe.weight_quantization,
+                    activation_bits=recipe.activation_bits,
+                    activation_group_size=recipe.activation_group_size,
+                    activation_quantization=recipe.activation_quantization,
+                    input_quantization=recipe.input_quantization,
+                    output_quantization=recipe.output_quantization,
+                    dynamic_activations=recipe.dynamic_activations,
+                    range_learning=recipe.range_learning,
+                )
+                quantized_linear.weight = module.weight
+                quantized_linear.bias = module.bias
+
+                # replace the module with the quantized linear module
+                attribute_name = name.rsplit(".", 1)[-1]
+                parent_of_module = get_layer_parent_by_name(model, name)
+                setattr(parent_of_module, attribute_name, quantized_linear)
+
+                # logger.info(f"replaced {name} with quantized linear")
+    return model
+
+
+def initialize_model_parameters(
+    model: nn.Module, recipe: QuantizationRecipe, dtype: torch.dtype = torch.float32
+) -> None:
+    """
+    Initialize the model weights and/or codebook if codebook quantization is used
+    """
+    if not recipe.dynamic_weights:
+        set_weight_min_max(model)
+    if recipe.weight_codebook:
+        kmeans_codebook(model, dtype=dtype)
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/quantized_modules.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/quantized_modules.py
new file mode 100644
index 0000000000000000000000000000000000000000..8cf9d5fb068b26f4eeb3c81fb93b4ba8d202ca5f
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/quantized_modules.py
@@ -0,0 +1,216 @@
+from typing import Optional, Tuple, Union
+
+import torch
+import torch.nn as nn
+import torch.nn.functional as F
+
+from torchao.prototype.quantization.module_swap.quantizers import (
+    CodeBookQuantizer,
+    IntQuantizer,
+    __supported_group_size_strings__,
+)
+
+SupportedQuantizers = Union[CodeBookQuantizer, IntQuantizer]
+
+
+class WeightModuleQuantizerBase:
+    def set_weight_scale_to_min_max(self) -> None:
+        if not self.weight_quantizer.dynamic:
+            self.weight_quantizer.set_scale_offset_to_min_max(self.weight)
+        else:
+            raise ValueError(
+                "Weights are quantized dynamically, no range/scale is used"
+            )
+
+    @property
+    def weight_scale(self) -> torch.Tensor:
+        return self.weight_quantizer.scale
+
+    @property
+    def quantized_weight(self) -> torch.Tensor:
+        return self.weight_quantizer(self.weight)
+
+
+class QuantizedLinear(nn.Linear, WeightModuleQuantizerBase):
+    def __init__(
+        self,
+        activation_bits: int,
+        weight_quantizer: SupportedQuantizers,
+        input_quantization: bool = True,
+        output_quantization: bool = False,
+        activation_group_size: Union[int, str] = "per_token",
+        weight_quantization: bool = True,
+        activation_quantization: bool = True,
+        dynamic_activations: bool = True,
+        range_learning: bool = False,
+        scale_eps: float = 1e-9,
+        *args,
+        **kwargs,
+    ) -> None:
+        super().__init__(*args, **kwargs)
+
+        weight_group_size, activation_group_size = self.validate_group_sizes(
+            weight_quantizer.group_size, activation_group_size, dynamic_activations
+        )
+
+        self.weight_quantizer: SupportedQuantizers = weight_quantizer
+        self.weight_quantizer.scale_eps = scale_eps
+        self.input_quantizer: Optional[IntQuantizer] = None
+        self.output_quantizer: Optional[IntQuantizer] = None
+
+        if input_quantization:
+            self.input_quantizer = IntQuantizer(
+                num_bits=activation_bits,
+                group_size=activation_group_size,
+                dynamic=dynamic_activations,
+                quantization_mode="asymmetric",
+                range_learning=range_learning,
+                scale_eps=scale_eps,
+            )
+        else:
+            self.input_quantizer = None
+        if output_quantization:
+            self.output_quantizer = IntQuantizer(
+                num_bits=activation_bits,
+                group_size=activation_group_size,
+                dynamic=dynamic_activations,
+                quantization_mode="asymmetric",
+                range_learning=range_learning,
+                scale_eps=scale_eps,
+            )
+        else:
+            self.output_quantizer = None
+
+        self.input_quantization = input_quantization
+        self.output_quantization = output_quantization
+        self.weight_quantization = weight_quantization
+        self.activation_quantization = activation_quantization
+
+        if not weight_quantizer.dynamic:
+            assert isinstance(self.weight_quantizer, IntQuantizer)
+            self.weight_quantizer.set_scale_offset_to_min_max(self.weight)
+
+        self.pre_transforms: nn.ModuleList = nn.ModuleList()
+        self.post_transforms: nn.ModuleList = nn.ModuleList()
+
+    def forward(self, input: torch.Tensor) -> torch.Tensor:
+        x = input
+
+        if self.input_quantization:
+            assert self.input_quantizer is not None
+            self.input_quantizer.quantize = self.activation_quantization
+            x = self.input_quantizer(x)
+
+        for transform in self.pre_transforms:
+            x = transform(x)
+
+        if self.weight_quantization:
+            weight = self.quantized_weight
+        else:
+            weight = self.weight
+
+        x = F.linear(x, weight, self.bias)
+
+        for transform in self.post_transforms:
+            x = transform(x)
+
+        if self.output_quantization:
+            assert self.output_quantizer is not None
+            self.output_quantizer.quantize = self.activation_quantization
+            x = self.output_quantizer(x)
+        return x
+
+    @staticmethod
+    def validate_group_sizes(
+        weight_group_size: Union[int, str],
+        activation_group_size: Union[int, str],
+        dynamic_activations: bool,
+    ) -> Tuple[Union[int, str], Union[int, str]]:
+        assert (
+            isinstance(weight_group_size, int)
+            or weight_group_size in __supported_group_size_strings__
+        )
+        if weight_group_size == "per_token":
+            raise ValueError(
+                "per_token is only available for dynamic activation quantization"
+            )
+
+        assert (
+            isinstance(activation_group_size, int)
+            or activation_group_size in __supported_group_size_strings__
+        )
+        if activation_group_size == "per_channel":
+            raise ValueError("per_channel is not supported for activatins")
+        if not dynamic_activations and activation_group_size != "per_tensor":
+            raise ValueError("Only per-tensor supported for static activations")
+
+        return weight_group_size, activation_group_size
+
+    def __repr__(self) -> str:
+        output_string = "QuantizedLinear("
+        empty_space = " " * len(output_string)
+        output_string += (
+            f"weight_quantizer={self.weight_quantizer} - {self.weight_quantization}, \n"
+        )
+        if self.input_quantizer is not None:
+            output_string += (
+                empty_space
+                + f"input_quant={self.input_quantizer} - {self.activation_quantization}, \n"
+            )
+        if self.output_quantizer is not None:
+            output_string += (
+                empty_space
+                + f"output_quant={self.output_quantizer} - {self.activation_quantization}, \n"
+            )
+        if self.pre_transforms:
+            output_string += empty_space + f"pre_transforms={self.pre_transforms}, \n"
+        if self.post_transforms:
+            output_string += empty_space + f"post_transforms={self.post_transforms}, \n"
+        output_string = output_string[:-3]
+        output_string += ")"
+        return output_string
+
+
+class QuantizedEmbedding(nn.Embedding, WeightModuleQuantizerBase):
+    def __init__(
+        self,
+        num_bits: int,
+        group_size: Union[int, str],
+        quantization_mode: str,
+        range_learning: bool = False,
+        scale_eps: float = 1e-9,
+        dynamic_weights: bool = False,
+        *args,
+        **kwargs,
+    ) -> None:
+        super().__init__(*args, **kwargs)
+        self.weight_quantizer = IntQuantizer(
+            num_bits=num_bits,
+            group_size=group_size,
+            dynamic=dynamic_weights,
+            quantization_mode="symmetric",
+            range_learning=range_learning,
+            scale_eps=scale_eps,
+        )
+        self.weight_quantization = True
+        self.dynamic_weights = dynamic_weights
+
+        if not self.dynamic_weights:
+            self.weight_quantizer.set_scale_offset_to_min_max(self.weight)
+        self._range_learning = range_learning
+
+    def forward(self, input: torch.Tensor) -> torch.Tensor:
+        if self.weight_quantization:
+            weight = self.weight_quantizer(self.weight)
+        else:
+            weight = self.weight
+
+        return torch.nn.functional.embedding(
+            input,
+            weight,
+            self.padding_idx,
+            self.max_norm,
+            self.norm_type,
+            self.scale_grad_by_freq,
+            self.sparse,
+        )
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/quantizers.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/quantizers.py
new file mode 100644
index 0000000000000000000000000000000000000000..a6f5e7ad9530d96af393c5354200c7c00365c340
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/quantizers.py
@@ -0,0 +1,347 @@
+from typing import Optional, Tuple, Union
+
+import torch
+import torch.nn as nn
+from torch.autograd import Function
+
+__supported_group_size_strings__ = ["per_token", "per_channel", "per_tensor"]
+
+
+class RoundStraightThrough(Function):
+    @staticmethod
+    def forward(ctx, x: torch.Tensor) -> torch.Tensor:
+        return torch.round(x)
+
+    @staticmethod
+    def backward(ctx, output_grad: torch.Tensor) -> torch.Tensor:
+        return output_grad
+
+
+class IntQuantizer(nn.Module):
+    def __init__(
+        self,
+        num_bits: int,
+        group_size: Union[int, str],
+        dynamic: bool,
+        quantization_mode: str,
+        range_learning: bool = False,
+        scale_eps: float = 1e-9,
+    ) -> None:
+        super().__init__()
+
+        self.num_bits = num_bits
+        self.group_size = group_size
+        self.dynamic = dynamic
+        self.quantization_mode = quantization_mode
+        self.scale_eps = scale_eps
+        self.scale: Optional[torch.Tensor] = None
+        self.offset: Optional[torch.Tensor] = None
+        self._range_learning = range_learning
+        self.quant_dtype: torch._C.dtype = torch.float32
+        self.quantize = True
+
+    def forward(self, x: torch.Tensor) -> torch.Tensor:
+        if not self.quantize:
+            return x
+
+        q_min, q_max = self.get_qmin_qmax(
+            self.num_bits, self.quant_mode_to_signed(self.quantization_mode)
+        )
+
+        if self.dynamic:
+            scale, offset = IntQuantizer.get_scale_offset(
+                x,
+                self.group_size,
+                self.quantization_mode,
+                q_min,
+                q_max,
+            )
+        else:
+            scale = self.scale
+            offset = self.offset
+
+        if scale is None:
+            raise ValueError("Initialize scale before first forward pass")
+
+        group_size = self.process_group_size_to_int(self.group_size, x)
+
+        if self._range_learning:
+            scale = torch.clamp(scale, min=self.scale_eps)
+            if offset is not None:
+                offset = RoundStraightThrough.apply(offset)
+                offset = torch.clamp(offset, q_min, q_max)
+
+        return self.quantize_forward(
+            x,
+            scale=scale,
+            offset=offset,
+            group_size=group_size,
+            q_min=q_min,
+            q_max=q_max,
+        )
+
+    @property
+    def q_min(self) -> int:
+        q_min, _ = self.get_qmin_qmax(
+            self.num_bits, self.quant_mode_to_signed(self.quantization_mode)
+        )
+        return q_min
+
+    @property
+    def q_max(self) -> int:
+        _, q_max = self.get_qmin_qmax(
+            self.num_bits, self.quant_mode_to_signed(self.quantization_mode)
+        )
+        return q_max
+
+    @staticmethod
+    def quant_mode_to_signed(quant_mode: str) -> bool:
+        if quant_mode == "symmetric":
+            return True
+        elif quant_mode == "asymmetric":
+            return False
+        else:
+            raise NotImplementedError
+
+    @staticmethod
+    def get_scale_param_size(
+        x: torch.Tensor, group_size: Union[int, str]
+    ) -> torch.Size:
+        int_group_size = IntQuantizer.process_group_size_to_int(group_size, x)
+        if int_group_size is None:
+            return torch.Size([1])
+        else:
+            if len(x.shape) == 1:
+                return torch.Size([x.shape[0] // int_group_size])
+            else:
+                size_list = [x.shape[i] for i in range(len(x.shape) - 1)]
+                size_list.append(x.shape[-1] // int_group_size)
+                return torch.Size(size_list)
+
+    @staticmethod
+    def get_qmin_qmax(n_bits: int, signed: bool) -> Tuple[int, int]:
+        if signed:
+            qmin = -(2 ** (n_bits - 1))
+            qmax = 2 ** (n_bits - 1) - 1
+        else:
+            qmin = 0
+            qmax = 2**n_bits - 1
+        return qmin, qmax
+
+    @staticmethod
+    def get_scale_offset(
+        x: torch.Tensor,
+        group_size: Union[int, str],
+        quantization_mode: str,
+        q_min: int,
+        q_max: int,
+        scale_eps: float = 1e-9,
+    ) -> Tuple[torch.Tensor, Optional[torch.Tensor]]:
+        if not isinstance(group_size, int) and group_size == "per_tensor":
+            x_min = torch.min(x)
+            x_max = torch.max(x)
+        else:
+            int_group_size = IntQuantizer.process_group_size_to_int(group_size, x)
+            assert int_group_size is not None
+            reshaped_x = x.reshape(
+                [*x.shape[:-1], x.shape[-1] // int_group_size, int_group_size]
+            )
+            x_min = torch.min(reshaped_x, dim=-1)[0]
+            x_max = torch.max(reshaped_x, dim=-1)[0]
+
+        if quantization_mode == "symmetric":
+            scale = IntQuantizer.get_scale_from_min_max(
+                x_min, x_max, q_min, q_max, scale_eps
+            )
+            offset = None
+        elif quantization_mode == "asymmetric":
+            scale, offset = IntQuantizer.get_scale_offset_from_min_max(
+                x_min, x_max, q_min, q_max, scale_eps
+            )
+        else:
+            raise NotImplementedError
+
+        return scale, offset
+
+    @staticmethod
+    def quantize_forward(
+        x: torch.Tensor,
+        scale: torch.Tensor,
+        offset: Optional[torch.Tensor],
+        q_min: int,
+        q_max: int,
+        group_size: Optional[int] = None,
+    ) -> torch.Tensor:
+        # if quantization is per_group, we need to reshape the tensor to apply it over
+        reshaped = False
+        orig_shape = x.shape
+        if group_size is not None and group_size != x.shape[-1]:
+            x = x.reshape(*x.shape[:-1], x.shape[-1] // group_size, group_size)
+            scale = torch.unsqueeze(scale, -1)
+            if offset is not None:
+                offset = torch.unsqueeze(offset, -1)
+            reshaped = True
+
+        if scale.device != x.device:
+            scale = scale.to(x.device)
+            if offset is not None:
+                offset = offset.to(x.device)
+
+        input_dtype = x.dtype
+
+        if offset is None or offset.numel() == 0:
+            x = torch.clamp(RoundStraightThrough.apply(x / scale), q_min, q_max)
+            x = x * scale
+        else:
+            x = torch.clamp(
+                RoundStraightThrough.apply(x / scale) + offset,
+                q_min,
+                q_max,
+            )
+            x = (x - offset) * scale
+
+        # reshape back to original shape if groups were used
+        if reshaped:
+            x = x.reshape(orig_shape)
+
+        return x.to(input_dtype)
+
+    @staticmethod
+    def process_group_size_to_int(
+        group_size: Union[int, str], x: torch.Tensor
+    ) -> Optional[int]:
+        if isinstance(group_size, int):
+            return group_size
+        elif group_size == "per_channel" or group_size == "per_token":
+            return x.shape[-1]
+        elif group_size == "per_tensor":
+            return None
+        else:
+            raise NotImplementedError
+
+    @staticmethod
+    def get_scale_from_min_max(
+        x_min: torch.Tensor,
+        x_max: torch.Tensor,
+        q_min: int,
+        q_max: int,
+        eps: float = 1e-9,
+    ) -> torch.Tensor:
+        smin = x_min / float(q_min)
+        smax = x_max / float(q_max)
+        mask = smin > smax
+        scale = torch.where(mask, smin, smax)
+        scale = torch.clamp(scale, min=eps)
+        return scale
+
+    @staticmethod
+    def get_scale_offset_from_min_max(
+        x_min: torch.Tensor,
+        x_max: torch.Tensor,
+        q_min: int,
+        q_max: int,
+        eps: float = 1e-9,
+    ) -> Tuple[torch.Tensor, torch.Tensor]:
+        scale = ((x_max - x_min) / (abs(q_min) + abs(q_max))).detach()
+        offset = (-x_min / scale).detach()
+
+        offset = torch.round(offset)
+        offset = torch.clamp(offset, q_min, q_max)
+
+        scale = torch.clamp(scale, min=eps)
+        return scale, offset
+
+    def set_scale_offset_to_min_max(self, x: torch.Tensor) -> None:
+        assert not self.dynamic
+
+        x = x.detach()
+        x = x.to(self.quant_dtype)
+
+        signed = self.quant_mode_to_signed(self.quantization_mode)
+
+        q_min, q_max = self.get_qmin_qmax(self.num_bits, signed=signed)
+        scale, offset = self.get_scale_offset(
+            x, self.group_size, self.quantization_mode, q_min, q_max
+        )
+
+        # with per-tensor we get empty tensors sometimes
+        if scale.data.shape == torch.Size([]):
+            scale_size_fix = torch.ones([1]).to(scale.device)
+            scale_size_fix *= scale
+            scale.data = scale_size_fix.data
+
+        if self._range_learning:
+            self.scale = torch.nn.Parameter(scale, requires_grad=True).to(
+                self.quant_dtype
+            )
+            if offset is not None:
+                self.offset = torch.nn.Parameter(offset, requires_grad=True).to(
+                    self.quant_dtype
+                )
+        else:
+            self.scale = scale
+            self.offset = offset
+
+
+class CodeBookQuantizer(nn.Module):
+    def __init__(
+        self,
+        n_bits: int,
+        features: int,
+        codebook_dim: int = 1,
+        seed: int = 1337,
+    ) -> None:
+        super().__init__()
+        self.group_size = codebook_dim
+        self.codebook_dim = codebook_dim
+        self.dynamic = True
+        self.scale_eps = 1e-9
+        assert features % codebook_dim == 0
+        torch.manual_seed(seed)
+
+        N = 2 ** (n_bits * codebook_dim)
+        codebook_shape = (N, codebook_dim)
+        self.codebook = nn.Parameter(
+            torch.Tensor(codebook_shape[0], codebook_shape[1]), requires_grad=False
+        )
+
+        self._codebook_shape: Tuple[int, int] = codebook_shape
+
+    def forward(self, x: torch.Tensor) -> torch.Tensor:
+        scaling_factor = torch.mean(abs(x), dim=1, keepdim=True).detach()
+        output = scaling_factor * VectorQuantizerFunction.apply(
+            x / scaling_factor, self.codebook
+        )
+        return output
+
+
+class VectorQuantizerFunction(torch.autograd.Function):
+    @staticmethod
+    # pyre-ignore[2, 14]
+    def forward(ctx, inputs: torch.Tensor, codebook: torch.Tensor) -> torch.Tensor:
+        flat_inputs = inputs.view(-1, codebook.shape[1])
+        distances = torch.cdist(flat_inputs, codebook)
+        indices = torch.argmin(distances, dim=1)
+        sums = torch.zeros_like(codebook).float().cuda()
+        counts = torch.zeros(codebook.size(0), dtype=torch.float).cuda()
+
+        # Accumulate sums using index_add_
+        sums.index_add_(0, indices, flat_inputs.float())
+
+        # Accumulate counts using index_add_
+        ones = torch.ones(flat_inputs.size(0), dtype=torch.float).cuda()
+        counts.index_add_(0, indices, ones)
+
+        # Avoid division by zero
+        counts = counts.unsqueeze(1).clamp(min=1.0)
+
+        # Update each centroid with the average of assigned inputs
+        codebook.copy_(sums / counts)
+
+        quantized = codebook[indices].view_as(inputs)
+        return quantized
+
+    @staticmethod
+    # pyre-ignore[2, 14]
+    def backward(ctx, grad_output: torch.Tensor) -> Tuple[torch.Tensor, None]:
+        return grad_output, None
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/range_setting_methods.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/range_setting_methods.py
new file mode 100644
index 0000000000000000000000000000000000000000..2ba93321fbe25236e3227436ad235e79c1744715
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/range_setting_methods.py
@@ -0,0 +1,216 @@
+import copy
+import logging
+from typing import Callable, Optional
+
+import torch
+import torch.nn as nn
+
+from torchao.prototype.quantization.module_swap.data_getters import (
+    DataGetter,
+    get_module_input_data,
+)
+from torchao.prototype.quantization.module_swap.quantized_modules import (
+    QuantizedLinear,
+)
+from torchao.prototype.quantization.module_swap.utils import (
+    all_activation_quantizers_off,
+    all_quantizers_off,
+    all_weight_quantizers_on,
+)
+
+logger: logging.Logger = logging.getLogger(__name__)
+
+
+def set_weight_min_max(model: nn.Module) -> None:
+    for _, module in model.named_modules():
+        if isinstance(module, QuantizedLinear):
+            module.set_weight_scale_to_min_max()
+
+
+def set_weight_mse(
+    model: nn.Module, num_points: int = 100, max_shrink: float = 0, norm: float = 2.0
+) -> None:
+    for _, module in model.named_modules():
+        if isinstance(module, QuantizedLinear):
+            loss_fn = lambda m: torch.sum(  # noqa
+                torch.pow(torch.abs(m.weight - m.quantized_weight), norm), dim=-1
+            )
+            best_scale = find_optimal_scales_with_loss(
+                module, loss_fn, num_points, max_shrink
+            )
+            module.weight_scale.data = best_scale
+
+
+def get_batched_output(
+    module: nn.Module, input_data: torch.Tensor, batch_size: int
+) -> torch.Tensor:
+    device = module.weight.device
+    dtype = module.weight.dtype
+
+    num_samples = input_data.shape[0]
+    num_batches = num_samples // batch_size
+
+    output_data = []
+    for i in range(num_batches):
+        this_batch = input_data[i * batch_size : (i + 1) * batch_size]
+        this_batch = this_batch.to(device).to(dtype)
+        output_data.append(module(this_batch).to(torch.float32).to("cpu"))
+
+    return torch.vstack(output_data)
+
+
+def set_weight_range_activation_loss(
+    model: nn.Module,
+    data: torch.Tensor,
+    batch_size: int,
+    num_points: int = 100,
+    progressive: bool = True,
+    data_getter: Optional[DataGetter] = None,
+) -> None:
+    # store quantization settings so this algorithm does not change those implicitly
+    quantization_setting_mapping_dict = {
+        name: [module.weight_quantization, module.activation_quantization]
+        for name, module in model.named_modules()
+        if isinstance(module, QuantizedLinear)
+    }
+
+    data_getter_progressive = None
+    if data_getter is not None:
+        data_getter.initialize(model, data, batch_size)
+        if progressive:
+            data_getter_progressive = copy.deepcopy(data_getter)
+
+    # TODO: This can all be optimized for efficiency (keep data on GPU) or Memory (keep data on CPU)
+    # Do the actual range setting
+    with torch.no_grad():
+        for name, module in model.named_modules():
+            if isinstance(module, QuantizedLinear):
+                logger.info(f"Range setting for {name}")
+                model.apply(all_quantizers_off)
+                # TODO: Some form of smart subsampling from all this sequential data
+                if data_getter is not None:
+                    input_data = data_getter.pop(model, name)
+                else:
+                    input_data = get_module_input_data(model, data, module, batch_size)
+                output_data = get_batched_output(module, input_data, batch_size)
+
+                if progressive:
+                    model.apply(all_weight_quantizers_on)
+                    if data_getter_progressive is not None:
+                        input_data = data_getter_progressive.pop(model, name)
+                    else:
+                        input_data = get_module_input_data(
+                            model, data, module, batch_size
+                        )
+
+                input_data = input_data.to(module.weight.device).to(module.weight.dtype)
+                output_data = output_data.to(module.weight.device).to(
+                    module.weight.dtype
+                )
+
+                module.weight_quantization = True
+                dim = tuple(range(input_data.dim() - 1))  # all but last
+
+                # TODO: batched loss getting
+                loss_fn = lambda m: torch.mean(  # noqa
+                    torch.pow(m(input_data) - output_data, 2),
+                    dim=dim,  # noqa
+                )
+
+                best_scale = find_optimal_scales_with_loss(module, loss_fn, num_points)
+                module.weight_scale.data = best_scale
+
+    # reset quantization settings to original values
+    for name, module in model.named_modules():
+        if isinstance(module, QuantizedLinear):
+            module.weight_quantization, module.activation_quantization = (
+                quantization_setting_mapping_dict[name]
+            )
+
+
+def set_activation_min_max(
+    model: nn.Module, data: torch.Tensor, batch_size: int
+) -> None:
+    # store quantization settings so this algorithm does not change those implicitly
+    quantization_setting_mapping_dict = {
+        name: [module.weight_quantization, module.activation_quantization]
+        for name, module in model.named_modules()
+        if isinstance(module, QuantizedLinear)
+    }
+
+    model.apply(all_activation_quantizers_off)
+    for name, module in model.named_modules():
+        if isinstance(module, QuantizedLinear):
+            logger.info(f"Activation min/max setting for {name}")
+            input_data = None
+            if module.input_quantization:
+                input_data = get_module_input_data(model, data, module, batch_size)
+                assert module.input_quantizer is not None
+                module.input_quantizer.set_scale_offset_to_min_max(input_data)
+            if module.output_quantization:
+                if input_data is None:
+                    input_data = get_module_input_data(model, data, module, batch_size)
+                output_data = module(input_data)
+                assert module.output_quantizer is not None
+                module.output_quantizer.set_scale_offset_to_min_max(output_data)
+
+    # reset quantization settings to original values
+    for name, module in model.named_modules():
+        if isinstance(module, QuantizedLinear):
+            module.weight_quantization, module.activation_quantization = (
+                quantization_setting_mapping_dict[name]
+            )
+
+
+def find_optimal_scales_with_loss(
+    module: QuantizedLinear,
+    loss_fn: Callable[[nn.Module], torch.Tensor],
+    num_points: int,
+    max_shrink: float = 0,
+) -> torch.Tensor:
+    assert max_shrink >= 0 and max_shrink < 1.0
+    assert num_points > 0
+
+    with torch.no_grad():
+        grid = torch.linspace(max_shrink, 1, num_points + 1)
+        module.set_weight_scale_to_min_max()
+
+        orig_scales = module.weight_scale.clone()
+        best_scale = module.weight_scale.clone()
+        best_loss = loss_fn(module)
+
+        for i in range(0, num_points - 1):
+            test_scale = orig_scales * grid[i]
+            module.weight_scale.data = test_scale
+            loss = loss_fn(module)
+            mask = loss < best_loss
+            best_loss[mask] = loss[mask]
+            best_scale[mask] = test_scale[mask]
+        return best_scale
+
+
+def quantize_per_group_scales(model: nn.Module, bit_width: int) -> None:
+    for name, module in model.named_modules():
+        if isinstance(module, QuantizedLinear):
+            scale = module.weight_quantizer.scale
+            assert isinstance(scale, torch.Tensor)
+
+            if len(scale.shape) < 2 or scale.shape[-1] == 1:
+                logger.warning(
+                    f"Module {name} is not quantized with group_wise quantization"
+                )
+                continue
+
+            per_channel_scales = torch.max(scale, dim=-1, keepdim=True).values
+            scale = scale / per_channel_scales  # scale to [0, 1]
+
+            # quantize the per_group scale to bit_width
+            quant_max = 2.0**bit_width
+            scale = (
+                torch.clamp(torch.ceil(scale * quant_max), min=1.0, max=quant_max)
+                / quant_max
+            )  # ceil to make sure clipping error is certainly 0
+
+            scale = scale * per_channel_scales  # fuse the fp16 scale
+
+            module.weight_quantizer.scale.data = scale
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/utils.py b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..b39dd9479ae35a4af073fddecd37d2e6180bcb90
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/module_swap/utils.py
@@ -0,0 +1,71 @@
+from typing import Dict
+
+import torch.nn as nn
+
+from torchao.prototype.quantization.module_swap.quantized_modules import QuantizedLinear
+from torchao.prototype.quantization.module_swap.quantizers import IntQuantizer
+
+
+def get_layer_by_name(model: nn.Module, query_name: str) -> nn.Module:
+    """
+    Retrieves a layer from a PyTorch model by its name.
+
+    Args:
+        model (nn.Module): The PyTorch model.
+        name (str): The name of the layer to retrieve.
+
+    Returns:
+        nn.Module: The retrieved layer.
+    """
+    for name, module in model.named_modules():
+        if name == query_name:
+            return module
+    raise ValueError(f"Layer '{query_name}' not found in model")
+
+
+def all_quantizers_off(module: nn.Module) -> None:
+    if isinstance(module, QuantizedLinear):
+        module.weight_quantization = False
+        module.activation_quantization = False
+
+
+def all_quantizers_on(module: nn.Module) -> None:
+    if isinstance(module, QuantizedLinear):
+        module.weight_quantization = True
+        module.activation_quantization = True
+
+
+def all_activation_quantizers_off(module: nn.Module) -> None:
+    if isinstance(module, QuantizedLinear):
+        module.activation_quantization = False
+
+
+def all_activation_quantizers_on(module: nn.Module) -> None:
+    if isinstance(module, QuantizedLinear):
+        module.activation_quantization = True
+
+
+def all_weight_quantizers_on(module: nn.Module) -> None:
+    if isinstance(module, QuantizedLinear):
+        module.weight_quantization = True
+
+
+def set_bit_widths_by_name(
+    model: nn.Module, bit_width_dict: Dict[str, Dict[str, int]]
+) -> None:
+    for name, bit_width_assignment in bit_width_dict.items():
+        this_layer = get_layer_by_name(model, name)
+        for quantizer, bit_width in bit_width_assignment.items():
+            assert isinstance(this_layer, QuantizedLinear)
+            if quantizer == "weight":
+                assert isinstance(this_layer.weight_quantizer, IntQuantizer)
+                this_layer.weight_quantizer.num_bits = bit_width
+            elif quantizer == "activation":
+                if this_layer.input_quantizer is not None:
+                    this_layer.input_quantizer.num_bits = bit_width
+                if this_layer.output_quantizer is not None:
+                    this_layer.output_quantizer.num_bits = bit_width
+            else:
+                raise ValueError(
+                    f"Unknown quantizer {quantizer}, should be either 'weight' or 'activation'"
+                )
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e5fc406829301a984bea78483dd4fd87e09c622d
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/__pycache__/extract_subgraphs.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/__pycache__/extract_subgraphs.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d5e9ffe765c78313ae9d25abe813b10289ff9d32
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/__pycache__/extract_subgraphs.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/extract_subgraphs.py b/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/extract_subgraphs.py
new file mode 100644
index 0000000000000000000000000000000000000000..d27f2a2431b7716a90facfc0a29b3b9831d1321f
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantization/subgraph_utils/extract_subgraphs.py
@@ -0,0 +1,685 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import csv
+import os
+import traceback
+from typing import Callable, Optional
+
+import torch
+import torch.nn.functional as F
+from torch.utils._pytree import tree_map
+
+graph_tabular_log = torch._logging.getArtifactLogger(__name__, "graph")
+
+# TODO(future): might be nice to have input shapes here, but needs a refactor since
+# they are easiest to get from the subgraph extraction function, but currently summary
+# is generated from the subgraph debug function.
+summary_headers = [
+    "extraction_idx",
+    "orig_node_name",
+    "subgraph_idx",
+    "lin1_shape",
+    "lin2_shape",
+    "subgraph_summary",
+]
+
+
+# A model can have multiple regions torch.compile'd separately. Because we currently
+# depend on torch._inductor.config.pre_grad_custom_pass, that means we will run
+# the extraction logic once per torch.compile'd region. The variable below tracks
+# how many times we have called the top level subgraph extractor, so we can
+# save results from each run without overwriting data.
+DEBUG_LINEARS_CALL_COUNTER = 0
+
+
+def maybe_short_name(torch_fn):
+    """
+    Tries to format things like
+
+      ''
+
+    as
+
+      'torch.cat'
+    """
+    if hasattr(torch_fn, "__name__"):
+        # torch.cat -> cat
+        if hasattr(torch, torch_fn.__name__):
+            if getattr(torch, torch_fn.__name__) == torch_fn:
+                return torch_fn.__name__
+
+        # F.layer_norm -> layer_norm
+        if hasattr(F, torch_fn.__name__):
+            if getattr(F, torch_fn.__name__) == torch_fn:
+                return torch_fn.__name__
+
+        # builtin function mul
+        # note: there is definitely a more generic way to do this
+        if torch_fn.__name__ == "mul":
+            return "mul"
+        if torch_fn.__name__ == "add":
+            return "add"
+
+        # activation modules
+        # note: there is definitely a more generic way to do this
+        if "torch.nn.modules.activation" in str(torch_fn):
+            return torch_fn.__name__
+
+    return torch_fn
+
+
+def get_meta_val(n: torch.fx.Node):
+    # from https://github.com/pytorch/pytorch/blob/8d708090c0eb306facfd8f85d58c578a8cbbe689/torch/fx/graph.py#L644-L647
+    meta_val = n.meta.get(
+        "val", n.meta.get("tensor_meta", n.meta.get("example_value", None))
+    )
+    return meta_val
+
+
+def get_stack_summary(n: torch.fx.Node):
+    # from https://github.com/pytorch/pytorch/blob/8d708090c0eb306facfd8f85d58c578a8cbbe689/torch/fx/graph.py#L609
+    if n.stack_trace:
+        parsed_stack_trace = torch.fx.graph._parse_stack_trace(n.stack_trace)
+        summary = parsed_stack_trace.get_summary_str()
+        return summary
+    return None
+
+
+def is_first_node_of_dual_linear(gm: torch.fx.GraphModule, n: torch.fx.Node):
+    first_user = list(n.users.items())[0][0]
+    if first_user.op == "call_module":
+        first_user_mod = getattr(gm, first_user.target)
+        if type(first_user_mod) is torch.nn.Linear:
+            return True
+    elif first_user.op == "call_function":
+        if first_user.target is torch._C._nn.linear:
+            return True
+    return False
+
+
+def debug_single_linear(
+    gm: torch.fx.GraphModule,
+    linear_node: torch.fx.Node,
+    linear_mod: torch.nn.Module,
+    debug_logs_filename: str,
+    subgraph_idx: int,
+):
+    def printme(s):
+        # write both to stdout and log file
+        # print(s)
+        with open(debug_logs_filename, "a") as f:
+            f.write(s + "\n")
+
+    printme(f"\ndebugging linear {linear_node.target} {subgraph_idx}")
+    printme("\ndebugging details\n")
+
+    prev_input_shape = None
+    prev_node_type = None
+    if linear_mod is not None:
+        cur_linear_size = linear_mod.in_features, linear_mod.out_features
+    else:
+        cur_linear_weight = linear_node.args[1]
+        weight_shape = get_meta_val(cur_linear_weight).shape
+        cur_linear_size = weight_shape[1], weight_shape[0]
+    cur_linear_2_size = None, None
+    next_node_types = []
+
+    # look at the preceding activation
+    for prev_n in linear_node.all_input_nodes:
+        if prev_n.op == "placeholder":
+            continue
+        # to get the shape of the input, we need to look at the previous node
+        for prev_prev_n in prev_n.all_input_nodes:
+            prev_prev_meta = get_meta_val(prev_prev_n)
+            if isinstance(prev_prev_meta, tuple):
+                prev_input_shape = ",".join(str(x.shape) for x in prev_prev_meta)
+            else:
+                prev_input_shape = prev_prev_meta.shape
+            printme(f"prev input shape: {prev_input_shape}")
+        printme(f"prev node: {prev_n.format_node()}")
+        printme(f"prev stack_summary: {get_stack_summary(prev_n)}")
+        if prev_n.op == "call_module":
+            mod = getattr(gm, prev_n.target)
+            prev_node_type = type(mod)
+            printme(f"prev mod: {mod}")
+        else:
+            prev_node_type = prev_n.target
+
+    # print info about current linear
+    printme(f"cur_linear node: {linear_node.format_node()}")
+    printme(f"cur_linear mod: {linear_mod}")
+    printme(f"cur_linear stack_summary: {get_stack_summary(linear_node)}")
+
+    # if there is a dual linear, print that too
+    linear_node_to_use = linear_node
+    dual_linear = False
+    if is_first_node_of_dual_linear(gm, linear_node):
+        dual_linear = True
+        linear_node_2 = list(linear_node.users.items())[0][0]
+        linear_mod_2 = None
+        if linear_mod is not None:
+            linear_mod_2 = getattr(gm, linear_node_2.target)
+            cur_linear_2_size = linear_mod_2.in_features, linear_mod_2.out_features
+        else:
+            cur_linear_2_weight = linear_node_2.args[1]
+            weight_shape = get_meta_val(cur_linear_2_weight).shape
+            cur_linear_2_size = weight_shape[1], weight_shape[0]
+
+        printme(f"cur_linear 2 node: {linear_node_2.format_node()}")
+        printme(f"cur_linear 2 mod: {linear_mod_2}")
+        printme(f"cur_linear 2 stack_summary: {get_stack_summary(linear_node_2)}")
+        linear_node_to_use = linear_node_2
+
+    # look at the subsequent ops
+    # note: sometimes this is a view, so might need to look farther
+    printme(f"num users: {len(linear_node_to_use.users)}")
+    for next_n, _ in linear_node_to_use.users.items():
+        for next_n_input in next_n.all_input_nodes:
+            printme(f"next input shape: {get_meta_val(next_n_input).shape}")
+        printme(f"next node: {next_n.format_node()}")
+        printme(f"next stack_summary: {get_stack_summary(next_n)}")
+        if next_n.op == "call_module":
+            mod = getattr(gm, next_n.target)
+            printme(f"next mod: {mod}")
+            next_node_types.append(type(mod))
+        else:
+            next_node_types.append(next_n.target)
+
+    printme("\ndebugging summary\n")
+    if not dual_linear:
+        linear_shape_str = f"{cur_linear_size}"
+        linear_str = "Linear"
+    else:
+        linear_shape_str = f"{cur_linear_size} {cur_linear_2_size}"
+        linear_str = "Linear -> Linear"
+    printme(f"input_shape {prev_input_shape}, (K, N) {linear_shape_str}")
+    subgraph_summary = f"{maybe_short_name(prev_node_type)} -> {linear_str} -> {[maybe_short_name(t) for t in next_node_types]}"
+    printme(subgraph_summary)
+    printme("\n")
+
+    summary_result = [
+        DEBUG_LINEARS_CALL_COUNTER,  # extraction_idx
+        linear_node.target,  # orig_node_name
+        subgraph_idx,
+        cur_linear_size,
+        cur_linear_2_size,
+        subgraph_summary,
+    ]
+    return summary_result
+
+
+def extract_linear_subgraph(
+    old_gm: torch.fx.GraphModule,
+    old_linear_node: torch.fx.Node,
+    old_linear_mod: torch.nn.Module,
+    subgraph_save_filename: str,
+) -> None:
+    """
+    Input: a GraphModule with a `linear_node` calling `linear_mod`.
+
+    This function does the following:
+    * find the subgraph prev_op -> linear_node -> [*next_ops]
+    * create a new GraphModule containing this subgraph
+    * save it to disk for further debugging
+    """
+
+    # to start, create a new module which just calls the linear
+    if old_linear_mod is not None:
+        new_m = torch.nn.Sequential(old_linear_mod)
+    else:
+        weight_val = get_meta_val(old_linear_node.args[1])
+
+        # handle dual linear for inlined here
+        # TODO(future): merge with code below for dual linear for non-inlined
+
+        old_shape = weight_val.shape
+        new_shape = old_shape[1], old_shape[0]
+
+        if not is_first_node_of_dual_linear(old_gm, old_linear_node):
+            new_m = torch.nn.Sequential(
+                torch.nn.Linear(*new_shape, dtype=weight_val.dtype),
+            ).cuda()
+
+        else:
+            old_2nd_linear_node = list(old_linear_node.users.items())[0][0]
+            weight2_val = get_meta_val(old_2nd_linear_node.args[1])
+            # TODO handle no bias and kwargs
+            get_meta_val(old_2nd_linear_node.args[2])
+
+            old_shape2 = weight2_val.shape
+            new_shape2 = old_shape2[1], old_shape2[0]
+            new_m = torch.nn.Sequential(
+                torch.nn.Linear(*new_shape, dtype=weight_val.dtype),
+                torch.nn.Linear(*new_shape2, dtype=weight2_val.dtype),
+            ).cuda()
+
+    new_gm = torch.fx.symbolic_trace(new_m)
+    new_g = new_gm.graph
+    new_linear_node = list(new_gm.graph.nodes)[1]
+    # print(f'new_gm: {new_gm}')
+    # print(f'new_linear_node: {new_linear_node}')
+
+    # copy the linear metadata over
+    new_linear_node.meta = old_linear_node.meta
+    new_linear_node.args[0].meta = old_linear_node.args[0].meta
+
+    #
+    # step 1: add the preceding activation node
+    #
+    # before: input -> linear
+    # after: input_args -> prev_op -> linear
+
+    # add the node inputs as placeholders, and copy the non-node inputs as is
+    prev_old_arg_to_new_arg = {}
+
+    def prev_node_map_arg(old_arg):
+        if isinstance(old_arg, torch.fx.Node):
+            if old_arg in prev_old_arg_to_new_arg:
+                return prev_old_arg_to_new_arg[old_arg]
+
+            with new_g.inserting_before(new_linear_node):
+                new_arg = new_g.placeholder(old_arg.name)
+                # copy the metadata over
+                new_arg.meta = old_arg.meta
+            prev_old_arg_to_new_arg[old_arg] = new_arg
+            return new_arg
+        return old_arg
+
+    old_prev_node = old_linear_node.all_input_nodes[0]
+
+    if old_prev_node.op == "call_module":
+        prev_mod = getattr(old_gm, old_prev_node.target)
+        new_name = "prev_mod"
+        setattr(new_gm, new_name, prev_mod)
+        new_args = tree_map(prev_node_map_arg, old_prev_node.args)
+        new_kwargs = tree_map(prev_node_map_arg, old_prev_node.kwargs)
+        with new_g.inserting_before(new_linear_node):
+            new_prev_node = new_g.call_module(new_name, new_args, new_kwargs)
+
+    elif old_prev_node.op == "call_function":
+        new_args = tree_map(prev_node_map_arg, old_prev_node.args)
+        new_kwargs = tree_map(prev_node_map_arg, old_prev_node.kwargs)
+        with new_g.inserting_before(new_linear_node):
+            new_prev_node = new_g.call_function(
+                old_prev_node.target, new_args, new_kwargs
+            )
+
+    elif old_prev_node.op == "call_method":
+        new_args = tree_map(prev_node_map_arg, old_prev_node.args)
+        new_kwargs = tree_map(prev_node_map_arg, old_prev_node.kwargs)
+        with new_g.inserting_before(new_linear_node):
+            new_prev_node = new_g.call_method(
+                old_prev_node.target, new_args, new_kwargs
+            )
+
+    elif old_prev_node.op == "placeholder":
+        new_prev_node = new_linear_node.args[0]
+
+    else:
+        raise AssertionError(f"old_prev_node.op: {old_prev_node.op} is unsupported")
+
+    # only erase placeholder if there is a previous op
+    if old_prev_node.op != "placeholder":
+        prev_placeholder = new_linear_node.args[0]
+        new_linear_node.args = (new_prev_node, *new_linear_node.args[1:])
+        new_g.erase_node(prev_placeholder)
+
+    new_prev_node.meta = old_prev_node.meta
+    new_gm.recompile()
+
+    #
+    # step 2 (optional): if there is a dual linear and dynamo is not inlining,
+    # handle it in a single subgraph. Note: the inlined case is handled above.
+    #
+    # before: input_args -> prev_op -> linear
+    # after:  input_args -> prev_op -> linear -> linear2
+    #
+    # then, in step 3, next_ops will be after linear2
+
+    # we still need to refer to the first linear in some places,
+    # save it
+    old_old_linear_node = old_linear_node
+    first_new_linear_node = new_linear_node
+
+    if is_first_node_of_dual_linear(old_gm, old_linear_node):
+        print("DUAL LINEAR")
+        if old_linear_mod is not None:
+            old_first_user = list(old_linear_node.users.items())[0][0]
+            old_first_user_mod = getattr(old_gm, old_first_user.target)
+            dual_linear_name = "1"
+            setattr(new_gm, dual_linear_name, old_first_user_mod)
+            new_args, new_kwargs = (new_linear_node,), {}
+
+            with new_g.inserting_after(new_linear_node):
+                new_dual_linear_node = new_g.call_module(
+                    dual_linear_name, new_args, new_kwargs
+                )
+            new_dual_linear_node.meta = old_first_user.meta
+
+            # make the following code treat the second linear as the root
+            new_linear_node = new_dual_linear_node
+            old_linear_node = old_first_user
+        else:
+            # make the following code treat the second linear as the root
+            old_first_user = list(old_linear_node.users.items())[0][0]
+            new_linear_node = list(new_linear_node.users.items())[0][0]
+            old_linear_node = old_first_user
+
+    #
+    # step 3: add the subsequent nodes (can be multiple users)
+    #
+    # before: input_args -> prev_op -> linear
+    # after: input_args -> prev_op -> linear -> next_op_1
+    #                                        -> ...
+    #                                        -> next_op_n
+
+    # create last_node to ensure graph order matches the original if there
+    # are multiple users of linear's output
+    new_last_node = new_linear_node
+    new_output_nodes = []
+    next_old_arg_to_new_arg = {}
+
+    def next_node_map_arg(old_arg):
+        if isinstance(old_arg, torch.fx.Node):
+            if old_arg in next_old_arg_to_new_arg:
+                # handle the same arg being used multiple times
+                return next_old_arg_to_new_arg[old_arg]
+            if old_arg == old_linear_node:
+                next_old_arg_to_new_arg[old_arg] = new_linear_node
+                return new_linear_node
+            elif old_arg == old_old_linear_node:
+                next_old_arg_to_new_arg[old_arg] = first_new_linear_node
+                return first_new_linear_node
+            elif old_arg == old_prev_node:
+                next_old_arg_to_new_arg[old_arg] = new_prev_node
+                return new_prev_node
+            elif old_arg in prev_old_arg_to_new_arg:
+                return prev_old_arg_to_new_arg[old_arg]
+            else:
+                # this is something else, make it a graph input
+                with new_g.inserting_before(new_linear_node):
+                    new_arg = new_g.placeholder(old_arg.name)
+                    # copy the metadata over
+                    new_arg.meta = old_arg.meta
+                next_old_arg_to_new_arg[old_arg] = new_arg
+                return new_arg
+        return old_arg
+
+    next_node_is_output = False
+    for counter, (old_next_n, _) in enumerate(old_linear_node.users.items()):
+        if old_next_n.op == "output":
+            # nothing to do
+            next_node_is_output = True
+            break
+
+        new_args = tree_map(next_node_map_arg, old_next_n.args)
+        new_kwargs = tree_map(next_node_map_arg, old_next_n.kwargs)
+        if old_next_n.op == "call_function":
+            with new_g.inserting_after(new_last_node):
+                new_next_n = new_g.call_function(
+                    old_next_n.target,
+                    new_args,
+                    new_kwargs,
+                )
+            new_output_nodes.append(new_next_n)
+            new_last_node = new_next_n
+        elif old_next_n.op == "call_method":
+            with new_g.inserting_after(new_last_node):
+                new_next_n = new_g.call_method(
+                    old_next_n.target,
+                    new_args,
+                    new_kwargs,
+                )
+            new_output_nodes.append(new_next_n)
+            new_last_node = new_next_n
+        elif old_next_n.op == "call_module":
+            prev_mod = getattr(old_gm, old_next_n.target)
+            new_name = f"next_mod_{counter}"
+            setattr(new_gm, new_name, prev_mod)
+            with new_g.inserting_after(new_last_node):
+                new_next_n = new_g.call_module(new_name, new_args, new_kwargs)
+            new_output_nodes.append(new_next_n)
+            new_last_node = new_next_n
+        else:
+            assert False, f"unsupported old_next_n.op, {old_next_n.op}"
+        new_next_n.meta = old_next_n.meta
+        new_gm.recompile()
+        # print(f'after adding next_node, {new_gm}')
+
+    if not next_node_is_output:
+        # reroute graph outputs from `linear` to `new_output_nodes`
+        cur_output_node = list(new_g.nodes)[-1]
+        # print(f'cur_output_node: {cur_output_node.format_node()}')
+
+        if len(new_output_nodes) == 1:
+            new_g.output(new_output_nodes[0])
+        else:
+            new_g.output(tuple(new_output_nodes))
+        # print(f'new_output_node: {cur_output_node.format_node()}')
+        new_g.erase_node(cur_output_node)
+        new_gm.recompile()
+        # print(f'after new output, {new_gm}')
+
+    # ensure every node has metas
+    for n in new_g.nodes:
+        if n.op == "output":
+            continue
+        assert n.meta is not None and n.meta != {}, f"{n}.meta is {n.meta}!"
+
+    test_inputs = []
+    for node in new_g.nodes:
+        if node.op != "placeholder":
+            continue
+        meta = get_meta_val(node)
+        new_inputs = None
+        if isinstance(meta, tuple):
+            new_inputs = tuple(
+                torch.randn(*inner_meta.shape, dtype=inner_meta.dtype, device="cuda")
+                for inner_meta in meta
+            )
+        else:
+            new_inputs = torch.randn(*meta.shape, dtype=meta.dtype, device="cuda")
+        test_inputs.append(new_inputs)
+
+    # save subgraph and inputs
+    torch.save((new_gm, test_inputs), subgraph_save_filename)
+
+    # test fwd
+    new_gm(*test_inputs)
+
+    # Note: cannot verify runnable after save/load here, because loading
+    # from disk in this file seems to try to use device meta as we are inside
+    # of dynamo tracing. Need to load from a separate process to properly test.
+
+
+def print_and_append_to_logs(logger, filename, s):
+    logger.debug(s)
+    with open(filename, "a") as f:
+        f.write(s + "\n")
+
+
+def prepare_target_folder(target_folder: str):
+    # ensure target folder exists
+    if not os.path.isdir(target_folder):
+        os.makedirs(target_folder)
+
+    # ensure target folder only has file extensions we could have written
+    for root, dirs, files in os.walk(target_folder):
+        for file in files:
+            if not (
+                file.endswith(".txt")
+                or file.endswith(".pt")
+                or file.endswith(".swp")
+                or file.endswith(".csv")
+                or file.endswith(".json")
+            ):
+                raise AssertionError(f"unknown file in target_dir: {file}")
+
+    # delete any existing files from previous run for this target_folder
+    for root, dirs, files in os.walk(target_folder):
+        for file in files:
+            os.unlink(os.path.join(root, file))
+
+    global DEBUG_LINEARS_CALL_COUNTER
+    DEBUG_LINEARS_CALL_COUNTER = 0
+
+
+def debug_linears_for_float8(
+    g: torch.fx.Graph,
+    target_folder: str,
+    linear_mod_filter_fn: Optional[Callable] = None,
+    linear_node_filter_fn: Optional[Callable] = None,
+) -> None:
+    """
+    This function:
+    1. looks for subgraphs containing `torch.nn.Linear` modules, including the preceding
+       and subsequent ops
+    2. for each found subgraph
+       - extracts metadata about the subgraph (ops, shapes, modeling code location) and saves it to disk
+       - extracts it into a new `torch.fx.Graphmodule` instance and saves it to disk, this
+         can then be loaded elsewhere to run microbenchmarks
+
+    Inputs:
+    - `g` - the graph to debug, assumed to come from dynamo's pre-dispatch trace and have torch IR
+    - `target_folder` - the folder to save metadata and microbenchmarks to, note that all folder
+      content is overwritten every time the script is run. The contents of this folder will be:
+        target_folder/
+          debug_logs_0.txt
+          skip_logs_0.txt
+          summary_0.csv
+          subgraph_with_inputs_0_0.pt
+          ...
+          subgraph_with_inputs_0_(n-1).pt
+    - `linear_mod_filter_fn`: optional filtering function on linear modules, if it returns false then subgraph
+      extraction is skipped for that linear
+    - `linear_node_filter_fn`: optional filtering function on linear nodes, if it returns false then subgraph
+      extraction is skipped for that linear
+
+    Format of summary_0.csv (column: example_value):
+      extraction_idx: 0
+      orig_node_name: fn_1
+      subgraph_idx: 0
+      lin1_shape: (2, 3)
+      lin2_shape: (3, 4)  # only applies to dual linear subgraphs
+      subgraph_summary: ReLU -> Linear -> ["cat"]
+
+    Format of subgraph_with_inputs_0_0.pt: Tuple[nn.Module, Tuple[torch.tensor]]
+    """
+    global DEBUG_LINEARS_CALL_COUNTER
+    debug_logs_filename = os.path.join(
+        target_folder, f"debug_logs_{DEBUG_LINEARS_CALL_COUNTER}.txt"
+    )
+    skip_logs_filename = os.path.join(
+        target_folder, f"skip_logs_{DEBUG_LINEARS_CALL_COUNTER}.txt"
+    )
+    summary_filename = os.path.join(
+        target_folder, f"summary_{DEBUG_LINEARS_CALL_COUNTER}.csv"
+    )
+    summary_results = [summary_headers]
+
+    gm = g.owning_module
+    assert gm is not None, "unsupported, gm needs to be specified"
+    graph_tabular_log.debug("\nstarting linear debug\n")
+
+    def log_skip_linear(n, mod, reason):
+        print_and_append_to_logs(
+            graph_tabular_log, skip_logs_filename, f"SKIP: {reason}"
+        )
+        print_and_append_to_logs(
+            graph_tabular_log, skip_logs_filename, f"node: {n.format_node()}"
+        )
+        print_and_append_to_logs(
+            graph_tabular_log, skip_logs_filename, f"node.meta: {get_meta_val(n)}"
+        )
+        print_and_append_to_logs(
+            graph_tabular_log, skip_logs_filename, f"node.stack: {get_stack_summary(n)}"
+        )
+        print_and_append_to_logs(graph_tabular_log, skip_logs_filename, f"mod: {mod}")
+        print_and_append_to_logs(graph_tabular_log, skip_logs_filename, "\n")
+
+    subgraph_idx = 0
+    module_fqn = None
+    for n in gm.graph.nodes:
+        if n.op == "call_module":
+            # check for linear
+            module_fqn = n.target
+            module_instance = getattr(gm, n.target)
+            if type(module_instance) is not torch.nn.Linear:
+                continue
+
+            if linear_mod_filter_fn is not None and not linear_mod_filter_fn(
+                module_instance
+            ):
+                log_skip_linear(n, module_instance, "failed filter function")
+                continue
+
+            # Note: we special case for linear -> linear,
+            # so if we are at the second linear then skip debug/extract to avoid duplication
+            is_second_linear_of_dual_linear = (
+                n.args[0].op == "call_module"
+                and type(getattr(gm, n.args[0].target)) is torch.nn.Linear
+                and len(n.args[0].users) == 1
+            )
+            if is_second_linear_of_dual_linear:
+                log_skip_linear(n, module_instance, "second of dual linear")
+                continue
+
+        elif n.op == "call_function":
+            if n.target != torch._C._nn.linear:
+                continue
+
+            if linear_node_filter_fn is not None and not linear_node_filter_fn(n):
+                log_skip_linear(n, None, "failed filter function")
+                continue
+
+            # Note: we special case for linear -> linear,
+            # so if we are at the second linear then skip debug/extract to avoid duplication
+            is_second_linear_of_dual_linear = (
+                n.args[0].op == "call_function"
+                and n.args[0].target is torch._C._nn.linear
+                and len(n.args[0].users) == 1
+            )
+            if is_second_linear_of_dual_linear:
+                log_skip_linear(n, module_instance, "second of dual linear")
+                continue
+
+            module_instance = None
+
+        else:
+            continue
+
+        # for now, the case where the linear's input is a graph input is not supported
+        if False:
+            is_input_placeholder = n.args[0].op == "placeholder"
+            if is_input_placeholder:
+                log_skip_linear(n, module_instance, "input is placeholder")
+                continue
+
+        try:
+            summary_result = debug_single_linear(
+                gm, n, module_instance, debug_logs_filename, subgraph_idx
+            )
+            subgraph_save_filename = os.path.join(
+                target_folder,
+                f"subgraph_with_inputs_{DEBUG_LINEARS_CALL_COUNTER}_{subgraph_idx}.pt",
+            )
+            extract_linear_subgraph(gm, n, module_instance, subgraph_save_filename)
+            summary_results.append(summary_result + [module_fqn])
+        except Exception as e:
+            print(e)
+            log_skip_linear(
+                n,
+                module_instance,
+                f"{subgraph_idx}, {str(e)}, {traceback.format_exc()}",
+            )
+        subgraph_idx += 1
+
+    with open(summary_filename, "w") as f:
+        csv.writer(f).writerows(summary_results)
+
+    graph_tabular_log.debug("\nending linear debug\n")
+
+    DEBUG_LINEARS_CALL_COUNTER += 1
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/__init__.py b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1a9577e21b1e28aff3bb959c04e4f873073ced7c
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__init__.py
@@ -0,0 +1,29 @@
+from .bitnet import (
+    BitNetTrainingLinearWeight,
+    bitnet_training,
+    precompute_bitnet_scale_for_fsdp,
+)
+from .int8 import (
+    Int8QuantizedTrainingLinearWeight,
+    int8_weight_only_quantized_training,
+    quantize_int8_rowwise,
+)
+from .int8_mixed_precision import (
+    Int8MixedPrecisionTrainingConfig,
+    Int8MixedPrecisionTrainingLinear,
+    Int8MixedPrecisionTrainingLinearWeight,
+    int8_mixed_precision_training,
+)
+
+__all__ = [
+    "BitNetTrainingLinearWeight",
+    "bitnet_training",
+    "precompute_bitnet_scale_for_fsdp",
+    "Int8MixedPrecisionTrainingConfig",
+    "Int8MixedPrecisionTrainingLinear",
+    "Int8MixedPrecisionTrainingLinearWeight",
+    "int8_mixed_precision_training",
+    "Int8QuantizedTrainingLinearWeight",
+    "int8_weight_only_quantized_training",
+    "quantize_int8_rowwise",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..445211aca27a45e078b84e54464c2893313ec1f3
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/bitnet.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/bitnet.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..774cd9279f09c42c8da9dd01802290093128b225
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/bitnet.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/int8.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/int8.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2100d40b22c5d9240c7d0a6656818af01e215a13
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/int8.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/int8_mixed_precision.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/int8_mixed_precision.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..32d94e5661103c35b2a43c82afb23d18d1e24355
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/int8_mixed_precision.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/int8_mm.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/int8_mm.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c8f306f3bd3321a201ca6be7274011b389093d59
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/quantized_training/__pycache__/int8_mm.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/bitnet.py b/lib/python3.12/site-packages/torchao/prototype/quantized_training/bitnet.py
new file mode 100644
index 0000000000000000000000000000000000000000..129c63414c4a04f35135636ef57686adb78322dd
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantized_training/bitnet.py
@@ -0,0 +1,404 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+# this file implements BitNet b1.58 https://arxiv.org/abs/2402.17764
+# a reference implementation is available at
+# https://github.com/microsoft/unilm/blob/master/bitnet/The-Era-of-1-bit-LLMs__Training_Tips_Code_FAQ.pdf
+
+from typing import Any, Optional, Tuple
+
+import torch
+import torch.distributed as dist
+import torch.nn.functional as F
+import torch.utils._pytree as pytree
+from torch import Tensor, nn
+from torch.distributed._tensor import DTensor
+from torch.utils._triton import has_triton
+
+from torchao.core.config import AOBaseConfig
+from torchao.quantization.transform_module import (
+    register_quantize_module_handler,
+)
+from torchao.utils import TorchAOBaseTensor
+
+from .int8 import quantize_int8_rowwise
+
+if has_triton():
+    from .int8_mm import scaled_int8_mm
+
+else:
+    # This is less performant than the explicit hand-written Triton kernel, though things might
+    # change in the future.
+    # Multiplying col_scale first is faster than the other way round.
+    def scaled_int8_mm(
+        A: Tensor, B: Tensor, row_scale: Tensor, col_scale: Tensor
+    ) -> Tensor:
+        return torch._int_mm(A, B) * col_scale.view(-1) * row_scale.view(-1, 1)
+
+
+aten = torch.ops.aten
+
+
+class BitNetTrainingLinearWeight(TorchAOBaseTensor):
+    @staticmethod
+    @torch._dynamo.disable
+    def __new__(cls, data: Tensor, precomputed_scale: Optional[Tensor] = None):
+        return Tensor._make_wrapper_subclass(
+            cls,
+            data.shape,
+            dtype=data.dtype,
+            device=data.device,
+        )
+
+    @torch._dynamo.disable
+    def __init__(self, data: Tensor, precomputed_scale: Optional[Tensor] = None):
+        self._data = data
+        self._precomputed_scale = precomputed_scale
+
+    def __tensor_flatten__(self):
+        if self._precomputed_scale is not None:
+            return ["_data", "_precomputed_scale"], []
+        else:
+            return ["_data"], []
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls, tensor_data_dict, tensor_attributes, outer_size=None, outer_stride=None
+    ):
+        return cls(
+            tensor_data_dict["_data"],
+            tensor_data_dict.get("_precomputed_scale", None),
+            *tensor_attributes,
+        )
+
+    def __repr__(self):
+        return f"{self.__class__.__name__}(data={self._data})"
+
+    # adapated from FP8 implementation of WeightWithDynamicFloat8CastTensor
+    @classmethod
+    def __torch_dispatch__(cls, func, types, args, kwargs):
+        out = func(
+            *pytree.tree_map_only(cls, lambda x: x._data, args),
+            **pytree.tree_map_only(cls, lambda x: x._data, kwargs),
+        )
+
+        # NOTE: _precomputed_scale does not propagate through any ops
+        if func is aten.copy_.default:
+            # return original object
+            return args[0]
+        elif func in {
+            aten.t.default,
+            aten.detach.default,
+            aten.empty_like.default,
+            aten.new_zeros.default,
+            aten.slice.Tensor,
+            aten.view.default,
+            aten.as_strided.default,
+            aten._to_copy.default,
+            aten._pin_memory.default,
+            aten.split.Tensor,
+            aten.clone.default,
+        }:
+            # return new wrapped object
+            return pytree.tree_map_only(Tensor, lambda x: cls(x), out)
+        else:
+            # return new unwrapped object
+            return out
+
+    # FSDP all-gather extension v1
+    def fsdp_pre_all_gather(self, mesh):
+        # quantize and pack into 2-bit to save comm bandwidth
+        if self._precomputed_scale is not None:
+            scale = self._precomputed_scale
+
+        else:
+            scale = get_bitnet_scale(self._data)
+            dist.all_reduce(scale, op=dist.ReduceOp.AVG)
+
+        # NOTE: scale is in FP32
+        data_i8 = quantize_bitnet_weight(self._data, scale)
+        data_i2 = _pack_i2_in_i8(data_i8)
+        return (data_i2,), (scale,)
+
+    def fsdp_post_all_gather(
+        self,
+        all_gather_outputs: Tuple[Tensor, ...],
+        metadata: Any,
+        param_dtype: torch.dtype,
+        *,
+        out: Optional[Tensor] = None,
+    ):
+        (data_i2,) = all_gather_outputs
+        (scale,) = metadata
+        scale = scale.to(param_dtype)
+        if out is not None:
+            assert isinstance(out, BitNetPacked2bitLinearWeight)
+            out.scale = scale
+            return
+        return BitNetPacked2bitLinearWeight(data_i2, scale), all_gather_outputs
+
+
+@BitNetTrainingLinearWeight.implements(F.linear)
+def _(func, types, args, kwargs):
+    if torch.is_autocast_enabled("cuda"):
+        dtype = torch.get_autocast_gpu_dtype()
+        args = tuple(x.to(dtype) if x is not None else x for x in args)
+    return _BitNetTrainingLinear.apply(*args, **kwargs)
+
+
+def get_bitnet_scale(x: Tensor):
+    "Tensor-wise abs-mean. Always return FP32."
+    return x.float().abs().mean()
+
+
+def quantize_bitnet_weight(w: Tensor, scale: Tensor, eps: float = 1e-5) -> Tensor:
+    w = w.float() / scale.clip(eps)
+    w = w.round().clip(-1, 1).to(torch.int8)
+    return w
+
+
+@torch.no_grad()
+def precompute_bitnet_scale_for_fsdp(module: nn.Module):
+    """Calculate scale for all BitNetTrainingLinearWeight parameters.
+    This should be run after the optimizer step. It performs a single all-reduce for all
+    parameters to reduce overhead.
+    """
+    bitnet_params = [
+        p
+        for p in module.parameters()
+        if isinstance(p, DTensor)
+        and isinstance(p._local_tensor, BitNetTrainingLinearWeight)
+    ]
+    if len(bitnet_params) == 0:
+        return
+
+    # NOTE: use torch.compile to save memory and increase speed?
+    bitnet_scales = [get_bitnet_scale(x) for x in bitnet_params]  # local absmean
+    bitnet_scales = torch.stack(bitnet_scales)
+    bitnet_scales = bitnet_scales.full_tensor()  # global absmean
+
+    for i, p in enumerate(bitnet_params):
+        p._local_tensor._precomputed_scale = bitnet_scales[i]
+
+
+class _BitNetTrainingLinear(torch.autograd.Function):
+    @staticmethod
+    def forward(
+        ctx,
+        input: Tensor,
+        weight: BitNetTrainingLinearWeight,
+        bias: Optional[Tensor] = None,
+    ):
+        batch_dims = input.shape[:-1]
+        input = input.view(-1, weight.shape[1])
+
+        # https://github.com/microsoft/unilm/blob/master/bitnet/The-Era-of-1-bit-LLMs__Training_Tips_Code_FAQ.pdf
+        # Figure 3
+        input_i8, row_scale = quantize_int8_rowwise(input, eps=1e-5)
+
+        # NOTE: use FP32 scale for weight quantization, but cast scale to possibly lower precision
+        # for matmul and backward
+        tensor_scale = get_bitnet_scale(weight._data)
+        weight_i8 = quantize_bitnet_weight(weight._data, tensor_scale)
+        tensor_scale = tensor_scale.to(weight.dtype)
+
+        ctx.save_for_backward(input_i8, row_scale, weight_i8, tensor_scale)
+
+        # use int8 tensor cores
+        out = scaled_int8_mm(
+            input_i8.contiguous(), weight_i8.contiguous().T, row_scale, tensor_scale
+        )
+        out = out.view(*batch_dims, weight.shape[0])
+
+        out = out + bias if bias is not None else out
+        return out
+
+    @staticmethod
+    def backward(ctx, grad_output):
+        input_i8, row_scale, weight_i8, tensor_scale = ctx.saved_tensors
+        grad_input = grad_weight = grad_bias = None
+
+        batch_dims = grad_output.shape[:-1]
+        grad_output = grad_output.view(-1, weight_i8.shape[0])
+
+        # NOTE: we can potentially speedup training by also quantizing the backward pass
+        # to use INT8 tensor cores
+        if ctx.needs_input_grad[0]:
+            # mixed mm
+            grad_input = (grad_output @ weight_i8.to(grad_output.dtype)) * tensor_scale
+            grad_input = grad_input.view(*batch_dims, weight_i8.shape[1])
+
+        if ctx.needs_input_grad[1]:
+            # NOTE: we use quantized activation for this calculation
+            grad_weight = grad_output.T @ (input_i8 * row_scale.view(-1, 1))
+
+        if ctx.needs_input_grad[2]:
+            grad_bias = grad_output.sum(0)
+
+        return grad_input, grad_weight, grad_bias
+
+
+class BitNetTrainingConfig(AOBaseConfig):
+    pass
+
+
+# for bc
+bitnet_training = BitNetTrainingConfig
+
+
+@register_quantize_module_handler(BitNetTrainingConfig)
+def _bitnet_training_transform(
+    module: torch.nn.Module,
+    config: BitNetTrainingConfig,
+) -> torch.nn.Module:
+    new_weight = BitNetTrainingLinearWeight(module.weight)
+    module.weight = torch.nn.Parameter(new_weight, requires_grad=True)
+    return module
+
+
+def _pack_i2_in_i8(x: Tensor):
+    # perform packing: [xxxx xxaa, xxxx xxxbb, xxxx xxcc, xxxx xxdd] -> [aabb ccdd]
+    # for each value, xxxx can be either all 0s or all 1s because these are signed numbers.
+    # thus, we have to mask out the 2 least significant bits (right-most) before bit-shift.
+    # e.g. 1111 1111 (value=-1) -> 0000 0011 -> 0011 0000
+
+    x0 = (
+        x[:, ::4] << 6
+    )  # don't need to mask this number because we shift it to the left-most
+    x1 = (x[:, 1::4] & 0b11) << 4
+    x2 = (x[:, 2::4] & 0b11) << 2
+    x3 = x[:, 3::4] & 0b11
+    return x0 | x1 | x2 | x3
+
+
+def _unpack_i2_in_i8(x: Tensor):
+    # NOTE: this is signed integer, so left-shift then right-shift will perform sign extension correctly
+    # e.g. aa10bbcc -> 10bbcc00 -> 11111110
+    return torch.stack([x >> 6, x << 2 >> 6, x << 4 >> 6, x << 6 >> 6], dim=-1).view(
+        x.shape[0], -1
+    )
+
+
+# currently this class mainly serves as a container for quantized FSDP2 all-gather,
+# so only a minimal set of ops are implemented. this can be extended for inference.
+class BitNetPacked2bitLinearWeight(TorchAOBaseTensor):
+    @staticmethod
+    @torch._dynamo.disable
+    def __new__(cls, int_data: Tensor, scale: Tensor):
+        M, N = int_data.shape
+        shape = (M, N * 4)
+        return Tensor._make_wrapper_subclass(
+            cls,
+            shape,
+            dtype=scale.dtype,
+            device=scale.device,
+        )
+
+    @torch._dynamo.disable
+    def __init__(self, int_data: Tensor, scale: Tensor):
+        assert int_data.dtype is torch.int8
+        assert scale.shape == ()
+        self.int_data = int_data
+        self.scale = scale
+
+    def __tensor_flatten__(self):
+        return ["int_data", "scale"], []
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls, tensor_data_dict, tensor_attributes, outer_size=None, outer_stride=None
+    ):
+        return cls(
+            tensor_data_dict["int_data"], tensor_data_dict["scale"], *tensor_attributes
+        )
+
+    def __repr__(self):
+        return f"{self.__class__.__name__}(data={self.dequantize()})"
+
+    def dequantize(self, out_dtype=None):
+        out = _unpack_i2_in_i8(self.int_data) * self.scale
+        if out_dtype is not None:
+            out = out.to(out_dtype)
+        return out
+
+
+@BitNetPacked2bitLinearWeight.implements(F.linear)
+def _(func, types, args, kwargs):
+    return _BitNetPacked2bitLinear.apply(*args, **kwargs)
+
+
+@BitNetPacked2bitLinearWeight.implements(
+    [
+        aten.detach.default,
+        aten.clone.default,
+    ]
+)
+def _(func, types, args, kwargs):
+    return BitNetPacked2bitLinearWeight(
+        func(args[0].int_data, *args[1:], **kwargs),
+        func(args[0].scale, *args[1:], **kwargs),
+    )
+
+
+# this is a workaround to make it work with FSDP2.
+# end-users should not call this op directly.
+@BitNetPacked2bitLinearWeight.implements(aten.as_strided.default)
+def _(func, types, args, kwargs):
+    return BitNetPacked2bitLinearWeight(args[0].int_data, args[0].scale)
+
+
+class _BitNetPacked2bitLinear(torch.autograd.Function):
+    @staticmethod
+    def forward(
+        ctx,
+        input: Tensor,
+        weight: BitNetPacked2bitLinearWeight,
+        bias: Optional[Tensor] = None,
+    ):
+        batch_dims = input.shape[:-1]
+        input = input.view(-1, weight.shape[1])
+
+        # https://github.com/microsoft/unilm/blob/master/bitnet/The-Era-of-1-bit-LLMs__Training_Tips_Code_FAQ.pdf
+        # Figure 3
+        input_i8, row_scale = quantize_int8_rowwise(input, eps=1e-5)
+        weight_i2, tensor_scale = weight.int_data, weight.scale
+
+        ctx.save_for_backward(input_i8, row_scale, weight_i2, tensor_scale)
+
+        # use int8 tensor cores
+        # NOTE: is doing dequant inside matmul faster when M is large?
+        weight_i8 = _unpack_i2_in_i8(weight_i2)
+        out = scaled_int8_mm(
+            input_i8.contiguous(), weight_i8.contiguous().T, row_scale, tensor_scale
+        )
+        out = out.view(*batch_dims, weight.shape[0])
+
+        out = out + bias if bias is not None else out
+        return out
+
+    @staticmethod
+    def backward(ctx, grad_output):
+        input_i8, row_scale, weight_i2, tensor_scale = ctx.saved_tensors
+        weight_i8 = _unpack_i2_in_i8(weight_i2)
+        grad_input = grad_weight = grad_bias = None
+
+        batch_dims = grad_output.shape[:-1]
+        grad_output = grad_output.view(-1, weight_i8.shape[0])
+
+        # NOTE: we can potentially speedup training by also quantizing the backward pass
+        # to use INT8 tensor cores
+        if ctx.needs_input_grad[0]:
+            # mixed mm
+            grad_input = (grad_output @ weight_i8.to(grad_output.dtype)) * tensor_scale
+            grad_input = grad_input.view(*batch_dims, weight_i8.shape[1])
+
+        if ctx.needs_input_grad[1]:
+            # NOTE: we use quantized activation for this calculation
+            grad_weight = grad_output.T @ (input_i8 * row_scale.view(-1, 1))
+
+        if ctx.needs_input_grad[2]:
+            grad_bias = grad_output.sum(0)
+
+        return grad_input, grad_weight, grad_bias
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/int8.py b/lib/python3.12/site-packages/torchao/prototype/quantized_training/int8.py
new file mode 100644
index 0000000000000000000000000000000000000000..6b438ca7872ce9f0a8d8c56dea3212f6dfdcb63b
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantized_training/int8.py
@@ -0,0 +1,319 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+from typing import Any, Optional, Tuple
+
+import torch
+from torch import Tensor
+from torch.utils._python_dispatch import return_and_correct_aliasing
+
+from torchao.core.config import AOBaseConfig
+from torchao.quantization.transform_module import (
+    register_quantize_module_handler,
+)
+from torchao.utils import TorchAOBaseTensor
+
+aten = torch.ops.aten
+c10d_functional = torch.ops.c10d_functional
+_c10d_functional = torch.ops._c10d_functional
+
+
+@torch.no_grad()
+def quantize_int8_rowwise(
+    tensor: Tensor, stochastic_rounding: bool = False, eps: float = 1e-12
+):
+    """Normal rounding will always round down small changes in weight update. To tackle this problem,
+    stochastic rounding can be used, which has a low chance, but not zero, of rounding up. The
+    probability of rounding up is equal to x - ⌊x⌋, which indicates how close the value is to the next
+    integer value. Thus, stochastic rounding also approximates the floating point value exactly.
+
+    Currently this function differs from AQT's `int8_weight_only()` in the following way:
+    1. Precision: AQT keeps original dtype when doing quantization, while this function upcasts input
+    to FP32 before quantization. Output scale maintains the original input dtype.
+    2. Calculate scale: AQT uses `input.abs().amax() / 127.5`, while `input.abs().amax() / 127` is
+    done here.
+    3. Apply scale: AQT uses `input * (1 / scale)`, while this function performs `input / scale`.
+    """
+    # absmax symmetric quantization
+    scale = tensor.abs().amax(1) / 127  # same dtype as tensor
+    inv_scale = 1.0 / scale.float().clip(eps)
+    tensor = tensor.float() * inv_scale.view(
+        -1, 1
+    )  # slightly faster than divide directly
+
+    if stochastic_rounding:
+        tensor = (tensor + torch.rand_like(tensor)).floor()
+    else:
+        tensor = tensor.round()
+
+    tensor = tensor.clip(-128, 127).to(torch.int8)
+    return tensor, scale
+
+
+class Int8QuantizedTrainingLinearWeight(TorchAOBaseTensor):
+    """INT8 symmetric quantization weight, with absmax scaling [-127, 127]. The main difference
+    of this tensor subclass from AffineQuantizedTensor:
+    1. `F.linear` is differentiable i.e. backward is defined.
+    2. All in-place ops, such as `aten.copy_`, will perform stochastic rounding.
+        `Int8QTLinearWeight.from_float()` does not perform stochastic rounding.
+    3. The numerics for quantization is slightly different. See `quantize_int8_rowwise()`
+        for more details.
+    """
+
+    @staticmethod
+    @torch._dynamo.disable
+    def __new__(cls, int_data: Tensor, scale: Tensor):
+        return Tensor._make_wrapper_subclass(
+            cls,
+            int_data.shape,
+            dtype=scale.dtype,
+            device=int_data.device,
+        )
+
+    @torch._dynamo.disable
+    def __init__(self, int_data: Tensor, scale: Tensor):
+        """Create a symmetric quantized INT8 weight. This tensor will appear to have the same dtype
+        as `scale.dtype`. All in-place update ops will perform stochastic rounding.
+        """
+        # NOTE: should scale always be FP32?
+        assert int_data.dtype is torch.int8
+        assert int_data.ndim == 2
+        assert scale.ndim == 1
+        self.int_data = int_data
+        self.scale = scale
+
+    def __tensor_flatten__(self):
+        return ["int_data", "scale"], []
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls, tensor_data_dict, tensor_attributes, outer_size=None, outer_stride=None
+    ):
+        return cls(
+            tensor_data_dict["int_data"], tensor_data_dict["scale"], *tensor_attributes
+        )
+
+    @classmethod
+    def from_float(cls, tensor: Tensor):
+        """Convert a float tensor into INT8 quantized weight. No stochastic rounding is performed.
+        This function is not differentiable.
+        """
+        int_data, scale = quantize_int8_rowwise(tensor.detach())
+        out = cls(int_data, scale)
+        out.requires_grad_(tensor.requires_grad)
+        return out
+
+    def dequantize(self):
+        return self.int_data * self.scale.view(-1, 1)
+
+    def __repr__(self):
+        return (
+            f"{self.__class__.__name__}(shape={tuple(self.shape)}, dtype={self.dtype}, device={self.device}, "
+            f"requires_grad={self.requires_grad})"
+        )
+
+    # FSDP all-gather extension v2
+    # https://github.com/pytorch/pytorch/pull/137005
+    # we need default values so this method still works with PyTorch 2.4 and 2.5
+    def fsdp_pre_all_gather(
+        self,
+        mesh,
+        outer_size=None,
+        outer_stride=None,
+        module=None,
+        mp_policy=None,
+    ):
+        scale = self.scale
+        if mp_policy is not None:
+            scale = scale.to(mp_policy.param_dtype)
+
+        return (self.int_data, scale), None
+
+    def fsdp_post_all_gather(
+        self,
+        all_gather_outputs: Tuple[Tensor, ...],
+        metadata: Any,
+        param_dtype: torch.dtype,
+        *,
+        out: Optional[Tensor] = None,
+    ):
+        int_data, scale = all_gather_outputs
+        return Int8QuantizedTrainingLinearWeight(int_data, scale), all_gather_outputs
+
+
+class _Int8WeightOnlyLinear(torch.autograd.Function):
+    @staticmethod
+    def forward(
+        ctx,
+        input: Tensor,
+        weight: Int8QuantizedTrainingLinearWeight,
+        bias: Optional[Tensor] = None,
+    ):
+        ctx.save_for_backward(input, weight)
+        ctx.bias = bias is not None
+
+        # NOTE: we have to .T before .to(input.dtype) for torch.compile() mixed matmul to work
+        out = (input @ weight.int_data.T.to(input.dtype)) * weight.scale
+        out = out + bias if bias is not None else out
+        return out
+
+    @staticmethod
+    def backward(ctx, grad_output):
+        input, weight = ctx.saved_tensors
+
+        grad_input = (grad_output * weight.scale) @ weight.int_data.to(
+            grad_output.dtype
+        )
+        grad_weight = grad_output.view(-1, weight.shape[0]).T @ input.view(
+            -1, weight.shape[1]
+        )
+        grad_bias = grad_output.view(-1, weight.shape[0]).sum(0) if ctx.bias else None
+        return grad_input, grad_weight, grad_bias
+
+
+implements = Int8QuantizedTrainingLinearWeight.implements
+
+
+@implements(torch.nn.functional.linear)
+def _(func, types, args, kwargs):
+    return _Int8WeightOnlyLinear.apply(*args, **kwargs)
+
+
+@implements(
+    [
+        aten.detach.default,
+        aten.clone.default,
+        # FSDP ops
+        aten.slice.Tensor,
+        c10d_functional.all_gather_into_tensor.default,
+        _c10d_functional.all_gather_into_tensor.default,
+        c10d_functional.wait_tensor.default,
+        _c10d_functional.wait_tensor.default,
+    ]
+)
+def _(func, types, args, kwargs):
+    # will error out if try to slice 2nd dim
+    out = Int8QuantizedTrainingLinearWeight(
+        func(args[0].int_data, *args[1:], **kwargs),
+        func(args[0].scale, *args[1:], **kwargs),
+    )
+    return return_and_correct_aliasing(func, args, kwargs, out)
+
+
+@implements(aten._to_copy.default)
+def _(func, types, args, kwargs):
+    # only perform dtype casting on scale, which determines the appearance dtype
+    # TODO: handle non_blocking kwarg?
+    device = kwargs.get("device", None)
+    dtype = kwargs.get("dtype", None)
+    out = Int8QuantizedTrainingLinearWeight(
+        args[0].int_data.to(device=device),
+        args[0].scale.to(device=device, dtype=dtype),
+    )
+    return return_and_correct_aliasing(func, args, kwargs, out)
+
+
+# to make training work with existing PyTorch optimizers, we return a normal tensor
+@implements(aten.zeros_like.default)
+def _(func, types, args, kwargs):
+    dtype = kwargs.get("dtype", args[0].dtype)
+    device = kwargs.get("device", args[0].device)
+    return torch.zeros(args[0].shape, dtype=dtype, device=device)
+
+
+# out-of-place math ops always return plain tensor
+@implements([aten.sub.Tensor, aten.mul.Tensor])
+def _(func, types, args, kwargs):
+    args = [
+        x.dequantize() if isinstance(x, Int8QuantizedTrainingLinearWeight) else x
+        for x in args
+    ]
+    return func(*args, **kwargs)
+
+
+@implements(aten.copy_.default)
+def _(func, types, args, kwargs):
+    if isinstance(args[0], Int8QuantizedTrainingLinearWeight) and isinstance(
+        args[1], Int8QuantizedTrainingLinearWeight
+    ):
+        args[0].int_data.copy_(args[1].int_data, **kwargs)
+        args[0].scale.copy_(args[1].scale, **kwargs)
+
+    elif isinstance(args[0], Int8QuantizedTrainingLinearWeight):
+        int_data, scale = quantize_int8_rowwise(args[1], stochastic_rounding=True)
+        args[0].int_data.copy_(int_data, **kwargs)
+        args[0].scale.copy_(scale, **kwargs)
+
+    else:
+        args[0].copy_(args[1].dequantize(), **kwargs)
+
+    return args[0]
+
+
+@implements([aten.addcdiv_.default, aten.add_.Tensor])
+def _(func, types, args, kwargs):
+    original = args[0]
+    out = func(args[0].dequantize(), *args[1:], **kwargs)
+    return original.copy_(out)
+
+
+# FSDP ops
+@implements(aten.split.Tensor)
+def _(func, types, args, kwargs):
+    if len(args) == 3 and args[2] != 0:
+        raise NotImplementedError("Int8QTLinearWeight only supports split at dim=0")
+
+    int8_weight: Int8QuantizedTrainingLinearWeight = args[0]
+    int_data_list = func(int8_weight.int_data, *args[1:], **kwargs)
+    scale_list = func(int8_weight.scale, *args[1:], **kwargs)
+
+    out = [
+        Int8QuantizedTrainingLinearWeight(int_data, scale)
+        for int_data, scale in zip(int_data_list, scale_list)
+    ]
+    return out
+
+
+@implements(aten.new_zeros.default)
+def _(func, types, args, kwargs):
+    size = args[1]
+    if len(size) != 2:
+        raise NotImplementedError
+
+    # TODO: handle pin_memory kwarg?
+    device = kwargs.get("device", args[0].device)
+    dtype = kwargs.get("dtype", args[0].dtype)
+    int_data = torch.zeros(size, device=device, dtype=torch.int8)
+    scale = torch.zeros(size[0], device=device, dtype=dtype)
+    return Int8QuantizedTrainingLinearWeight(int_data, scale)
+
+
+# FSDP2 will call these two ops, expecting a view, not a copy. It doesn't make sense to
+# correctly support these ops. For example, `.scale` depends on the shape of the weight,
+# since this is channel-wise quantization.
+# Thus, this is a workaround for FSDP2. Users SHOULD NOT call these ops directly, since
+# they will produce unexpected or wrong results.
+@implements([aten.view.default, aten.as_strided.default])
+def _(func, types, args, kwargs):
+    out = Int8QuantizedTrainingLinearWeight(args[0].int_data, args[0].scale)
+    return return_and_correct_aliasing(func, args, kwargs, out)
+
+
+class Int8WeightOnlyQuantizedTrainingConfig(AOBaseConfig):
+    pass
+
+
+# for bc
+int8_weight_only_quantized_training = Int8WeightOnlyQuantizedTrainingConfig
+
+
+@register_quantize_module_handler(Int8WeightOnlyQuantizedTrainingConfig)
+def _int8_weight_only_quantized_training_transform(
+    module: torch.nn.Module,
+    config: Int8WeightOnlyQuantizedTrainingConfig,
+) -> torch.nn.Module:
+    new_weight = Int8QuantizedTrainingLinearWeight.from_float(module.weight)
+    module.weight = torch.nn.Parameter(new_weight, requires_grad=True)
+    return module
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/int8_mixed_precision.py b/lib/python3.12/site-packages/torchao/prototype/quantized_training/int8_mixed_precision.py
new file mode 100644
index 0000000000000000000000000000000000000000..44cd72e682da99643ddbcb3d2c640763677cc90a
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantized_training/int8_mixed_precision.py
@@ -0,0 +1,302 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+from dataclasses import dataclass
+from typing import Any, Optional, Tuple, Union
+
+import torch
+import torch.utils._pytree as pytree
+from torch import Tensor, nn
+from torch.utils._triton import has_triton
+
+from torchao.core.config import AOBaseConfig
+from torchao.quantization.transform_module import (
+    register_quantize_module_handler,
+)
+from torchao.utils import TorchAOBaseTensor
+
+from .int8 import quantize_int8_rowwise
+
+if has_triton():
+    from .int8_mm import scaled_int8_mm
+
+else:
+    # This is less performant than the explicit hand-written Triton kernel, though things might
+    # change in the future.
+    # Multiplying col_scale first is faster than the other way round.
+    def scaled_int8_mm(
+        A: Tensor, B: Tensor, row_scale: Tensor, col_scale: Tensor
+    ) -> Tensor:
+        return torch._int_mm(A, B) * col_scale.view(-1) * row_scale.view(-1, 1)
+
+
+@dataclass
+class Int8MixedPrecisionTrainingConfig(AOBaseConfig):
+    output: bool = True
+    grad_input: bool = True
+    grad_weight: bool = True
+    module_swap: bool = False
+
+
+# for bc
+int8_mixed_precision_training = Int8MixedPrecisionTrainingConfig
+
+
+_DEFAULT_CONFIG = Int8MixedPrecisionTrainingConfig()
+
+
+aten = torch.ops.aten
+
+
+class Int8MixedPrecisionTrainingLinearWeight(TorchAOBaseTensor):
+    """Linear weight for INT8 mixed-precision training. The weight is in original precision (e.g. FP32 or BF16).
+    During training, weight and activation are dynamically quantized and cast to INT8 to utilize INT8 Tensor Cores,
+    and then scaled back to original precision. This is also applied to backward pass.
+    """
+
+    @staticmethod
+    @torch._dynamo.disable
+    def __new__(cls, data: Tensor, config: Int8MixedPrecisionTrainingConfig):
+        return Tensor._make_wrapper_subclass(
+            cls,
+            data.shape,
+            data.stride(),
+            data.storage_offset(),
+            dtype=data.dtype,
+            device=data.device,
+        )
+
+    @torch._dynamo.disable
+    def __init__(self, data: Tensor, config: Int8MixedPrecisionTrainingConfig):
+        self._data = data
+        self.config = config
+
+    def __tensor_flatten__(self):
+        return ["_data"], [self.config]
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls, tensor_data_dict, tensor_attributes, outer_size=None, outer_stride=None
+    ):
+        return cls(tensor_data_dict["_data"], *tensor_attributes)
+
+    def __repr__(self):
+        return f"{self.__class__.__name__}(data={self._data}, config={self.config})"
+
+    def to_original(self):
+        return self._data.clone()
+
+    # adapated from FP8 implementation of WeightWithDynamicFloat8CastTensor
+    @classmethod
+    def __torch_dispatch__(cls, func, types, args, kwargs):
+        config = None
+
+        def unwrap(x):
+            nonlocal config
+            if config is None:
+                config = x.config
+            else:
+                assert x.config == config
+            return x._data
+
+        out = func(
+            *pytree.tree_map_only(cls, unwrap, args),
+            **pytree.tree_map_only(cls, unwrap, kwargs),
+        )
+
+        if func is aten.copy_.default:
+            # return original object
+            return args[0]
+        elif func in {
+            aten.t.default,
+            aten.detach.default,
+            aten.empty_like.default,
+            aten.new_zeros.default,
+            aten.slice.Tensor,
+            aten.view.default,
+            aten.as_strided.default,
+            aten._to_copy.default,
+            aten._pin_memory.default,
+            aten.split.Tensor,
+            aten.clone.default,
+        }:
+            # return new wrapped object
+            return pytree.tree_map_only(Tensor, lambda x: cls(x, config), out)
+        else:
+            # return new unwrapped object
+            return out
+
+    # FSDP all-gather extension v2
+    # https://github.com/pytorch/pytorch/pull/137005
+    # we need default values so this method still works with PyTorch 2.4 and 2.5
+    def fsdp_pre_all_gather(
+        self,
+        mesh,
+        outer_size=None,
+        outer_stride=None,
+        module=None,
+        mp_policy=None,
+    ):
+        # TODO: pre-quantize weight here -> reduce comm bandwidth.
+        # we will need another tensor subclass to hold the quantized weight.
+        data = self._data
+        if mp_policy is not None:
+            data = data.to(mp_policy.param_dtype)
+
+        return (data,), (self.config,)
+
+    def fsdp_post_all_gather(
+        self,
+        all_gather_outputs: Tuple[Tensor, ...],
+        metadata: Any,
+        param_dtype: torch.dtype,
+        *,
+        out: Optional[Tensor] = None,
+    ):
+        (data,) = all_gather_outputs
+        (config,) = metadata
+        if out is not None:
+            assert isinstance(out, Int8MixedPrecisionTrainingLinearWeight)
+            assert out.config == config
+            return
+        return Int8MixedPrecisionTrainingLinearWeight(data, config), all_gather_outputs
+
+
+@Int8MixedPrecisionTrainingLinearWeight.implements(torch.nn.functional.linear)
+def _(func, types, args, kwargs):
+    if torch.is_autocast_enabled("cuda"):
+        dtype = torch.get_autocast_gpu_dtype()
+        args = tuple(x.to(dtype) if x is not None else x for x in args)
+    return _Int8MixedPrecisionTrainingLinearFunction.apply(*args, **kwargs)
+
+
+class Int8MixedPrecisionTrainingLinear(nn.Linear):
+    def __init__(
+        self, *args, config: Int8MixedPrecisionTrainingConfig, **kwargs
+    ) -> None:
+        super().__init__(*args, **kwargs)
+        self.config = config
+
+    def forward(self, input: Tensor) -> Tensor:
+        return _Int8MixedPrecisionTrainingLinearFunction.apply(
+            input, self.weight, self.bias, self.config
+        )
+
+
+def _dynamic_int8_mm(A: Tensor, B: Tensor) -> Tensor:
+    """Dynamically quantize A and B to perform INT8 matmul, then scale the results back to original precision.
+    To fuse scaling to matmul output, we use row-wise scaling for A and column-wise scaling for B.
+
+    We transpose B before quantization for 2 reasons:
+      - INT8 matmul is the most performant when A is row-major and B is column-major.
+      - Row-wise scaling for B.T is column-wise scaling for B -> we only need to implement row-wise scaling.
+
+    Note that inputs and outputs of `quantize_int8_rowwise()` are not guaranteed to be contiguous. We call
+    `.contiguous()` to outputs of the quantize op to make sure:
+      - Performant layout for INT8 matmul inputs (see above).
+      - Scales are contiguous (this is a limitation of our triton kernel).
+
+    We hope that the `.contiguous()` calls, as well as possible layout transpose before quantization, are
+    fused into quantize op by torch compiler.
+
+    TODO: check if transpose+quantize are actually fused.
+    """
+    # A may have more than 2 dims, while B must be exactly 2-dim
+    A_i8, A_scale_rowwise = quantize_int8_rowwise(A.view(-1, A.shape[-1]))
+    B_t_i8, B_scale_colwise = quantize_int8_rowwise(B.T)
+    out = scaled_int8_mm(
+        A_i8.contiguous(),
+        B_t_i8.contiguous().T,
+        A_scale_rowwise.contiguous(),
+        B_scale_colwise.contiguous(),
+    )
+    return out.view(*A.shape[:-1], out.shape[-1])
+
+
+@torch.compiler.allow_in_graph  # this is required for module-swap, but not for tensor subclass
+class _Int8MixedPrecisionTrainingLinearFunction(torch.autograd.Function):
+    @staticmethod
+    def forward(
+        ctx,
+        input: Tensor,
+        weight: Union[Int8MixedPrecisionTrainingLinearWeight, Tensor],
+        bias: Optional[Tensor],
+        config: Optional[Int8MixedPrecisionTrainingConfig] = None,
+    ):
+        # unpack tensor subclass and dequant if necessary.
+        # NOTE: we have to do this inside autograd.Function so that autograd works correctly.
+        if isinstance(weight, Int8MixedPrecisionTrainingLinearWeight):
+            config = weight.config  # override `config` input argument
+            weight = weight._data
+
+        ctx.config = config
+        ctx.save_for_backward(input, weight)
+        ctx.bias = bias is not None
+
+        # for NF4Tensor, this will dequantize the tensor.
+        # NOTE: not all quantized tensor subclasses implement .to() this way.
+        # e.g. AffineQuantizedTensor.to(dtype=dtype) returns the same AQT tensor.
+        # casting weight dtype may also introduce unintended behavior.
+        # e.g. FP32 activations and BF16 weight (both plain tensors), which should raise an error,
+        # but now we cast BF16 weight to FP32 instead (and return results in FP32).
+        weight = weight.to(input.dtype)
+
+        if config.output:
+            out = _dynamic_int8_mm(input, weight.T)
+        else:
+            out = input @ weight.T
+        out = out + bias if bias is not None else out
+        return out
+
+    @staticmethod
+    def backward(ctx, grad_output):
+        input, weight = ctx.saved_tensors
+        weight = weight.to(input.dtype)  # dequant NF4
+
+        grad_input = grad_weight = grad_bias = None
+
+        if ctx.needs_input_grad[0]:
+            if ctx.config.grad_input:
+                grad_input = _dynamic_int8_mm(grad_output, weight)
+            else:
+                grad_input = grad_output @ weight
+
+        if ctx.needs_input_grad[1]:
+            grad_output = grad_output.view(-1, weight.shape[0])
+            input = input.view(-1, weight.shape[1])
+            if ctx.config.grad_weight:
+                # grad_weight = _dynamic_int8_mm(grad_output.T, input)
+                grad_weight = _dynamic_int8_mm(
+                    input.T, grad_output
+                ).T  # this is slightly faster
+            else:
+                grad_weight = grad_output.T @ input
+
+        if ctx.needs_input_grad[2] and ctx.bias:
+            grad_bias = grad_output.sum(0)
+
+        return grad_input, grad_weight, grad_bias, None
+
+
+@register_quantize_module_handler(Int8MixedPrecisionTrainingConfig)
+def _int8_mixed_precision_training_transform(
+    module: torch.nn.Module,
+    config: Int8MixedPrecisionTrainingConfig,
+):
+    module_swap = config.module_swap
+
+    # TODO: skip small layers that don't have perf gain.
+    if module_swap:
+        # module swap implementation
+        module.__class__ = Int8MixedPrecisionTrainingLinear
+        module.config = config
+        return module
+
+    else:
+        # tensor subclass implementation
+
+        new_weight = Int8MixedPrecisionTrainingLinearWeight(module.weight, config)
+        module.weight = torch.nn.Parameter(new_weight, requires_grad=True)
+        return module
diff --git a/lib/python3.12/site-packages/torchao/prototype/quantized_training/int8_mm.py b/lib/python3.12/site-packages/torchao/prototype/quantized_training/int8_mm.py
new file mode 100644
index 0000000000000000000000000000000000000000..56846f98a7414af73cbaa070e1f1a5cd8bb34ad2
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/quantized_training/int8_mm.py
@@ -0,0 +1,187 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+# TODO: might merge this with torchao/kernel/intmm_triton.py
+
+import torch
+import triton
+import triton.language as tl
+from torch import Tensor
+
+lib = torch.library.Library("torchao", "FRAGMENT")
+
+
+# TODO: prune configs to speedup triton autotune
+# https://triton-lang.org/main/getting-started/tutorials/03-matrix-multiplication.html
+# (BLOCK_M, BLOCK_N, BLOCK_K, num_stages, num_warps)
+configs = [
+    (128, 256, 64, 3, 8),
+    (64, 256, 32, 4, 4),
+    (128, 128, 32, 4, 4),
+    (128, 64, 32, 4, 4),
+    (64, 128, 32, 4, 4),
+    (128, 32, 32, 4, 4),
+    (64, 32, 32, 5, 2),
+    (32, 64, 32, 5, 2),
+    # Good config for fp8 inputs
+    (128, 256, 128, 3, 8),
+    (256, 128, 128, 3, 8),
+    (256, 64, 128, 4, 4),
+    (64, 256, 128, 4, 4),
+    (128, 128, 128, 4, 4),
+    (128, 64, 64, 4, 4),
+    (64, 128, 64, 4, 4),
+    (128, 32, 64, 4, 4),
+    # https://github.com/pytorch/pytorch/blob/7868b65c4d4f34133607b0166f08e9fbf3b257c4/torch/_inductor/kernel/mm_common.py#L172
+    (64, 64, 32, 2, 4),
+    (64, 128, 32, 3, 4),
+    (128, 64, 32, 3, 4),
+    (64, 128, 32, 4, 8),
+    (128, 64, 32, 4, 8),
+    (64, 32, 32, 5, 8),
+    (32, 64, 32, 5, 8),
+    (128, 128, 32, 2, 8),
+    (64, 64, 64, 3, 8),
+    (128, 256, 128, 3, 8),
+    (256, 128, 128, 3, 8),
+]
+
+configs = [
+    triton.Config(
+        dict(BLOCK_M=BLOCK_M, BLOCK_N=BLOCK_N, BLOCK_K=BLOCK_K),
+        num_stages=num_stages,
+        num_warps=num_warps,
+    )
+    for BLOCK_M, BLOCK_N, BLOCK_K, num_stages, num_warps in configs
+]
+
+
+@triton.autotune(configs=configs, key=["M", "N", "K", "stride_ak", "stride_bk"])
+@triton.heuristics({"EVEN_K": lambda args: args["K"] % args["BLOCK_K"] == 0})
+@triton.jit
+def _scaled_int8_mm_kernel(
+    A_ptr,
+    B_ptr,
+    C_ptr,
+    row_scale_ptr,
+    col_scale_ptr,
+    M,
+    N,
+    K,
+    stride_am,
+    stride_ak,
+    stride_bk,
+    stride_bn,
+    stride_cm,
+    stride_cn,
+    BLOCK_M: tl.constexpr,
+    BLOCK_N: tl.constexpr,
+    BLOCK_K: tl.constexpr,
+    GROUP_M: tl.constexpr = 8,
+    EVEN_K: tl.constexpr = True,
+    COL_SCALE_SCALAR: tl.constexpr = False,
+):
+    # based on triton.ops.matmul
+    pid = tl.program_id(0)
+    grid_m = (M + BLOCK_M - 1) // BLOCK_M
+    grid_n = (N + BLOCK_N - 1) // BLOCK_N
+
+    # re-order program ID for better L2 performance
+    width = GROUP_M * grid_n
+    group_id = pid // width
+    group_size = min(grid_m - group_id * GROUP_M, GROUP_M)
+    pid_m = group_id * GROUP_M + (pid % group_size)
+    pid_n = (pid % width) // (group_size)
+
+    rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
+    rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
+    ram = tl.max_contiguous(tl.multiple_of(rm % M, BLOCK_M), BLOCK_M)
+    rbn = tl.max_contiguous(tl.multiple_of(rn % N, BLOCK_N), BLOCK_N)
+    rk = tl.arange(0, BLOCK_K)
+    A = A_ptr + (ram[:, None] * stride_am + rk[None, :] * stride_ak)
+    B = B_ptr + (rk[:, None] * stride_bk + rbn[None, :] * stride_bn)
+
+    acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.int32)
+    for k in range(K, 0, -BLOCK_K):
+        if EVEN_K:
+            a = tl.load(A)
+            b = tl.load(B)
+        else:
+            a = tl.load(A, mask=rk[None, :] < k, other=0.0)
+            b = tl.load(B, mask=rk[:, None] < k, other=0.0)
+        acc += tl.dot(a, b)
+        A += BLOCK_K * stride_ak
+        B += BLOCK_K * stride_bk
+
+    # rematerialize rm and rn to save registers
+    rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
+    rn = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
+    idx_m = rm[:, None]
+    idx_n = rn[None, :]
+    mask = (idx_m < M) & (idx_n < N)
+
+    row_scale = tl.load(row_scale_ptr + idx_m, mask=idx_m < M).to(tl.float32)
+    if COL_SCALE_SCALAR:
+        # hack to support BitNet. col_scale is now a scalar
+        col_scale = tl.load(col_scale_ptr).to(tl.float32)
+    else:
+        col_scale = tl.load(col_scale_ptr + idx_n, mask=idx_n < N).to(tl.float32)
+    acc = acc.to(tl.float32) * row_scale * col_scale
+
+    # inductor generates a suffix
+    xindex = idx_m * stride_cm + idx_n * stride_cn
+    tl.store(C_ptr + tl.broadcast_to(xindex, mask.shape), acc, mask)
+
+
+lib.define(
+    "scaled_int8_mm(Tensor A, Tensor B, Tensor A_scale, Tensor B_scale) -> Tensor"
+)
+
+
+def scaled_int8_mm(
+    A: Tensor, B: Tensor, row_scale: Tensor, col_scale: Tensor
+) -> Tensor:
+    """Compute `(A @ B) * row_scale * col_scale`, where `A` and `B` are INT8 to utilize
+    INT8 tensor cores. `col_scale` can be a scalar.
+    """
+    assert A.dtype is torch.int8 and B.dtype is torch.int8
+    assert row_scale.dtype is col_scale.dtype
+    assert A.shape[1] == B.shape[0]
+    assert row_scale.squeeze().shape == (A.shape[0],)
+    assert col_scale.squeeze().shape in ((B.shape[1],), ())
+    assert row_scale.is_contiguous()
+    assert col_scale.is_contiguous()
+    return torch.ops.torchao.scaled_int8_mm(A, B, row_scale, col_scale)
+
+
+@torch.library.impl(lib, "scaled_int8_mm", "Meta")
+def _(A: Tensor, B: Tensor, row_scale: Tensor, col_scale: Tensor):
+    return torch.empty((A.shape[0], B.shape[1]), device=A.device, dtype=row_scale.dtype)
+
+
+@torch.library.impl(lib, "scaled_int8_mm", "CUDA")
+def scaled_int8_mm_cuda(A: Tensor, B: Tensor, row_scale: Tensor, col_scale: Tensor):
+    M, K = A.shape
+    _, N = B.shape
+    C = torch.empty(M, N, device=A.device, dtype=row_scale.dtype)
+    grid = lambda meta: (
+        triton.cdiv(meta["M"], meta["BLOCK_M"])
+        * triton.cdiv(meta["N"], meta["BLOCK_N"]),
+    )
+    _scaled_int8_mm_kernel[grid](
+        A,
+        B,
+        C,
+        row_scale,
+        col_scale,
+        M,
+        N,
+        K,
+        *A.stride(),
+        *B.stride(),
+        *C.stride(),
+        COL_SCALE_SCALAR=col_scale.numel() == 1,
+    )
+    return C
diff --git a/lib/python3.12/site-packages/torchao/prototype/spinquant/__init__.py b/lib/python3.12/site-packages/torchao/prototype/spinquant/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..b20f7abc0ad968ee7e3d4f0c496c76877c793703
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/spinquant/__init__.py
@@ -0,0 +1,5 @@
+from .spinquant import apply_spinquant
+
+__all__ = [
+    "apply_spinquant",
+]
diff --git a/lib/python3.12/site-packages/torchao/prototype/spinquant/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/spinquant/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ab6da86e30f0d4e54125a7d18ef585de6d249c2d
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/spinquant/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/spinquant/__pycache__/hadamard_utils.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/spinquant/__pycache__/hadamard_utils.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c3c62f8d008ebc2a993251ab5d6cd9906818958f
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/spinquant/__pycache__/hadamard_utils.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/spinquant/__pycache__/spinquant.cpython-312.pyc b/lib/python3.12/site-packages/torchao/prototype/spinquant/__pycache__/spinquant.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dadf6e21e956e56f1f4dc5b9dca3e0771ab07665
Binary files /dev/null and b/lib/python3.12/site-packages/torchao/prototype/spinquant/__pycache__/spinquant.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/torchao/prototype/spinquant/_hadamard_matrices.py b/lib/python3.12/site-packages/torchao/prototype/spinquant/_hadamard_matrices.py
new file mode 100644
index 0000000000000000000000000000000000000000..91e29cd64bf3a0d64e3193293ced40961911517d
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/spinquant/_hadamard_matrices.py
@@ -0,0 +1,99321 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import torch
+
+
+# hadamard matrices for had12, had36.pal2, had52,will,
+# # had60.pal, had108.pal, had140.pal, had156.will, had172.will:
+# http://www.neilsloane.com/hadamard/index.html
+def get_had12():
+    return torch.FloatTensor(
+        [
+            [+1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1],
+            [+1, +1, -1, +1, -1, -1, -1, +1, +1, +1, -1, +1],
+            [+1, +1, +1, -1, +1, -1, -1, -1, +1, +1, +1, -1],
+            [+1, -1, +1, +1, -1, +1, -1, -1, -1, +1, +1, +1],
+            [+1, +1, -1, +1, +1, -1, +1, -1, -1, -1, +1, +1],
+            [+1, +1, +1, -1, +1, +1, -1, +1, -1, -1, -1, +1],
+            [+1, +1, +1, +1, -1, +1, +1, -1, +1, -1, -1, -1],
+            [+1, -1, +1, +1, +1, -1, +1, +1, -1, +1, -1, -1],
+            [+1, -1, -1, +1, +1, +1, -1, +1, +1, -1, +1, -1],
+            [+1, -1, -1, -1, +1, +1, +1, -1, +1, +1, -1, +1],
+            [+1, +1, -1, -1, -1, +1, +1, +1, -1, +1, +1, -1],
+            [+1, -1, +1, -1, -1, -1, +1, +1, +1, -1, +1, +1],
+        ]
+    )
+
+
+def get_had44():
+    return torch.FloatTensor(
+        [
+            [
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+            ],
+            [
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+            ],
+            [
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+                -1,
+            ],
+            [
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                -1,
+                1,
+                1,
+                1,
+                1,
+                1,
+                -1,
+                1,
+                1,
+                1,
+                -1,
+                -1,
+                1,
+                -1,
+                1,
+                -1,
+                -1,
+                1,
+                1,
+            ],
+        ]
+    )
+
+
+def get_had40():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+        ]
+    )
+
+
+def get_had20():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+        ]
+    )
+
+
+def get_had28():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+        ]
+    )
+
+
+def get_had36():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+        ]
+    )
+
+
+def get_had60():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+        ]
+    )
+
+
+def get_had52():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+        ]
+    )
+
+
+def get_had108():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+        ]
+    )
+
+
+def get_had140():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+        ]
+    )
+
+
+def get_had156():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+        ]
+    )
+
+
+def get_had172():
+    return torch.FloatTensor(
+        [
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+            ],
+            [
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+            [
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                -1,
+            ],
+            [
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+            ],
+            [
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                -1,
+                +1,
+                -1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                -1,
+                +1,
+                -1,
+                +1,
+                +1,
+                +1,
+                +1,
+                -1,
+                -1,
+                +1,
+                +1,
+                -1,
+                -1,
+                -1,
+                +1,
+            ],
+        ]
+    )
diff --git a/lib/python3.12/site-packages/torchao/prototype/spinquant/hadamard_utils.py b/lib/python3.12/site-packages/torchao/prototype/spinquant/hadamard_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1c779c56366b9a08f8dfc7f6965bfe24202c027
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/spinquant/hadamard_utils.py
@@ -0,0 +1,276 @@
+# coding=utf-8
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the license found in the
+# LICENSE file in the root directory of this source tree.
+
+# This code is based on QuaRot(https://github.com/spcl/QuaRot/tree/main/quarot).
+# Licensed under Apache License 2.0.
+# Adapted from https://github.com/Cornell-RelaxML/quip-sharp/blob/main/lib/utils/matmul_had.py
+
+import torch
+
+from torchao.ops import lib
+from torchao.prototype.spinquant._hadamard_matrices import (
+    get_had12,
+    get_had20,
+    get_had28,
+    get_had36,
+    get_had40,
+    get_had44,
+    get_had52,
+    get_had60,
+    get_had108,
+    get_had140,
+    get_had156,
+    get_had172,
+)
+from torchao.utils import TORCH_VERSION_AT_LEAST_2_4
+
+try:
+    from fast_hadamard_transform import hadamard_transform as _fast_hadamard_transform
+
+    def matmul_hadU(X, hadK, K):
+        if X.is_cuda:
+            return matmul_hadU_fast(X, hadK, K)
+        else:
+            return matmul_hadU_slow(X, hadK, K)
+
+except ImportError:
+    print(
+        "NOTE: Using slow Hadamard transform for SpinQuant. "
+        "For better performance on GPU, install `fast_hadamard_transform`: "
+        "`pip install git+https://github.com/Dao-AILab/fast-hadamard-transform.git`"
+    )
+
+    def matmul_hadU(X, hadK, K):
+        return matmul_hadU_slow(X, hadK, K)
+
+
+def register_custom_op_impl(name):
+    def decorator(func):
+        if TORCH_VERSION_AT_LEAST_2_4:
+            return torch.library.custom_op(f"{name}", mutates_args=())(func)
+        else:
+            lib.define("hadamard_transform(Tensor x, float scale = 0.0) -> Tensor")
+            return torch.library.impl(f"{name}", "cuda")(func)
+
+    return decorator
+
+
+def register_custom_op_abstract(name):
+    def decorator(func):
+        if TORCH_VERSION_AT_LEAST_2_4:
+            return torch.library.register_fake(f"{name}")(func)
+        else:
+            return torch.library.impl_abstract(f"{name}")(func)
+
+    return decorator
+
+
+@register_custom_op_impl("torchao::hadamard_transform")
+def hadamard_transform(x: torch.Tensor, scale: float = 1.0) -> torch.Tensor:
+    """
+    Arguments:
+        x: (..., dim)
+        scale: float. Multiply the output by this number.
+    Returns:
+        out: (..., dim)
+
+    Multiply each row of x by the Hadamard transform matrix.
+    Equivalent to F.linear(x, torch.tensor(scipy.linalg.hadamard(dim))) * scale.
+    If dim is not a power of 2, we implicitly pad x with zero so that dim is the next power of 2.
+
+    Source: https://github.com/Dao-AILab/fast-hadamard-transform
+    """
+    return _fast_hadamard_transform(x, scale)
+
+
+@register_custom_op_abstract("torchao::hadamard_transform")
+def _(x: torch.Tensor, scale: float = 1.0) -> torch.Tensor:
+    torch._check(
+        x.dim() >= 1, lambda: f"input should be at least a 1D tensor, got {x.dim()}D"
+    )
+    return torch.empty_like(x)
+
+
+class HadamardTransform(torch.autograd.Function):
+    """The unnormalized Hadamard transform (i.e. without dividing by sqrt(2))"""
+
+    @staticmethod
+    def forward(ctx, u):
+        return _fast_hadamard_transform(u)
+
+    @staticmethod
+    def backward(ctx, grad):
+        return _fast_hadamard_transform(grad)
+
+
+def is_pow2(n):
+    return (n & (n - 1) == 0) and (n > 0)
+
+
+def get_hadK(n, transpose=False):
+    hadK, K = None, None
+    if n % 172 == 0:  # llama-2-7b up
+        assert is_pow2(n // 172)
+
+        K = 172
+        hadK = get_had172().T if transpose else get_had172()
+    elif n % 156 == 0:  # llama-1-30b 3x hidden
+        assert is_pow2(n // 156)
+
+        K = 156
+        hadK = get_had156().T if transpose else get_had156()
+    elif n % 140 == 0:  # llama-1-30b intermediate
+        assert is_pow2(n // 140)
+
+        K = 140
+        hadK = get_had140().T if transpose else get_had140()
+    elif n % 108 == 0:  # llama-1-13b intermediate
+        assert is_pow2(n // 108)
+
+        K = 108
+        hadK = get_had108().T if transpose else get_had108()
+    elif n % 60 == 0:  # llama-1-13b 3x hidden
+        assert is_pow2(n // 60)
+
+        K = 60
+        hadK = get_had60().T if transpose else get_had60()
+    elif n % 52 == 0:  # llama-1-13b 1x hidden
+        assert is_pow2(n // 52)
+
+        K = 52
+        hadK = get_had52().T if transpose else get_had52()
+    elif n % 36 == 0:
+        assert is_pow2(n // 36)
+
+        K = 36
+        hadK = get_had36().T if transpose else get_had36()
+    elif n % 28 == 0:
+        assert is_pow2(n // 28)
+
+        K = 28
+        hadK = get_had28().T if transpose else get_had28()
+    elif n % 44 == 0:
+        assert is_pow2(n // 44)
+
+        K = 44
+        hadK = get_had44().T if transpose else get_had44()
+    elif n % 40 == 0:
+        assert is_pow2(n // 40)
+
+        K = 40
+        hadK = get_had40().T if transpose else get_had40()
+    elif n % 20 == 0:
+        assert is_pow2(n // 20)
+
+        K = 20
+        hadK = get_had20().T if transpose else get_had20()
+    elif n % 12 == 0:
+        assert is_pow2(n // 12)
+
+        K = 12
+        hadK = get_had12().T if transpose else get_had12()
+    else:
+        assert is_pow2(n)
+
+        K = 1
+
+    return hadK, K
+
+
+def matmul_hadU_slow(X, hadK, K):
+    n = X.shape[-1]
+    input = X.clone().view(-1, n, 1)
+    output = input.clone()
+    while input.shape[1] > K:
+        input = input.view(input.shape[0], input.shape[1] // 2, 2, input.shape[2])
+        output = output.view(input.shape)
+        output[:, :, 0, :] = input[:, :, 0, :] + input[:, :, 1, :]
+        output[:, :, 1, :] = input[:, :, 0, :] - input[:, :, 1, :]
+        output = output.view(input.shape[0], input.shape[1], -1)
+        (input, output) = (output, input)
+    del output
+
+    if K > 1:
+        # Do not explicitly repeat - OOM
+        # input = torch.bmm(
+        #     hadK.repeat(len(input), 1, 1).to(input.device).to(input.dtype), input)
+        # Use bcast instead
+        input = hadK.view(1, K, K).to(input) @ input
+
+    return input.view(X.shape) / torch.tensor(n).sqrt()
+
+
+def matmul_hadU_fast(X, hadK, K):
+    n = X.shape[-1]
+    if K == 1:
+        return (
+            torch.ops.torchao.hadamard_transform.default(X.contiguous())
+            / torch.tensor(n).sqrt()
+        )
+    input = X.view(-1, K, n // K)
+    input = (
+        torch.ops.torchao.hadamard_transform.default(input.contiguous())
+        / torch.tensor(n).sqrt()
+    )
+    input = hadK.to(input.device).to(input.dtype) @ input
+    return input.reshape(X.shape)
+
+
+def random_hadamard_matrix(size, device, seed=0):
+    # See https://cornell-relaxml.github.io/quip-sharp/ , Section "Randomized Hadamard Transformation"
+    gen = torch.Generator()
+    gen.manual_seed(seed)
+    Q = torch.randint(low=0, high=2, size=(size,), generator=gen).to(torch.float64)
+    Q = Q * 2 - 1
+    Q = torch.diag(Q)
+    hadK, K = get_hadK(size)
+    return matmul_hadU_slow(Q, hadK, K).to(device)
+
+
+def hadamard_matrix(size, device):
+    # See https://cornell-relaxml.github.io/quip-sharp/ , Section "Randomized Hadamard Transformation"
+    Q = torch.eye(size)
+    hadK, K = get_hadK(size)
+    return matmul_hadU_slow(Q, hadK, K).to(device)
+
+
+def apply_exact_had_to_linear(module, had_dim=-1, output=False, R2=None):
+    assert isinstance(module, torch.nn.Linear)
+    in_features, out_features = module.in_features, module.out_features
+
+    if had_dim != -1:
+        assert is_pow2(had_dim), "Hadamard dimension must be a power of 2!"
+
+    W = module.weight.data
+    dtype_orig = W.dtype
+    W = W.float()
+
+    if had_dim == -1:
+        if output:
+            had_K, K = get_hadK(out_features)
+            W = matmul_hadU(W.t(), had_K.to(W.device), K).t()
+        else:
+            had_K, K = get_hadK(in_features)
+            W = matmul_hadU(W, had_K.to(W.device), K)
+    else:
+        if R2 is not None:
+            hadK = R2.to(torch.float64)
+        else:
+            hadK = hadamard_matrix(had_dim, W.device).to(torch.float64)
+
+        if output:
+            W = W.t()
+
+        shape = W.shape
+        temp = W.reshape(-1, shape[-1] // had_dim, had_dim)
+        temp = temp.to(torch.float64) @ hadK
+        W = temp.reshape(shape)
+
+        if output:
+            W = W.t()
+
+    module.weight.data = W.to(dtype=dtype_orig)
diff --git a/lib/python3.12/site-packages/torchao/prototype/spinquant/spinquant.py b/lib/python3.12/site-packages/torchao/prototype/spinquant/spinquant.py
new file mode 100644
index 0000000000000000000000000000000000000000..3c5733615a5703d5cbc180f533cf4cdf716ce38c
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/prototype/spinquant/spinquant.py
@@ -0,0 +1,294 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+"""
+SpinQuant implementation (https://arxiv.org/abs/2405.16406)
+
+Based on https://github.com/facebookresearch/SpinQuant
+"""
+
+import typing
+from pathlib import Path
+
+import torch
+from torch import nn
+
+from torchao._models.llama.model import RMSNorm, Transformer
+from torchao.prototype.spinquant.hadamard_utils import (
+    apply_exact_had_to_linear,
+    get_hadK,
+    matmul_hadU,
+    random_hadamard_matrix,
+)
+
+
+class HadamardMultiplier(nn.Module):
+    """Multiply the input by a Hadamard transform matrix."""
+
+    def __init__(self, had_K, K, use_fp32=False):
+        super().__init__()
+        assert had_K is not None, "had_K must be provided"
+        self.register_buffer("had_K", had_K)
+        self.K = K
+        self.use_fp32 = use_fp32
+
+    def forward(self, x):
+        if self.use_fp32:
+            x = matmul_hadU(x.float(), self.had_K, self.K).to(x.dtype)
+        else:
+            x = matmul_hadU(x, self.had_K, self.K)
+        return x
+
+
+def apply_spinquant(
+    model: Transformer,
+    use_r1=False,
+    use_r2=False,
+    use_r4=True,
+    pretrained_rotation_path=None,
+):
+    """
+    Apply SpinQuant to a Transformer model: https://arxiv.org/abs/2405.16406
+
+    Currently, the R1, R2, and R4 rotation matrices are implemented, and can be used independently
+    from each other. For R1 and R2, random Hadamard matrices are used. The default is to only use R4,
+    which appears to show best results in many cases (see https://github.com/pytorch/ao/pull/983).
+
+    Note that the R3 rotation matrix and Cayley optimization for R1/R2 are currently not implemented.
+    """
+    assert isinstance(model, Transformer), "Only Transformer models are supported"
+
+    original_device = next(model.parameters()).device
+    device = "cuda" if torch.cuda.is_available() else "cpu"
+    model.to(device=device)
+
+    # For testing purposes
+    # Weights link: https://drive.google.com/drive/folders/1nV9juzE6_OHr10y6Ke5KCyOiGqDr0srX
+    # pretrained_rotation_path = "7B_W4A16KV16_lr_1.5_seed_0/R.bin"
+
+    if pretrained_rotation_path is not None:
+        assert Path(pretrained_rotation_path).is_file(), (
+            "Pretrained rotation path does not exist"
+        )
+        assert Path(pretrained_rotation_path).suffix == ".bin", "Expected a .bin file."
+
+    if use_r1:
+        fuse_layernorm_into_linear(model)
+        apply_spinquant_r1(model, device, pretrained_rotation_path)
+    if use_r2:
+        apply_spinquant_r2(model, device, pretrained_rotation_path)
+    if use_r4:
+        apply_spinquant_r4(model, device)
+
+    model.to(device=original_device)
+
+
+def apply_spinquant_r1(model, device, pretrained_rotation_path=None):
+    """Apply the SpinQuant R1 rotation matrix to the model."""
+
+    if pretrained_rotation_path is not None:
+        R1 = torch.load(pretrained_rotation_path)["R1"].to(device).to(torch.float64)
+        assert R1.shape == (
+            model.config.dim,
+            model.config.dim,
+        ), f"{R1.shape} vs {model.config.dim}"
+    else:
+        R1 = random_hadamard_matrix(model.config.dim, device)
+
+    _rotate_model_r1(model, R1)
+
+
+def apply_spinquant_r2(model, device, pretrained_rotation_path=None):
+    """Apply the SpinQuant R2 rotation matrices to the model."""
+
+    R2s = []  # note that unlike R1, there are multiple R2 matrices (one per layer)
+    head_dim = model.config.head_dim
+    for i, _ in enumerate(model.layers):
+        if pretrained_rotation_path is not None:
+            key = f"model.layers.{i}.self_attn.R2"
+            R2s_ = torch.load(pretrained_rotation_path)
+            R2 = R2s_[key].to(device).to(torch.float64)
+            assert R2.shape == (
+                head_dim,
+                head_dim,
+            ), f"{R2.shape} != ({head_dim}, {head_dim})"
+        else:
+            R2 = random_hadamard_matrix(head_dim, device)
+        R2s.append(R2)
+
+    _rotate_model_r2(model, R2s)
+
+
+def apply_spinquant_r4(model, device):
+    """Apply the SpinQuant R4 rotation matrix to the model."""
+    _rotate_model_r4(model)
+    _add_activation_wrappers_r4(model)
+
+
+@torch.no_grad()
+def _fuse_layernorm_into_linear(
+    layernorm: RMSNorm, linear_layers: typing.Iterable[torch.nn.Linear]
+):
+    """Fuse the linear operations in Layernorm into the adjacent linear blocks."""
+    for linear in linear_layers:
+        linear_dtype = linear.weight.dtype
+
+        # Calculate new weight and bias values
+        W = linear.weight.data.double()
+        linear.weight.data = (W * layernorm.weight.double()).to(linear_dtype)
+
+        if hasattr(layernorm, "bias"):  # not true for RMSNorm
+            if linear.bias is None:
+                linear.bias = torch.nn.Parameter(
+                    torch.zeros(linear.out_features, dtype=torch.float64)
+                )
+            linear.bias.data = linear.bias.data.double() + torch.matmul(
+                W, layernorm.bias.double()
+            )
+            linear.bias.data = linear.bias.data.to(linear_dtype)
+
+    # Set the original layernorm scale parameters to 1 (identity transform)
+    layernorm.weight.data = torch.ones_like(layernorm.weight.data)
+
+
+@torch.no_grad()
+def _rotate_model_r1(model, R1):
+    _rotate_embeddings(model, R1)
+    _rotate_head(model, R1)
+
+    for layer in model.layers:
+        _rotate_attention_inputs(layer, R1)
+        _rotate_attention_output(layer, R1)
+        _rotate_mlp_input(layer, R1)
+        _rotate_mlp_output(layer, R1)
+
+
+@torch.no_grad()
+def _rotate_model_r2(model, R2s):
+    """Rotate the W_v and W_o weights of the multi-head self-attention modules."""
+
+    head_dim = model.config.head_dim
+
+    # Apply R2 rotation to all multi-head self-attention modules
+    for idx, layer in enumerate(model.layers):
+        attn = layer.attention
+
+        R2 = R2s[idx]
+
+        # Rotate W_o
+        apply_exact_had_to_linear(attn.wo, had_dim=head_dim, output=False, R2=R2)
+
+        # Extract W_v
+        kv_size = model.config.n_local_heads * head_dim
+        wq, wk, wv = attn.wqkv.weight.data.split(
+            [model.config.dim, kv_size, kv_size], dim=0
+        )
+        out_features, in_features = wv.shape
+        wv_mod = nn.Linear(
+            in_features,
+            out_features,
+            bias=attn.wqkv.bias is not None,
+            device=wv.device,
+            dtype=wv.dtype,
+        )
+        wv_mod.weight.data = wv
+
+        # Rotate W_v
+        apply_exact_had_to_linear(wv_mod, had_dim=head_dim, output=True, R2=R2)
+
+        attn.wqkv.weight.data = torch.cat([wq, wk, wv_mod.weight.data], dim=0)
+
+
+@torch.no_grad()
+def _rotate_model_r4(model):
+    """Rotate the MLP output weights."""
+
+    for layer in model.layers:
+        W = layer.feed_forward.w2
+        # print(f"Min/max before R4 rotation: {W.weight.data.min().item():.2f}/{W.weight.data.max().item():.2f}")
+        apply_exact_had_to_linear(
+            W, had_dim=-1, output=False
+        )  # apply exact (inverse) hadamard
+        # print(f"Min/max *after* R4 rotation: {W.weight.data.min().item():.2f}/{W.weight.data.max().item():.2f}")
+
+
+def _add_activation_wrappers_r4(model):
+    """Modify the forward pass to rotate the activations at specific points."""
+    # eval_utils/main.py:36
+    had_K, K = get_hadK(model.config.intermediate_size)
+    # print(f"K: {K}")
+    for layer in model.layers:
+        layer.feed_forward.w2 = nn.Sequential(
+            HadamardMultiplier(had_K, K, use_fp32=False), layer.feed_forward.w2
+        )
+
+
+@torch.no_grad()
+def fuse_layernorm_into_linear(model):
+    """
+    Fuse RMSNorm weights into the subsequent linear layers.
+
+    This is done in the paper specifically to make pre-norm LLMs like LLaMa
+    rotation-invariant when quantization is not present.
+    """
+    # Embedding fusion (from SpinQuant repo: utils/fuse_norm_utils.py:43)
+    # I currently don't understand why this is necessary, so I contacted the
+    # authors about it: https://github.com/facebookresearch/SpinQuant/issues/14
+    W = model.tok_embeddings
+    W_ = W.weight.data.double()
+    W.weight.data = (W_ - W_.mean(dim=-1, keepdim=True)).to(W.weight.data.dtype)
+
+    for layer in model.layers:
+        _fuse_layernorm_into_linear(
+            layer.ffn_norm, [layer.feed_forward.w1, layer.feed_forward.w3]
+        )
+        _fuse_layernorm_into_linear(layer.attention_norm, [layer.attention.wqkv])
+
+    _fuse_layernorm_into_linear(model.norm, [model.output])
+
+
+def _rotate_mlp_output(layer, R1):
+    mod = layer.feed_forward.w2
+    _rotate_mod_weight_left(mod, R1)
+    if mod.bias is not None:
+        b = mod.bias.data.to(dtype=torch.float64)
+        mod.bias.data = torch.matmul(R1.T, b).to(dtype=mod.weight.dtype)
+
+
+def _rotate_mlp_input(layer, R1):
+    _rotate_mod_weight_right(layer.feed_forward.w1, R1)
+    _rotate_mod_weight_right(layer.feed_forward.w3, R1)
+
+
+def _rotate_attention_output(layer, R1):
+    mod = layer.attention.wo
+    _rotate_mod_weight_left(mod, R1)
+    if mod.bias is not None:
+        b = mod.bias.data.to(dtype=torch.float64)
+        mod.bias.data = torch.matmul(R1.T, b).to(dtype=mod.weight.dtype)
+
+
+def _rotate_attention_inputs(layer, R1):
+    _rotate_mod_weight_right(layer.attention.wqkv, R1)
+
+
+def _rotate_head(model, R1):
+    _rotate_mod_weight_right(model.output, R1)
+
+
+def _rotate_embeddings(model, R1):
+    _rotate_mod_weight_right(model.tok_embeddings, R1)
+
+
+def _rotate_mod_weight_right(mod, R):
+    dtype = mod.weight.dtype
+    W = mod.weight.data.to(dtype=torch.float64)
+    mod.weight.data = torch.matmul(W, R).to(dtype=dtype)
+
+
+def _rotate_mod_weight_left(mod, R):
+    dtype = mod.weight.dtype
+    W = mod.weight.data.to(dtype=torch.float64)
+    mod.weight.data = torch.matmul(R.T, W).to(dtype=dtype)
diff --git a/lib/python3.12/site-packages/torchao/utils.py b/lib/python3.12/site-packages/torchao/utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..280da4e63278de77aa1f5fd930ea96d709dc289e
--- /dev/null
+++ b/lib/python3.12/site-packages/torchao/utils.py
@@ -0,0 +1,696 @@
+# Copyright (c) Meta Platforms, Inc. and affiliates.
+# All rights reserved.
+#
+# This source code is licensed under the BSD 3-Clause license found in the
+# LICENSE file in the root directory of this source tree.
+import functools
+import itertools
+import re
+import time
+from functools import reduce
+from importlib.metadata import version
+from math import gcd
+from typing import Any, Callable
+
+import torch
+import torch.nn.utils.parametrize as parametrize
+
+__all__ = [
+    "benchmark_model",
+    "profiler_runner",
+    "get_available_devices",
+    "get_compute_capability",
+    "benchmark_torch_function_in_microseconds",
+    "find_multiple",
+    "_register_custom_op",
+    "get_model_size_in_bytes",
+    "unwrap_tensor_subclass",
+    "TorchAOBaseTensor",
+    "TORCH_VERSION_AT_LEAST_2_2",
+    "TORCH_VERSION_AT_LEAST_2_3",
+    "TORCH_VERSION_AT_LEAST_2_4",
+    "TORCH_VERSION_AT_LEAST_2_5",
+    "TORCH_VERSION_AT_LEAST_2_6",
+    "TORCH_VERSION_AT_LEAST_2_7",
+    # Needs to be deprecated in the future
+    "TORCH_VERSION_AFTER_2_2",
+    "TORCH_VERSION_AFTER_2_3",
+    "TORCH_VERSION_AFTER_2_4",
+    "TORCH_VERSION_AFTER_2_5",
+    "is_MI300",
+    "is_sm_at_least_89",
+    "is_sm_at_least_90",
+]
+
+
+# Referenced from: https://github.com/pytorch/pytorch/blob/9105d54c6b37099575c0059ef274c86c4dc80c57/torch/ao/quantization/utils.py#L711
+def _assert_and_get_unique_device(module: torch.nn.Module) -> Any:
+    """
+    Returns the unique device for a module, or None if no device is found.
+    Throws an error if multiple devices are detected.
+    """
+    devices = {p.device for p in module.parameters()} | {
+        p.device for p in module.buffers()
+    }
+
+    assert len(devices) <= 1, (
+        "prepare only works with cpu or single-device CUDA modules, "
+        f"but got devices {devices}"
+    )
+    device = next(iter(devices)) if len(devices) > 0 else None
+    return device
+
+
+def benchmark_model(model, num_runs, args=(), kwargs=None, device_type=None):
+    """Benchmark model runs with `args` and `kwargs` both are optional"""
+    if kwargs is None:
+        kwargs = {}
+
+    if device_type is None:
+        assert isinstance(model, torch.nn.Module), (
+            "Expecting `model` to be torch.nn.Module if device_type is not provided"
+        )
+        device_type = _assert_and_get_unique_device(model).type
+
+    if device_type == "cuda":
+        torch.cuda.synchronize()
+        start_event = torch.cuda.Event(enable_timing=True)
+        end_event = torch.cuda.Event(enable_timing=True)
+        start_event.record()
+
+        # benchmark
+        for _ in range(num_runs):
+            with torch.autograd.profiler.record_function("timed region"):
+                model(*args, **kwargs)
+
+        end_event.record()
+        torch.cuda.synchronize()
+        return start_event.elapsed_time(end_event) / num_runs
+
+    elif device_type == "mps":
+        torch.mps.synchronize()
+        start_event = torch.mps.event.Event(enable_timing=True)
+        end_event = torch.mps.event.Event(enable_timing=True)
+        start_event.record()
+
+        # benchmark
+        for _ in range(num_runs):
+            with torch.autograd.profiler.record_function("timed region"):
+                model(*args, **kwargs)
+
+        end_event.record()
+        torch.mps.synchronize()
+        return start_event.elapsed_time(end_event) / num_runs
+
+    elif device_type == "cpu":
+        torch.cpu.synchronize()
+        start_time = time.time()
+
+        # benchmark
+        for _ in range(num_runs):
+            with torch.autograd.profiler.record_function("timed region"):
+                model(*args, **kwargs)
+
+        end_time = time.time()
+        torch.cpu.synchronize()
+        average_time_per_run = (end_time - start_time) / num_runs
+        return average_time_per_run
+
+
+def profiler_runner(path, fn, *args, **kwargs):
+    with torch.profiler.profile(
+        activities=[
+            torch.profiler.ProfilerActivity.CPU,
+            torch.profiler.ProfilerActivity.CUDA,
+        ],
+        record_shapes=True,
+    ) as prof:
+        result = fn(*args, **kwargs)
+    prof.export_chrome_trace(path)
+    return result
+
+
+def get_available_devices():
+    devices = ["cpu"]
+    if torch.cuda.is_available():
+        devices.append("cuda")
+    elif torch.xpu.is_available():
+        devices.append("xpu")
+    if TORCH_VERSION_AT_LEAST_2_5:
+        if torch.mps.is_available():
+            devices.append("mps")
+    return devices
+
+
+def get_compute_capability():
+    if torch.cuda.is_available():
+        capability = torch.cuda.get_device_capability()
+        return float(f"{capability[0]}.{capability[1]}")
+    return 0.0
+
+
+def compute_max_diff(output: torch.Tensor, output_ref: torch.Tensor) -> torch.Tensor:
+    return torch.mean(torch.abs(output - output_ref)) / torch.mean(
+        torch.abs(output_ref)
+    )
+
+
+def benchmark_torch_function_in_microseconds(f, *args, **kwargs):
+    import torch.utils.benchmark as benchmark  # this avoids importing numpy when torchao module is loaded
+
+    # Manual warmup
+    f(*args, **kwargs)
+    f(*args, **kwargs)
+
+    t0 = benchmark.Timer(
+        stmt="f(*args, **kwargs)",
+        globals={"args": args, "kwargs": kwargs, "f": f},  # noqa: E501
+    )
+    measurement = t0.blocked_autorange()
+    return measurement.mean * 1e6
+
+
+def find_multiple(n: int, *args: int) -> int:
+    k: int = reduce(lambda x, y: x * y // gcd(x, y), args + (1,))  # type: ignore[9]
+    if n % k == 0:
+        return n
+    return n + k - (n % k)
+
+
+def _register_custom_op(lib):
+    """This decorator is used to preserve some high level operators for torch.export.export
+    while still allow them to be decomposed for inductor path
+
+    requirement: make sure `fn.__name__[1:]` is the operator name you want to register
+
+    NOTE: This should be applied at the top, after all other decorators have been applied
+    NOTE: We haven't tested the case when `fn` accepts tensor subclass instance as input,
+    e.g. uint4 tensor subclass instance, and we'll probably need to figure out what would make
+    sense for downstream system (like executorch) to accept as well
+
+    Example:
+        lib = torch.library.Library("my_namespace', "FRAGMENT")
+
+        register_custom_op = _register_custom_op(lib)
+
+        @register_custom_op
+        def _the_op_that_needs_to_be_preserved(...)
+            ...
+
+        # after this, `_the_op_that_needs_to_be_preserved` will be preserved as
+        # torch.ops.my_namespace.the_op_that_needs_to_be_preserved operator after
+        # torch.export.export / torch._export.export_for_training
+
+    """
+    from torch._inductor.decomposition import register_decomposition
+
+    def decorator(fn):
+        if TORCH_VERSION_AT_LEAST_2_5:
+            from torch._library.infer_schema import infer_schema
+
+            # expecting fn.__name__ starts with `_` and we want to take the rest
+            # to be the name of the custom op
+            assert fn.__name__[0] == "_", (
+                f"Expecting function name starts with `_`, got {fn.__name__}"
+            )
+            assert not any(c in fn.__name__ for c in ".<>"), (
+                f"Expecting op to be defined in normal functions, not lambda or local: {fn.__name__}"
+            )
+            op_name = fn.__name__[1:]
+            schema = op_name + infer_schema(fn, mutates_args={})
+            lib.define(schema)
+            lib.impl(op_name, fn, "CompositeImplicitAutograd")
+
+            lib_namespace = lib.ns
+            op = getattr(getattr(torch.ops, lib_namespace), op_name)
+            register_decomposition([op])(fn)
+            return op
+        else:
+            return fn
+
+    return decorator
+
+
+def get_model_size_in_bytes(model, ignore_embeddings=False):
+    """
+    Returns the model size in bytes. The option to ignore embeddings
+    is useful for models with disproportionately large embeddings compared
+    to other model parameters that get quantized/sparsified.
+    """
+
+    def flat_size(tensor):
+        if hasattr(tensor, "__tensor_flatten__"):
+            size = 0
+            # 0th element is a list of attributes that
+            # hold tensors
+            for attr_name in tensor.__tensor_flatten__()[0]:
+                sub_tensor = getattr(tensor, attr_name)
+                size += flat_size(sub_tensor)
+            return size
+        else:
+            return tensor.numel() * tensor.element_size()
+
+    model_size = 0
+    for name, child in model.named_children():
+        if not (isinstance(child, torch.nn.Embedding) and ignore_embeddings):
+            for p in itertools.chain(
+                child.parameters(recurse=False), child.buffers(recurse=False)
+            ):
+                model_size += flat_size(p)
+            model_size += get_model_size_in_bytes(child, ignore_embeddings)
+    return model_size
+
+
+class UnwrapTensorSubclass(torch.nn.Module):
+    def forward(self, *tensors):
+        todo = list(tensors)
+        for tp, meta, inner_tensors in reversed(self.rebuild_stack):
+            nb_tensor = len(inner_tensors)
+            inner_tensors = {a: b for a, b in zip(inner_tensors, todo[-nb_tensor:])}
+            todo = todo[nb_tensor:]
+            rebuilt = tp.__tensor_unflatten__(inner_tensors, meta, None, None)
+            todo.append(rebuilt)
+
+        assert len(todo) == 1
+        return todo[0]
+
+    def right_inverse(self, tensor):
+        assert type(tensor) is not torch.Tensor
+        rebuild_stack = []
+        plain_tensors = []
+        todo = [tensor]
+        while todo:
+            obj = todo.pop()
+            inner_tensors, metadata = obj.__tensor_flatten__()
+            rebuild_stack.append((type(obj), metadata, inner_tensors))
+            for attr_name in inner_tensors:
+                val = getattr(obj, attr_name)
+                if type(val) is torch.Tensor:
+                    plain_tensors.append(val)
+                else:
+                    assert isinstance(val, torch.Tensor)
+                    todo.append(val)
+
+        self.rebuild_stack = rebuild_stack
+
+        return plain_tensors
+
+
+def unwrap_tensor_subclass(model, filter_fn=None):
+    """Unwraps (nested) tensor subclass in the model to plain tensors
+    This is a workaround to make a model with tensor subclass to work with `torch.export.export`
+    and `torch.aot_compile`, we hope this can be integrated into compile stack soon
+    tracking issue: https://github.com/pytorch/ao/issues/345
+    """
+    for name, child in model.named_children():
+        # make sure child.weight is a tensor subclass
+        if (
+            (
+                isinstance(child, torch.nn.Linear)
+                or isinstance(child, torch.nn.Embedding)
+            )
+            and hasattr(child, "weight")
+            and type(child.weight) is not torch.Tensor
+            and type(child.weight) is not torch.nn.Parameter
+            and isinstance(child.weight, torch.Tensor)
+            and issubclass(type(child.weight), torch.Tensor)
+            and isinstance(child.weight, TorchAOBaseTensor)
+            and not parametrize.is_parametrized(child)
+        ):
+            parametrize.register_parametrization(
+                child, "weight", UnwrapTensorSubclass()
+            )
+        unwrap_tensor_subclass(child)
+    return model
+
+
+def _is_float8_type(dtype: torch.dtype) -> bool:
+    fp8_types = {
+        torch.float8_e4m3fn,
+        torch.float8_e4m3fnuz,
+        torch.float8_e5m2,
+        torch.float8_e5m2fnuz,
+    }
+    return dtype in fp8_types
+
+
+def parse_version(version_string):
+    # Extract just the X.Y.Z part from the version string
+    match = re.match(r"(\d+\.\d+\.\d+)", version_string)
+    if match:
+        version = match.group(1)
+        return [int(x) for x in version.split(".")]
+    else:
+        raise ValueError(f"Invalid version string format: {version_string}")
+
+
+def compare_versions(v1, v2):
+    v1_parts = parse_version(v1)
+    v2_parts = parse_version(v2)
+    return (v1_parts > v2_parts) - (v1_parts < v2_parts)
+
+
+def is_fbcode():
+    return not hasattr(torch.version, "git_version")
+
+
+def torch_version_at_least(min_version):
+    return is_fbcode() or compare_versions(torch.__version__, min_version) >= 0
+
+
+TORCH_VERSION_AT_LEAST_2_8 = torch_version_at_least("2.8.0")
+TORCH_VERSION_AT_LEAST_2_7 = torch_version_at_least("2.7.0")
+TORCH_VERSION_AT_LEAST_2_6 = torch_version_at_least("2.6.0")
+TORCH_VERSION_AT_LEAST_2_5 = torch_version_at_least("2.5.0")
+TORCH_VERSION_AT_LEAST_2_4 = torch_version_at_least("2.4.0")
+TORCH_VERSION_AT_LEAST_2_3 = torch_version_at_least("2.3.0")
+TORCH_VERSION_AT_LEAST_2_2 = torch_version_at_least("2.2.0")
+
+
+"""
+Helper function for implementing aten op or torch function dispatch
+and dispatching to these implementations.
+"""
+
+
+def _implements(cls, aten_ops_or_torch_fns):
+    """Use this decorator to implement a function for an aten ops in __torch_dispatch__
+    (if user passed in a list of ops)
+    or torch function in __torch_function__ (if user passed in a single object)
+
+    class MyTensor(torch.Tensor):
+        ...
+        implements = classmethod(_implements)
+
+    implements = MyTensor.implements
+
+    @implements(torch.nn.functional.linear):
+    def _(func, types, args, kwargs):
+        ...
+
+    """
+    if not hasattr(cls, "_ATEN_OP_OR_TORCH_FN_TABLE"):
+        cls._ATEN_OP_OR_TORCH_FN_TABLE = {}
+
+    if not isinstance(aten_ops_or_torch_fns, (list, tuple)):
+        aten_ops_or_torch_fns = [aten_ops_or_torch_fns]
+
+    def decorator(func):
+        for op in aten_ops_or_torch_fns:
+
+            @functools.wraps(op)
+            def wrapper(f, types, args, kwargs):
+                return func(f, types, args, kwargs)
+
+            cls._ATEN_OP_OR_TORCH_FN_TABLE[op] = wrapper
+        return func
+
+    return decorator
+
+
+def _dispatch__torch_function__(cls, func, types, args=(), kwargs=None):
+    """Use this util function for a common `__torch_function__` implementation
+    that dispatches to ops/functions registered with `_implements`
+
+    class MyTensor(torch.Tensor):
+        ...
+        __torch_function__ = classmethod(_dispatch__torch_function__)
+    """
+    kwargs = {} if kwargs is None else kwargs
+    if (
+        hasattr(cls, "_ATEN_OP_OR_TORCH_FN_TABLE")
+        and func in cls._ATEN_OP_OR_TORCH_FN_TABLE
+    ):
+        return cls._ATEN_OP_OR_TORCH_FN_TABLE[func](func, types, args, kwargs)
+
+    with torch._C.DisableTorchFunctionSubclass():
+        return func(*args, **kwargs)
+
+
+def _dispatch__torch_dispatch__(cls, func, types, args, kwargs):
+    """Use this util function for a common `__torch_dispatch__` implementation
+    that dispatches to ops/functions registered with `_implements`
+
+    class MyTensor(torch.Tensor):
+        ...
+        __torch_dispatch__ = classmethod(_dispatch__torch_dispatch__)
+    """
+    if (
+        hasattr(cls, "_ATEN_OP_OR_TORCH_FN_TABLE")
+        and func in cls._ATEN_OP_OR_TORCH_FN_TABLE
+    ):
+        return cls._ATEN_OP_OR_TORCH_FN_TABLE[func](func, types, args, kwargs)
+
+    arg_types = tuple(type(arg) for arg in args)
+    kwarg_types = {k: type(arg) for k, arg in kwargs.items()}
+    raise NotImplementedError(
+        f"{cls.__name__} dispatch: attempting to run unimplemented operator/function: {func=}, {types=}, {arg_types=}, {kwarg_types=}"
+    )
+
+
+def _register_layout(tensor_class: Callable, layout_class: Callable):
+    """Helper function for layout registrations, this is used to implement
+    register_layout decorator for each tensor subclass, see aqt.py for example usage
+
+    Args:
+        tensor_class: Tensor subclass type
+        layout_class: the class type of subclass of `Layout`, e.g. `PlainLayout`
+
+    Returns:
+        a decorator that registers the tensor impl constructor in the table
+    """
+
+    # tensor_class._LAYOUT_CONSTRUCTOR_TABLE is a map from layout_class like TensorCoreTiledLayout
+    # to tensor_impl class constructor like TensorCoreTiledAQTTensorImpl.from_plain that can construct a tensor_impl
+    # from plain data like (quantized, unpacked) `data`, `scale`, `zero_point`
+    if not hasattr(tensor_class, "_LAYOUT_CONSTRUCTOR_TABLE"):
+        tensor_class._LAYOUT_CONSTRUCTOR_TABLE = {}
+
+    def decorator(tensor_impl_class):
+        tensor_class._LAYOUT_CONSTRUCTOR_TABLE[layout_class] = (
+            tensor_impl_class.from_plain
+        )
+        if TORCH_VERSION_AT_LEAST_2_5:
+            # Allow serialization to work for models uses this tensor impl subclass
+            torch.serialization.add_safe_globals([layout_class, tensor_impl_class])
+        return tensor_impl_class
+
+    return decorator
+
+
+def _get_tensor_impl_constructor(
+    tensor_class: Callable, layout_class: Callable
+) -> Callable:
+    """Get TensorImpl class constructor (TensorImplClass.from_plain) for `tensor_class` based on `layout_class`
+    `layout_class` means the class type of subclass of `Layout`, e.g. `PlainLayout`
+
+    Args:
+        tensor_class: Tensor subclass type
+        layout_class: the class type of subclass of `Layout`, e.g. `PlainLayout`
+
+    Returns:
+        tensor impl subclass constructor for the layout_class
+    """
+    if not hasattr(tensor_class, "_LAYOUT_CONSTRUCTOR_TABLE"):
+        raise ValueError(
+            f"no registered tensor_impl class constructor for: {tensor_class}"
+        )
+    if layout_class not in tensor_class._LAYOUT_CONSTRUCTOR_TABLE:
+        raise ValueError(
+            f"layout_name: {layout_class} is not supported yet for {tensor_class}"
+        )
+
+    return tensor_class._LAYOUT_CONSTRUCTOR_TABLE[layout_class]
+
+
+def _get_to_kwargs(self, *args, **kwargs):
+    # `torch._C._nn._parse_to` can't handle `layout` argument
+    for arg in args:
+        if isinstance(arg, torch.layout):
+            args.remove(arg)
+    if "layout" in kwargs:
+        kwargs.pop("layout")
+    # ignoring `non_blocking` and `memory_format` args since these are not
+    # very useful for most of the tensor subclasses
+    # if in the future there are use cases that need these, we'd recommend
+    # to override `_get_to_kwargs` and return these args
+    device, dtype, _, _ = torch._C._nn._parse_to(*args, **kwargs)
+    device = self.device if device is None else device
+    dtype = self.dtype if dtype is None else dtype
+    kwargs = {
+        "device": device,
+        "dtype": dtype,
+    }
+    return kwargs
+
+
+class TorchAOBaseTensor(torch.Tensor):
+    """A util tensor subclass that provides commonly used functions
+       new tensor subclass can inherit it to get all the utility functions
+
+       class MyTensor(TorchAOBaseTensor):
+           pass
+
+    This includes:
+       `_get_to_kwargs` that can get the kwargs for `to`
+            class MyTensor(TorchAOBaseTensor):
+                def to(self, *args, **kwargs):
+                    kwargs = _get_to_kwargs(*args, **kwargs)
+                    ...
+        `implements`:
+            implements = MyTensor.implements
+
+            @implements(torch.nn.functional.linear):
+            def _(func, types, args, kwargs):
+                ...
+
+        `register_layout`:
+            register_layout = MyTensor.register_layout
+
+            @register_layout(PlainLayout)
+            class PlainAQTTensorImpl(...):
+                ...
+
+         `get_tensor_impl_constructor`:
+            get_tensor_impl_constructor = MyTensor.get_tensor_impl_constructor
+            # in constructor of MyTensor:
+            tensor_impl_ctr = get_tensor_impl_constructor(type(_layout))
+            tensor_impl = tensor_impl_ctr(data, scale, zero_point, _layout)
+
+    """
+
+    implements = classmethod(_implements)
+    __torch_dispatch__ = classmethod(_dispatch__torch_dispatch__)
+    __torch_function__ = classmethod(_dispatch__torch_function__)
+    register_layout = classmethod(_register_layout)
+    get_tensor_impl_constructor = classmethod(_get_tensor_impl_constructor)
+    _get_to_kwargs = _get_to_kwargs
+
+    def __tensor_flatten__(self):
+        raise NotImplementedError("Subclasses must implement __tensor_flatten__")
+
+    @classmethod
+    def __tensor_unflatten__(
+        cls, tensor_data_dict, tensor_attributes, outer_size, outer_stride
+    ):
+        raise NotImplementedError("Subclasses must implement __tensor_unflatten__")
+
+    def __repr__(self):
+        raise NotImplementedError("Subclasses must implement __repr__")
+
+    def get_layout(self):
+        if not hasattr(self, "_layout"):
+            return None
+        return self._layout
+
+
+def fill_defaults(args, n, defaults_tail):
+    """
+    __torch_dispatch__ doesn't guarantee the number of arguments you are
+    passed (e.g., defaulted arguments are not passed); but usually it is
+    convenient to pad out the arguments list with defaults.  This function
+    helps you do that.
+    Args:
+        args: the list of positional arguments passed to __torch_dispatch__
+        n: the number of arguments you are expecting to get
+        defaults_tail: default values for the arguments, starting from the
+            end of the list
+    Example:
+        >>> fill_defaults([1, 2, 3], 5, [3, 4, 5])
+        [1, 2, 3, 4, 5]
+        >>> fill_defaults([1, 2, 3], 5, [None, None, None])
+        [1, 2, 3, None, None]]
+    """
+    if n - len(defaults_tail) > len(args):
+        raise RuntimeError("not enough defaults to fill arguments")
+    r = list(args)
+    for i in range(len(args), n):
+        r.append(defaults_tail[i - n + len(defaults_tail)])
+    return r
+
+
+## Deprecated, will be deleted in the future
+def _torch_version_at_least(min_version):
+    return is_fbcode() or version("torch") >= min_version
+
+
+# Supported AMD GPU Models and their LLVM gfx Codes:
+#
+# | AMD GPU Model | LLVM gfx Code          |
+# |---------------|------------------------|
+# | Navi4         | gfx1200, gfx1201       |
+# | MI300X        | gfx940, gfx941, gfx942 |
+# | MI350         | gfx950                 |
+
+
+def is_ROCM():
+    return torch.cuda.is_available() and torch.version.hip
+
+
+def is_MI300():
+    if is_ROCM():
+        mxArchName = ["gfx940", "gfx941", "gfx942"]
+        archName = torch.cuda.get_device_properties(0).gcnArchName
+        for arch in mxArchName:
+            if arch in archName:
+                return True
+    return False
+
+
+def is_MI350():
+    if is_ROCM():
+        archName = torch.cuda.get_device_properties(0).gcnArchName
+        if "gfx950" in archName:
+            return True
+    return False
+
+
+def is_Navi4():
+    if is_ROCM():
+        archName = torch.cuda.get_device_properties(0).gcnArchName
+        if "gfx1200" or "gfx1201" in archName:
+            return True
+    return False
+
+
+def is_sm_at_least_89():
+    return (
+        torch.cuda.is_available()
+        and torch.version.cuda
+        and torch.cuda.get_device_capability() >= (8, 9)
+    )
+
+
+def is_sm_at_least_90():
+    return (
+        torch.cuda.is_available()
+        and torch.version.cuda
+        and torch.cuda.get_device_capability() >= (9, 0)
+    )
+
+
+# TODO(future PR): rename to 8_9, 9_0, 10_0 instead of 89, 10, 100
+def is_sm_at_least_100():
+    return (
+        torch.cuda.is_available()
+        and torch.version.cuda
+        and torch.cuda.get_device_capability() >= (10, 0)
+    )
+
+
+def check_cpu_version(device, version="2.6.0"):
+    if isinstance(device, torch.device):
+        device = device.type
+    return device == "cpu" and compare_versions(torch.__version__, version) >= 0
+
+
+def check_xpu_version(device, version="2.8.0"):
+    if isinstance(device, torch.device):
+        device = device.type
+    return device == "xpu" and compare_versions(torch.__version__, version) >= 0
+
+
+TORCH_VERSION_AFTER_2_5 = _torch_version_at_least("2.5.0.dev")
+TORCH_VERSION_AFTER_2_4 = _torch_version_at_least("2.4.0.dev")
+TORCH_VERSION_AFTER_2_3 = _torch_version_at_least("2.3.0.dev")
+TORCH_VERSION_AFTER_2_2 = _torch_version_at_least("2.2.0.dev")
diff --git a/lib/python3.12/site-packages/uvloop/__init__.py b/lib/python3.12/site-packages/uvloop/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9bb6592b824bfa2e21d5c2024627effc67fa501f
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/__init__.py
@@ -0,0 +1,168 @@
+import asyncio as __asyncio
+import typing as _typing
+import sys as _sys
+import warnings as _warnings
+
+from asyncio.events import BaseDefaultEventLoopPolicy as __BasePolicy
+
+from . import includes as __includes  # NOQA
+from .loop import Loop as __BaseLoop  # NOQA
+from ._version import __version__  # NOQA
+
+
+__all__ = ('new_event_loop', 'install', 'EventLoopPolicy')
+
+
+_T = _typing.TypeVar("_T")
+
+
+class Loop(__BaseLoop, __asyncio.AbstractEventLoop):  # type: ignore[misc]
+    pass
+
+
+def new_event_loop() -> Loop:
+    """Return a new event loop."""
+    return Loop()
+
+
+def install() -> None:
+    """A helper function to install uvloop policy."""
+    if _sys.version_info[:2] >= (3, 12):
+        _warnings.warn(
+            'uvloop.install() is deprecated in favor of uvloop.run() '
+            'starting with Python 3.12.',
+            DeprecationWarning,
+            stacklevel=1,
+        )
+    __asyncio.set_event_loop_policy(EventLoopPolicy())
+
+
+if _typing.TYPE_CHECKING:
+    def run(
+        main: _typing.Coroutine[_typing.Any, _typing.Any, _T],
+        *,
+        loop_factory: _typing.Optional[
+            _typing.Callable[[], Loop]
+        ] = new_event_loop,
+        debug: _typing.Optional[bool]=None,
+    ) -> _T:
+        """The preferred way of running a coroutine with uvloop."""
+else:
+    def run(main, *, loop_factory=new_event_loop, debug=None, **run_kwargs):
+        """The preferred way of running a coroutine with uvloop."""
+
+        async def wrapper():
+            # If `loop_factory` is provided we want it to return
+            # either uvloop.Loop or a subtype of it, assuming the user
+            # is using `uvloop.run()` intentionally.
+            loop = __asyncio._get_running_loop()
+            if not isinstance(loop, Loop):
+                raise TypeError('uvloop.run() uses a non-uvloop event loop')
+            return await main
+
+        vi = _sys.version_info[:2]
+
+        if vi <= (3, 10):
+            # Copied from python/cpython
+
+            if __asyncio._get_running_loop() is not None:
+                raise RuntimeError(
+                    "asyncio.run() cannot be called from a running event loop")
+
+            if not __asyncio.iscoroutine(main):
+                raise ValueError(
+                    "a coroutine was expected, got {!r}".format(main)
+                )
+
+            loop = loop_factory()
+            try:
+                __asyncio.set_event_loop(loop)
+                if debug is not None:
+                    loop.set_debug(debug)
+                return loop.run_until_complete(wrapper())
+            finally:
+                try:
+                    _cancel_all_tasks(loop)
+                    loop.run_until_complete(loop.shutdown_asyncgens())
+                    if hasattr(loop, 'shutdown_default_executor'):
+                        loop.run_until_complete(
+                            loop.shutdown_default_executor()
+                        )
+                finally:
+                    __asyncio.set_event_loop(None)
+                    loop.close()
+
+        elif vi == (3, 11):
+            if __asyncio._get_running_loop() is not None:
+                raise RuntimeError(
+                    "asyncio.run() cannot be called from a running event loop")
+
+            with __asyncio.Runner(
+                loop_factory=loop_factory,
+                debug=debug,
+                **run_kwargs
+            ) as runner:
+                return runner.run(wrapper())
+
+        else:
+            assert vi >= (3, 12)
+            return __asyncio.run(
+                wrapper(),
+                loop_factory=loop_factory,
+                debug=debug,
+                **run_kwargs
+            )
+
+
+def _cancel_all_tasks(loop: __asyncio.AbstractEventLoop) -> None:
+    # Copied from python/cpython
+
+    to_cancel = __asyncio.all_tasks(loop)
+    if not to_cancel:
+        return
+
+    for task in to_cancel:
+        task.cancel()
+
+    loop.run_until_complete(
+        __asyncio.gather(*to_cancel, return_exceptions=True)
+    )
+
+    for task in to_cancel:
+        if task.cancelled():
+            continue
+        if task.exception() is not None:
+            loop.call_exception_handler({
+                'message': 'unhandled exception during asyncio.run() shutdown',
+                'exception': task.exception(),
+                'task': task,
+            })
+
+
+class EventLoopPolicy(__BasePolicy):
+    """Event loop policy.
+
+    The preferred way to make your application use uvloop:
+
+    >>> import asyncio
+    >>> import uvloop
+    >>> asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
+    >>> asyncio.get_event_loop()
+    
+    """
+
+    def _loop_factory(self) -> Loop:
+        return new_event_loop()
+
+    if _typing.TYPE_CHECKING:
+        # EventLoopPolicy doesn't implement these, but since they are marked
+        # as abstract in typeshed, we have to put them in so mypy thinks
+        # the base methods are overridden. This is the same approach taken
+        # for the Windows event loop policy classes in typeshed.
+        def get_child_watcher(self) -> _typing.NoReturn:
+            ...
+
+        def set_child_watcher(
+            self, watcher: _typing.Any
+        ) -> _typing.NoReturn:
+            ...
diff --git a/lib/python3.12/site-packages/uvloop/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/uvloop/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ba7958bfb32a05ddcf3bb654c6dd21a0450e566f
Binary files /dev/null and b/lib/python3.12/site-packages/uvloop/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/uvloop/__pycache__/_noop.cpython-312.pyc b/lib/python3.12/site-packages/uvloop/__pycache__/_noop.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..73cc2566a194dbe70918cf6d131cfbcef3bdb6ca
Binary files /dev/null and b/lib/python3.12/site-packages/uvloop/__pycache__/_noop.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/uvloop/__pycache__/_testbase.cpython-312.pyc b/lib/python3.12/site-packages/uvloop/__pycache__/_testbase.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..74993d41b89465dc7910aeb3a7687ff25383caba
Binary files /dev/null and b/lib/python3.12/site-packages/uvloop/__pycache__/_testbase.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/uvloop/__pycache__/_version.cpython-312.pyc b/lib/python3.12/site-packages/uvloop/__pycache__/_version.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..99c92e01dade6a49d75b2e396741dec1ea1e7bf9
Binary files /dev/null and b/lib/python3.12/site-packages/uvloop/__pycache__/_version.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/uvloop/_noop.py b/lib/python3.12/site-packages/uvloop/_noop.py
new file mode 100644
index 0000000000000000000000000000000000000000..bfc14dccbb926df611d002a4a7620510a55d8be6
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/_noop.py
@@ -0,0 +1,3 @@
+def noop() -> None:
+    """Empty function to invoke CPython ceval loop."""
+    return
diff --git a/lib/python3.12/site-packages/uvloop/_testbase.py b/lib/python3.12/site-packages/uvloop/_testbase.py
new file mode 100644
index 0000000000000000000000000000000000000000..e620e1584546dc62fc367a6c502fc82f894addea
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/_testbase.py
@@ -0,0 +1,552 @@
+"""Test utilities. Don't use outside of the uvloop project."""
+
+
+import asyncio
+import asyncio.events
+import collections
+import contextlib
+import gc
+import logging
+import os
+import pprint
+import re
+import select
+import socket
+import ssl
+import sys
+import tempfile
+import threading
+import time
+import unittest
+import uvloop
+
+
+class MockPattern(str):
+    def __eq__(self, other):
+        return bool(re.search(str(self), other, re.S))
+
+
+class TestCaseDict(collections.UserDict):
+
+    def __init__(self, name):
+        super().__init__()
+        self.name = name
+
+    def __setitem__(self, key, value):
+        if key in self.data:
+            raise RuntimeError('duplicate test {}.{}'.format(
+                self.name, key))
+        super().__setitem__(key, value)
+
+
+class BaseTestCaseMeta(type):
+
+    @classmethod
+    def __prepare__(mcls, name, bases):
+        return TestCaseDict(name)
+
+    def __new__(mcls, name, bases, dct):
+        for test_name in dct:
+            if not test_name.startswith('test_'):
+                continue
+            for base in bases:
+                if hasattr(base, test_name):
+                    raise RuntimeError(
+                        'duplicate test {}.{} (also defined in {} '
+                        'parent class)'.format(
+                            name, test_name, base.__name__))
+
+        return super().__new__(mcls, name, bases, dict(dct))
+
+
+class BaseTestCase(unittest.TestCase, metaclass=BaseTestCaseMeta):
+
+    def new_loop(self):
+        raise NotImplementedError
+
+    def new_policy(self):
+        raise NotImplementedError
+
+    def mock_pattern(self, str):
+        return MockPattern(str)
+
+    async def wait_closed(self, obj):
+        if not isinstance(obj, asyncio.StreamWriter):
+            return
+        try:
+            await obj.wait_closed()
+        except (BrokenPipeError, ConnectionError):
+            pass
+
+    def is_asyncio_loop(self):
+        return type(self.loop).__module__.startswith('asyncio.')
+
+    def run_loop_briefly(self, *, delay=0.01):
+        self.loop.run_until_complete(asyncio.sleep(delay))
+
+    def loop_exception_handler(self, loop, context):
+        self.__unhandled_exceptions.append(context)
+        self.loop.default_exception_handler(context)
+
+    def setUp(self):
+        self.loop = self.new_loop()
+        asyncio.set_event_loop_policy(self.new_policy())
+        asyncio.set_event_loop(self.loop)
+        self._check_unclosed_resources_in_debug = True
+
+        self.loop.set_exception_handler(self.loop_exception_handler)
+        self.__unhandled_exceptions = []
+
+    def tearDown(self):
+        self.loop.close()
+
+        if self.__unhandled_exceptions:
+            print('Unexpected calls to loop.call_exception_handler():')
+            pprint.pprint(self.__unhandled_exceptions)
+            self.fail('unexpected calls to loop.call_exception_handler()')
+            return
+
+        if not self._check_unclosed_resources_in_debug:
+            return
+
+        # GC to show any resource warnings as the test completes
+        gc.collect()
+        gc.collect()
+        gc.collect()
+
+        if getattr(self.loop, '_debug_cc', False):
+            gc.collect()
+            gc.collect()
+            gc.collect()
+
+            self.assertEqual(
+                self.loop._debug_uv_handles_total,
+                self.loop._debug_uv_handles_freed,
+                'not all uv_handle_t handles were freed')
+
+            self.assertEqual(
+                self.loop._debug_cb_handles_count, 0,
+                'not all callbacks (call_soon) are GCed')
+
+            self.assertEqual(
+                self.loop._debug_cb_timer_handles_count, 0,
+                'not all timer callbacks (call_later) are GCed')
+
+            self.assertEqual(
+                self.loop._debug_stream_write_ctx_cnt, 0,
+                'not all stream write contexts are GCed')
+
+            for h_name, h_cnt in self.loop._debug_handles_current.items():
+                with self.subTest('Alive handle after test',
+                                  handle_name=h_name):
+                    self.assertEqual(
+                        h_cnt, 0,
+                        'alive {} after test'.format(h_name))
+
+            for h_name, h_cnt in self.loop._debug_handles_total.items():
+                with self.subTest('Total/closed handles',
+                                  handle_name=h_name):
+                    self.assertEqual(
+                        h_cnt, self.loop._debug_handles_closed[h_name],
+                        'total != closed for {}'.format(h_name))
+
+        asyncio.set_event_loop(None)
+        asyncio.set_event_loop_policy(None)
+        self.loop = None
+
+    def skip_unclosed_handles_check(self):
+        self._check_unclosed_resources_in_debug = False
+
+    def tcp_server(self, server_prog, *,
+                   family=socket.AF_INET,
+                   addr=None,
+                   timeout=5,
+                   backlog=1,
+                   max_clients=10):
+
+        if addr is None:
+            if family == socket.AF_UNIX:
+                with tempfile.NamedTemporaryFile() as tmp:
+                    addr = tmp.name
+            else:
+                addr = ('127.0.0.1', 0)
+
+        sock = socket.socket(family, socket.SOCK_STREAM)
+
+        if timeout is None:
+            raise RuntimeError('timeout is required')
+        if timeout <= 0:
+            raise RuntimeError('only blocking sockets are supported')
+        sock.settimeout(timeout)
+
+        try:
+            sock.bind(addr)
+            sock.listen(backlog)
+        except OSError as ex:
+            sock.close()
+            raise ex
+
+        return TestThreadedServer(
+            self, sock, server_prog, timeout, max_clients)
+
+    def tcp_client(self, client_prog,
+                   family=socket.AF_INET,
+                   timeout=10):
+
+        sock = socket.socket(family, socket.SOCK_STREAM)
+
+        if timeout is None:
+            raise RuntimeError('timeout is required')
+        if timeout <= 0:
+            raise RuntimeError('only blocking sockets are supported')
+        sock.settimeout(timeout)
+
+        return TestThreadedClient(
+            self, sock, client_prog, timeout)
+
+    def unix_server(self, *args, **kwargs):
+        return self.tcp_server(*args, family=socket.AF_UNIX, **kwargs)
+
+    def unix_client(self, *args, **kwargs):
+        return self.tcp_client(*args, family=socket.AF_UNIX, **kwargs)
+
+    @contextlib.contextmanager
+    def unix_sock_name(self):
+        with tempfile.TemporaryDirectory() as td:
+            fn = os.path.join(td, 'sock')
+            try:
+                yield fn
+            finally:
+                try:
+                    os.unlink(fn)
+                except OSError:
+                    pass
+
+    def _abort_socket_test(self, ex):
+        try:
+            self.loop.stop()
+        finally:
+            self.fail(ex)
+
+
+def _cert_fullname(test_file_name, cert_file_name):
+    fullname = os.path.abspath(os.path.join(
+        os.path.dirname(test_file_name), 'certs', cert_file_name))
+    assert os.path.isfile(fullname)
+    return fullname
+
+
+@contextlib.contextmanager
+def silence_long_exec_warning():
+
+    class Filter(logging.Filter):
+        def filter(self, record):
+            return not (record.msg.startswith('Executing') and
+                        record.msg.endswith('seconds'))
+
+    logger = logging.getLogger('asyncio')
+    filter = Filter()
+    logger.addFilter(filter)
+    try:
+        yield
+    finally:
+        logger.removeFilter(filter)
+
+
+def find_free_port(start_from=50000):
+    for port in range(start_from, start_from + 500):
+        sock = socket.socket()
+        with sock:
+            try:
+                sock.bind(('', port))
+            except socket.error:
+                continue
+            else:
+                return port
+    raise RuntimeError('could not find a free port')
+
+
+class SSLTestCase:
+
+    def _create_server_ssl_context(self, certfile, keyfile=None):
+        if hasattr(ssl, 'PROTOCOL_TLS_SERVER'):
+            sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
+        elif hasattr(ssl, 'PROTOCOL_TLS'):
+            sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS)
+        else:
+            sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+        sslcontext.options |= ssl.OP_NO_SSLv2
+        sslcontext.load_cert_chain(certfile, keyfile)
+        return sslcontext
+
+    def _create_client_ssl_context(self, *, disable_verify=True):
+        sslcontext = ssl.create_default_context()
+        sslcontext.check_hostname = False
+        if disable_verify:
+            sslcontext.verify_mode = ssl.CERT_NONE
+        return sslcontext
+
+    @contextlib.contextmanager
+    def _silence_eof_received_warning(self):
+        # TODO This warning has to be fixed in asyncio.
+        logger = logging.getLogger('asyncio')
+        filter = logging.Filter('has no effect when using ssl')
+        logger.addFilter(filter)
+        try:
+            yield
+        finally:
+            logger.removeFilter(filter)
+
+
+class UVTestCase(BaseTestCase):
+
+    implementation = 'uvloop'
+
+    def new_loop(self):
+        return uvloop.new_event_loop()
+
+    def new_policy(self):
+        return uvloop.EventLoopPolicy()
+
+
+class AIOTestCase(BaseTestCase):
+
+    implementation = 'asyncio'
+
+    def setUp(self):
+        super().setUp()
+
+        if sys.version_info < (3, 12):
+            watcher = asyncio.SafeChildWatcher()
+            watcher.attach_loop(self.loop)
+            asyncio.set_child_watcher(watcher)
+
+    def tearDown(self):
+        if sys.version_info < (3, 12):
+            asyncio.set_child_watcher(None)
+        super().tearDown()
+
+    def new_loop(self):
+        return asyncio.new_event_loop()
+
+    def new_policy(self):
+        return asyncio.DefaultEventLoopPolicy()
+
+
+def has_IPv6():
+    server_sock = socket.socket(socket.AF_INET6)
+    with server_sock:
+        try:
+            server_sock.bind(('::1', 0))
+        except OSError:
+            return False
+        else:
+            return True
+
+
+has_IPv6 = has_IPv6()
+
+
+###############################################################################
+# Socket Testing Utilities
+###############################################################################
+
+
+class TestSocketWrapper:
+
+    def __init__(self, sock):
+        self.__sock = sock
+
+    def recv_all(self, n):
+        buf = b''
+        while len(buf) < n:
+            data = self.recv(n - len(buf))
+            if data == b'':
+                raise ConnectionAbortedError
+            buf += data
+        return buf
+
+    def starttls(self, ssl_context, *,
+                 server_side=False,
+                 server_hostname=None,
+                 do_handshake_on_connect=True):
+
+        assert isinstance(ssl_context, ssl.SSLContext)
+
+        ssl_sock = ssl_context.wrap_socket(
+            self.__sock, server_side=server_side,
+            server_hostname=server_hostname,
+            do_handshake_on_connect=do_handshake_on_connect)
+
+        if server_side:
+            ssl_sock.do_handshake()
+
+        self.__sock.close()
+        self.__sock = ssl_sock
+
+    def __getattr__(self, name):
+        return getattr(self.__sock, name)
+
+    def __repr__(self):
+        return '<{} {!r}>'.format(type(self).__name__, self.__sock)
+
+
+class SocketThread(threading.Thread):
+
+    def stop(self):
+        self._active = False
+        self.join()
+
+    def __enter__(self):
+        self.start()
+        return self
+
+    def __exit__(self, *exc):
+        self.stop()
+
+
+class TestThreadedClient(SocketThread):
+
+    def __init__(self, test, sock, prog, timeout):
+        threading.Thread.__init__(self, None, None, 'test-client')
+        self.daemon = True
+
+        self._timeout = timeout
+        self._sock = sock
+        self._active = True
+        self._prog = prog
+        self._test = test
+
+    def run(self):
+        try:
+            self._prog(TestSocketWrapper(self._sock))
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException as ex:
+            self._test._abort_socket_test(ex)
+
+
+class TestThreadedServer(SocketThread):
+
+    def __init__(self, test, sock, prog, timeout, max_clients):
+        threading.Thread.__init__(self, None, None, 'test-server')
+        self.daemon = True
+
+        self._clients = 0
+        self._finished_clients = 0
+        self._max_clients = max_clients
+        self._timeout = timeout
+        self._sock = sock
+        self._active = True
+
+        self._prog = prog
+
+        self._s1, self._s2 = socket.socketpair()
+        self._s1.setblocking(False)
+
+        self._test = test
+
+    def stop(self):
+        try:
+            if self._s2 and self._s2.fileno() != -1:
+                try:
+                    self._s2.send(b'stop')
+                except OSError:
+                    pass
+        finally:
+            super().stop()
+
+    def run(self):
+        try:
+            with self._sock:
+                self._sock.setblocking(0)
+                self._run()
+        finally:
+            self._s1.close()
+            self._s2.close()
+
+    def _run(self):
+        while self._active:
+            if self._clients >= self._max_clients:
+                return
+
+            r, w, x = select.select(
+                [self._sock, self._s1], [], [], self._timeout)
+
+            if self._s1 in r:
+                return
+
+            if self._sock in r:
+                try:
+                    conn, addr = self._sock.accept()
+                except BlockingIOError:
+                    continue
+                except socket.timeout:
+                    if not self._active:
+                        return
+                    else:
+                        raise
+                else:
+                    self._clients += 1
+                    conn.settimeout(self._timeout)
+                    try:
+                        with conn:
+                            self._handle_client(conn)
+                    except (KeyboardInterrupt, SystemExit):
+                        raise
+                    except BaseException as ex:
+                        self._active = False
+                        try:
+                            raise
+                        finally:
+                            self._test._abort_socket_test(ex)
+
+    def _handle_client(self, sock):
+        self._prog(TestSocketWrapper(sock))
+
+    @property
+    def addr(self):
+        return self._sock.getsockname()
+
+
+###############################################################################
+# A few helpers from asyncio/tests/testutils.py
+###############################################################################
+
+
+def run_briefly(loop):
+    async def once():
+        pass
+    gen = once()
+    t = loop.create_task(gen)
+    # Don't log a warning if the task is not done after run_until_complete().
+    # It occurs if the loop is stopped or if a task raises a BaseException.
+    t._log_destroy_pending = False
+    try:
+        loop.run_until_complete(t)
+    finally:
+        gen.close()
+
+
+def run_until(loop, pred, timeout=30):
+    deadline = time.time() + timeout
+    while not pred():
+        if timeout is not None:
+            timeout = deadline - time.time()
+            if timeout <= 0:
+                raise asyncio.futures.TimeoutError()
+        loop.run_until_complete(asyncio.tasks.sleep(0.001))
+
+
+@contextlib.contextmanager
+def disable_logger():
+    """Context manager to disable asyncio logger.
+
+    For example, it can be used to ignore warnings in debug mode.
+    """
+    old_level = asyncio.log.logger.level
+    try:
+        asyncio.log.logger.setLevel(logging.CRITICAL + 1)
+        yield
+    finally:
+        asyncio.log.logger.setLevel(old_level)
diff --git a/lib/python3.12/site-packages/uvloop/_version.py b/lib/python3.12/site-packages/uvloop/_version.py
new file mode 100644
index 0000000000000000000000000000000000000000..9e1722c0a291a4f97d41348551689908b0ba362c
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/_version.py
@@ -0,0 +1,13 @@
+# This file MUST NOT contain anything but the __version__ assignment.
+#
+# When making a release, change the value of __version__
+# to an appropriate value, and open a pull request against
+# the correct branch (master if making a new feature release).
+# The commit message MUST contain a properly formatted release
+# log, and the commit must be signed.
+#
+# The release automation will: build and test the packages for the
+# supported platforms, publish the packages on PyPI, merge the PR
+# to the target branch, create a Git tag pointing to the commit.
+
+__version__ = '0.21.0'
diff --git a/lib/python3.12/site-packages/uvloop/cbhandles.pxd b/lib/python3.12/site-packages/uvloop/cbhandles.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..e594b133128fa7ca2c1321b7faa8a5412ffec5a7
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/cbhandles.pxd
@@ -0,0 +1,39 @@
+cdef class Handle:
+    cdef:
+        Loop loop
+        object context
+        bint _cancelled
+
+        str meth_name
+        int cb_type
+        void *callback
+        object arg1, arg2, arg3, arg4
+
+        object __weakref__
+
+        readonly _source_traceback
+
+    cdef inline _set_loop(self, Loop loop)
+    cdef inline _set_context(self, object context)
+
+    cdef inline _run(self)
+    cdef _cancel(self)
+
+    cdef _format_handle(self)
+
+
+cdef class TimerHandle:
+    cdef:
+        object callback
+        tuple args
+        bint _cancelled
+        UVTimer timer
+        Loop loop
+        object context
+        tuple _debug_info
+        object __weakref__
+        object _when
+
+    cdef _run(self)
+    cdef _cancel(self)
+    cdef inline _clear(self)
diff --git a/lib/python3.12/site-packages/uvloop/cbhandles.pyx b/lib/python3.12/site-packages/uvloop/cbhandles.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..2914b42e38ca2240a48fe64ac384f1eb5e065a56
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/cbhandles.pyx
@@ -0,0 +1,434 @@
+@cython.no_gc_clear
+@cython.freelist(DEFAULT_FREELIST_SIZE)
+cdef class Handle:
+    def __cinit__(self):
+        self._cancelled = 0
+        self.cb_type = 0
+        self._source_traceback = None
+
+    cdef inline _set_loop(self, Loop loop):
+        self.loop = loop
+        if UVLOOP_DEBUG:
+            loop._debug_cb_handles_total += 1
+            loop._debug_cb_handles_count += 1
+        if loop._debug:
+            self._source_traceback = extract_stack()
+
+    cdef inline _set_context(self, object context):
+        if context is None:
+            context = Context_CopyCurrent()
+        self.context = context
+
+    def __dealloc__(self):
+        if UVLOOP_DEBUG and self.loop is not None:
+            self.loop._debug_cb_handles_count -= 1
+        if self.loop is None:
+            raise RuntimeError('Handle.loop is None in Handle.__dealloc__')
+
+    def __init__(self):
+        raise TypeError(
+            '{} is not supposed to be instantiated from Python'.format(
+                self.__class__.__name__))
+
+    cdef inline _run(self):
+        cdef:
+            int cb_type
+            object callback
+
+        if self._cancelled:
+            return
+
+        cb_type = self.cb_type
+
+        # Since _run is a cdef and there's no BoundMethod,
+        # we guard 'self' manually (since the callback
+        # might cause GC of the handle.)
+        Py_INCREF(self)
+
+        try:
+            assert self.context is not None
+            Context_Enter(self.context)
+
+            if cb_type == 1:
+                callback = self.arg1
+                if callback is None:
+                    raise RuntimeError(
+                        'cannot run Handle; callback is not set')
+
+                args = self.arg2
+
+                if args is None:
+                    callback()
+                else:
+                    callback(*args)
+
+            elif cb_type == 2:
+                (self.callback)(self.arg1)
+
+            elif cb_type == 3:
+                (self.callback)(self.arg1, self.arg2)
+
+            elif cb_type == 4:
+                (self.callback)(self.arg1, self.arg2, self.arg3)
+
+            elif cb_type == 5:
+                (self.callback)(
+                    self.arg1, self.arg2, self.arg3, self.arg4)
+
+            else:
+                raise RuntimeError('invalid Handle.cb_type: {}'.format(
+                    cb_type))
+
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException as ex:
+            if cb_type == 1:
+                msg = 'Exception in callback {}'.format(callback)
+            else:
+                msg = 'Exception in callback {}'.format(self.meth_name)
+
+            context = {
+                'message': msg,
+                'exception': ex,
+                'handle': self,
+            }
+
+            if self._source_traceback is not None:
+                context['source_traceback'] = self._source_traceback
+
+            self.loop.call_exception_handler(context)
+
+        finally:
+            context = self.context
+            Py_DECREF(self)
+            Context_Exit(context)
+
+    cdef _cancel(self):
+        self._cancelled = 1
+        self.callback = NULL
+        self.arg1 = self.arg2 = self.arg3 = self.arg4 = None
+
+    cdef _format_handle(self):
+        # Mirrors `asyncio.base_events._format_handle`.
+        if self.cb_type == 1 and self.arg1 is not None:
+            cb = self.arg1
+            if isinstance(getattr(cb, '__self__', None), aio_Task):
+                try:
+                    return repr(cb.__self__)
+                except (AttributeError, TypeError, ValueError) as ex:
+                    # Cython generates empty __code__ objects for coroutines
+                    # that can crash asyncio.Task.__repr__ with an
+                    # AttributeError etc.  Guard against that.
+                    self.loop.call_exception_handler({
+                        'message': 'exception in Task.__repr__',
+                        'task': cb.__self__,
+                        'exception': ex,
+                        'handle': self,
+                    })
+        return repr(self)
+
+    # Public API
+
+    def __repr__(self):
+        info = [self.__class__.__name__]
+
+        if self._cancelled:
+            info.append('cancelled')
+
+        if self.cb_type == 1 and self.arg1 is not None:
+            func = self.arg1
+            # Cython can unset func.__qualname__/__name__, hence the checks.
+            if hasattr(func, '__qualname__') and func.__qualname__:
+                cb_name = func.__qualname__
+            elif hasattr(func, '__name__') and func.__name__:
+                cb_name = func.__name__
+            else:
+                cb_name = repr(func)
+
+            info.append(cb_name)
+        elif self.meth_name is not None:
+            info.append(self.meth_name)
+
+        if self._source_traceback is not None:
+            frame = self._source_traceback[-1]
+            info.append('created at {}:{}'.format(frame[0], frame[1]))
+
+        return '<' + ' '.join(info) + '>'
+
+    def cancel(self):
+        self._cancel()
+
+    def cancelled(self):
+        return self._cancelled
+
+
+@cython.no_gc_clear
+@cython.freelist(DEFAULT_FREELIST_SIZE)
+cdef class TimerHandle:
+    def __cinit__(self, Loop loop, object callback, object args,
+                  uint64_t delay, object context):
+
+        self.loop = loop
+        self.callback = callback
+        self.args = args
+        self._cancelled = 0
+
+        if UVLOOP_DEBUG:
+            self.loop._debug_cb_timer_handles_total += 1
+            self.loop._debug_cb_timer_handles_count += 1
+
+        if context is None:
+            context = Context_CopyCurrent()
+        self.context = context
+
+        if loop._debug:
+            self._debug_info = (
+                format_callback_name(callback),
+                extract_stack()
+            )
+        else:
+            self._debug_info = None
+
+        self.timer = UVTimer.new(
+            loop, self._run, self, delay)
+
+        self.timer.start()
+        self._when = self.timer.get_when() * 1e-3
+
+        # Only add to loop._timers when `self.timer` is successfully created
+        loop._timers.add(self)
+
+    property _source_traceback:
+        def __get__(self):
+            if self._debug_info is not None:
+                return self._debug_info[1]
+
+    def __dealloc__(self):
+        if UVLOOP_DEBUG:
+            self.loop._debug_cb_timer_handles_count -= 1
+        if self.timer is not None:
+            raise RuntimeError('active TimerHandle is deallacating')
+
+    cdef _cancel(self):
+        if self._cancelled == 1:
+            return
+        self._cancelled = 1
+        self._clear()
+
+    cdef inline _clear(self):
+        if self.timer is None:
+            return
+
+        self.callback = None
+        self.args = None
+
+        try:
+            self.loop._timers.remove(self)
+        finally:
+            self.timer._close()
+            self.timer = None  # let the UVTimer handle GC
+
+    cdef _run(self):
+        if self._cancelled == 1:
+            return
+        if self.callback is None:
+            raise RuntimeError('cannot run TimerHandle; callback is not set')
+
+        callback = self.callback
+        args = self.args
+
+        # Since _run is a cdef and there's no BoundMethod,
+        # we guard 'self' manually.
+        Py_INCREF(self)
+
+        if self.loop._debug:
+            started = time_monotonic()
+        try:
+            assert self.context is not None
+            Context_Enter(self.context)
+
+            if args is not None:
+                callback(*args)
+            else:
+                callback()
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException as ex:
+            context = {
+                'message': 'Exception in callback {}'.format(callback),
+                'exception': ex,
+                'handle': self,
+            }
+
+            if self._debug_info is not None:
+                context['source_traceback'] = self._debug_info[1]
+
+            self.loop.call_exception_handler(context)
+        else:
+            if self.loop._debug:
+                delta = time_monotonic() - started
+                if delta > self.loop.slow_callback_duration:
+                    aio_logger.warning(
+                        'Executing %r took %.3f seconds',
+                        self, delta)
+        finally:
+            context = self.context
+            Py_DECREF(self)
+            Context_Exit(context)
+            self._clear()
+
+    # Public API
+
+    def __repr__(self):
+        info = [self.__class__.__name__]
+
+        if self._cancelled:
+            info.append('cancelled')
+
+        if self._debug_info is not None:
+            callback_name = self._debug_info[0]
+            source_traceback = self._debug_info[1]
+        else:
+            callback_name = None
+            source_traceback = None
+
+        if callback_name is not None:
+            info.append(callback_name)
+        elif self.callback is not None:
+            info.append(format_callback_name(self.callback))
+
+        if source_traceback is not None:
+            frame = source_traceback[-1]
+            info.append('created at {}:{}'.format(frame[0], frame[1]))
+
+        return '<' + ' '.join(info) + '>'
+
+    def cancelled(self):
+        return self._cancelled
+
+    def cancel(self):
+        self._cancel()
+
+    def when(self):
+        return self._when
+
+
+cdef format_callback_name(func):
+    if hasattr(func, '__qualname__'):
+        cb_name = getattr(func, '__qualname__')
+    elif hasattr(func, '__name__'):
+        cb_name = getattr(func, '__name__')
+    else:
+        cb_name = repr(func)
+    return cb_name
+
+
+cdef new_Handle(Loop loop, object callback, object args, object context):
+    cdef Handle handle
+    handle = Handle.__new__(Handle)
+    handle._set_loop(loop)
+    handle._set_context(context)
+
+    handle.cb_type = 1
+
+    handle.arg1 = callback
+    handle.arg2 = args
+
+    return handle
+
+
+cdef new_MethodHandle(Loop loop, str name, method_t callback, object context,
+                      object bound_to):
+    cdef Handle handle
+    handle = Handle.__new__(Handle)
+    handle._set_loop(loop)
+    handle._set_context(context)
+
+    handle.cb_type = 2
+    handle.meth_name = name
+
+    handle.callback =  callback
+    handle.arg1 = bound_to
+
+    return handle
+
+
+cdef new_MethodHandle1(Loop loop, str name, method1_t callback, object context,
+                       object bound_to, object arg):
+
+    cdef Handle handle
+    handle = Handle.__new__(Handle)
+    handle._set_loop(loop)
+    handle._set_context(context)
+
+    handle.cb_type = 3
+    handle.meth_name = name
+
+    handle.callback =  callback
+    handle.arg1 = bound_to
+    handle.arg2 = arg
+
+    return handle
+
+
+cdef new_MethodHandle2(Loop loop, str name, method2_t callback, object context,
+                       object bound_to, object arg1, object arg2):
+
+    cdef Handle handle
+    handle = Handle.__new__(Handle)
+    handle._set_loop(loop)
+    handle._set_context(context)
+
+    handle.cb_type = 4
+    handle.meth_name = name
+
+    handle.callback =  callback
+    handle.arg1 = bound_to
+    handle.arg2 = arg1
+    handle.arg3 = arg2
+
+    return handle
+
+
+cdef new_MethodHandle3(Loop loop, str name, method3_t callback, object context,
+                       object bound_to, object arg1, object arg2, object arg3):
+
+    cdef Handle handle
+    handle = Handle.__new__(Handle)
+    handle._set_loop(loop)
+    handle._set_context(context)
+
+    handle.cb_type = 5
+    handle.meth_name = name
+
+    handle.callback =  callback
+    handle.arg1 = bound_to
+    handle.arg2 = arg1
+    handle.arg3 = arg2
+    handle.arg4 = arg3
+
+    return handle
+
+
+cdef extract_stack():
+    """Replacement for traceback.extract_stack() that only does the
+    necessary work for asyncio debug mode.
+    """
+    try:
+        f = sys_getframe()
+    # sys._getframe() might raise ValueError if being called without a frame, e.g.
+    # from Cython or similar C extensions.
+    except ValueError:
+        return None
+    if f is None:
+        return
+
+    try:
+        stack = tb_StackSummary.extract(tb_walk_stack(f),
+                                        limit=DEBUG_STACK_DEPTH,
+                                        lookup_lines=False)
+    finally:
+        f = None
+
+    stack.reverse()
+    return stack
diff --git a/lib/python3.12/site-packages/uvloop/dns.pyx b/lib/python3.12/site-packages/uvloop/dns.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..67aeb595e951e26914458508c4963cdeafcadd9f
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/dns.pyx
@@ -0,0 +1,479 @@
+cdef __port_to_int(port, proto):
+    if type(port) is int:
+        return port
+
+    if port is None or port == '' or port == b'':
+        return 0
+
+    try:
+        return int(port)
+    except (ValueError, TypeError):
+        pass
+
+    if isinstance(port, bytes):
+        port = port.decode()
+
+    if isinstance(port, str) and proto is not None:
+        if proto == uv.IPPROTO_TCP:
+            return socket_getservbyname(port, 'tcp')
+        elif proto == uv.IPPROTO_UDP:
+            return socket_getservbyname(port, 'udp')
+
+    raise OSError('service/proto not found')
+
+
+cdef __convert_sockaddr_to_pyaddr(const system.sockaddr* addr):
+    # Converts sockaddr structs into what Python socket
+    # module can understand:
+    #   - for IPv4 a tuple of (host, port)
+    #   - for IPv6 a tuple of (host, port, flowinfo, scope_id)
+
+    cdef:
+        char buf[128]  # INET6_ADDRSTRLEN is usually 46
+        int err
+        system.sockaddr_in *addr4
+        system.sockaddr_in6 *addr6
+        system.sockaddr_un *addr_un
+
+    if addr.sa_family == uv.AF_INET:
+        addr4 = addr
+
+        err = uv.uv_ip4_name(addr4, buf, sizeof(buf))
+        if err < 0:
+            raise convert_error(err)
+
+        return (
+            PyUnicode_FromString(buf),
+            system.ntohs(addr4.sin_port)
+        )
+
+    elif addr.sa_family == uv.AF_INET6:
+        addr6 = addr
+
+        err = uv.uv_ip6_name(addr6, buf, sizeof(buf))
+        if err < 0:
+            raise convert_error(err)
+
+        return (
+            PyUnicode_FromString(buf),
+            system.ntohs(addr6.sin6_port),
+            system.ntohl(addr6.sin6_flowinfo),
+            addr6.sin6_scope_id
+        )
+
+    elif addr.sa_family == uv.AF_UNIX:
+        addr_un = addr
+        return system.MakeUnixSockPyAddr(addr_un)
+
+    raise RuntimeError("cannot convert sockaddr into Python object")
+
+
+@cython.freelist(DEFAULT_FREELIST_SIZE)
+cdef class SockAddrHolder:
+    cdef:
+        int family
+        system.sockaddr_storage addr
+        Py_ssize_t addr_size
+
+
+cdef LruCache sockaddrs = LruCache(maxsize=DNS_PYADDR_TO_SOCKADDR_CACHE_SIZE)
+
+
+cdef __convert_pyaddr_to_sockaddr(int family, object addr,
+                                  system.sockaddr* res):
+    cdef:
+        int err
+        int addr_len
+        int scope_id = 0
+        int flowinfo = 0
+        char *buf
+        Py_ssize_t buflen
+        SockAddrHolder ret
+
+    ret = sockaddrs.get(addr, None)
+    if ret is not None and ret.family == family:
+        memcpy(res, &ret.addr, ret.addr_size)
+        return
+
+    ret = SockAddrHolder.__new__(SockAddrHolder)
+    if family == uv.AF_INET:
+        if not isinstance(addr, tuple):
+            raise TypeError('AF_INET address must be tuple')
+        if len(addr) != 2:
+            raise ValueError('AF_INET address must be tuple of (host, port)')
+        host, port = addr
+        if isinstance(host, str):
+            try:
+                # idna codec is rather slow, so we try ascii first.
+                host = host.encode('ascii')
+            except UnicodeEncodeError:
+                host = host.encode('idna')
+        if not isinstance(host, (bytes, bytearray)):
+            raise TypeError('host must be a string or bytes object')
+
+        port = __port_to_int(port, None)
+
+        ret.addr_size = sizeof(system.sockaddr_in)
+        err = uv.uv_ip4_addr(host, port, &ret.addr)
+        if err < 0:
+            raise convert_error(err)
+
+    elif family == uv.AF_INET6:
+        if not isinstance(addr, tuple):
+            raise TypeError('AF_INET6 address must be tuple')
+
+        addr_len = len(addr)
+        if addr_len < 2 or addr_len > 4:
+            raise ValueError(
+                'AF_INET6 must be a tuple of 2-4 parameters: '
+                '(host, port, flowinfo?, scope_id?)')
+
+        host = addr[0]
+        if isinstance(host, str):
+            try:
+                # idna codec is rather slow, so we try ascii first.
+                host = host.encode('ascii')
+            except UnicodeEncodeError:
+                host = host.encode('idna')
+        if not isinstance(host, (bytes, bytearray)):
+            raise TypeError('host must be a string or bytes object')
+
+        port = __port_to_int(addr[1], None)
+
+        if addr_len > 2:
+            flowinfo = addr[2]
+        if addr_len > 3:
+            scope_id = addr[3]
+
+        ret.addr_size = sizeof(system.sockaddr_in6)
+
+        err = uv.uv_ip6_addr(host, port, &ret.addr)
+        if err < 0:
+            raise convert_error(err)
+
+        (&ret.addr).sin6_flowinfo = flowinfo
+        (&ret.addr).sin6_scope_id = scope_id
+
+    elif family == uv.AF_UNIX:
+        if isinstance(addr, str):
+            addr = addr.encode(sys_getfilesystemencoding())
+        elif not isinstance(addr, bytes):
+            raise TypeError('AF_UNIX address must be a str or a bytes object')
+
+        PyBytes_AsStringAndSize(addr, &buf, &buflen)
+        if buflen > 107:
+            raise ValueError(
+                f'unix socket path {addr!r} is longer than 107 characters')
+
+        ret.addr_size = sizeof(system.sockaddr_un)
+        memset(&ret.addr, 0, sizeof(system.sockaddr_un))
+        (&ret.addr).sun_family = uv.AF_UNIX
+        memcpy((&ret.addr).sun_path, buf, buflen)
+
+    else:
+        raise ValueError(
+            f'expected AF_INET, AF_INET6, or AF_UNIX family, got {family}')
+
+    ret.family = family
+    sockaddrs[addr] = ret
+    memcpy(res, &ret.addr, ret.addr_size)
+
+
+cdef __static_getaddrinfo(object host, object port,
+                          int family, int type,
+                          int proto,
+                          system.sockaddr *addr):
+
+    if proto not in {0, uv.IPPROTO_TCP, uv.IPPROTO_UDP}:
+        return
+
+    if _is_sock_stream(type):
+        proto = uv.IPPROTO_TCP
+    elif _is_sock_dgram(type):
+        proto = uv.IPPROTO_UDP
+    else:
+        return
+
+    try:
+        port = __port_to_int(port, proto)
+    except Exception:
+        return
+
+    hp = (host, port)
+    if family == uv.AF_UNSPEC:
+        try:
+            __convert_pyaddr_to_sockaddr(uv.AF_INET, hp, addr)
+        except Exception:
+            pass
+        else:
+            return (uv.AF_INET, type, proto)
+
+        try:
+            __convert_pyaddr_to_sockaddr(uv.AF_INET6, hp, addr)
+        except Exception:
+            pass
+        else:
+            return (uv.AF_INET6, type, proto)
+
+    else:
+        try:
+            __convert_pyaddr_to_sockaddr(family, hp, addr)
+        except Exception:
+            pass
+        else:
+            return (family, type, proto)
+
+
+cdef __static_getaddrinfo_pyaddr(object host, object port,
+                                 int family, int type,
+                                 int proto, int flags):
+
+    cdef:
+        system.sockaddr_storage addr
+        object triplet
+
+    triplet = __static_getaddrinfo(
+        host, port, family, type,
+        proto, &addr)
+    if triplet is None:
+        return
+
+    af, type, proto = triplet
+
+    try:
+        pyaddr = __convert_sockaddr_to_pyaddr(&addr)
+    except Exception:
+        return
+
+    # When the host is an IP while type is one of TCP or UDP, different libc
+    # implementations of getaddrinfo() behave differently:
+    # 1. When AI_CANONNAME is set:
+    #    * glibc: returns ai_canonname
+    #    * musl: returns ai_canonname
+    #    * macOS: returns an empty string for ai_canonname
+    # 2. When AI_CANONNAME is NOT set:
+    #    * glibc: returns an empty string for ai_canonname
+    #    * musl: returns ai_canonname
+    #    * macOS: returns an empty string for ai_canonname
+    # At the same time, libuv and CPython both uses libc directly, even though
+    # this different behavior is violating what is in the documentation.
+    #
+    # uvloop potentially should be a 100% drop-in replacement for asyncio,
+    # doing whatever asyncio does, especially when the libc implementations are
+    # also different in the same way. However, making our implementation to be
+    # consistent with libc/CPython would be complex and hard to maintain
+    # (including caching libc behaviors when flag is/not set), therefore we
+    # decided to simply normalize the behavior in uvloop for this very marginal
+    # case following the documentation, even though uvloop would behave
+    # differently to asyncio on macOS and musl platforms, when again the host
+    # is an IP and type is one of TCP or UDP.
+    # All other cases are still asyncio-compatible.
+    if flags & socket_AI_CANONNAME:
+        if isinstance(host, str):
+            canon_name = host
+        else:
+            canon_name = host.decode('ascii')
+    else:
+        canon_name = ''
+
+    return (
+        _intenum_converter(af, socket_AddressFamily),
+        _intenum_converter(type, socket_SocketKind),
+        proto,
+        canon_name,
+        pyaddr,
+    )
+
+
+@cython.freelist(DEFAULT_FREELIST_SIZE)
+cdef class AddrInfo:
+    cdef:
+        system.addrinfo *data
+
+    def __cinit__(self):
+        self.data = NULL
+
+    def __dealloc__(self):
+        if self.data is not NULL:
+            uv.uv_freeaddrinfo(self.data)  # returns void
+            self.data = NULL
+
+    cdef void set_data(self, system.addrinfo *data) noexcept:
+        self.data = data
+
+    cdef unpack(self):
+        cdef:
+            list result = []
+            system.addrinfo *ptr
+
+        if self.data is NULL:
+            raise RuntimeError('AddrInfo.data is NULL')
+
+        ptr = self.data
+        while ptr != NULL:
+            if ptr.ai_addr.sa_family in (uv.AF_INET, uv.AF_INET6):
+                result.append((
+                    _intenum_converter(ptr.ai_family, socket_AddressFamily),
+                    _intenum_converter(ptr.ai_socktype, socket_SocketKind),
+                    ptr.ai_protocol,
+                    ('' if ptr.ai_canonname is NULL else
+                        (ptr.ai_canonname).decode()),
+                    __convert_sockaddr_to_pyaddr(ptr.ai_addr)
+                ))
+
+            ptr = ptr.ai_next
+
+        return result
+
+    @staticmethod
+    cdef int isinstance(object other):
+        return type(other) is AddrInfo
+
+
+cdef class AddrInfoRequest(UVRequest):
+    cdef:
+        system.addrinfo hints
+        object callback
+        uv.uv_getaddrinfo_t _req_data
+
+    def __cinit__(self, Loop loop,
+                  bytes host, bytes port,
+                  int family, int type, int proto, int flags,
+                  object callback):
+
+        cdef:
+            int err
+            char *chost
+            char *cport
+
+        if host is None:
+            chost = NULL
+        elif host == b'' and sys.platform == 'darwin':
+            # It seems `getaddrinfo("", ...)` on macOS is equivalent to
+            # `getaddrinfo("localhost", ...)`. This is inconsistent with
+            # libuv 1.48 which treats empty nodename as EINVAL.
+            chost = 'localhost'
+        else:
+            chost = host
+
+        if port is None:
+            cport = NULL
+        else:
+            cport = port
+
+        memset(&self.hints, 0, sizeof(system.addrinfo))
+        self.hints.ai_flags = flags
+        self.hints.ai_family = family
+        self.hints.ai_socktype = type
+        self.hints.ai_protocol = proto
+
+        self.request =  &self._req_data
+        self.callback = callback
+        self.request.data = self
+
+        err = uv.uv_getaddrinfo(loop.uvloop,
+                                self.request,
+                                __on_addrinfo_resolved,
+                                chost,
+                                cport,
+                                &self.hints)
+
+        if err < 0:
+            self.on_done()
+            try:
+                if err == uv.UV_EINVAL:
+                    # Convert UV_EINVAL to EAI_NONAME to match libc behavior
+                    msg = system.gai_strerror(socket_EAI_NONAME).decode('utf-8')
+                    ex = socket_gaierror(socket_EAI_NONAME, msg)
+                else:
+                    ex = convert_error(err)
+            except Exception as ex:
+                callback(ex)
+            else:
+                callback(ex)
+
+
+cdef class NameInfoRequest(UVRequest):
+    cdef:
+        object callback
+        uv.uv_getnameinfo_t _req_data
+
+    def __cinit__(self, Loop loop, callback):
+        self.request =  &self._req_data
+        self.callback = callback
+        self.request.data = self
+
+    cdef query(self, system.sockaddr *addr, int flags):
+        cdef int err
+        err = uv.uv_getnameinfo(self.loop.uvloop,
+                                self.request,
+                                __on_nameinfo_resolved,
+                                addr,
+                                flags)
+        if err < 0:
+            self.on_done()
+            self.callback(convert_error(err))
+
+
+cdef _intenum_converter(value, enum_klass):
+    try:
+        return enum_klass(value)
+    except ValueError:
+        return value
+
+
+cdef void __on_addrinfo_resolved(
+    uv.uv_getaddrinfo_t *resolver,
+    int status,
+    system.addrinfo *res,
+) noexcept with gil:
+
+    if resolver.data is NULL:
+        aio_logger.error(
+            'AddrInfoRequest callback called with NULL resolver.data')
+        return
+
+    cdef:
+        AddrInfoRequest request =  resolver.data
+        Loop loop = request.loop
+        object callback = request.callback
+        AddrInfo ai
+
+    try:
+        if status < 0:
+            callback(convert_error(status))
+        else:
+            ai = AddrInfo()
+            ai.set_data(res)
+            callback(ai)
+    except (KeyboardInterrupt, SystemExit):
+        raise
+    except BaseException as ex:
+        loop._handle_exception(ex)
+    finally:
+        request.on_done()
+
+
+cdef void __on_nameinfo_resolved(
+    uv.uv_getnameinfo_t* req,
+    int status,
+    const char* hostname,
+    const char* service,
+) noexcept with gil:
+    cdef:
+        NameInfoRequest request =  req.data
+        Loop loop = request.loop
+        object callback = request.callback
+
+    try:
+        if status < 0:
+            callback(convert_error(status))
+        else:
+            callback(((hostname).decode(),
+                      (service).decode()))
+    except (KeyboardInterrupt, SystemExit):
+        raise
+    except BaseException as ex:
+        loop._handle_exception(ex)
+    finally:
+        request.on_done()
diff --git a/lib/python3.12/site-packages/uvloop/errors.pyx b/lib/python3.12/site-packages/uvloop/errors.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..d810d65ee58ad1dc40c33e2d54f5a3e8fcc1e64f
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/errors.pyx
@@ -0,0 +1,113 @@
+cdef str __strerr(int errno):
+    return strerror(errno).decode()
+
+
+cdef __convert_python_error(int uverr):
+    # XXX Won't work for Windows:
+    # From libuv docs:
+    #      Implementation detail: on Unix error codes are the
+    #      negated errno (or -errno), while on Windows they
+    #      are defined by libuv to arbitrary negative numbers.
+    cdef int oserr = -uverr
+
+    exc = OSError
+
+    if uverr in (uv.UV_EACCES, uv.UV_EPERM):
+        exc = PermissionError
+
+    elif uverr in (uv.UV_EAGAIN, uv.UV_EALREADY):
+        exc = BlockingIOError
+
+    elif uverr in (uv.UV_EPIPE, uv.UV_ESHUTDOWN):
+        exc = BrokenPipeError
+
+    elif uverr == uv.UV_ECONNABORTED:
+        exc = ConnectionAbortedError
+
+    elif uverr == uv.UV_ECONNREFUSED:
+        exc = ConnectionRefusedError
+
+    elif uverr == uv.UV_ECONNRESET:
+        exc = ConnectionResetError
+
+    elif uverr == uv.UV_EEXIST:
+        exc = FileExistsError
+
+    elif uverr == uv.UV_ENOENT:
+        exc = FileNotFoundError
+
+    elif uverr == uv.UV_EINTR:
+        exc = InterruptedError
+
+    elif uverr == uv.UV_EISDIR:
+        exc = IsADirectoryError
+
+    elif uverr == uv.UV_ESRCH:
+        exc = ProcessLookupError
+
+    elif uverr == uv.UV_ETIMEDOUT:
+        exc = TimeoutError
+
+    return exc(oserr, __strerr(oserr))
+
+
+cdef int __convert_socket_error(int uverr):
+    cdef int sock_err = 0
+
+    if uverr == uv.UV_EAI_ADDRFAMILY:
+        sock_err = socket_EAI_ADDRFAMILY
+
+    elif uverr == uv.UV_EAI_AGAIN:
+        sock_err = socket_EAI_AGAIN
+
+    elif uverr == uv.UV_EAI_BADFLAGS:
+        sock_err = socket_EAI_BADFLAGS
+
+    elif uverr == uv.UV_EAI_BADHINTS:
+        sock_err = socket_EAI_BADHINTS
+
+    elif uverr == uv.UV_EAI_CANCELED:
+        sock_err = socket_EAI_CANCELED
+
+    elif uverr == uv.UV_EAI_FAIL:
+        sock_err = socket_EAI_FAIL
+
+    elif uverr == uv.UV_EAI_FAMILY:
+        sock_err = socket_EAI_FAMILY
+
+    elif uverr == uv.UV_EAI_MEMORY:
+        sock_err = socket_EAI_MEMORY
+
+    elif uverr == uv.UV_EAI_NODATA:
+        sock_err = socket_EAI_NODATA
+
+    elif uverr == uv.UV_EAI_NONAME:
+        sock_err = socket_EAI_NONAME
+
+    elif uverr == uv.UV_EAI_OVERFLOW:
+        sock_err = socket_EAI_OVERFLOW
+
+    elif uverr == uv.UV_EAI_PROTOCOL:
+        sock_err = socket_EAI_PROTOCOL
+
+    elif uverr == uv.UV_EAI_SERVICE:
+        sock_err = socket_EAI_SERVICE
+
+    elif uverr == uv.UV_EAI_SOCKTYPE:
+        sock_err = socket_EAI_SOCKTYPE
+
+    return sock_err
+
+
+cdef convert_error(int uverr):
+    cdef int sock_err
+
+    if uverr == uv.UV_ECANCELED:
+        return aio_CancelledError()
+
+    sock_err = __convert_socket_error(uverr)
+    if sock_err:
+        msg = system.gai_strerror(sock_err).decode('utf-8')
+        return socket_gaierror(sock_err, msg)
+
+    return __convert_python_error(uverr)
diff --git a/lib/python3.12/site-packages/uvloop/handles/async_.pxd b/lib/python3.12/site-packages/uvloop/handles/async_.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..5f0d820166b68ce1ab1ffaf4f5c3d43eadbdd895
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/async_.pxd
@@ -0,0 +1,11 @@
+cdef class UVAsync(UVHandle):
+    cdef:
+        method_t callback
+        object ctx
+
+    cdef _init(self, Loop loop, method_t callback, object ctx)
+
+    cdef send(self)
+
+    @staticmethod
+    cdef UVAsync new(Loop loop, method_t callback, object ctx)
diff --git a/lib/python3.12/site-packages/uvloop/handles/async_.pyx b/lib/python3.12/site-packages/uvloop/handles/async_.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..5c740cfeb9c97339f2e2c0de840bec2cac2dd9c6
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/async_.pyx
@@ -0,0 +1,56 @@
+@cython.no_gc_clear
+cdef class UVAsync(UVHandle):
+    cdef _init(self, Loop loop, method_t callback, object ctx):
+        cdef int err
+
+        self._start_init(loop)
+
+        self._handle = PyMem_RawMalloc(sizeof(uv.uv_async_t))
+        if self._handle is NULL:
+            self._abort_init()
+            raise MemoryError()
+
+        err = uv.uv_async_init(self._loop.uvloop,
+                               self._handle,
+                               __uvasync_callback)
+        if err < 0:
+            self._abort_init()
+            raise convert_error(err)
+
+        self._finish_init()
+
+        self.callback = callback
+        self.ctx = ctx
+
+    cdef send(self):
+        cdef int err
+
+        self._ensure_alive()
+
+        err = uv.uv_async_send(self._handle)
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+
+    @staticmethod
+    cdef UVAsync new(Loop loop, method_t callback, object ctx):
+        cdef UVAsync handle
+        handle = UVAsync.__new__(UVAsync)
+        handle._init(loop, callback, ctx)
+        return handle
+
+
+cdef void __uvasync_callback(
+    uv.uv_async_t* handle,
+) noexcept with gil:
+    if __ensure_handle_data(handle, "UVAsync callback") == 0:
+        return
+
+    cdef:
+        UVAsync async_ =  handle.data
+        method_t cb = async_.callback
+    try:
+        cb(async_.ctx)
+    except BaseException as ex:
+        async_._error(ex, False)
diff --git a/lib/python3.12/site-packages/uvloop/handles/basetransport.pxd b/lib/python3.12/site-packages/uvloop/handles/basetransport.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..ba356a789441c8c58baf9f6ddb0c5a0e5b821ff9
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/basetransport.pxd
@@ -0,0 +1,54 @@
+cdef class UVBaseTransport(UVSocketHandle):
+
+    cdef:
+        readonly bint _closing
+
+        bint _protocol_connected
+        bint _protocol_paused
+        object _protocol_data_received
+        size_t _high_water
+        size_t _low_water
+
+        object _protocol
+        Server _server
+        object _waiter
+
+        dict _extra_info
+
+        uint32_t _conn_lost
+
+        object __weakref__
+
+    # All "inline" methods are final
+
+    cdef inline _maybe_pause_protocol(self)
+    cdef inline _maybe_resume_protocol(self)
+
+    cdef inline _schedule_call_connection_made(self)
+    cdef inline _schedule_call_connection_lost(self, exc)
+
+    cdef _wakeup_waiter(self)
+    cdef _call_connection_made(self)
+    cdef _call_connection_lost(self, exc)
+
+    # Overloads of UVHandle methods:
+    cdef _fatal_error(self, exc, throw, reason=?)
+    cdef _close(self)
+
+    cdef inline _set_server(self, Server server)
+    cdef inline _set_waiter(self, object waiter)
+
+    cdef _set_protocol(self, object protocol)
+    cdef _clear_protocol(self)
+
+    cdef inline _init_protocol(self)
+    cdef inline _add_extra_info(self, str name, object obj)
+
+    # === overloads ===
+
+    cdef _new_socket(self)
+    cdef size_t _get_write_buffer_size(self)
+
+    cdef bint _is_reading(self)
+    cdef _start_reading(self)
+    cdef _stop_reading(self)
diff --git a/lib/python3.12/site-packages/uvloop/handles/basetransport.pyx b/lib/python3.12/site-packages/uvloop/handles/basetransport.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..28b30794799249c3af2d3274fbbac95b07ae8f4e
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/basetransport.pyx
@@ -0,0 +1,293 @@
+cdef class UVBaseTransport(UVSocketHandle):
+
+    def __cinit__(self):
+        # Flow control
+        self._high_water = FLOW_CONTROL_HIGH_WATER * 1024
+        self._low_water = FLOW_CONTROL_HIGH_WATER // 4
+
+        self._protocol = None
+        self._protocol_connected = 0
+        self._protocol_paused = 0
+        self._protocol_data_received = None
+
+        self._server = None
+        self._waiter = None
+        self._extra_info = None
+
+        self._conn_lost = 0
+
+        self._closing = 0
+
+    cdef size_t _get_write_buffer_size(self):
+        return 0
+
+    cdef inline _schedule_call_connection_made(self):
+        self._loop._call_soon_handle(
+            new_MethodHandle(self._loop,
+                             "UVTransport._call_connection_made",
+                             self._call_connection_made,
+                             self.context,
+                             self))
+
+    cdef inline _schedule_call_connection_lost(self, exc):
+        self._loop._call_soon_handle(
+            new_MethodHandle1(self._loop,
+                              "UVTransport._call_connection_lost",
+                              self._call_connection_lost,
+                              self.context,
+                              self, exc))
+
+    cdef _fatal_error(self, exc, throw, reason=None):
+        # Overload UVHandle._fatal_error
+
+        self._force_close(exc)
+
+        if not isinstance(exc, OSError):
+
+            if throw or self._loop is None:
+                raise exc
+
+            msg = f'Fatal error on transport {self.__class__.__name__}'
+            if reason is not None:
+                msg = f'{msg} ({reason})'
+
+            self._loop.call_exception_handler({
+                'message': msg,
+                'exception': exc,
+                'transport': self,
+                'protocol': self._protocol,
+            })
+
+    cdef inline _maybe_pause_protocol(self):
+        cdef:
+            size_t size = self._get_write_buffer_size()
+
+        if size <= self._high_water:
+            return
+
+        if not self._protocol_paused:
+            self._protocol_paused = 1
+            try:
+                # _maybe_pause_protocol() is always triggered from user-calls,
+                # so we must copy the context to avoid entering context twice
+                run_in_context(
+                    self.context.copy(), self._protocol.pause_writing,
+                )
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException as exc:
+                self._loop.call_exception_handler({
+                    'message': 'protocol.pause_writing() failed',
+                    'exception': exc,
+                    'transport': self,
+                    'protocol': self._protocol,
+                })
+
+    cdef inline _maybe_resume_protocol(self):
+        cdef:
+            size_t size = self._get_write_buffer_size()
+
+        if self._protocol_paused and size <= self._low_water:
+            self._protocol_paused = 0
+            try:
+                # We're copying the context to avoid entering context twice,
+                # even though it's not always necessary to copy - it's easier
+                # to copy here than passing down a copied context.
+                run_in_context(
+                    self.context.copy(), self._protocol.resume_writing,
+                )
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException as exc:
+                self._loop.call_exception_handler({
+                    'message': 'protocol.resume_writing() failed',
+                    'exception': exc,
+                    'transport': self,
+                    'protocol': self._protocol,
+                })
+
+    cdef _wakeup_waiter(self):
+        if self._waiter is not None:
+            if not self._waiter.cancelled():
+                if not self._is_alive():
+                    self._waiter.set_exception(
+                        RuntimeError(
+                            'closed Transport handle and unset waiter'))
+                else:
+                    self._waiter.set_result(True)
+            self._waiter = None
+
+    cdef _call_connection_made(self):
+        if self._protocol is None:
+            raise RuntimeError(
+                'protocol is not set, cannot call connection_made()')
+
+        # We use `_is_alive()` and not `_closing`, because we call
+        # `transport._close()` in `loop.create_connection()` if an
+        # exception happens during `await waiter`.
+        if not self._is_alive():
+            # A connection waiter can be cancelled between
+            # 'await loop.create_connection()' and
+            # `_schedule_call_connection_made` and
+            # the actual `_call_connection_made`.
+            self._wakeup_waiter()
+            return
+
+        # Set _protocol_connected to 1 before calling "connection_made":
+        # if transport is aborted or closed, "connection_lost" will
+        # still be scheduled.
+        self._protocol_connected = 1
+
+        try:
+            self._protocol.connection_made(self)
+        except BaseException:
+            self._wakeup_waiter()
+            raise
+
+        if not self._is_alive():
+            # This might happen when "transport.abort()" is called
+            # from "Protocol.connection_made".
+            self._wakeup_waiter()
+            return
+
+        self._start_reading()
+        self._wakeup_waiter()
+
+    cdef _call_connection_lost(self, exc):
+        if self._waiter is not None:
+            if not self._waiter.done():
+                self._waiter.set_exception(exc)
+            self._waiter = None
+
+        if self._closed:
+            # The handle is closed -- likely, _call_connection_lost
+            # was already called before.
+            return
+
+        try:
+            if self._protocol_connected:
+                self._protocol.connection_lost(exc)
+        finally:
+            self._clear_protocol()
+
+            self._close()
+
+            server = self._server
+            if server is not None:
+                (server)._detach()
+                self._server = None
+
+    cdef inline _set_server(self, Server server):
+        self._server = server
+        (server)._attach()
+
+    cdef inline _set_waiter(self, object waiter):
+        if waiter is not None and not isfuture(waiter):
+            raise TypeError(
+                f'invalid waiter object {waiter!r}, expected asyncio.Future')
+
+        self._waiter = waiter
+
+    cdef _set_protocol(self, object protocol):
+        self._protocol = protocol
+        # Store a reference to the bound method directly
+        try:
+            self._protocol_data_received = protocol.data_received
+        except AttributeError:
+            pass
+
+    cdef _clear_protocol(self):
+        self._protocol = None
+        self._protocol_data_received = None
+
+    cdef inline _init_protocol(self):
+        self._loop._track_transport(self)
+        if self._protocol is None:
+            raise RuntimeError('invalid _init_protocol call')
+        self._schedule_call_connection_made()
+
+    cdef inline _add_extra_info(self, str name, object obj):
+        if self._extra_info is None:
+            self._extra_info = {}
+        self._extra_info[name] = obj
+
+    cdef bint _is_reading(self):
+        raise NotImplementedError
+
+    cdef _start_reading(self):
+        raise NotImplementedError
+
+    cdef _stop_reading(self):
+        raise NotImplementedError
+
+    # === Public API ===
+
+    property _paused:
+        # Used by SSLProto.  Might be removed in the future.
+        def __get__(self):
+            return bool(not self._is_reading())
+
+    def get_protocol(self):
+        return self._protocol
+
+    def set_protocol(self, protocol):
+        self._set_protocol(protocol)
+        if self._is_reading():
+            self._stop_reading()
+            self._start_reading()
+
+    def _force_close(self, exc):
+        # Used by SSLProto.  Might be removed in the future.
+        if self._conn_lost or self._closed:
+            return
+        if not self._closing:
+            self._closing = 1
+            self._stop_reading()
+        self._conn_lost += 1
+        self._schedule_call_connection_lost(exc)
+
+    def abort(self):
+        self._force_close(None)
+
+    def close(self):
+        if self._closing or self._closed:
+            return
+
+        self._closing = 1
+        self._stop_reading()
+
+        if not self._get_write_buffer_size():
+            # The write buffer is empty
+            self._conn_lost += 1
+            self._schedule_call_connection_lost(None)
+
+    def is_closing(self):
+        return self._closing
+
+    def get_write_buffer_size(self):
+        return self._get_write_buffer_size()
+
+    def set_write_buffer_limits(self, high=None, low=None):
+        self._ensure_alive()
+
+        self._high_water, self._low_water = add_flowcontrol_defaults(
+            high, low, FLOW_CONTROL_HIGH_WATER)
+
+        self._maybe_pause_protocol()
+
+    def get_write_buffer_limits(self):
+        return (self._low_water, self._high_water)
+
+    def get_extra_info(self, name, default=None):
+        if self._extra_info is not None and name in self._extra_info:
+            return self._extra_info[name]
+        if name == 'socket':
+            return self._get_socket()
+        if name == 'sockname':
+            return self._get_socket().getsockname()
+        if name == 'peername':
+            try:
+                return self._get_socket().getpeername()
+            except socket_error:
+                return default
+        return default
diff --git a/lib/python3.12/site-packages/uvloop/handles/check.pxd b/lib/python3.12/site-packages/uvloop/handles/check.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..86cfd8fb8e065bc3f662395d571a4b43eaae2a87
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/check.pxd
@@ -0,0 +1,14 @@
+cdef class UVCheck(UVHandle):
+    cdef:
+        Handle h
+        bint running
+
+    # All "inline" methods are final
+
+    cdef _init(self, Loop loop, Handle h)
+
+    cdef inline stop(self)
+    cdef inline start(self)
+
+    @staticmethod
+    cdef UVCheck new(Loop loop, Handle h)
diff --git a/lib/python3.12/site-packages/uvloop/handles/check.pyx b/lib/python3.12/site-packages/uvloop/handles/check.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..1a61c4e91bdd30a8cc238adca2c3d7c158afbfe0
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/check.pyx
@@ -0,0 +1,72 @@
+@cython.no_gc_clear
+cdef class UVCheck(UVHandle):
+    cdef _init(self, Loop loop, Handle h):
+        cdef int err
+
+        self._start_init(loop)
+
+        self._handle = PyMem_RawMalloc(sizeof(uv.uv_check_t))
+        if self._handle is NULL:
+            self._abort_init()
+            raise MemoryError()
+
+        err = uv.uv_check_init(self._loop.uvloop, self._handle)
+        if err < 0:
+            self._abort_init()
+            raise convert_error(err)
+
+        self._finish_init()
+
+        self.h = h
+        self.running = 0
+
+    cdef inline stop(self):
+        cdef int err
+
+        if not self._is_alive():
+            self.running = 0
+            return
+
+        if self.running == 1:
+            err = uv.uv_check_stop(self._handle)
+            self.running = 0
+            if err < 0:
+                exc = convert_error(err)
+                self._fatal_error(exc, True)
+                return
+
+    cdef inline start(self):
+        cdef int err
+
+        self._ensure_alive()
+
+        if self.running == 0:
+            err = uv.uv_check_start(self._handle,
+                                    cb_check_callback)
+            if err < 0:
+                exc = convert_error(err)
+                self._fatal_error(exc, True)
+                return
+            self.running = 1
+
+    @staticmethod
+    cdef UVCheck new(Loop loop, Handle h):
+        cdef UVCheck handle
+        handle = UVCheck.__new__(UVCheck)
+        handle._init(loop, h)
+        return handle
+
+
+cdef void cb_check_callback(
+    uv.uv_check_t* handle,
+) noexcept with gil:
+    if __ensure_handle_data(handle, "UVCheck callback") == 0:
+        return
+
+    cdef:
+        UVCheck check =  handle.data
+        Handle h = check.h
+    try:
+        h._run()
+    except BaseException as ex:
+        check._error(ex, False)
diff --git a/lib/python3.12/site-packages/uvloop/handles/fsevent.pxd b/lib/python3.12/site-packages/uvloop/handles/fsevent.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..3a32428506f73dc54c77088d50e602aa088596ce
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/fsevent.pxd
@@ -0,0 +1,12 @@
+cdef class UVFSEvent(UVHandle):
+    cdef:
+        object callback
+        bint running
+
+    cdef _init(self, Loop loop, object callback, object context)
+    cdef _close(self)
+    cdef start(self, char* path, int flags)
+    cdef stop(self)
+
+    @staticmethod
+    cdef UVFSEvent new(Loop loop, object callback, object context)
diff --git a/lib/python3.12/site-packages/uvloop/handles/fsevent.pyx b/lib/python3.12/site-packages/uvloop/handles/fsevent.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..6ed6433ca410e829ef997f8dc519608e1948bea8
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/fsevent.pyx
@@ -0,0 +1,116 @@
+import enum
+
+
+class FileSystemEvent(enum.IntEnum):
+    RENAME = uv.UV_RENAME
+    CHANGE = uv.UV_CHANGE
+    RENAME_CHANGE = RENAME | CHANGE
+
+
+@cython.no_gc_clear
+cdef class UVFSEvent(UVHandle):
+    cdef _init(self, Loop loop, object callback, object context):
+        cdef int err
+
+        self._start_init(loop)
+
+        self._handle = PyMem_RawMalloc(
+            sizeof(uv.uv_fs_event_t)
+        )
+        if self._handle is NULL:
+            self._abort_init()
+            raise MemoryError()
+
+        err = uv.uv_fs_event_init(
+            self._loop.uvloop, self._handle
+        )
+        if err < 0:
+            self._abort_init()
+            raise convert_error(err)
+
+        self._finish_init()
+
+        self.running = 0
+        self.callback = callback
+        if context is None:
+            context = Context_CopyCurrent()
+        self.context = context
+
+    cdef start(self, char* path, int flags):
+        cdef int err
+
+        self._ensure_alive()
+
+        if self.running == 0:
+            err = uv.uv_fs_event_start(
+                self._handle,
+                __uvfsevent_callback,
+                path,
+                flags,
+            )
+            if err < 0:
+                exc = convert_error(err)
+                self._fatal_error(exc, True)
+                return
+            self.running = 1
+
+    cdef stop(self):
+        cdef int err
+
+        if not self._is_alive():
+            self.running = 0
+            return
+
+        if self.running == 1:
+            err = uv.uv_fs_event_stop(self._handle)
+            self.running = 0
+            if err < 0:
+                exc = convert_error(err)
+                self._fatal_error(exc, True)
+                return
+
+    cdef _close(self):
+        try:
+            self.stop()
+        finally:
+            UVHandle._close(self)
+
+    def cancel(self):
+        self._close()
+
+    def cancelled(self):
+        return self.running == 0
+
+    @staticmethod
+    cdef UVFSEvent new(Loop loop, object callback, object context):
+        cdef UVFSEvent handle
+        handle = UVFSEvent.__new__(UVFSEvent)
+        handle._init(loop, callback, context)
+        return handle
+
+
+cdef void __uvfsevent_callback(
+    uv.uv_fs_event_t* handle,
+    const char *filename,
+    int events,
+    int status,
+) noexcept with gil:
+    if __ensure_handle_data(
+        handle, "UVFSEvent callback"
+    ) == 0:
+        return
+
+    cdef:
+        UVFSEvent fs_event =  handle.data
+        Handle h
+
+    try:
+        h = new_Handle(
+            fs_event._loop,
+            fs_event.callback,
+            (filename, FileSystemEvent(events)),
+            fs_event.context,
+        )
+        h._run()
+    except BaseException as ex:
+        fs_event._error(ex, False)
diff --git a/lib/python3.12/site-packages/uvloop/handles/handle.pxd b/lib/python3.12/site-packages/uvloop/handles/handle.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..5af1c14cfcedbae283422797dfc7b1f1eb97af60
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/handle.pxd
@@ -0,0 +1,48 @@
+cdef class UVHandle:
+    cdef:
+        uv.uv_handle_t *_handle
+        Loop _loop
+        readonly _source_traceback
+        bint _closed
+        bint _inited
+        object context
+
+        # Added to enable current UDPTransport implementation,
+        # which doesn't use libuv handles.
+        bint _has_handle
+
+    # All "inline" methods are final
+
+    cdef inline _start_init(self, Loop loop)
+    cdef inline _abort_init(self)
+    cdef inline _finish_init(self)
+
+    cdef inline bint _is_alive(self)
+    cdef inline _ensure_alive(self)
+
+    cdef _error(self, exc, throw)
+    cdef _fatal_error(self, exc, throw, reason=?)
+
+    cdef _warn_unclosed(self)
+
+    cdef _free(self)
+    cdef _close(self)
+
+
+cdef class UVSocketHandle(UVHandle):
+    cdef:
+        # Points to a Python file-object that should be closed
+        # when the transport is closing.  Used by pipes.  This
+        # should probably be refactored somehow.
+        object _fileobj
+        object __cached_socket
+
+    # All "inline" methods are final
+
+    cdef _fileno(self)
+
+    cdef _new_socket(self)
+    cdef inline _get_socket(self)
+    cdef inline _attach_fileobj(self, object file)
+
+    cdef _open(self, int sockfd)
diff --git a/lib/python3.12/site-packages/uvloop/handles/handle.pyx b/lib/python3.12/site-packages/uvloop/handles/handle.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..2c96458b1c897fd9a88211b683dd44d2d329ec09
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/handle.pyx
@@ -0,0 +1,395 @@
+cdef class UVHandle:
+    """A base class for all libuv handles.
+
+    Automatically manages memory deallocation and closing.
+
+    Important:
+
+       1. call "_ensure_alive()" before calling any libuv functions on
+          your handles.
+
+       2. call "__ensure_handle_data" in *all* libuv handle callbacks.
+    """
+
+    def __cinit__(self):
+        self._closed = 0
+        self._inited = 0
+        self._has_handle = 1
+        self._handle = NULL
+        self._loop = None
+        self._source_traceback = None
+
+    def __init__(self):
+        raise TypeError(
+            '{} is not supposed to be instantiated from Python'.format(
+                self.__class__.__name__))
+
+    def __dealloc__(self):
+        if UVLOOP_DEBUG:
+            if self._loop is not None:
+                if self._inited:
+                    self._loop._debug_handles_current.subtract([
+                        self.__class__.__name__])
+            else:
+                # No "@cython.no_gc_clear" decorator on this UVHandle
+                raise RuntimeError(
+                    '{} without @no_gc_clear; loop was set to None by GC'
+                    .format(self.__class__.__name__))
+
+        if self._handle is NULL:
+            return
+
+        # -> When we're at this point, something is wrong <-
+
+        if self._handle.loop is NULL:
+            # The handle wasn't initialized with "uv_{handle}_init"
+            self._closed = 1
+            self._free()
+            raise RuntimeError(
+                '{} is open in __dealloc__ with loop set to NULL'
+                .format(self.__class__.__name__))
+
+        if self._closed:
+            # So _handle is not NULL and self._closed == 1?
+            raise RuntimeError(
+                '{}.__dealloc__: _handle is NULL, _closed == 1'.format(
+                    self.__class__.__name__))
+
+        # The handle is dealloced while open.  Let's try to close it.
+        # Situations when this is possible include unhandled exceptions,
+        # errors during Handle.__cinit__/__init__ etc.
+        if self._inited:
+            self._handle.data = NULL
+            uv.uv_close(self._handle, __uv_close_handle_cb)  # void; no errors
+            self._handle = NULL
+            self._warn_unclosed()
+        else:
+            # The handle was allocated, but not initialized
+            self._closed = 1
+            self._free()
+
+    cdef _free(self):
+        if self._handle == NULL:
+            return
+
+        if UVLOOP_DEBUG and self._inited:
+            self._loop._debug_uv_handles_freed += 1
+
+        PyMem_RawFree(self._handle)
+        self._handle = NULL
+
+    cdef _warn_unclosed(self):
+        if self._source_traceback is not None:
+            try:
+                tb = ''.join(tb_format_list(self._source_traceback))
+                tb = 'object created at (most recent call last):\n{}'.format(
+                    tb.rstrip())
+            except Exception as ex:
+                msg = (
+                    'unclosed resource {!r}; could not serialize '
+                    'debug traceback: {}: {}'
+                ).format(self, type(ex).__name__, ex)
+            else:
+                msg = 'unclosed resource {!r}; {}'.format(self, tb)
+        else:
+            msg = 'unclosed resource {!r}'.format(self)
+        warnings_warn(msg, ResourceWarning)
+
+    cdef inline _abort_init(self):
+        if self._handle is not NULL:
+            self._free()
+
+        try:
+            if UVLOOP_DEBUG:
+                name = self.__class__.__name__
+                if self._inited:
+                    raise RuntimeError(
+                        '_abort_init: {}._inited is set'.format(name))
+                if self._closed:
+                    raise RuntimeError(
+                        '_abort_init: {}._closed is set'.format(name))
+        finally:
+            self._closed = 1
+
+    cdef inline _finish_init(self):
+        self._inited = 1
+        if self._has_handle == 1:
+            self._handle.data = self
+        if self._loop._debug:
+            self._source_traceback = extract_stack()
+        if UVLOOP_DEBUG:
+            cls_name = self.__class__.__name__
+            self._loop._debug_uv_handles_total += 1
+            self._loop._debug_handles_total.update([cls_name])
+            self._loop._debug_handles_current.update([cls_name])
+
+    cdef inline _start_init(self, Loop loop):
+        if UVLOOP_DEBUG:
+            if self._loop is not None:
+                raise RuntimeError(
+                    '{}._start_init can only be called once'.format(
+                        self.__class__.__name__))
+
+        self._loop = loop
+
+    cdef inline bint _is_alive(self):
+        cdef bint res
+        res = self._closed != 1 and self._inited == 1
+        if UVLOOP_DEBUG:
+            if res and self._has_handle == 1:
+                name = self.__class__.__name__
+                if self._handle is NULL:
+                    raise RuntimeError(
+                        '{} is alive, but _handle is NULL'.format(name))
+                if self._loop is None:
+                    raise RuntimeError(
+                        '{} is alive, but _loop is None'.format(name))
+                if self._handle.loop is not self._loop.uvloop:
+                    raise RuntimeError(
+                        '{} is alive, but _handle.loop is not '
+                        'initialized'.format(name))
+                if self._handle.data is not self:
+                    raise RuntimeError(
+                        '{} is alive, but _handle.data is not '
+                        'initialized'.format(name))
+        return res
+
+    cdef inline _ensure_alive(self):
+        if not self._is_alive():
+            raise RuntimeError(
+                'unable to perform operation on {!r}; '
+                'the handler is closed'.format(self))
+
+    cdef _fatal_error(self, exc, throw, reason=None):
+        # Fatal error means an error that was returned by the
+        # underlying libuv handle function.  We usually can't
+        # recover from that, hence we just close the handle.
+        self._close()
+
+        if throw or self._loop is None:
+            raise exc
+        else:
+            self._loop._handle_exception(exc)
+
+    cdef _error(self, exc, throw):
+        # A non-fatal error is usually an error that was caught
+        # by the handler, but was originated in the client code
+        # (not in libuv).  In this case we either want to simply
+        # raise or log it.
+        if throw or self._loop is None:
+            raise exc
+        else:
+            self._loop._handle_exception(exc)
+
+    cdef _close(self):
+        if self._closed == 1:
+            return
+
+        self._closed = 1
+
+        if self._handle is NULL:
+            return
+
+        if UVLOOP_DEBUG:
+            if self._handle.data is NULL:
+                raise RuntimeError(
+                    '{}._close: _handle.data is NULL'.format(
+                        self.__class__.__name__))
+
+            if self._handle.data is not self:
+                raise RuntimeError(
+                    '{}._close: _handle.data is not UVHandle/self'.format(
+                        self.__class__.__name__))
+
+            if uv.uv_is_closing(self._handle):
+                raise RuntimeError(
+                    '{}._close: uv_is_closing() is true'.format(
+                        self.__class__.__name__))
+
+        # We want the handle wrapper (UVHandle) to stay alive until
+        # the closing callback fires.
+        Py_INCREF(self)
+        uv.uv_close(self._handle, __uv_close_handle_cb)  # void; no errors
+
+    def __repr__(self):
+        return '<{} closed={} {:#x}>'.format(
+            self.__class__.__name__,
+            self._closed,
+            id(self))
+
+
+cdef class UVSocketHandle(UVHandle):
+
+    def __cinit__(self):
+        self._fileobj = None
+        self.__cached_socket = None
+
+    cdef _fileno(self):
+        cdef:
+            int fd
+            int err
+
+        self._ensure_alive()
+        err = uv.uv_fileno(self._handle, &fd)
+        if err < 0:
+            raise convert_error(err)
+
+        return fd
+
+    cdef _new_socket(self):
+        raise NotImplementedError
+
+    cdef inline _get_socket(self):
+        if self.__cached_socket is not None:
+            return self.__cached_socket
+
+        if not self._is_alive():
+            return None
+
+        self.__cached_socket = self._new_socket()
+        if UVLOOP_DEBUG:
+            # We don't "dup" for the "__cached_socket".
+            assert self.__cached_socket.fileno() == self._fileno()
+        return self.__cached_socket
+
+    cdef inline _attach_fileobj(self, object file):
+        # When we create a TCP/PIPE/etc connection/server based on
+        # a Python file object, we need to close the file object when
+        # the uv handle is closed.
+        socket_inc_io_ref(file)
+        self._fileobj = file
+
+    cdef _close(self):
+        if self.__cached_socket is not None:
+            (self.__cached_socket)._fd = -1
+
+        UVHandle._close(self)
+
+        try:
+            # This code will only run for transports created from
+            # Python sockets, i.e. with `loop.create_server(sock=sock)` etc.
+            if self._fileobj is not None:
+                if isinstance(self._fileobj, socket_socket):
+                    # Detaching the socket object is the ideal solution:
+                    # * libuv will actually close the FD;
+                    # * detach() call will reset FD for the Python socket
+                    #   object, which means that it won't be closed 2nd time
+                    #   when the socket object is GCed.
+                    #
+                    # No need to call `socket_dec_io_ref()`, as
+                    # `socket.detach()` ignores `socket._io_refs`.
+                    self._fileobj.detach()
+                else:
+                    try:
+                        # `socket.close()` will raise an EBADF because libuv
+                        # has already closed the underlying FD.
+                        self._fileobj.close()
+                    except OSError as ex:
+                        if ex.errno != errno_EBADF:
+                            raise
+        except Exception as ex:
+            self._loop.call_exception_handler({
+                'exception': ex,
+                'transport': self,
+                'message': f'could not close attached file object '
+                           f'{self._fileobj!r}',
+            })
+        finally:
+            self._fileobj = None
+
+    cdef _open(self, int sockfd):
+        raise NotImplementedError
+
+
+cdef inline bint __ensure_handle_data(uv.uv_handle_t* handle,
+                                      const char* handle_ctx):
+
+    cdef Loop loop
+
+    if UVLOOP_DEBUG:
+        if handle.loop is NULL:
+            raise RuntimeError(
+                'handle.loop is NULL in __ensure_handle_data')
+
+        if handle.loop.data is NULL:
+            raise RuntimeError(
+                'handle.loop.data is NULL in __ensure_handle_data')
+
+    if handle.data is NULL:
+        loop = handle.loop.data
+        loop.call_exception_handler({
+            'message': '{} called with handle.data == NULL'.format(
+                handle_ctx.decode('latin-1'))
+        })
+        return 0
+
+    if handle.data is NULL:
+        # The underlying UVHandle object was GCed with an open uv_handle_t.
+        loop = handle.loop.data
+        loop.call_exception_handler({
+            'message': '{} called after destroying the UVHandle'.format(
+                handle_ctx.decode('latin-1'))
+        })
+        return 0
+
+    return 1
+
+
+cdef void __uv_close_handle_cb(uv.uv_handle_t* handle) noexcept with gil:
+    cdef UVHandle h
+
+    if handle.data is NULL:
+        # The original UVHandle is long dead. Just free the mem of
+        # the uv_handle_t* handler.
+
+        if UVLOOP_DEBUG:
+            if handle.loop == NULL or handle.loop.data == NULL:
+                raise RuntimeError(
+                    '__uv_close_handle_cb: handle.loop is invalid')
+            (handle.loop.data)._debug_uv_handles_freed += 1
+
+        PyMem_RawFree(handle)
+    else:
+        h = handle.data
+        try:
+            if UVLOOP_DEBUG:
+                if not h._has_handle:
+                    raise RuntimeError(
+                        'has_handle=0 in __uv_close_handle_cb')
+                h._loop._debug_handles_closed.update([
+                    h.__class__.__name__])
+            h._free()
+        finally:
+            Py_DECREF(h)  # Was INCREFed in UVHandle._close
+
+
+cdef void __close_all_handles(Loop loop) noexcept:
+    uv.uv_walk(loop.uvloop,
+               __uv_walk_close_all_handles_cb,
+               loop)  # void
+
+
+cdef void __uv_walk_close_all_handles_cb(
+    uv.uv_handle_t* handle,
+    void* arg,
+) noexcept with gil:
+
+    cdef:
+        Loop loop = arg
+        UVHandle h
+
+    if uv.uv_is_closing(handle):
+        # The handle is closed or is closing.
+        return
+
+    if handle.data is NULL:
+        # This shouldn't happen. Ever.
+        loop.call_exception_handler({
+            'message': 'handle.data is NULL in __close_all_handles_cb'
+        })
+        return
+
+    h = handle.data
+    if not h._closed:
+        h._warn_unclosed()
+        h._close()
diff --git a/lib/python3.12/site-packages/uvloop/handles/idle.pxd b/lib/python3.12/site-packages/uvloop/handles/idle.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..cf7b19f64b46551d815c4e6d4f6545e3d70b2636
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/idle.pxd
@@ -0,0 +1,14 @@
+cdef class UVIdle(UVHandle):
+    cdef:
+        Handle h
+        bint running
+
+    # All "inline" methods are final
+
+    cdef _init(self, Loop loop, Handle h)
+
+    cdef inline stop(self)
+    cdef inline start(self)
+
+    @staticmethod
+    cdef UVIdle new(Loop loop, Handle h)
diff --git a/lib/python3.12/site-packages/uvloop/handles/idle.pyx b/lib/python3.12/site-packages/uvloop/handles/idle.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..91c641f6c0170de4cb9e7797a1179a2621198ef7
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/idle.pyx
@@ -0,0 +1,72 @@
+@cython.no_gc_clear
+cdef class UVIdle(UVHandle):
+    cdef _init(self, Loop loop, Handle h):
+        cdef int err
+
+        self._start_init(loop)
+
+        self._handle = PyMem_RawMalloc(sizeof(uv.uv_idle_t))
+        if self._handle is NULL:
+            self._abort_init()
+            raise MemoryError()
+
+        err = uv.uv_idle_init(self._loop.uvloop, self._handle)
+        if err < 0:
+            self._abort_init()
+            raise convert_error(err)
+
+        self._finish_init()
+
+        self.h = h
+        self.running = 0
+
+    cdef inline stop(self):
+        cdef int err
+
+        if not self._is_alive():
+            self.running = 0
+            return
+
+        if self.running == 1:
+            err = uv.uv_idle_stop(self._handle)
+            self.running = 0
+            if err < 0:
+                exc = convert_error(err)
+                self._fatal_error(exc, True)
+                return
+
+    cdef inline start(self):
+        cdef int err
+
+        self._ensure_alive()
+
+        if self.running == 0:
+            err = uv.uv_idle_start(self._handle,
+                                   cb_idle_callback)
+            if err < 0:
+                exc = convert_error(err)
+                self._fatal_error(exc, True)
+                return
+            self.running = 1
+
+    @staticmethod
+    cdef UVIdle new(Loop loop, Handle h):
+        cdef UVIdle handle
+        handle = UVIdle.__new__(UVIdle)
+        handle._init(loop, h)
+        return handle
+
+
+cdef void cb_idle_callback(
+    uv.uv_idle_t* handle,
+) noexcept with gil:
+    if __ensure_handle_data(handle, "UVIdle callback") == 0:
+        return
+
+    cdef:
+        UVIdle idle =  handle.data
+        Handle h = idle.h
+    try:
+        h._run()
+    except BaseException as ex:
+        idle._error(ex, False)
diff --git a/lib/python3.12/site-packages/uvloop/handles/pipe.pxd b/lib/python3.12/site-packages/uvloop/handles/pipe.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..56fc2658bb1e223bbc342283bdf641aba77d4733
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/pipe.pxd
@@ -0,0 +1,33 @@
+cdef class UnixServer(UVStreamServer):
+
+    cdef bind(self, str path)
+
+    @staticmethod
+    cdef UnixServer new(Loop loop, object protocol_factory, Server server,
+                        object backlog,
+                        object ssl,
+                        object ssl_handshake_timeout,
+                        object ssl_shutdown_timeout)
+
+
+cdef class UnixTransport(UVStream):
+
+    @staticmethod
+    cdef UnixTransport new(Loop loop, object protocol, Server server,
+                           object waiter, object context)
+
+    cdef connect(self, char* addr)
+
+
+cdef class ReadUnixTransport(UVStream):
+
+    @staticmethod
+    cdef ReadUnixTransport new(Loop loop, object protocol, Server server,
+                               object waiter)
+
+
+cdef class WriteUnixTransport(UVStream):
+
+    @staticmethod
+    cdef WriteUnixTransport new(Loop loop, object protocol, Server server,
+                                object waiter)
diff --git a/lib/python3.12/site-packages/uvloop/handles/pipe.pyx b/lib/python3.12/site-packages/uvloop/handles/pipe.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..4b95ed6e9deb41bf3f014b06af673f1a18a55557
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/pipe.pyx
@@ -0,0 +1,247 @@
+cdef __pipe_init_uv_handle(UVStream handle, Loop loop):
+    cdef int err
+
+    handle._handle = PyMem_RawMalloc(sizeof(uv.uv_pipe_t))
+    if handle._handle is NULL:
+        handle._abort_init()
+        raise MemoryError()
+
+    # Initialize pipe handle with ipc=0.
+    # ipc=1 means that libuv will use recvmsg/sendmsg
+    # instead of recv/send.
+    err = uv.uv_pipe_init(handle._loop.uvloop,
+                          handle._handle,
+                          0)
+    # UV_HANDLE_READABLE allows calling uv_read_start() on this pipe
+    # even if it is O_WRONLY, see also #317, libuv/libuv#2058
+    handle._handle.flags |= uv.UV_INTERNAL_HANDLE_READABLE
+    if err < 0:
+        handle._abort_init()
+        raise convert_error(err)
+
+    handle._finish_init()
+
+
+cdef __pipe_open(UVStream handle, int fd):
+    cdef int err
+    err = uv.uv_pipe_open(handle._handle,
+                          fd)
+    if err < 0:
+        exc = convert_error(err)
+        raise exc
+
+
+cdef __pipe_get_socket(UVSocketHandle handle):
+    fileno = handle._fileno()
+    return PseudoSocket(uv.AF_UNIX, uv.SOCK_STREAM, 0, fileno)
+
+
+@cython.no_gc_clear
+cdef class UnixServer(UVStreamServer):
+
+    @staticmethod
+    cdef UnixServer new(Loop loop, object protocol_factory, Server server,
+                        object backlog,
+                        object ssl,
+                        object ssl_handshake_timeout,
+                        object ssl_shutdown_timeout):
+
+        cdef UnixServer handle
+        handle = UnixServer.__new__(UnixServer)
+        handle._init(loop, protocol_factory, server, backlog,
+                     ssl, ssl_handshake_timeout, ssl_shutdown_timeout)
+        __pipe_init_uv_handle(handle, loop)
+        return handle
+
+    cdef _new_socket(self):
+        return __pipe_get_socket(self)
+
+    cdef _open(self, int sockfd):
+        self._ensure_alive()
+        __pipe_open(self, sockfd)
+        self._mark_as_open()
+
+    cdef bind(self, str path):
+        cdef int err
+        self._ensure_alive()
+        err = uv.uv_pipe_bind(self._handle,
+                              path.encode())
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+
+        self._mark_as_open()
+
+    cdef UVStream _make_new_transport(self, object protocol, object waiter,
+                                      object context):
+        cdef UnixTransport tr
+        tr = UnixTransport.new(self._loop, protocol, self._server, waiter,
+                               context)
+        return tr
+
+    cdef _close(self):
+        sock = self._fileobj
+        if sock is not None and sock in self._loop._unix_server_sockets:
+            path = sock.getsockname()
+        else:
+            path = None
+
+        UVStreamServer._close(self)
+
+        if path is not None:
+            prev_ino = self._loop._unix_server_sockets[sock]
+            del self._loop._unix_server_sockets[sock]
+            try:
+                if os_stat(path).st_ino == prev_ino:
+                    os_unlink(path)
+            except FileNotFoundError:
+                pass
+            except OSError as err:
+                aio_logger.error('Unable to clean up listening UNIX socket '
+                                 '%r: %r', path, err)
+
+
+@cython.no_gc_clear
+cdef class UnixTransport(UVStream):
+
+    @staticmethod
+    cdef UnixTransport new(Loop loop, object protocol, Server server,
+                           object waiter, object context):
+
+        cdef UnixTransport handle
+        handle = UnixTransport.__new__(UnixTransport)
+        handle._init(loop, protocol, server, waiter, context)
+        __pipe_init_uv_handle(handle, loop)
+        return handle
+
+    cdef _new_socket(self):
+        return __pipe_get_socket(self)
+
+    cdef _open(self, int sockfd):
+        __pipe_open(self, sockfd)
+
+    cdef connect(self, char* addr):
+        cdef _PipeConnectRequest req
+        req = _PipeConnectRequest(self._loop, self)
+        req.connect(addr)
+
+
+@cython.no_gc_clear
+cdef class ReadUnixTransport(UVStream):
+
+    @staticmethod
+    cdef ReadUnixTransport new(Loop loop, object protocol, Server server,
+                               object waiter):
+        cdef ReadUnixTransport handle
+        handle = ReadUnixTransport.__new__(ReadUnixTransport)
+        # This is only used in connect_read_pipe() and subprocess_shell/exec()
+        # directly, we could simply copy the current context.
+        handle._init(loop, protocol, server, waiter, Context_CopyCurrent())
+        __pipe_init_uv_handle(handle, loop)
+        return handle
+
+    cdef _new_socket(self):
+        return __pipe_get_socket(self)
+
+    cdef _open(self, int sockfd):
+        __pipe_open(self, sockfd)
+
+    def get_write_buffer_limits(self):
+        raise NotImplementedError
+
+    def set_write_buffer_limits(self, high=None, low=None):
+        raise NotImplementedError
+
+    def get_write_buffer_size(self):
+        raise NotImplementedError
+
+    def write(self, data):
+        raise NotImplementedError
+
+    def writelines(self, list_of_data):
+        raise NotImplementedError
+
+    def write_eof(self):
+        raise NotImplementedError
+
+    def can_write_eof(self):
+        raise NotImplementedError
+
+    def abort(self):
+        raise NotImplementedError
+
+
+@cython.no_gc_clear
+cdef class WriteUnixTransport(UVStream):
+
+    @staticmethod
+    cdef WriteUnixTransport new(Loop loop, object protocol, Server server,
+                                object waiter):
+        cdef WriteUnixTransport handle
+        handle = WriteUnixTransport.__new__(WriteUnixTransport)
+
+        # We listen for read events on write-end of the pipe. When
+        # the read-end is close, the uv_stream_t.read callback will
+        # receive an error -- we want to silence that error, and just
+        # close the transport.
+        handle._close_on_read_error()
+
+        # This is only used in connect_write_pipe() and subprocess_shell/exec()
+        # directly, we could simply copy the current context.
+        handle._init(loop, protocol, server, waiter, Context_CopyCurrent())
+        __pipe_init_uv_handle(handle, loop)
+        return handle
+
+    cdef _new_socket(self):
+        return __pipe_get_socket(self)
+
+    cdef _open(self, int sockfd):
+        __pipe_open(self, sockfd)
+
+    def pause_reading(self):
+        raise NotImplementedError
+
+    def resume_reading(self):
+        raise NotImplementedError
+
+
+cdef class _PipeConnectRequest(UVRequest):
+    cdef:
+        UnixTransport transport
+        uv.uv_connect_t _req_data
+
+    def __cinit__(self, loop, transport):
+        self.request =  &self._req_data
+        self.request.data = self
+        self.transport = transport
+
+    cdef connect(self, char* addr):
+        # uv_pipe_connect returns void
+        uv.uv_pipe_connect(self.request,
+                           self.transport._handle,
+                           addr,
+                           __pipe_connect_callback)
+
+cdef void __pipe_connect_callback(
+    uv.uv_connect_t* req,
+    int status,
+) noexcept with gil:
+    cdef:
+        _PipeConnectRequest wrapper
+        UnixTransport transport
+
+    wrapper = <_PipeConnectRequest> req.data
+    transport = wrapper.transport
+
+    if status < 0:
+        exc = convert_error(status)
+    else:
+        exc = None
+
+    try:
+        transport._on_connect(exc)
+    except BaseException as ex:
+        wrapper.transport._fatal_error(ex, False)
+    finally:
+        wrapper.on_done()
diff --git a/lib/python3.12/site-packages/uvloop/handles/poll.pxd b/lib/python3.12/site-packages/uvloop/handles/poll.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..c220540269cde4f7a32d4170c966af05d046501d
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/poll.pxd
@@ -0,0 +1,25 @@
+cdef class UVPoll(UVHandle):
+    cdef:
+        int fd
+        Handle reading_handle
+        Handle writing_handle
+
+    cdef _init(self, Loop loop, int fd)
+    cdef _close(self)
+
+    cdef inline _poll_start(self, int flags)
+    cdef inline _poll_stop(self)
+
+    cdef int is_active(self) noexcept
+
+    cdef is_reading(self)
+    cdef is_writing(self)
+
+    cdef start_reading(self, Handle callback)
+    cdef start_writing(self, Handle callback)
+    cdef stop_reading(self)
+    cdef stop_writing(self)
+    cdef stop(self)
+
+    @staticmethod
+    cdef UVPoll new(Loop loop, int fd)
diff --git a/lib/python3.12/site-packages/uvloop/handles/poll.pyx b/lib/python3.12/site-packages/uvloop/handles/poll.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..c905e9b0b7ee9668099b98aea1db9ad2bbf53f4a
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/poll.pyx
@@ -0,0 +1,233 @@
+@cython.no_gc_clear
+cdef class UVPoll(UVHandle):
+    cdef _init(self, Loop loop, int fd):
+        cdef int err
+
+        self._start_init(loop)
+
+        self._handle = PyMem_RawMalloc(sizeof(uv.uv_poll_t))
+        if self._handle is NULL:
+            self._abort_init()
+            raise MemoryError()
+
+        err = uv.uv_poll_init(self._loop.uvloop,
+                              self._handle, fd)
+        if err < 0:
+            self._abort_init()
+            raise convert_error(err)
+
+        self._finish_init()
+
+        self.fd = fd
+        self.reading_handle = None
+        self.writing_handle = None
+
+    @staticmethod
+    cdef UVPoll new(Loop loop, int fd):
+        cdef UVPoll handle
+        handle = UVPoll.__new__(UVPoll)
+        handle._init(loop, fd)
+        return handle
+
+    cdef int is_active(self) noexcept:
+        return (self.reading_handle is not None or
+                self.writing_handle is not None)
+
+    cdef inline _poll_start(self, int flags):
+        cdef int err
+
+        self._ensure_alive()
+
+        err = uv.uv_poll_start(
+            self._handle,
+            flags,
+            __on_uvpoll_event)
+
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+
+    cdef inline _poll_stop(self):
+        cdef int err
+
+        if not self._is_alive():
+            return
+
+        err = uv.uv_poll_stop(self._handle)
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+
+        cdef:
+            int backend_id
+            system.epoll_event dummy_event
+
+        if system.PLATFORM_IS_LINUX:
+            # libuv doesn't remove the FD from epoll immediately
+            # after uv_poll_stop or uv_poll_close, causing hard
+            # to debug issue with dup-ed file descriptors causing
+            # CPU burn in epoll/epoll_ctl:
+            #    https://github.com/MagicStack/uvloop/issues/61
+            #
+            # It's safe though to manually call epoll_ctl here,
+            # after calling uv_poll_stop.
+
+            backend_id = uv.uv_backend_fd(self._loop.uvloop)
+            if backend_id != -1:
+                memset(&dummy_event, 0, sizeof(dummy_event))
+                system.epoll_ctl(
+                    backend_id,
+                    system.EPOLL_CTL_DEL,
+                    self.fd,
+                    &dummy_event)  # ignore errors
+
+    cdef is_reading(self):
+        return self._is_alive() and self.reading_handle is not None
+
+    cdef is_writing(self):
+        return self._is_alive() and self.writing_handle is not None
+
+    cdef start_reading(self, Handle callback):
+        cdef:
+            int mask = 0
+
+        if self.reading_handle is None:
+            # not reading right now, setup the handle
+
+            mask = uv.UV_READABLE
+            if self.writing_handle is not None:
+                # are we writing right now?
+                mask |= uv.UV_WRITABLE
+
+            self._poll_start(mask)
+        else:
+            self.reading_handle._cancel()
+
+        self.reading_handle = callback
+
+    cdef start_writing(self, Handle callback):
+        cdef:
+            int mask = 0
+
+        if self.writing_handle is None:
+            # not writing right now, setup the handle
+
+            mask = uv.UV_WRITABLE
+            if self.reading_handle is not None:
+                # are we reading right now?
+                mask |= uv.UV_READABLE
+
+            self._poll_start(mask)
+        else:
+            self.writing_handle._cancel()
+
+        self.writing_handle = callback
+
+    cdef stop_reading(self):
+        if self.reading_handle is None:
+            return False
+
+        self.reading_handle._cancel()
+        self.reading_handle = None
+
+        if self.writing_handle is None:
+            self.stop()
+        else:
+            self._poll_start(uv.UV_WRITABLE)
+
+        return True
+
+    cdef stop_writing(self):
+        if self.writing_handle is None:
+            return False
+
+        self.writing_handle._cancel()
+        self.writing_handle = None
+
+        if self.reading_handle is None:
+            self.stop()
+        else:
+            self._poll_start(uv.UV_READABLE)
+
+        return True
+
+    cdef stop(self):
+        if self.reading_handle is not None:
+            self.reading_handle._cancel()
+            self.reading_handle = None
+
+        if self.writing_handle is not None:
+            self.writing_handle._cancel()
+            self.writing_handle = None
+
+        self._poll_stop()
+
+    cdef _close(self):
+        if self.is_active():
+            self.stop()
+
+        UVHandle._close(self)
+
+    cdef _fatal_error(self, exc, throw, reason=None):
+        try:
+            if self.reading_handle is not None:
+                try:
+                    self.reading_handle._run()
+                except BaseException as ex:
+                    self._loop._handle_exception(ex)
+                self.reading_handle = None
+
+            if self.writing_handle is not None:
+                try:
+                    self.writing_handle._run()
+                except BaseException as ex:
+                    self._loop._handle_exception(ex)
+                self.writing_handle = None
+
+        finally:
+            self._close()
+
+
+cdef void __on_uvpoll_event(
+    uv.uv_poll_t* handle,
+    int status,
+    int events,
+) noexcept with gil:
+
+    if __ensure_handle_data(handle, "UVPoll callback") == 0:
+        return
+
+    cdef:
+        UVPoll poll =  handle.data
+
+    if status < 0:
+        exc = convert_error(status)
+        poll._fatal_error(exc, False)
+        return
+
+    if ((events & (uv.UV_READABLE | uv.UV_DISCONNECT)) and
+            poll.reading_handle is not None):
+
+        try:
+            if UVLOOP_DEBUG:
+                poll._loop._poll_read_events_total += 1
+            poll.reading_handle._run()
+        except BaseException as ex:
+            if UVLOOP_DEBUG:
+                poll._loop._poll_read_cb_errors_total += 1
+            poll._error(ex, False)
+            # continue code execution
+
+    if ((events & (uv.UV_WRITABLE | uv.UV_DISCONNECT)) and
+            poll.writing_handle is not None):
+
+        try:
+            if UVLOOP_DEBUG:
+                poll._loop._poll_write_events_total += 1
+            poll.writing_handle._run()
+        except BaseException as ex:
+            if UVLOOP_DEBUG:
+                poll._loop._poll_write_cb_errors_total += 1
+            poll._error(ex, False)
diff --git a/lib/python3.12/site-packages/uvloop/handles/process.pxd b/lib/python3.12/site-packages/uvloop/handles/process.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..970abcfc84d73ea41516a81959f131ef507cb593
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/process.pxd
@@ -0,0 +1,80 @@
+cdef class UVProcess(UVHandle):
+    cdef:
+        object _returncode
+        object _pid
+
+        object _errpipe_read
+        object _errpipe_write
+        object _preexec_fn
+        bint _restore_signals
+
+        list _fds_to_close
+
+        # Attributes used to compose uv_process_options_t:
+        uv.uv_process_options_t options
+        uv.uv_stdio_container_t[3] iocnt
+        list __env
+        char **uv_opt_env
+        list __args
+        char **uv_opt_args
+        char *uv_opt_file
+        bytes __cwd
+
+    cdef _close_process_handle(self)
+
+    cdef _init(self, Loop loop, list args, dict env, cwd,
+               start_new_session,
+               _stdin, _stdout, _stderr, pass_fds,
+               debug_flags, preexec_fn, restore_signals)
+
+    cdef _after_fork(self)
+
+    cdef char** __to_cstring_array(self, list arr)
+    cdef _init_args(self, list args)
+    cdef _init_env(self, dict env)
+    cdef _init_files(self, _stdin, _stdout, _stderr)
+    cdef _init_options(self, list args, dict env, cwd, start_new_session,
+                       _stdin, _stdout, _stderr, bint force_fork)
+
+    cdef _close_after_spawn(self, int fd)
+
+    cdef _on_exit(self, int64_t exit_status, int term_signal)
+    cdef _kill(self, int signum)
+
+
+cdef class UVProcessTransport(UVProcess):
+    cdef:
+        list _exit_waiters
+        list _init_futs
+        bint _stdio_ready
+        list _pending_calls
+        object _protocol
+        bint _finished
+
+        WriteUnixTransport _stdin
+        ReadUnixTransport _stdout
+        ReadUnixTransport _stderr
+
+        object stdin_proto
+        object stdout_proto
+        object stderr_proto
+
+    cdef _file_redirect_stdio(self, int fd)
+    cdef _file_devnull(self)
+    cdef _file_inpipe(self)
+    cdef _file_outpipe(self)
+
+    cdef _check_proc(self)
+    cdef _pipe_connection_lost(self, int fd, exc)
+    cdef _pipe_data_received(self, int fd, data)
+
+    cdef _call_connection_made(self, waiter)
+    cdef _try_finish(self)
+
+    @staticmethod
+    cdef UVProcessTransport new(Loop loop, protocol, args, env, cwd,
+                                start_new_session,
+                                _stdin, _stdout, _stderr, pass_fds,
+                                waiter,
+                                debug_flags,
+                                preexec_fn, restore_signals)
diff --git a/lib/python3.12/site-packages/uvloop/handles/process.pyx b/lib/python3.12/site-packages/uvloop/handles/process.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..63b982ae597695edb63ac9b17740393bc5399786
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/process.pyx
@@ -0,0 +1,792 @@
+@cython.no_gc_clear
+cdef class UVProcess(UVHandle):
+    """Abstract class; wrapper over uv_process_t handle."""
+
+    def __cinit__(self):
+        self.uv_opt_env = NULL
+        self.uv_opt_args = NULL
+        self._returncode = None
+        self._pid = None
+        self._fds_to_close = list()
+        self._preexec_fn = None
+        self._restore_signals = True
+        self.context = Context_CopyCurrent()
+
+    cdef _close_process_handle(self):
+        # XXX: This is a workaround for a libuv bug:
+        # - https://github.com/libuv/libuv/issues/1933
+        # - https://github.com/libuv/libuv/pull/551
+        if self._handle is NULL:
+            return
+        self._handle.data = NULL
+        uv.uv_close(self._handle, __uv_close_process_handle_cb)
+        self._handle = NULL  # close callback will free() the memory
+
+    cdef _init(self, Loop loop, list args, dict env,
+               cwd, start_new_session,
+               _stdin, _stdout, _stderr,  # std* can be defined as macros in C
+               pass_fds, debug_flags, preexec_fn, restore_signals):
+
+        global __forking
+        global __forking_loop
+        global __forkHandler
+
+        cdef int err
+
+        self._start_init(loop)
+
+        self._handle = PyMem_RawMalloc(
+            sizeof(uv.uv_process_t))
+        if self._handle is NULL:
+            self._abort_init()
+            raise MemoryError()
+
+        # Too early to call _finish_init, but still a lot of work to do.
+        # Let's set handle.data to NULL, so in case something goes wrong,
+        # callbacks have a chance to avoid casting *something* into UVHandle.
+        self._handle.data = NULL
+
+        force_fork = False
+        if system.PLATFORM_IS_APPLE and not (
+            preexec_fn is None
+            and not pass_fds
+        ):
+            # see _execute_child() in CPython/subprocess.py
+            force_fork = True
+
+        try:
+            self._init_options(args, env, cwd, start_new_session,
+                               _stdin, _stdout, _stderr, force_fork)
+
+            restore_inheritable = set()
+            if pass_fds:
+                for fd in pass_fds:
+                    if not os_get_inheritable(fd):
+                        restore_inheritable.add(fd)
+                        os_set_inheritable(fd, True)
+        except Exception:
+            self._abort_init()
+            raise
+
+        if __forking or loop.active_process_handler is not None:
+            # Our pthread_atfork handlers won't work correctly when
+            # another loop is forking in another thread (even though
+            # GIL should help us to avoid that.)
+            self._abort_init()
+            raise RuntimeError(
+                'Racing with another loop to spawn a process.')
+
+        self._errpipe_read, self._errpipe_write = os_pipe()
+        fds_to_close = self._fds_to_close
+        self._fds_to_close = None
+        fds_to_close.append(self._errpipe_read)
+        # add the write pipe last so we can close it early
+        fds_to_close.append(self._errpipe_write)
+        try:
+            os_set_inheritable(self._errpipe_write, True)
+
+            self._preexec_fn = preexec_fn
+            self._restore_signals = restore_signals
+
+            loop.active_process_handler = self
+            __forking = 1
+            __forking_loop = loop
+            system.setForkHandler(&__get_fork_handler)
+
+            PyOS_BeforeFork()
+
+            err = uv.uv_spawn(loop.uvloop,
+                              self._handle,
+                              &self.options)
+
+            __forking = 0
+            __forking_loop = None
+            system.resetForkHandler()
+            loop.active_process_handler = None
+
+            PyOS_AfterFork_Parent()
+
+            if err < 0:
+                self._close_process_handle()
+                self._abort_init()
+                raise convert_error(err)
+
+            self._finish_init()
+
+            # close the write pipe early
+            os_close(fds_to_close.pop())
+
+            if preexec_fn is not None:
+                errpipe_data = bytearray()
+                while True:
+                    # XXX: This is a blocking code that has to be
+                    # rewritten (using loop.connect_read_pipe() or
+                    # otherwise.)
+                    part = os_read(self._errpipe_read, 50000)
+                    errpipe_data += part
+                    if not part or len(errpipe_data) > 50000:
+                        break
+
+        finally:
+            while fds_to_close:
+                os_close(fds_to_close.pop())
+
+            for fd in restore_inheritable:
+                os_set_inheritable(fd, False)
+
+        # asyncio caches the PID in BaseSubprocessTransport,
+        # so that the transport knows what the PID was even
+        # after the process is finished.
+        self._pid = (self._handle).pid
+
+        # Track the process handle (create a strong ref to it)
+        # to guarantee that __dealloc__ doesn't happen in an
+        # uncontrolled fashion.  We want to wait until the process
+        # exits and libuv calls __uvprocess_on_exit_callback,
+        # which will call `UVProcess._close()`, which will, in turn,
+        # untrack this handle.
+        self._loop._track_process(self)
+
+        if debug_flags & __PROCESS_DEBUG_SLEEP_AFTER_FORK:
+            time_sleep(1)
+
+        if preexec_fn is not None and errpipe_data:
+            # preexec_fn has raised an exception.  The child
+            # process must be dead now.
+            try:
+                exc_name, exc_msg = errpipe_data.split(b':', 1)
+                exc_name = exc_name.decode()
+                exc_msg = exc_msg.decode()
+            except Exception:
+                self._close()
+                raise subprocess_SubprocessError(
+                    'Bad exception data from child: {!r}'.format(
+                        errpipe_data))
+            exc_cls = getattr(__builtins__, exc_name,
+                              subprocess_SubprocessError)
+
+            exc = subprocess_SubprocessError(
+                'Exception occurred in preexec_fn.')
+            exc.__cause__ = exc_cls(exc_msg)
+            self._close()
+            raise exc
+
+    cdef _after_fork(self):
+        # See CPython/_posixsubprocess.c for details
+        cdef int err
+
+        if self._restore_signals:
+            _Py_RestoreSignals()
+
+        PyOS_AfterFork_Child()
+
+        err = uv.uv_loop_fork(self._loop.uvloop)
+        if err < 0:
+            raise convert_error(err)
+
+        if self._preexec_fn is not None:
+            try:
+                gc_disable()
+                self._preexec_fn()
+            except BaseException as ex:
+                try:
+                    with open(self._errpipe_write, 'wb') as f:
+                        f.write(str(ex.__class__.__name__).encode())
+                        f.write(b':')
+                        f.write(str(ex.args[0]).encode())
+                finally:
+                    system._exit(255)
+                    return
+            else:
+                os_close(self._errpipe_write)
+        else:
+            os_close(self._errpipe_write)
+
+    cdef _close_after_spawn(self, int fd):
+        if self._fds_to_close is None:
+            raise RuntimeError(
+                'UVProcess._close_after_spawn called after uv_spawn')
+        self._fds_to_close.append(fd)
+
+    def __dealloc__(self):
+        if self.uv_opt_env is not NULL:
+            PyMem_RawFree(self.uv_opt_env)
+            self.uv_opt_env = NULL
+
+        if self.uv_opt_args is not NULL:
+            PyMem_RawFree(self.uv_opt_args)
+            self.uv_opt_args = NULL
+
+    cdef char** __to_cstring_array(self, list arr):
+        cdef:
+            int i
+            ssize_t arr_len = len(arr)
+            bytes el
+
+            char **ret
+
+        ret = PyMem_RawMalloc((arr_len + 1) * sizeof(char *))
+        if ret is NULL:
+            raise MemoryError()
+
+        for i in range(arr_len):
+            el = arr[i]
+            # NB: PyBytes_AsString doesn't copy the data;
+            # we have to be careful when the "arr" is GCed,
+            # and it shouldn't be ever mutated.
+            ret[i] = PyBytes_AsString(el)
+
+        ret[arr_len] = NULL
+        return ret
+
+    cdef _init_options(self, list args, dict env, cwd, start_new_session,
+                       _stdin, _stdout, _stderr, bint force_fork):
+
+        memset(&self.options, 0, sizeof(uv.uv_process_options_t))
+
+        self._init_env(env)
+        self.options.env = self.uv_opt_env
+
+        self._init_args(args)
+        self.options.file = self.uv_opt_file
+        self.options.args = self.uv_opt_args
+
+        if start_new_session:
+            self.options.flags |= uv.UV_PROCESS_DETACHED
+
+        if force_fork:
+            # This is a hack to work around the change in libuv 1.44:
+            #    > macos: use posix_spawn instead of fork
+            # where Python subprocess options like preexec_fn are
+            # crippled. CPython only uses posix_spawn under a pretty
+            # strict list of conditions (see subprocess.py), and falls
+            # back to using fork() otherwise. We'd like to simulate such
+            # behavior with libuv, but unfortunately libuv doesn't
+            # provide explicit API to choose such implementation detail.
+            # Based on current (libuv 1.46) behavior, setting
+            # UV_PROCESS_SETUID or UV_PROCESS_SETGID would reliably make
+            # libuv fallback to use fork, so let's just use it for now.
+            self.options.flags |= uv.UV_PROCESS_SETUID
+            self.options.uid = uv.getuid()
+
+        if cwd is not None:
+            cwd = os_fspath(cwd)
+
+            if isinstance(cwd, str):
+                cwd = PyUnicode_EncodeFSDefault(cwd)
+            if not isinstance(cwd, bytes):
+                raise ValueError('cwd must be a str or bytes object')
+
+            self.__cwd = cwd
+            self.options.cwd = PyBytes_AsString(self.__cwd)
+
+        self.options.exit_cb = &__uvprocess_on_exit_callback
+
+        self._init_files(_stdin, _stdout, _stderr)
+
+    cdef _init_args(self, list args):
+        cdef:
+            bytes path
+            int an = len(args)
+
+        if an < 1:
+            raise ValueError('cannot spawn a process: args are empty')
+
+        self.__args = args.copy()
+        for i in range(an):
+            arg = os_fspath(args[i])
+            if isinstance(arg, str):
+                self.__args[i] = PyUnicode_EncodeFSDefault(arg)
+            elif not isinstance(arg, bytes):
+                raise TypeError('all args must be str or bytes')
+
+        path = self.__args[0]
+        self.uv_opt_file = PyBytes_AsString(path)
+        self.uv_opt_args = self.__to_cstring_array(self.__args)
+
+    cdef _init_env(self, dict env):
+        if env is not None:
+            self.__env = list()
+            for key in env:
+                val = env[key]
+
+                if isinstance(key, str):
+                    key = PyUnicode_EncodeFSDefault(key)
+                elif not isinstance(key, bytes):
+                    raise TypeError(
+                        'all environment vars must be bytes or str')
+
+                if isinstance(val, str):
+                    val = PyUnicode_EncodeFSDefault(val)
+                elif not isinstance(val, bytes):
+                    raise TypeError(
+                        'all environment values must be bytes or str')
+
+                self.__env.append(key + b'=' + val)
+
+            self.uv_opt_env = self.__to_cstring_array(self.__env)
+        else:
+            self.__env = None
+
+    cdef _init_files(self, _stdin, _stdout, _stderr):
+        self.options.stdio_count = 0
+
+    cdef _kill(self, int signum):
+        cdef int err
+        self._ensure_alive()
+        err = uv.uv_process_kill(self._handle, signum)
+        if err < 0:
+            raise convert_error(err)
+
+    cdef _on_exit(self, int64_t exit_status, int term_signal):
+        if term_signal:
+            # From Python docs:
+            #    A negative value -N indicates that the child was
+            #    terminated by signal N (POSIX only).
+            self._returncode = -term_signal
+        else:
+            self._returncode = exit_status
+
+        self._close()
+
+    cdef _close(self):
+        try:
+            if self._loop is not None:
+                self._loop._untrack_process(self)
+        finally:
+            UVHandle._close(self)
+
+
+DEF _CALL_PIPE_DATA_RECEIVED = 0
+DEF _CALL_PIPE_CONNECTION_LOST = 1
+DEF _CALL_PROCESS_EXITED = 2
+DEF _CALL_CONNECTION_LOST = 3
+
+
+@cython.no_gc_clear
+cdef class UVProcessTransport(UVProcess):
+    def __cinit__(self):
+        self._exit_waiters = []
+        self._protocol = None
+
+        self._init_futs = []
+        self._pending_calls = []
+        self._stdio_ready = 0
+
+        self._stdin = self._stdout = self._stderr = None
+        self.stdin_proto = self.stdout_proto = self.stderr_proto = None
+
+        self._finished = 0
+
+    cdef _on_exit(self, int64_t exit_status, int term_signal):
+        UVProcess._on_exit(self, exit_status, term_signal)
+
+        if self._stdio_ready:
+            self._loop.call_soon(self._protocol.process_exited,
+                                 context=self.context)
+        else:
+            self._pending_calls.append((_CALL_PROCESS_EXITED, None, None))
+
+        self._try_finish()
+
+        for waiter in self._exit_waiters:
+            if not waiter.cancelled():
+                waiter.set_result(self._returncode)
+        self._exit_waiters.clear()
+
+        self._close()
+
+    cdef _check_proc(self):
+        if not self._is_alive() or self._returncode is not None:
+            raise ProcessLookupError()
+
+    cdef _pipe_connection_lost(self, int fd, exc):
+        if self._stdio_ready:
+            self._loop.call_soon(self._protocol.pipe_connection_lost, fd, exc,
+                                 context=self.context)
+            self._try_finish()
+        else:
+            self._pending_calls.append((_CALL_PIPE_CONNECTION_LOST, fd, exc))
+
+    cdef _pipe_data_received(self, int fd, data):
+        if self._stdio_ready:
+            self._loop.call_soon(self._protocol.pipe_data_received, fd, data,
+                                 context=self.context)
+        else:
+            self._pending_calls.append((_CALL_PIPE_DATA_RECEIVED, fd, data))
+
+    cdef _file_redirect_stdio(self, int fd):
+        fd = os_dup(fd)
+        os_set_inheritable(fd, True)
+        self._close_after_spawn(fd)
+        return fd
+
+    cdef _file_devnull(self):
+        dn = os_open(os_devnull, os_O_RDWR)
+        os_set_inheritable(dn, True)
+        self._close_after_spawn(dn)
+        return dn
+
+    cdef _file_outpipe(self):
+        r, w = __socketpair()
+        os_set_inheritable(w, True)
+        self._close_after_spawn(w)
+        return r, w
+
+    cdef _file_inpipe(self):
+        r, w = __socketpair()
+        os_set_inheritable(r, True)
+        self._close_after_spawn(r)
+        return r, w
+
+    cdef _init_files(self, _stdin, _stdout, _stderr):
+        cdef uv.uv_stdio_container_t *iocnt
+
+        UVProcess._init_files(self, _stdin, _stdout, _stderr)
+
+        io = [None, None, None]
+
+        self.options.stdio_count = 3
+        self.options.stdio = self.iocnt
+
+        if _stdin is not None:
+            if _stdin == subprocess_PIPE:
+                r, w = self._file_inpipe()
+                io[0] = r
+
+                self.stdin_proto = WriteSubprocessPipeProto(self, 0)
+                waiter = self._loop._new_future()
+                self._stdin = WriteUnixTransport.new(
+                    self._loop, self.stdin_proto, None, waiter)
+                self._init_futs.append(waiter)
+                self._stdin._open(w)
+                self._stdin._init_protocol()
+            elif _stdin == subprocess_DEVNULL:
+                io[0] = self._file_devnull()
+            elif _stdout == subprocess_STDOUT:
+                raise ValueError(
+                    'subprocess.STDOUT is supported only by stderr parameter')
+            else:
+                io[0] = self._file_redirect_stdio(_stdin)
+        else:
+            io[0] = self._file_redirect_stdio(0)
+
+        if _stdout is not None:
+            if _stdout == subprocess_PIPE:
+                # We can't use UV_CREATE_PIPE here, since 'stderr' might be
+                # set to 'subprocess.STDOUT', and there is no way to
+                # emulate that functionality with libuv high-level
+                # streams API. Therefore, we create pipes for stdout and
+                # stderr manually.
+
+                r, w = self._file_outpipe()
+                io[1] = w
+
+                self.stdout_proto = ReadSubprocessPipeProto(self, 1)
+                waiter = self._loop._new_future()
+                self._stdout = ReadUnixTransport.new(
+                    self._loop, self.stdout_proto, None, waiter)
+                self._init_futs.append(waiter)
+                self._stdout._open(r)
+                self._stdout._init_protocol()
+            elif _stdout == subprocess_DEVNULL:
+                io[1] = self._file_devnull()
+            elif _stdout == subprocess_STDOUT:
+                raise ValueError(
+                    'subprocess.STDOUT is supported only by stderr parameter')
+            else:
+                io[1] = self._file_redirect_stdio(_stdout)
+        else:
+            io[1] = self._file_redirect_stdio(1)
+
+        if _stderr is not None:
+            if _stderr == subprocess_PIPE:
+                r, w = self._file_outpipe()
+                io[2] = w
+
+                self.stderr_proto = ReadSubprocessPipeProto(self, 2)
+                waiter = self._loop._new_future()
+                self._stderr = ReadUnixTransport.new(
+                    self._loop, self.stderr_proto, None, waiter)
+                self._init_futs.append(waiter)
+                self._stderr._open(r)
+                self._stderr._init_protocol()
+            elif _stderr == subprocess_STDOUT:
+                if io[1] is None:
+                    # shouldn't ever happen
+                    raise RuntimeError('cannot apply subprocess.STDOUT')
+
+                io[2] = self._file_redirect_stdio(io[1])
+            elif _stderr == subprocess_DEVNULL:
+                io[2] = self._file_devnull()
+            else:
+                io[2] = self._file_redirect_stdio(_stderr)
+        else:
+            io[2] = self._file_redirect_stdio(2)
+
+        assert len(io) == 3
+        for idx in range(3):
+            iocnt = &self.iocnt[idx]
+            if io[idx] is not None:
+                iocnt.flags = uv.UV_INHERIT_FD
+                iocnt.data.fd = io[idx]
+            else:
+                iocnt.flags = uv.UV_IGNORE
+
+    cdef _call_connection_made(self, waiter):
+        try:
+            # we're always called in the right context, so just call the user's
+            self._protocol.connection_made(self)
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException as ex:
+            if waiter is not None and not waiter.cancelled():
+                waiter.set_exception(ex)
+            else:
+                raise
+        else:
+            if waiter is not None and not waiter.cancelled():
+                waiter.set_result(True)
+
+        self._stdio_ready = 1
+        if self._pending_calls:
+            pending_calls = self._pending_calls.copy()
+            self._pending_calls.clear()
+            for (type, fd, arg) in pending_calls:
+                if type == _CALL_PIPE_CONNECTION_LOST:
+                    self._pipe_connection_lost(fd, arg)
+                elif type == _CALL_PIPE_DATA_RECEIVED:
+                    self._pipe_data_received(fd, arg)
+                elif type == _CALL_PROCESS_EXITED:
+                    self._loop.call_soon(self._protocol.process_exited)
+                elif type == _CALL_CONNECTION_LOST:
+                    self._loop.call_soon(self._protocol.connection_lost, None)
+
+    cdef _try_finish(self):
+        if self._returncode is None or self._finished:
+            return
+
+        if ((self.stdin_proto is None or self.stdin_proto.disconnected) and
+                (self.stdout_proto is None or
+                    self.stdout_proto.disconnected) and
+                (self.stderr_proto is None or
+                    self.stderr_proto.disconnected)):
+
+            self._finished = 1
+
+            if self._stdio_ready:
+                # copy self.context for simplicity
+                self._loop.call_soon(self._protocol.connection_lost, None,
+                                     context=self.context)
+            else:
+                self._pending_calls.append((_CALL_CONNECTION_LOST, None, None))
+
+    def __stdio_inited(self, waiter, stdio_fut):
+        exc = stdio_fut.exception()
+        if exc is not None:
+            if waiter is None:
+                raise exc
+            else:
+                waiter.set_exception(exc)
+        else:
+            self._loop._call_soon_handle(
+                new_MethodHandle1(self._loop,
+                                  "UVProcessTransport._call_connection_made",
+                                  self._call_connection_made,
+                                  None,  # means to copy the current context
+                                  self, waiter))
+
+    @staticmethod
+    cdef UVProcessTransport new(Loop loop, protocol, args, env,
+                                cwd, start_new_session,
+                                _stdin, _stdout, _stderr, pass_fds,
+                                waiter,
+                                debug_flags,
+                                preexec_fn,
+                                restore_signals):
+
+        cdef UVProcessTransport handle
+        handle = UVProcessTransport.__new__(UVProcessTransport)
+        handle._protocol = protocol
+        handle._init(loop, args, env, cwd, start_new_session,
+                     __process_convert_fileno(_stdin),
+                     __process_convert_fileno(_stdout),
+                     __process_convert_fileno(_stderr),
+                     pass_fds,
+                     debug_flags,
+                     preexec_fn,
+                     restore_signals)
+
+        if handle._init_futs:
+            handle._stdio_ready = 0
+            init_fut = aio_gather(*handle._init_futs)
+            # add_done_callback will copy the current context and run the
+            # callback within the context
+            init_fut.add_done_callback(
+                ft_partial(handle.__stdio_inited, waiter))
+        else:
+            handle._stdio_ready = 1
+            loop._call_soon_handle(
+                new_MethodHandle1(loop,
+                                  "UVProcessTransport._call_connection_made",
+                                  handle._call_connection_made,
+                                  None,  # means to copy the current context
+                                  handle, waiter))
+
+        return handle
+
+    def get_protocol(self):
+        return self._protocol
+
+    def set_protocol(self, protocol):
+        self._protocol = protocol
+
+    def get_pid(self):
+        return self._pid
+
+    def get_returncode(self):
+        return self._returncode
+
+    def get_pipe_transport(self, fd):
+        if fd == 0:
+            return self._stdin
+        elif fd == 1:
+            return self._stdout
+        elif fd == 2:
+            return self._stderr
+
+    def terminate(self):
+        self._check_proc()
+        self._kill(uv.SIGTERM)
+
+    def kill(self):
+        self._check_proc()
+        self._kill(uv.SIGKILL)
+
+    def send_signal(self, int signal):
+        self._check_proc()
+        self._kill(signal)
+
+    def is_closing(self):
+        return self._closed
+
+    def close(self):
+        if self._returncode is None:
+            self._kill(uv.SIGKILL)
+
+        if self._stdin is not None:
+            self._stdin.close()
+        if self._stdout is not None:
+            self._stdout.close()
+        if self._stderr is not None:
+            self._stderr.close()
+
+        if self._returncode is not None:
+            # The process is dead, just close the UV handle.
+            #
+            # (If "self._returncode is None", the process should have been
+            # killed already and we're just waiting for a SIGCHLD; after
+            # which the transport will be GC'ed and the uvhandle will be
+            # closed in UVHandle.__dealloc__.)
+            self._close()
+
+    def get_extra_info(self, name, default=None):
+        return default
+
+    def _wait(self):
+        fut = self._loop._new_future()
+        if self._returncode is not None:
+            fut.set_result(self._returncode)
+            return fut
+
+        self._exit_waiters.append(fut)
+        return fut
+
+
+class WriteSubprocessPipeProto(aio_BaseProtocol):
+
+    def __init__(self, proc, fd):
+        if UVLOOP_DEBUG:
+            if type(proc) is not UVProcessTransport:
+                raise TypeError
+            if not isinstance(fd, int):
+                raise TypeError
+        self.proc = proc
+        self.fd = fd
+        self.pipe = None
+        self.disconnected = False
+
+    def connection_made(self, transport):
+        self.pipe = transport
+
+    def __repr__(self):
+        return ('<%s fd=%s pipe=%r>'
+                % (self.__class__.__name__, self.fd, self.pipe))
+
+    def connection_lost(self, exc):
+        self.disconnected = True
+        (self.proc)._pipe_connection_lost(self.fd, exc)
+        self.proc = None
+
+    def pause_writing(self):
+        (self.proc)._protocol.pause_writing()
+
+    def resume_writing(self):
+        (self.proc)._protocol.resume_writing()
+
+
+class ReadSubprocessPipeProto(WriteSubprocessPipeProto,
+                              aio_Protocol):
+
+    def data_received(self, data):
+        (self.proc)._pipe_data_received(self.fd, data)
+
+
+cdef __process_convert_fileno(object obj):
+    if obj is None or isinstance(obj, int):
+        return obj
+
+    fileno = obj.fileno()
+    if not isinstance(fileno, int):
+        raise TypeError(
+            '{!r}.fileno() returned non-integer'.format(obj))
+    return fileno
+
+
+cdef void __uvprocess_on_exit_callback(
+    uv.uv_process_t *handle,
+    int64_t exit_status,
+    int term_signal,
+) noexcept with gil:
+
+    if __ensure_handle_data(handle,
+                            "UVProcess exit callback") == 0:
+        return
+
+    cdef UVProcess proc =  handle.data
+    try:
+        proc._on_exit(exit_status, term_signal)
+    except BaseException as ex:
+        proc._error(ex, False)
+
+
+cdef __socketpair():
+    cdef:
+        int fds[2]
+        int err
+
+    err = system.socketpair(uv.AF_UNIX, uv.SOCK_STREAM, 0, fds)
+    if err:
+        exc = convert_error(-err)
+        raise exc
+
+    os_set_inheritable(fds[0], False)
+    os_set_inheritable(fds[1], False)
+
+    return fds[0], fds[1]
+
+
+cdef void __uv_close_process_handle_cb(
+    uv.uv_handle_t* handle
+) noexcept with gil:
+    PyMem_RawFree(handle)
diff --git a/lib/python3.12/site-packages/uvloop/handles/stream.pxd b/lib/python3.12/site-packages/uvloop/handles/stream.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..8ca87437429dd3c3f474cb54712f43afffd1b7c5
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/stream.pxd
@@ -0,0 +1,50 @@
+cdef class UVStream(UVBaseTransport):
+    cdef:
+        uv.uv_shutdown_t _shutdown_req
+        bint __shutting_down
+        bint __reading
+        bint __read_error_close
+
+        bint __buffered
+        object _protocol_get_buffer
+        object _protocol_buffer_updated
+
+        bint _eof
+        list _buffer
+        size_t _buffer_size
+
+        Py_buffer _read_pybuf
+        bint _read_pybuf_acquired
+
+    # All "inline" methods are final
+
+    cdef inline _init(self, Loop loop, object protocol, Server server,
+                      object waiter, object context)
+
+
+    cdef inline _shutdown(self)
+    cdef inline _accept(self, UVStream server)
+
+    cdef inline _close_on_read_error(self)
+
+    cdef inline __reading_started(self)
+    cdef inline __reading_stopped(self)
+
+    # The user API write() and writelines() firstly call _buffer_write() to
+    # buffer up user data chunks, potentially multiple times in writelines(),
+    # and then call _initiate_write() to start writing either immediately or in
+    # the next iteration (loop._queue_write()).
+    cdef inline _buffer_write(self, object data)
+    cdef inline _initiate_write(self)
+
+    # _exec_write() is the method that does the actual send, and _try_write()
+    # is a fast-path used in _exec_write() to send a single chunk.
+    cdef inline _exec_write(self)
+    cdef inline _try_write(self, object data)
+
+    cdef _close(self)
+
+    cdef inline _on_accept(self)
+    cdef inline _on_eof(self)
+    cdef inline _on_write(self)
+    cdef inline _on_connect(self, object exc)
diff --git a/lib/python3.12/site-packages/uvloop/handles/stream.pyx b/lib/python3.12/site-packages/uvloop/handles/stream.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..9fbc5a51a41678c479f93482192d22fdb6e31e86
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/stream.pyx
@@ -0,0 +1,1019 @@
+cdef extern from *:
+    '''
+    enum {__PREALLOCED_BUFS = 4};
+    '''
+    const bint __PREALLOCED_BUFS
+
+
+@cython.no_gc_clear
+@cython.freelist(DEFAULT_FREELIST_SIZE)
+cdef class _StreamWriteContext:
+    # used to hold additional write request information for uv_write
+
+    cdef:
+        uv.uv_write_t   req
+
+        list            buffers
+
+        uv.uv_buf_t     uv_bufs_sml[__PREALLOCED_BUFS]
+        Py_buffer       py_bufs_sml[__PREALLOCED_BUFS]
+        bint            py_bufs_sml_inuse
+
+        uv.uv_buf_t*    uv_bufs
+        Py_buffer*      py_bufs
+        size_t          py_bufs_len
+
+        uv.uv_buf_t*    uv_bufs_start
+        size_t          uv_bufs_len
+
+        UVStream        stream
+
+        bint            closed
+
+    cdef free_bufs(self):
+        cdef size_t i
+
+        if self.uv_bufs is not NULL:
+            PyMem_RawFree(self.uv_bufs)
+            self.uv_bufs = NULL
+            if UVLOOP_DEBUG:
+                if self.py_bufs_sml_inuse:
+                    raise RuntimeError(
+                        '_StreamWriteContext.close: uv_bufs != NULL and '
+                        'py_bufs_sml_inuse is True')
+
+        if self.py_bufs is not NULL:
+            for i from 0 <= i < self.py_bufs_len:
+                PyBuffer_Release(&self.py_bufs[i])
+            PyMem_RawFree(self.py_bufs)
+            self.py_bufs = NULL
+            if UVLOOP_DEBUG:
+                if self.py_bufs_sml_inuse:
+                    raise RuntimeError(
+                        '_StreamWriteContext.close: py_bufs != NULL and '
+                        'py_bufs_sml_inuse is True')
+
+        if self.py_bufs_sml_inuse:
+            for i from 0 <= i < self.py_bufs_len:
+                PyBuffer_Release(&self.py_bufs_sml[i])
+            self.py_bufs_sml_inuse = 0
+
+        self.py_bufs_len = 0
+        self.buffers = None
+
+    cdef close(self):
+        if self.closed:
+            return
+        self.closed = 1
+        self.free_bufs()
+        Py_DECREF(self)
+
+    cdef advance_uv_buf(self, size_t sent):
+        # Advance the pointer to first uv_buf and the
+        # pointer to first byte in that buffer.
+        #
+        # We do this after a "uv_try_write" call, which
+        # sometimes sends only a portion of data.
+        # We then call "advance_uv_buf" on the write
+        # context, and reuse it in a "uv_write" call.
+
+        cdef:
+            uv.uv_buf_t* buf
+            size_t idx
+
+        for idx from 0 <= idx < self.uv_bufs_len:
+            buf = &self.uv_bufs_start[idx]
+            if buf.len > sent:
+                buf.len -= sent
+                buf.base = buf.base + sent
+                self.uv_bufs_start = buf
+                self.uv_bufs_len -= idx
+                return
+            else:
+                sent -= self.uv_bufs_start[idx].len
+
+            if UVLOOP_DEBUG:
+                if sent < 0:
+                    raise RuntimeError('fatal: sent < 0 in advance_uv_buf')
+
+        raise RuntimeError('fatal: Could not advance _StreamWriteContext')
+
+    @staticmethod
+    cdef _StreamWriteContext new(UVStream stream, list buffers):
+        cdef:
+            _StreamWriteContext ctx
+            int uv_bufs_idx = 0
+            size_t py_bufs_len = 0
+            int i
+
+            Py_buffer* p_pybufs
+            uv.uv_buf_t* p_uvbufs
+
+        ctx = _StreamWriteContext.__new__(_StreamWriteContext)
+        ctx.stream = None
+        ctx.closed = 1
+        ctx.py_bufs_len = 0
+        ctx.py_bufs_sml_inuse = 0
+        ctx.uv_bufs = NULL
+        ctx.py_bufs = NULL
+        ctx.buffers = buffers
+        ctx.stream = stream
+
+        if len(buffers) <= __PREALLOCED_BUFS:
+            # We've got a small number of buffers to write, don't
+            # need to use malloc.
+            ctx.py_bufs_sml_inuse = 1
+            p_pybufs = &ctx.py_bufs_sml
+            p_uvbufs = &ctx.uv_bufs_sml
+
+        else:
+            for buf in buffers:
+                if UVLOOP_DEBUG:
+                    if not isinstance(buf, (bytes, bytearray, memoryview)):
+                        raise RuntimeError(
+                            'invalid data in writebuf: an instance of '
+                            'bytes, bytearray or memoryview was expected, '
+                            'got {}'.format(type(buf)))
+
+                if not PyBytes_CheckExact(buf):
+                    py_bufs_len += 1
+
+            if py_bufs_len > 0:
+                ctx.py_bufs = PyMem_RawMalloc(
+                    py_bufs_len * sizeof(Py_buffer))
+                if ctx.py_bufs is NULL:
+                    raise MemoryError()
+
+            ctx.uv_bufs = PyMem_RawMalloc(
+                len(buffers) * sizeof(uv.uv_buf_t))
+            if ctx.uv_bufs is NULL:
+                raise MemoryError()
+
+            p_pybufs = ctx.py_bufs
+            p_uvbufs = ctx.uv_bufs
+
+        py_bufs_len = 0
+        for buf in buffers:
+            if PyBytes_CheckExact(buf):
+                # We can only use this hack for bytes since it's
+                # immutable.  For everything else it is only safe to
+                # use buffer protocol.
+                p_uvbufs[uv_bufs_idx].base = PyBytes_AS_STRING(buf)
+                p_uvbufs[uv_bufs_idx].len = Py_SIZE(buf)
+
+            else:
+                try:
+                    PyObject_GetBuffer(
+                        buf, &p_pybufs[py_bufs_len], PyBUF_SIMPLE)
+                except Exception:
+                    # This shouldn't ever happen, as `UVStream._buffer_write`
+                    # casts non-bytes objects to `memoryviews`.
+                    ctx.py_bufs_len = py_bufs_len
+                    ctx.free_bufs()
+                    raise
+
+                p_uvbufs[uv_bufs_idx].base = p_pybufs[py_bufs_len].buf
+                p_uvbufs[uv_bufs_idx].len = p_pybufs[py_bufs_len].len
+
+                py_bufs_len += 1
+
+            uv_bufs_idx += 1
+
+        ctx.uv_bufs_start = p_uvbufs
+        ctx.uv_bufs_len = uv_bufs_idx
+
+        ctx.py_bufs_len = py_bufs_len
+        ctx.req.data =  ctx
+
+        if UVLOOP_DEBUG:
+            stream._loop._debug_stream_write_ctx_total += 1
+            stream._loop._debug_stream_write_ctx_cnt += 1
+
+        # Do incref after everything else is done.
+        # Under no circumstances we want `ctx` to be GCed while
+        # libuv is still working with `ctx.uv_bufs`.
+        Py_INCREF(ctx)
+        ctx.closed = 0
+        return ctx
+
+    def __dealloc__(self):
+        if not self.closed:
+            # Because we do an INCREF in _StreamWriteContext.new,
+            # __dealloc__ shouldn't ever happen with `self.closed == 1`
+            raise RuntimeError(
+                'open _StreamWriteContext is being deallocated')
+
+        if UVLOOP_DEBUG:
+            if self.stream is not None:
+                self.stream._loop._debug_stream_write_ctx_cnt -= 1
+                self.stream = None
+
+
+@cython.no_gc_clear
+cdef class UVStream(UVBaseTransport):
+
+    def __cinit__(self):
+        self.__shutting_down = 0
+        self.__reading = 0
+        self.__read_error_close = 0
+        self.__buffered = 0
+        self._eof = 0
+        self._buffer = []
+        self._buffer_size = 0
+
+        self._protocol_get_buffer = None
+        self._protocol_buffer_updated = None
+
+        self._read_pybuf_acquired = False
+
+    cdef _set_protocol(self, object protocol):
+        if protocol is None:
+            raise TypeError('protocol is required')
+
+        UVBaseTransport._set_protocol(self, protocol)
+
+        if (hasattr(protocol, 'get_buffer') and
+                not isinstance(protocol, aio_Protocol)):
+            try:
+                self._protocol_get_buffer = protocol.get_buffer
+                self._protocol_buffer_updated = protocol.buffer_updated
+                self.__buffered = 1
+            except AttributeError:
+                pass
+        else:
+            self.__buffered = 0
+
+    cdef _clear_protocol(self):
+        UVBaseTransport._clear_protocol(self)
+        self._protocol_get_buffer = None
+        self._protocol_buffer_updated = None
+        self.__buffered = 0
+
+    cdef inline _shutdown(self):
+        cdef int err
+
+        if self.__shutting_down:
+            return
+        self.__shutting_down = 1
+
+        self._ensure_alive()
+
+        self._shutdown_req.data =  self
+        err = uv.uv_shutdown(&self._shutdown_req,
+                              self._handle,
+                             __uv_stream_on_shutdown)
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+
+    cdef inline _accept(self, UVStream server):
+        cdef int err
+        self._ensure_alive()
+
+        err = uv.uv_accept(server._handle,
+                           self._handle)
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+
+        self._on_accept()
+
+    cdef inline _close_on_read_error(self):
+        self.__read_error_close = 1
+
+    cdef bint _is_reading(self):
+        return self.__reading
+
+    cdef _start_reading(self):
+        cdef int err
+
+        if self._closing:
+            return
+
+        self._ensure_alive()
+
+        if self.__reading:
+            return
+
+        if self.__buffered:
+            err = uv.uv_read_start(self._handle,
+                                   __uv_stream_buffered_alloc,
+                                   __uv_stream_buffered_on_read)
+        else:
+            err = uv.uv_read_start(self._handle,
+                                   __loop_alloc_buffer,
+                                   __uv_stream_on_read)
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+        else:
+            # UVStream must live until the read callback is called
+            self.__reading_started()
+
+    cdef inline __reading_started(self):
+        if self.__reading:
+            return
+        self.__reading = 1
+        Py_INCREF(self)
+
+    cdef inline __reading_stopped(self):
+        if not self.__reading:
+            return
+        self.__reading = 0
+        Py_DECREF(self)
+
+    cdef _stop_reading(self):
+        cdef int err
+
+        if not self.__reading:
+            return
+
+        self._ensure_alive()
+
+        # From libuv docs:
+        #    This function is idempotent and may be safely
+        #    called on a stopped stream.
+        err = uv.uv_read_stop(self._handle)
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+        else:
+            self.__reading_stopped()
+
+    cdef inline _try_write(self, object data):
+        cdef:
+            ssize_t written
+            bint used_buf = 0
+            Py_buffer py_buf
+            void* buf
+            size_t blen
+            int saved_errno
+            int fd
+
+        if (self._handle).write_queue_size != 0:
+            raise RuntimeError(
+                'UVStream._try_write called with data in uv buffers')
+
+        if PyBytes_CheckExact(data):
+            # We can only use this hack for bytes since it's
+            # immutable.  For everything else it is only safe to
+            # use buffer protocol.
+            buf = PyBytes_AS_STRING(data)
+            blen = Py_SIZE(data)
+        else:
+            PyObject_GetBuffer(data, &py_buf, PyBUF_SIMPLE)
+            used_buf = 1
+            buf = py_buf.buf
+            blen = py_buf.len
+
+        if blen == 0:
+            # Empty data, do nothing.
+            return 0
+
+        fd = self._fileno()
+        # Use `unistd.h/write` directly, it's faster than
+        # uv_try_write -- less layers of code.  The error
+        # checking logic is copied from libuv.
+        written = system.write(fd, buf, blen)
+        while written == -1 and (
+                errno.errno == errno.EINTR or
+                (system.PLATFORM_IS_APPLE and
+                    errno.errno == errno.EPROTOTYPE)):
+            # From libuv code (unix/stream.c):
+            #   Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+            #   EPROTOTYPE can be returned while trying to write to a socket
+            #   that is shutting down. If we retry the write, we should get
+            #   the expected EPIPE instead.
+            written = system.write(fd, buf, blen)
+        saved_errno = errno.errno
+
+        if used_buf:
+            PyBuffer_Release(&py_buf)
+
+        if written < 0:
+            if saved_errno == errno.EAGAIN or \
+                    saved_errno == system.EWOULDBLOCK:
+                return -1
+            else:
+                exc = convert_error(-saved_errno)
+                self._fatal_error(exc, True)
+                return
+
+        if UVLOOP_DEBUG:
+            self._loop._debug_stream_write_tries += 1
+
+        if written == blen:
+            return 0
+
+        return written
+
+    cdef inline _buffer_write(self, object data):
+        cdef int dlen
+
+        if not PyBytes_CheckExact(data):
+            data = memoryview(data).cast('b')
+
+        dlen = len(data)
+        if not dlen:
+            return
+
+        self._buffer_size += dlen
+        self._buffer.append(data)
+
+    cdef inline _initiate_write(self):
+        if (not self._protocol_paused and
+                (self._handle).write_queue_size == 0 and
+                self._buffer_size > self._high_water):
+            # Fast-path.  If:
+            #   - the protocol isn't yet paused,
+            #   - there is no data in libuv buffers for this stream,
+            #   - the protocol will be paused if we continue to buffer data
+            #
+            # Then:
+            #   - Try to write all buffered data right now.
+            all_sent = self._exec_write()
+            if UVLOOP_DEBUG:
+                if self._buffer_size != 0 or self._buffer != []:
+                    raise RuntimeError(
+                        '_buffer_size is not 0 after a successful _exec_write')
+
+            # There is no need to call `_queue_write` anymore,
+            # as `uv_write` should be called already.
+
+            if not all_sent:
+                # If not all of the data was sent successfully,
+                # we might need to pause the protocol.
+                self._maybe_pause_protocol()
+
+        elif self._buffer_size > 0:
+            self._maybe_pause_protocol()
+            self._loop._queue_write(self)
+
+    cdef inline _exec_write(self):
+        cdef:
+            int err
+            int buf_len
+            _StreamWriteContext ctx = None
+
+        if self._closed:
+            # If the handle is closed, just return, it's too
+            # late to do anything.
+            return
+
+        buf_len = len(self._buffer)
+        if not buf_len:
+            return
+
+        if (self._handle).write_queue_size == 0:
+            # libuv internal write buffers for this stream are empty.
+            if buf_len == 1:
+                # If we only have one piece of data to send, let's
+                # use our fast implementation of try_write.
+                data = self._buffer[0]
+                sent = self._try_write(data)
+
+                if sent is None:
+                    # A `self._fatal_error` was called.
+                    # It might not raise an exception under some
+                    # conditions.
+                    self._buffer_size = 0
+                    self._buffer.clear()
+                    if not self._closing:
+                        # This should never happen.
+                        raise RuntimeError(
+                            'stream is open after UVStream._try_write '
+                            'returned None')
+                    return
+
+                if sent == 0:
+                    # All data was successfully written.
+                    self._buffer_size = 0
+                    self._buffer.clear()
+                    # on_write will call "maybe_resume_protocol".
+                    self._on_write()
+                    return True
+
+                if sent > 0:
+                    if UVLOOP_DEBUG:
+                        if sent == len(data):
+                            raise RuntimeError(
+                                '_try_write sent all data and returned '
+                                'non-zero')
+
+                    if PyBytes_CheckExact(data):
+                        # Cast bytes to memoryview to avoid copying
+                        # data that wasn't sent.
+                        data = memoryview(data)
+                    data = data[sent:]
+
+                    self._buffer_size -= sent
+                    self._buffer[0] = data
+
+                # At this point it's either data was sent partially,
+                # or an EAGAIN has happened.
+
+            else:
+                ctx = _StreamWriteContext.new(self, self._buffer)
+
+                err = uv.uv_try_write(self._handle,
+                                      ctx.uv_bufs_start,
+                                      ctx.uv_bufs_len)
+
+                if err > 0:
+                    # Some data was successfully sent.
+
+                    if err == self._buffer_size:
+                        # Everything was sent.
+                        ctx.close()
+                        self._buffer.clear()
+                        self._buffer_size = 0
+                        # on_write will call "maybe_resume_protocol".
+                        self._on_write()
+                        return True
+
+                    try:
+                        # Advance pointers to uv_bufs in `ctx`,
+                        # we will reuse it soon for a uv_write
+                        # call.
+                        ctx.advance_uv_buf(err)
+                    except Exception as ex:  # This should never happen.
+                        # Let's try to close the `ctx` anyways.
+                        ctx.close()
+                        self._fatal_error(ex, True)
+                        self._buffer.clear()
+                        self._buffer_size = 0
+                        return
+
+                elif err != uv.UV_EAGAIN:
+                    ctx.close()
+                    exc = convert_error(err)
+                    self._fatal_error(exc, True)
+                    self._buffer.clear()
+                    self._buffer_size = 0
+                    return
+
+                # fall through
+
+        if ctx is None:
+            ctx = _StreamWriteContext.new(self, self._buffer)
+
+        err = uv.uv_write(&ctx.req,
+                          self._handle,
+                          ctx.uv_bufs_start,
+                          ctx.uv_bufs_len,
+                          __uv_stream_on_write)
+
+        self._buffer_size = 0
+        # Can't use `_buffer.clear()` here: `ctx` holds a reference to
+        # the `_buffer`.
+        self._buffer = []
+
+        if err < 0:
+            # close write context
+            ctx.close()
+
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+
+        self._maybe_resume_protocol()
+
+    cdef size_t _get_write_buffer_size(self):
+        if self._handle is NULL:
+            return 0
+        return ((self._handle).write_queue_size +
+                self._buffer_size)
+
+    cdef _close(self):
+        try:
+            if self._read_pybuf_acquired:
+                # Should never happen. libuv always calls uv_alloc/uv_read
+                # in pairs.
+                self._loop.call_exception_handler({
+                    'transport': self,
+                    'message': 'XXX: an allocated buffer in transport._close()'
+                })
+                self._read_pybuf_acquired = 0
+                PyBuffer_Release(&self._read_pybuf)
+
+            self._stop_reading()
+        finally:
+            UVSocketHandle._close(self)
+
+    cdef inline _on_accept(self):
+        # Ultimately called by __uv_stream_on_listen.
+        self._init_protocol()
+
+    cdef inline _on_eof(self):
+        # Any exception raised here will be caught in
+        # __uv_stream_on_read.
+
+        try:
+            meth = self._protocol.eof_received
+        except AttributeError:
+            keep_open = False
+        else:
+            keep_open = run_in_context(self.context, meth)
+
+        if keep_open:
+            # We're keeping the connection open so the
+            # protocol can write more, but we still can't
+            # receive more, so remove the reader callback.
+            self._stop_reading()
+        else:
+            self.close()
+
+    cdef inline _on_write(self):
+        self._maybe_resume_protocol()
+        if not self._get_write_buffer_size():
+            if self._closing:
+                self._schedule_call_connection_lost(None)
+            elif self._eof:
+                self._shutdown()
+
+    cdef inline _init(self, Loop loop, object protocol, Server server,
+                      object waiter, object context):
+        self.context = context
+        self._set_protocol(protocol)
+        self._start_init(loop)
+
+        if server is not None:
+            self._set_server(server)
+
+        if waiter is not None:
+            self._set_waiter(waiter)
+
+    cdef inline _on_connect(self, object exc):
+        # Called from __tcp_connect_callback (tcp.pyx) and
+        # __pipe_connect_callback (pipe.pyx).
+        if exc is None:
+            self._init_protocol()
+        else:
+            if self._waiter is None:
+                self._fatal_error(exc, False, "connect failed")
+            elif self._waiter.cancelled():
+                # Connect call was cancelled; just close the transport
+                # silently.
+                self._close()
+            elif self._waiter.done():
+                self._fatal_error(exc, False, "connect failed")
+            else:
+                self._waiter.set_exception(exc)
+                self._close()
+
+    # === Public API ===
+
+    def __repr__(self):
+        return '<{} closed={} reading={} {:#x}>'.format(
+            self.__class__.__name__,
+            self._closed,
+            self.__reading,
+            id(self))
+
+    def write(self, object buf):
+        self._ensure_alive()
+
+        if self._eof:
+            raise RuntimeError('Cannot call write() after write_eof()')
+        if not buf:
+            return
+        if self._conn_lost:
+            self._conn_lost += 1
+            return
+        self._buffer_write(buf)
+        self._initiate_write()
+
+    def writelines(self, bufs):
+        self._ensure_alive()
+
+        if self._eof:
+            raise RuntimeError('Cannot call writelines() after write_eof()')
+        if self._conn_lost:
+            self._conn_lost += 1
+            return
+        for buf in bufs:
+            self._buffer_write(buf)
+        self._initiate_write()
+
+    def write_eof(self):
+        self._ensure_alive()
+
+        if self._eof:
+            return
+
+        self._eof = 1
+        if not self._get_write_buffer_size():
+            self._shutdown()
+
+    def can_write_eof(self):
+        return True
+
+    def is_reading(self):
+        return self._is_reading()
+
+    def pause_reading(self):
+        if self._closing or not self._is_reading():
+            return
+        self._stop_reading()
+
+    def resume_reading(self):
+        if self._is_reading() or self._closing:
+            return
+        self._start_reading()
+
+
+cdef void __uv_stream_on_shutdown(uv.uv_shutdown_t* req,
+                                  int status) noexcept with gil:
+
+    # callback for uv_shutdown
+
+    if req.data is NULL:
+        aio_logger.error(
+            'UVStream.shutdown callback called with NULL req.data, status=%r',
+            status)
+        return
+
+    cdef UVStream stream =  req.data
+
+    if status < 0 and status != uv.UV_ECANCELED:
+        # From libuv source code:
+        #     The ECANCELED error code is a lie, the shutdown(2) syscall is a
+        #     fait accompli at this point. Maybe we should revisit this in
+        #     v0.11.  A possible reason for leaving it unchanged is that it
+        #     informs the callee that the handle has been destroyed.
+
+        if UVLOOP_DEBUG:
+            stream._loop._debug_stream_shutdown_errors_total += 1
+
+        exc = convert_error(status)
+        stream._fatal_error(
+            exc, False, "error status in uv_stream_t.shutdown callback")
+        return
+
+
+cdef inline bint __uv_stream_on_read_common(
+    UVStream sc,
+    Loop loop,
+    ssize_t nread,
+):
+    if sc._closed:
+        # The stream was closed, there is no reason to
+        # do any work now.
+        sc.__reading_stopped()  # Just in case.
+        return True
+
+    if nread == uv.UV_EOF:
+        # From libuv docs:
+        #     The callee is responsible for stopping closing the stream
+        #     when an error happens by calling uv_read_stop() or uv_close().
+        #     Trying to read from the stream again is undefined.
+        try:
+            if UVLOOP_DEBUG:
+                loop._debug_stream_read_eof_total += 1
+
+            sc._stop_reading()
+            sc._on_eof()
+        except BaseException as ex:
+            if UVLOOP_DEBUG:
+                loop._debug_stream_read_eof_cb_errors_total += 1
+
+            sc._fatal_error(ex, False)
+        finally:
+            return True
+
+    if nread == 0:
+        # From libuv docs:
+        #     nread might be 0, which does not indicate an error or EOF.
+        #     This is equivalent to EAGAIN or EWOULDBLOCK under read(2).
+        return True
+
+    if nread < 0:
+        # From libuv docs:
+        #     The callee is responsible for stopping closing the stream
+        #     when an error happens by calling uv_read_stop() or uv_close().
+        #     Trying to read from the stream again is undefined.
+        #
+        # Therefore, we're closing the stream.  Since "UVHandle._close()"
+        # doesn't raise exceptions unless uvloop is built with DEBUG=1,
+        # we don't need try...finally here.
+
+        if UVLOOP_DEBUG:
+            loop._debug_stream_read_errors_total += 1
+
+        if sc.__read_error_close:
+            # Used for getting notified when a pipe is closed.
+            # See WriteUnixTransport for the explanation.
+            sc._on_eof()
+            return True
+
+        exc = convert_error(nread)
+        sc._fatal_error(
+            exc, False, "error status in uv_stream_t.read callback")
+        return True
+
+    return False
+
+
+cdef inline void __uv_stream_on_read_impl(
+    uv.uv_stream_t* stream,
+    ssize_t nread,
+    const uv.uv_buf_t* buf,
+):
+    cdef:
+        UVStream sc = stream.data
+        Loop loop = sc._loop
+
+    # It's OK to free the buffer early, since nothing will
+    # be able to touch it until this method is done.
+    __loop_free_buffer(loop)
+
+    if __uv_stream_on_read_common(sc, loop, nread):
+        return
+
+    try:
+        if UVLOOP_DEBUG:
+            loop._debug_stream_read_cb_total += 1
+
+        run_in_context1(
+            sc.context,
+            sc._protocol_data_received,
+            loop._recv_buffer[:nread],
+        )
+    except BaseException as exc:
+        if UVLOOP_DEBUG:
+            loop._debug_stream_read_cb_errors_total += 1
+
+        sc._fatal_error(exc, False)
+
+
+cdef inline void __uv_stream_on_write_impl(
+    uv.uv_write_t* req,
+    int status,
+):
+    cdef:
+        _StreamWriteContext ctx = <_StreamWriteContext> req.data
+        UVStream stream = ctx.stream
+
+    ctx.close()
+
+    if stream._closed:
+        # The stream was closed, there is nothing to do.
+        # Even if there is an error, like EPIPE, there
+        # is no reason to report it.
+        return
+
+    if status < 0:
+        if UVLOOP_DEBUG:
+            stream._loop._debug_stream_write_errors_total += 1
+
+        exc = convert_error(status)
+        stream._fatal_error(
+            exc, False, "error status in uv_stream_t.write callback")
+        return
+
+    try:
+        stream._on_write()
+    except BaseException as exc:
+        if UVLOOP_DEBUG:
+            stream._loop._debug_stream_write_cb_errors_total += 1
+
+        stream._fatal_error(exc, False)
+
+
+cdef void __uv_stream_on_read(
+    uv.uv_stream_t* stream,
+    ssize_t nread,
+    const uv.uv_buf_t* buf,
+) noexcept with gil:
+
+    if __ensure_handle_data(stream,
+                            "UVStream read callback") == 0:
+        return
+
+    # Don't need try-finally, __uv_stream_on_read_impl is void
+    __uv_stream_on_read_impl(stream, nread, buf)
+
+
+cdef void __uv_stream_on_write(
+    uv.uv_write_t* req,
+    int status,
+) noexcept with gil:
+
+    if UVLOOP_DEBUG:
+        if req.data is NULL:
+            aio_logger.error(
+                'UVStream.write callback called with NULL req.data, status=%r',
+                status)
+            return
+
+    # Don't need try-finally, __uv_stream_on_write_impl is void
+    __uv_stream_on_write_impl(req, status)
+
+
+cdef void __uv_stream_buffered_alloc(
+    uv.uv_handle_t* stream,
+    size_t suggested_size,
+    uv.uv_buf_t* uvbuf,
+) noexcept with gil:
+
+    if __ensure_handle_data(stream,
+                            "UVStream alloc buffer callback") == 0:
+        return
+
+    cdef:
+        UVStream sc = stream.data
+        Loop loop = sc._loop
+        Py_buffer* pybuf = &sc._read_pybuf
+        int got_buf = 0
+
+    if sc._read_pybuf_acquired:
+        uvbuf.len = 0
+        uvbuf.base = NULL
+        return
+
+    sc._read_pybuf_acquired = 0
+    try:
+        buf = run_in_context1(
+            sc.context,
+            sc._protocol_get_buffer,
+            suggested_size,
+        )
+        PyObject_GetBuffer(buf, pybuf, PyBUF_WRITABLE)
+        got_buf = 1
+    except BaseException as exc:
+        # Can't call 'sc._fatal_error' or 'sc._close', libuv will SF.
+        # We'll do it later in __uv_stream_buffered_on_read when we
+        # receive UV_ENOBUFS.
+        uvbuf.len = 0
+        uvbuf.base = NULL
+        return
+
+    if not pybuf.len:
+        uvbuf.len = 0
+        uvbuf.base = NULL
+        if got_buf:
+            PyBuffer_Release(pybuf)
+        return
+
+    sc._read_pybuf_acquired = 1
+    uvbuf.base = pybuf.buf
+    uvbuf.len = pybuf.len
+
+
+cdef void __uv_stream_buffered_on_read(
+    uv.uv_stream_t* stream,
+    ssize_t nread,
+    const uv.uv_buf_t* buf,
+) noexcept with gil:
+
+    if __ensure_handle_data(stream,
+                            "UVStream buffered read callback") == 0:
+        return
+
+    cdef:
+        UVStream sc = stream.data
+        Loop loop = sc._loop
+        Py_buffer* pybuf = &sc._read_pybuf
+
+    if nread == uv.UV_ENOBUFS:
+        sc._fatal_error(
+            RuntimeError(
+                'unhandled error (or an empty buffer) in get_buffer()'),
+            False)
+        return
+
+    try:
+        if nread > 0 and not sc._read_pybuf_acquired:
+            # From libuv docs:
+            #     nread is > 0 if there is data available or < 0 on error. When
+            #     we’ve reached EOF, nread will be set to UV_EOF. When
+            #     nread < 0, the buf parameter might not point to a valid
+            #     buffer; in that case buf.len and buf.base are both set to 0.
+            raise RuntimeError(
+                f'no python buffer is allocated in on_read; nread={nread}')
+
+        if nread == 0:
+            # From libuv docs:
+            #     nread might be 0, which does not indicate an error or EOF.
+            #     This is equivalent to EAGAIN or EWOULDBLOCK under read(2).
+            return
+
+        if __uv_stream_on_read_common(sc, loop, nread):
+            return
+
+        if UVLOOP_DEBUG:
+            loop._debug_stream_read_cb_total += 1
+
+        run_in_context1(sc.context, sc._protocol_buffer_updated, nread)
+    except BaseException as exc:
+        if UVLOOP_DEBUG:
+            loop._debug_stream_read_cb_errors_total += 1
+
+        sc._fatal_error(exc, False)
+    finally:
+        sc._read_pybuf_acquired = 0
+        PyBuffer_Release(pybuf)
diff --git a/lib/python3.12/site-packages/uvloop/handles/streamserver.pxd b/lib/python3.12/site-packages/uvloop/handles/streamserver.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..a004efd9b8df19cda9e2cb04eb9794e8f4a14487
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/streamserver.pxd
@@ -0,0 +1,26 @@
+cdef class UVStreamServer(UVSocketHandle):
+    cdef:
+        int backlog
+        object ssl
+        object ssl_handshake_timeout
+        object ssl_shutdown_timeout
+        object protocol_factory
+        bint opened
+        Server _server
+
+    # All "inline" methods are final
+
+    cdef inline _init(self, Loop loop, object protocol_factory,
+                      Server server,
+                      object backlog,
+                      object ssl,
+                      object ssl_handshake_timeout,
+                      object ssl_shutdown_timeout)
+
+    cdef inline _mark_as_open(self)
+
+    cdef inline listen(self)
+    cdef inline _on_listen(self)
+
+    cdef UVStream _make_new_transport(self, object protocol, object waiter,
+                                      object context)
diff --git a/lib/python3.12/site-packages/uvloop/handles/streamserver.pyx b/lib/python3.12/site-packages/uvloop/handles/streamserver.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..99933177953ec00d138126634598abb32e034d24
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/streamserver.pyx
@@ -0,0 +1,150 @@
+@cython.no_gc_clear
+cdef class UVStreamServer(UVSocketHandle):
+
+    def __cinit__(self):
+        self.opened = 0
+        self._server = None
+        self.ssl = None
+        self.ssl_handshake_timeout = None
+        self.ssl_shutdown_timeout = None
+        self.protocol_factory = None
+
+    cdef inline _init(self, Loop loop, object protocol_factory,
+                      Server server,
+                      object backlog,
+                      object ssl,
+                      object ssl_handshake_timeout,
+                      object ssl_shutdown_timeout):
+
+        if not isinstance(backlog, int):
+            # Don't allow floats
+            raise TypeError('integer argument expected, got {}'.format(
+                type(backlog).__name__))
+
+        if ssl is not None:
+            if not isinstance(ssl, ssl_SSLContext):
+                raise TypeError(
+                    'ssl is expected to be None or an instance of '
+                    'ssl.SSLContext, got {!r}'.format(ssl))
+        else:
+            if ssl_handshake_timeout is not None:
+                raise ValueError(
+                    'ssl_handshake_timeout is only meaningful with ssl')
+            if ssl_shutdown_timeout is not None:
+                raise ValueError(
+                    'ssl_shutdown_timeout is only meaningful with ssl')
+
+        self.backlog = backlog
+        self.ssl = ssl
+        self.ssl_handshake_timeout = ssl_handshake_timeout
+        self.ssl_shutdown_timeout = ssl_shutdown_timeout
+
+        self._start_init(loop)
+        self.protocol_factory = protocol_factory
+        self._server = server
+
+    cdef inline listen(self):
+        cdef int err
+        self._ensure_alive()
+
+        if self.protocol_factory is None:
+            raise RuntimeError('unable to listen(); no protocol_factory')
+
+        if self.opened != 1:
+            raise RuntimeError('unopened TCPServer')
+
+        self.context = Context_CopyCurrent()
+
+        err = uv.uv_listen( self._handle,
+                           self.backlog,
+                           __uv_streamserver_on_listen)
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+
+    cdef inline _on_listen(self):
+        cdef UVStream client
+
+        protocol = run_in_context(self.context, self.protocol_factory)
+
+        if self.ssl is None:
+            client = self._make_new_transport(protocol, None, self.context)
+
+        else:
+            waiter = self._loop._new_future()
+
+            ssl_protocol = SSLProtocol(
+                self._loop, protocol, self.ssl,
+                waiter,
+                server_side=True,
+                server_hostname=None,
+                ssl_handshake_timeout=self.ssl_handshake_timeout,
+                ssl_shutdown_timeout=self.ssl_shutdown_timeout)
+
+            client = self._make_new_transport(ssl_protocol, None, self.context)
+
+            waiter.add_done_callback(
+                ft_partial(self.__on_ssl_connected, client))
+
+        client._accept(self)
+
+    cdef _fatal_error(self, exc, throw, reason=None):
+        # Overload UVHandle._fatal_error
+
+        self._close()
+
+        if not isinstance(exc, OSError):
+
+            if throw or self._loop is None:
+                raise exc
+
+            msg = f'Fatal error on server {self.__class__.__name__}'
+            if reason is not None:
+                msg = f'{msg} ({reason})'
+
+            self._loop.call_exception_handler({
+                'message': msg,
+                'exception': exc,
+            })
+
+    cdef inline _mark_as_open(self):
+        self.opened = 1
+
+    cdef UVStream _make_new_transport(self, object protocol, object waiter,
+                                      object context):
+        raise NotImplementedError
+
+    def __on_ssl_connected(self, transport, fut):
+        exc = fut.exception()
+        if exc is not None:
+            transport._force_close(exc)
+
+
+cdef void __uv_streamserver_on_listen(
+    uv.uv_stream_t* handle,
+    int status,
+) noexcept with gil:
+
+    # callback for uv_listen
+
+    if __ensure_handle_data(handle,
+                            "UVStream listen callback") == 0:
+        return
+
+    cdef:
+        UVStreamServer stream =  handle.data
+
+    if status < 0:
+        if UVLOOP_DEBUG:
+            stream._loop._debug_stream_listen_errors_total += 1
+
+        exc = convert_error(status)
+        stream._fatal_error(
+            exc, False, "error status in uv_stream_t.listen callback")
+        return
+
+    try:
+        stream._on_listen()
+    except BaseException as exc:
+        stream._error(exc, False)
diff --git a/lib/python3.12/site-packages/uvloop/handles/tcp.pxd b/lib/python3.12/site-packages/uvloop/handles/tcp.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..8d388ef065f5fe3722abf53a4518c7a66d8b7aec
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/tcp.pxd
@@ -0,0 +1,26 @@
+cdef class TCPServer(UVStreamServer):
+    cdef bind(self, system.sockaddr* addr, unsigned int flags=*)
+
+    @staticmethod
+    cdef TCPServer new(Loop loop, object protocol_factory, Server server,
+                       unsigned int flags,
+                       object backlog,
+                       object ssl,
+                       object ssl_handshake_timeout,
+                       object ssl_shutdown_timeout)
+
+
+cdef class TCPTransport(UVStream):
+    cdef:
+        bint __peername_set
+        bint __sockname_set
+        system.sockaddr_storage __peername
+        system.sockaddr_storage __sockname
+
+    cdef bind(self, system.sockaddr* addr, unsigned int flags=*)
+    cdef connect(self, system.sockaddr* addr)
+    cdef _set_nodelay(self)
+
+    @staticmethod
+    cdef TCPTransport new(Loop loop, object protocol, Server server,
+                          object waiter, object context)
diff --git a/lib/python3.12/site-packages/uvloop/handles/tcp.pyx b/lib/python3.12/site-packages/uvloop/handles/tcp.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..d5fe827a07547be356976983dd93162620594f17
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/tcp.pyx
@@ -0,0 +1,228 @@
+cdef __tcp_init_uv_handle(UVStream handle, Loop loop, unsigned int flags):
+    cdef int err
+
+    handle._handle = PyMem_RawMalloc(sizeof(uv.uv_tcp_t))
+    if handle._handle is NULL:
+        handle._abort_init()
+        raise MemoryError()
+
+    err = uv.uv_tcp_init_ex(handle._loop.uvloop,
+                            handle._handle,
+                            flags)
+    if err < 0:
+        handle._abort_init()
+        raise convert_error(err)
+
+    handle._finish_init()
+
+
+cdef __tcp_bind(UVStream handle, system.sockaddr* addr, unsigned int flags):
+    cdef int err
+    err = uv.uv_tcp_bind(handle._handle,
+                         addr, flags)
+    if err < 0:
+        exc = convert_error(err)
+        raise exc
+
+
+cdef __tcp_open(UVStream handle, int sockfd):
+    cdef int err
+    err = uv.uv_tcp_open(handle._handle,
+                         sockfd)
+    if err < 0:
+        exc = convert_error(err)
+        raise exc
+
+
+cdef __tcp_get_socket(UVSocketHandle handle):
+    cdef:
+        int buf_len = sizeof(system.sockaddr_storage)
+        int fileno
+        int err
+        system.sockaddr_storage buf
+
+    fileno = handle._fileno()
+
+    err = uv.uv_tcp_getsockname(handle._handle,
+                                &buf,
+                                &buf_len)
+    if err < 0:
+        raise convert_error(err)
+
+    return PseudoSocket(buf.ss_family, uv.SOCK_STREAM, 0, fileno)
+
+
+@cython.no_gc_clear
+cdef class TCPServer(UVStreamServer):
+
+    @staticmethod
+    cdef TCPServer new(Loop loop, object protocol_factory, Server server,
+                       unsigned int flags,
+                       object backlog,
+                       object ssl,
+                       object ssl_handshake_timeout,
+                       object ssl_shutdown_timeout):
+
+        cdef TCPServer handle
+        handle = TCPServer.__new__(TCPServer)
+        handle._init(loop, protocol_factory, server, backlog,
+                     ssl, ssl_handshake_timeout, ssl_shutdown_timeout)
+        __tcp_init_uv_handle(handle, loop, flags)
+        return handle
+
+    cdef _new_socket(self):
+        return __tcp_get_socket(self)
+
+    cdef _open(self, int sockfd):
+        self._ensure_alive()
+        try:
+            __tcp_open(self, sockfd)
+        except Exception as exc:
+            self._fatal_error(exc, True)
+        else:
+            self._mark_as_open()
+
+    cdef bind(self, system.sockaddr* addr, unsigned int flags=0):
+        self._ensure_alive()
+        try:
+            __tcp_bind(self, addr, flags)
+        except Exception as exc:
+            self._fatal_error(exc, True)
+        else:
+            self._mark_as_open()
+
+    cdef UVStream _make_new_transport(self, object protocol, object waiter,
+                                      object context):
+        cdef TCPTransport tr
+        tr = TCPTransport.new(self._loop, protocol, self._server, waiter,
+                              context)
+        return tr
+
+
+@cython.no_gc_clear
+cdef class TCPTransport(UVStream):
+
+    @staticmethod
+    cdef TCPTransport new(Loop loop, object protocol, Server server,
+                          object waiter, object context):
+
+        cdef TCPTransport handle
+        handle = TCPTransport.__new__(TCPTransport)
+        handle._init(loop, protocol, server, waiter, context)
+        __tcp_init_uv_handle(handle, loop, uv.AF_UNSPEC)
+        handle.__peername_set = 0
+        handle.__sockname_set = 0
+        handle._set_nodelay()
+        return handle
+
+    cdef _set_nodelay(self):
+        cdef int err
+        self._ensure_alive()
+        err = uv.uv_tcp_nodelay(self._handle, 1)
+        if err < 0:
+            raise convert_error(err)
+
+    cdef _call_connection_made(self):
+        # asyncio saves peername & sockname when transports are instantiated,
+        # so that they're accessible even after the transport is closed.
+        # We are doing the same thing here, except that we create Python
+        # objects lazily, on request in get_extra_info()
+
+        cdef:
+            int err
+            int buf_len
+
+        buf_len = sizeof(system.sockaddr_storage)
+        err = uv.uv_tcp_getsockname(self._handle,
+                                    &self.__sockname,
+                                    &buf_len)
+        if err >= 0:
+            # Ignore errors, this is an optional thing.
+            # If something serious is going on, the transport
+            # will crash later (in roughly the same way how
+            # an asyncio transport would.)
+            self.__sockname_set = 1
+
+        buf_len = sizeof(system.sockaddr_storage)
+        err = uv.uv_tcp_getpeername(self._handle,
+                                    &self.__peername,
+                                    &buf_len)
+        if err >= 0:
+            # Same as few lines above -- we don't really care
+            # about error case here.
+            self.__peername_set = 1
+
+        UVBaseTransport._call_connection_made(self)
+
+    def get_extra_info(self, name, default=None):
+        if name == 'sockname':
+            if self.__sockname_set:
+                return __convert_sockaddr_to_pyaddr(
+                    &self.__sockname)
+        elif name == 'peername':
+            if self.__peername_set:
+                return __convert_sockaddr_to_pyaddr(
+                    &self.__peername)
+        return super().get_extra_info(name, default)
+
+    cdef _new_socket(self):
+        return __tcp_get_socket(self)
+
+    cdef bind(self, system.sockaddr* addr, unsigned int flags=0):
+        self._ensure_alive()
+        __tcp_bind(self, addr, flags)
+
+    cdef _open(self, int sockfd):
+        self._ensure_alive()
+        __tcp_open(self, sockfd)
+
+    cdef connect(self, system.sockaddr* addr):
+        cdef _TCPConnectRequest req
+        req = _TCPConnectRequest(self._loop, self)
+        req.connect(addr)
+
+
+cdef class _TCPConnectRequest(UVRequest):
+    cdef:
+        TCPTransport transport
+        uv.uv_connect_t _req_data
+
+    def __cinit__(self, loop, transport):
+        self.request = &self._req_data
+        self.request.data = self
+        self.transport = transport
+
+    cdef connect(self, system.sockaddr* addr):
+        cdef int err
+        err = uv.uv_tcp_connect(self.request,
+                                self.transport._handle,
+                                addr,
+                                __tcp_connect_callback)
+        if err < 0:
+            exc = convert_error(err)
+            self.on_done()
+            raise exc
+
+
+cdef void __tcp_connect_callback(
+    uv.uv_connect_t* req,
+    int status,
+) noexcept with gil:
+    cdef:
+        _TCPConnectRequest wrapper
+        TCPTransport transport
+
+    wrapper = <_TCPConnectRequest> req.data
+    transport = wrapper.transport
+
+    if status < 0:
+        exc = convert_error(status)
+    else:
+        exc = None
+
+    try:
+        transport._on_connect(exc)
+    except BaseException as ex:
+        wrapper.transport._fatal_error(ex, False)
+    finally:
+        wrapper.on_done()
diff --git a/lib/python3.12/site-packages/uvloop/handles/timer.pxd b/lib/python3.12/site-packages/uvloop/handles/timer.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..fda23b67c1f3e2987e67a956f77c9ca867836ac9
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/timer.pxd
@@ -0,0 +1,18 @@
+cdef class UVTimer(UVHandle):
+    cdef:
+        method_t callback
+        object ctx
+        bint running
+        uint64_t timeout
+        uint64_t start_t
+
+    cdef _init(self, Loop loop, method_t callback, object ctx,
+               uint64_t timeout)
+
+    cdef stop(self)
+    cdef start(self)
+    cdef get_when(self)
+
+    @staticmethod
+    cdef UVTimer new(Loop loop, method_t callback, object ctx,
+                     uint64_t timeout)
diff --git a/lib/python3.12/site-packages/uvloop/handles/timer.pyx b/lib/python3.12/site-packages/uvloop/handles/timer.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..86d46ef02a76296c792f32be3b43182cc0937684
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/timer.pyx
@@ -0,0 +1,89 @@
+@cython.no_gc_clear
+cdef class UVTimer(UVHandle):
+    cdef _init(self, Loop loop, method_t callback, object ctx,
+               uint64_t timeout):
+
+        cdef int err
+
+        self._start_init(loop)
+
+        self._handle =  PyMem_RawMalloc(sizeof(uv.uv_timer_t))
+        if self._handle is NULL:
+            self._abort_init()
+            raise MemoryError()
+
+        err = uv.uv_timer_init(self._loop.uvloop, self._handle)
+        if err < 0:
+            self._abort_init()
+            raise convert_error(err)
+
+        self._finish_init()
+
+        self.callback = callback
+        self.ctx = ctx
+        self.running = 0
+        self.timeout = timeout
+        self.start_t = 0
+
+    cdef stop(self):
+        cdef int err
+
+        if not self._is_alive():
+            self.running = 0
+            return
+
+        if self.running == 1:
+            err = uv.uv_timer_stop(self._handle)
+            self.running = 0
+            if err < 0:
+                exc = convert_error(err)
+                self._fatal_error(exc, True)
+                return
+
+    cdef start(self):
+        cdef int err
+
+        self._ensure_alive()
+
+        if self.running == 0:
+            # Update libuv internal time.
+            uv.uv_update_time(self._loop.uvloop)  # void
+            self.start_t = uv.uv_now(self._loop.uvloop)
+
+            err = uv.uv_timer_start(self._handle,
+                                    __uvtimer_callback,
+                                    self.timeout, 0)
+            if err < 0:
+                exc = convert_error(err)
+                self._fatal_error(exc, True)
+                return
+            self.running = 1
+
+    cdef get_when(self):
+        return self.start_t + self.timeout
+
+    @staticmethod
+    cdef UVTimer new(Loop loop, method_t callback, object ctx,
+                     uint64_t timeout):
+
+        cdef UVTimer handle
+        handle = UVTimer.__new__(UVTimer)
+        handle._init(loop, callback, ctx, timeout)
+        return handle
+
+
+cdef void __uvtimer_callback(
+    uv.uv_timer_t* handle,
+) noexcept with gil:
+    if __ensure_handle_data(handle, "UVTimer callback") == 0:
+        return
+
+    cdef:
+        UVTimer timer =  handle.data
+        method_t cb = timer.callback
+
+    timer.running = 0
+    try:
+        cb(timer.ctx)
+    except BaseException as ex:
+        timer._error(ex, False)
diff --git a/lib/python3.12/site-packages/uvloop/handles/udp.pxd b/lib/python3.12/site-packages/uvloop/handles/udp.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..daa9a1beeb99cab30a00ad4f5aae76ef67f0c576
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/udp.pxd
@@ -0,0 +1,22 @@
+cdef class UDPTransport(UVBaseTransport):
+    cdef:
+        bint __receiving
+        int _family
+        object _address
+
+    cdef _init(self, Loop loop, unsigned int family)
+    cdef _set_address(self, system.addrinfo *addr)
+
+    cdef _connect(self, system.sockaddr* addr, size_t addr_len)
+
+    cdef _bind(self, system.sockaddr* addr)
+    cdef open(self, int family, int sockfd)
+    cdef _set_broadcast(self, bint on)
+
+    cdef inline __receiving_started(self)
+    cdef inline __receiving_stopped(self)
+
+    cdef _send(self, object data, object addr)
+
+    cdef _on_receive(self, bytes data, object exc, object addr)
+    cdef _on_sent(self, object exc, object context=*)
diff --git a/lib/python3.12/site-packages/uvloop/handles/udp.pyx b/lib/python3.12/site-packages/uvloop/handles/udp.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..ef20c3f7cca717376c7e3ba7c259f8b980c33bd7
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/handles/udp.pyx
@@ -0,0 +1,408 @@
+@cython.no_gc_clear
+@cython.freelist(DEFAULT_FREELIST_SIZE)
+cdef class _UDPSendContext:
+    # used to hold additional write request information for uv_write
+
+    cdef:
+        uv.uv_udp_send_t   req
+
+        uv.uv_buf_t     uv_buf
+        Py_buffer       py_buf
+
+        UDPTransport    udp
+
+        bint            closed
+
+    cdef close(self):
+        if self.closed:
+            return
+
+        self.closed = 1
+        PyBuffer_Release(&self.py_buf)  # void
+        self.req.data = NULL
+        self.uv_buf.base = NULL
+        Py_DECREF(self)
+        self.udp = None
+
+    @staticmethod
+    cdef _UDPSendContext new(UDPTransport udp, object data):
+        cdef _UDPSendContext ctx
+        ctx = _UDPSendContext.__new__(_UDPSendContext)
+        ctx.udp = None
+        ctx.closed = 1
+
+        ctx.req.data =  ctx
+        Py_INCREF(ctx)
+
+        PyObject_GetBuffer(data, &ctx.py_buf, PyBUF_SIMPLE)
+        ctx.uv_buf.base = ctx.py_buf.buf
+        ctx.uv_buf.len = ctx.py_buf.len
+        ctx.udp = udp
+
+        ctx.closed = 0
+        return ctx
+
+    def __dealloc__(self):
+        if UVLOOP_DEBUG:
+            if not self.closed:
+                raise RuntimeError(
+                    'open _UDPSendContext is being deallocated')
+        self.udp = None
+
+
+@cython.no_gc_clear
+cdef class UDPTransport(UVBaseTransport):
+    def __cinit__(self):
+        self._family = uv.AF_UNSPEC
+        self.__receiving = 0
+        self._address = None
+        self.context = Context_CopyCurrent()
+
+    cdef _init(self, Loop loop, unsigned int family):
+        cdef int err
+
+        self._start_init(loop)
+
+        self._handle = PyMem_RawMalloc(sizeof(uv.uv_udp_t))
+        if self._handle is NULL:
+            self._abort_init()
+            raise MemoryError()
+
+        err = uv.uv_udp_init_ex(loop.uvloop,
+                                self._handle,
+                                family)
+        if err < 0:
+            self._abort_init()
+            raise convert_error(err)
+
+        if family in (uv.AF_INET, uv.AF_INET6):
+            self._family = family
+
+        self._finish_init()
+
+    cdef _set_address(self, system.addrinfo *addr):
+        self._address = __convert_sockaddr_to_pyaddr(addr.ai_addr)
+
+    cdef _connect(self, system.sockaddr* addr, size_t addr_len):
+        cdef int err
+        err = uv.uv_udp_connect(self._handle, addr)
+        if err < 0:
+            exc = convert_error(err)
+            raise exc
+
+    cdef open(self, int family, int sockfd):
+        if family in (uv.AF_INET, uv.AF_INET6, uv.AF_UNIX):
+            self._family = family
+        else:
+            raise ValueError(
+                'cannot open a UDP handle, invalid family {}'.format(family))
+
+        cdef int err
+        err = uv.uv_udp_open(self._handle,
+                             sockfd)
+
+        if err < 0:
+            exc = convert_error(err)
+            raise exc
+
+    cdef _bind(self, system.sockaddr* addr):
+        cdef:
+            int err
+            int flags = 0
+
+        self._ensure_alive()
+
+        err = uv.uv_udp_bind(self._handle, addr, flags)
+        if err < 0:
+            exc = convert_error(err)
+            raise exc
+
+    cdef _set_broadcast(self, bint on):
+        cdef int err
+
+        self._ensure_alive()
+
+        err = uv.uv_udp_set_broadcast(self._handle, on)
+        if err < 0:
+            exc = convert_error(err)
+            raise exc
+
+    cdef size_t _get_write_buffer_size(self):
+        if self._handle is NULL:
+            return 0
+        return (self._handle).send_queue_size
+
+    cdef bint _is_reading(self):
+        return self.__receiving
+
+    cdef _start_reading(self):
+        cdef int err
+
+        if self.__receiving:
+            return
+
+        self._ensure_alive()
+
+        err = uv.uv_udp_recv_start(self._handle,
+                                   __loop_alloc_buffer,
+                                   __uv_udp_on_receive)
+
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+        else:
+            # UDPTransport must live until the read callback is called
+            self.__receiving_started()
+
+    cdef _stop_reading(self):
+        cdef int err
+
+        if not self.__receiving:
+            return
+
+        self._ensure_alive()
+
+        err = uv.uv_udp_recv_stop(self._handle)
+        if err < 0:
+            exc = convert_error(err)
+            self._fatal_error(exc, True)
+            return
+        else:
+            self.__receiving_stopped()
+
+    cdef inline __receiving_started(self):
+        if self.__receiving:
+            return
+        self.__receiving = 1
+        Py_INCREF(self)
+
+    cdef inline __receiving_stopped(self):
+        if not self.__receiving:
+            return
+        self.__receiving = 0
+        Py_DECREF(self)
+
+    cdef _new_socket(self):
+        if self._family not in (uv.AF_INET, uv.AF_INET6, uv.AF_UNIX):
+            raise RuntimeError(
+                'UDPTransport.family is undefined; '
+                'cannot create python socket')
+
+        fileno = self._fileno()
+        return PseudoSocket(self._family, uv.SOCK_DGRAM, 0, fileno)
+
+    cdef _send(self, object data, object addr):
+        cdef:
+            _UDPSendContext ctx
+            system.sockaddr_storage saddr_st
+            system.sockaddr *saddr
+            Py_buffer       try_pybuf
+            uv.uv_buf_t     try_uvbuf
+
+        self._ensure_alive()
+
+        if self._family not in (uv.AF_INET, uv.AF_INET6, uv.AF_UNIX):
+            raise RuntimeError('UDPTransport.family is undefined; cannot send')
+
+        if addr is None:
+            saddr = NULL
+        else:
+            try:
+                __convert_pyaddr_to_sockaddr(self._family, addr,
+                                             &saddr_st)
+            except (ValueError, TypeError):
+                raise
+            except Exception:
+                raise ValueError(
+                    f'{addr!r}: socket family mismatch or '
+                    f'a DNS lookup is required')
+            saddr = (&saddr_st)
+
+        if self._get_write_buffer_size() == 0:
+            PyObject_GetBuffer(data, &try_pybuf, PyBUF_SIMPLE)
+            try_uvbuf.base = try_pybuf.buf
+            try_uvbuf.len = try_pybuf.len
+            err = uv.uv_udp_try_send(self._handle,
+                                     &try_uvbuf,
+                                     1,
+                                     saddr)
+            PyBuffer_Release(&try_pybuf)
+        else:
+            err = uv.UV_EAGAIN
+
+        if err == uv.UV_EAGAIN:
+            ctx = _UDPSendContext.new(self, data)
+            err = uv.uv_udp_send(&ctx.req,
+                                 self._handle,
+                                 &ctx.uv_buf,
+                                 1,
+                                 saddr,
+                                 __uv_udp_on_send)
+
+            if err < 0:
+                ctx.close()
+
+                exc = convert_error(err)
+                if isinstance(exc, OSError):
+                    run_in_context1(self.context.copy(), self._protocol.error_received, exc)
+                else:
+                    self._fatal_error(exc, True)
+            else:
+                self._maybe_pause_protocol()
+
+        else:
+            self._on_sent(convert_error(err) if err < 0 else None, self.context.copy())
+
+    cdef _on_receive(self, bytes data, object exc, object addr):
+        if exc is None:
+            run_in_context2(
+                self.context, self._protocol.datagram_received, data, addr,
+            )
+        else:
+            run_in_context1(self.context, self._protocol.error_received, exc)
+
+    cdef _on_sent(self, object exc, object context=None):
+        if exc is not None:
+            if isinstance(exc, OSError):
+                if context is None:
+                    context = self.context
+                run_in_context1(context, self._protocol.error_received, exc)
+            else:
+                self._fatal_error(
+                    exc, False, 'Fatal write error on datagram transport')
+
+        self._maybe_resume_protocol()
+        if not self._get_write_buffer_size():
+            if self._closing:
+                self._schedule_call_connection_lost(None)
+
+    # === Public API ===
+
+    def sendto(self, data, addr=None):
+        if not data:
+            # Replicating asyncio logic here.
+            return
+
+        if self._address:
+            if addr not in (None, self._address):
+                # Replicating asyncio logic here.
+                raise ValueError(
+                    'Invalid address: must be None or %s' % (self._address,))
+
+            # Instead of setting addr to self._address below like what asyncio
+            # does, we depend on previous uv_udp_connect() to set the address
+            addr = None
+
+        if self._conn_lost:
+            # Replicating asyncio logic here.
+            if self._conn_lost >= LOG_THRESHOLD_FOR_CONNLOST_WRITES:
+                aio_logger.warning('socket.send() raised exception.')
+            self._conn_lost += 1
+            return
+
+        self._send(data, addr)
+
+
+cdef void __uv_udp_on_receive(
+    uv.uv_udp_t* handle,
+    ssize_t nread,
+    const uv.uv_buf_t* buf,
+    const system.sockaddr* addr,
+    unsigned flags
+) noexcept with gil:
+
+    if __ensure_handle_data(handle,
+                            "UDPTransport receive callback") == 0:
+        return
+
+    cdef:
+        UDPTransport udp = handle.data
+        Loop loop = udp._loop
+        bytes data
+        object pyaddr
+
+    # It's OK to free the buffer early, since nothing will
+    # be able to touch it until this method is done.
+    __loop_free_buffer(loop)
+
+    if udp._closed:
+        # The handle was closed, there is no reason to
+        # do any work now.
+        udp.__receiving_stopped()  # Just in case.
+        return
+
+    if addr is NULL and nread == 0:
+        # From libuv docs:
+        #      addr: struct sockaddr* containing the address
+        #      of the sender. Can be NULL. Valid for the duration
+        #      of the callback only.
+        #      [...]
+        #      The receive callback will be called with
+        #      nread == 0 and addr == NULL when there is
+        #      nothing to read, and with nread == 0 and
+        #      addr != NULL when an empty UDP packet is
+        #      received.
+        return
+
+    if addr is NULL:
+        pyaddr = None
+    elif addr.sa_family == uv.AF_UNSPEC:
+        # https://github.com/MagicStack/uvloop/issues/304
+        if system.PLATFORM_IS_LINUX:
+            pyaddr = None
+        else:
+            pyaddr = ''
+    else:
+        try:
+            pyaddr = __convert_sockaddr_to_pyaddr(addr)
+        except BaseException as exc:
+            udp._error(exc, False)
+            return
+
+    if nread < 0:
+        exc = convert_error(nread)
+        udp._on_receive(None, exc, pyaddr)
+        return
+
+    if nread == 0:
+        data = b''
+    else:
+        data = loop._recv_buffer[:nread]
+
+    try:
+        udp._on_receive(data, None, pyaddr)
+    except BaseException as exc:
+        udp._error(exc, False)
+
+
+cdef void __uv_udp_on_send(
+    uv.uv_udp_send_t* req,
+    int status,
+) noexcept with gil:
+
+    if req.data is NULL:
+        # Shouldn't happen as:
+        #    - _UDPSendContext does an extra INCREF in its 'init()'
+        #    - _UDPSendContext holds a ref to the relevant UDPTransport
+        aio_logger.error(
+            'UVStream.write callback called with NULL req.data, status=%r',
+            status)
+        return
+
+    cdef:
+        _UDPSendContext ctx = <_UDPSendContext> req.data
+        UDPTransport udp = ctx.udp
+
+    ctx.close()
+
+    if status < 0:
+        exc = convert_error(status)
+        print(exc)
+    else:
+        exc = None
+
+    try:
+        udp._on_sent(exc)
+    except BaseException as exc:
+        udp._error(exc, False)
diff --git a/lib/python3.12/site-packages/uvloop/includes/__init__.py b/lib/python3.12/site-packages/uvloop/includes/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..2ccf9cae31016b266b5a8a656b3aea0c3e571fc9
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/includes/__init__.py
@@ -0,0 +1,23 @@
+# flake8: noqa
+
+# These have to be synced with the stdlib.pxi
+import asyncio
+import collections
+import concurrent.futures
+import errno
+import functools
+import gc
+import inspect
+import itertools
+import os
+import signal
+import socket
+import subprocess
+import ssl
+import stat
+import sys
+import threading
+import traceback
+import time
+import warnings
+import weakref
diff --git a/lib/python3.12/site-packages/uvloop/includes/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/uvloop/includes/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..53ebcaf5be9c0403f15b83039a1b53460e69e504
Binary files /dev/null and b/lib/python3.12/site-packages/uvloop/includes/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/uvloop/includes/consts.pxi b/lib/python3.12/site-packages/uvloop/includes/consts.pxi
new file mode 100644
index 0000000000000000000000000000000000000000..82f3c327fb26ed84ed81cc7d8422f3bf1359c49e
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/includes/consts.pxi
@@ -0,0 +1,33 @@
+cdef enum:
+    UV_STREAM_RECV_BUF_SIZE = 256000  # 250kb
+
+    FLOW_CONTROL_HIGH_WATER = 64  # KiB
+    FLOW_CONTROL_HIGH_WATER_SSL_READ = 256  # KiB
+    FLOW_CONTROL_HIGH_WATER_SSL_WRITE = 512  # KiB
+
+    DEFAULT_FREELIST_SIZE = 250
+    DNS_PYADDR_TO_SOCKADDR_CACHE_SIZE = 2048
+
+    DEBUG_STACK_DEPTH = 10
+
+
+    __PROCESS_DEBUG_SLEEP_AFTER_FORK = 1
+
+
+    LOG_THRESHOLD_FOR_CONNLOST_WRITES = 5
+    SSL_READ_MAX_SIZE = 256 * 1024
+
+
+cdef extern from *:
+    '''
+    // Number of seconds to wait for SSL handshake to complete
+    // The default timeout matches that of Nginx.
+    #define SSL_HANDSHAKE_TIMEOUT 60.0
+
+    // Number of seconds to wait for SSL shutdown to complete
+    // The default timeout mimics lingering_time
+    #define SSL_SHUTDOWN_TIMEOUT 30.0
+    '''
+
+    const float SSL_HANDSHAKE_TIMEOUT
+    const float SSL_SHUTDOWN_TIMEOUT
diff --git a/lib/python3.12/site-packages/uvloop/includes/debug.pxd b/lib/python3.12/site-packages/uvloop/includes/debug.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..a825def3c27511d9d860c2f4d0110fcb6561a8ff
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/includes/debug.pxd
@@ -0,0 +1,3 @@
+cdef extern from "includes/debug.h":
+
+    cdef int UVLOOP_DEBUG
diff --git a/lib/python3.12/site-packages/uvloop/includes/flowcontrol.pxd b/lib/python3.12/site-packages/uvloop/includes/flowcontrol.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..f22f1a7a541cb681b4c6f0f034bb1be248d189f1
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/includes/flowcontrol.pxd
@@ -0,0 +1,23 @@
+# flake8: noqa
+
+
+cdef inline add_flowcontrol_defaults(high, low, int kb):
+    cdef int h, l
+    if high is None:
+        if low is None:
+            h = kb * 1024
+        else:
+            l = low
+            h = 4 * l
+    else:
+        h = high
+    if low is None:
+        l = h // 4
+    else:
+        l = low
+
+    if not h >= l >= 0:
+        raise ValueError('high (%r) must be >= low (%r) must be >= 0' %
+                         (h, l))
+
+    return h, l
diff --git a/lib/python3.12/site-packages/uvloop/includes/python.pxd b/lib/python3.12/site-packages/uvloop/includes/python.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..94007e537381bb41af0749b1e67896db84e0266e
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/includes/python.pxd
@@ -0,0 +1,31 @@
+cdef extern from "Python.h":
+    int PY_VERSION_HEX
+
+    unicode PyUnicode_FromString(const char *)
+
+    void* PyMem_RawMalloc(size_t n) nogil
+    void* PyMem_RawRealloc(void *p, size_t n) nogil
+    void* PyMem_RawCalloc(size_t nelem, size_t elsize) nogil
+    void PyMem_RawFree(void *p) nogil
+
+    object PyUnicode_EncodeFSDefault(object)
+    void PyErr_SetInterrupt() nogil
+
+    object PyMemoryView_FromMemory(char *mem, ssize_t size, int flags)
+    object PyMemoryView_FromObject(object obj)
+    int PyMemoryView_Check(object obj)
+
+    cdef enum:
+        PyBUF_WRITE
+
+
+cdef extern from "includes/compat.h":
+    object Context_CopyCurrent()
+    int Context_Enter(object) except -1
+    int Context_Exit(object) except -1
+
+    void PyOS_BeforeFork()
+    void PyOS_AfterFork_Parent()
+    void PyOS_AfterFork_Child()
+
+    void _Py_RestoreSignals()
diff --git a/lib/python3.12/site-packages/uvloop/includes/stdlib.pxi b/lib/python3.12/site-packages/uvloop/includes/stdlib.pxi
new file mode 100644
index 0000000000000000000000000000000000000000..4152b8a7bb79e09c6971daec72c86a7cd7b23573
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/includes/stdlib.pxi
@@ -0,0 +1,176 @@
+# flake8: noqa
+
+
+import asyncio, asyncio.log, asyncio.base_events, \
+       asyncio.sslproto, asyncio.coroutines, \
+       asyncio.futures, asyncio.transports
+import collections.abc
+import concurrent.futures
+import errno
+import functools
+import gc
+import inspect
+import itertools
+import os
+import signal
+import socket
+import subprocess
+import ssl
+import stat
+import sys
+import threading
+import traceback
+import time
+import warnings
+import weakref
+
+
+cdef aio_get_event_loop = asyncio.get_event_loop
+cdef aio_CancelledError = asyncio.CancelledError
+cdef aio_InvalidStateError = asyncio.InvalidStateError
+cdef aio_TimeoutError = asyncio.TimeoutError
+cdef aio_Future = asyncio.Future
+cdef aio_Task = asyncio.Task
+cdef aio_ensure_future = asyncio.ensure_future
+cdef aio_gather = asyncio.gather
+cdef aio_wait = asyncio.wait
+cdef aio_wrap_future = asyncio.wrap_future
+cdef aio_logger = asyncio.log.logger
+cdef aio_iscoroutine = asyncio.iscoroutine
+cdef aio_iscoroutinefunction = asyncio.iscoroutinefunction
+cdef aio_BaseProtocol = asyncio.BaseProtocol
+cdef aio_Protocol = asyncio.Protocol
+cdef aio_isfuture = getattr(asyncio, 'isfuture', None)
+cdef aio_get_running_loop = getattr(asyncio, '_get_running_loop', None)
+cdef aio_set_running_loop = getattr(asyncio, '_set_running_loop', None)
+cdef aio_debug_wrapper = getattr(asyncio.coroutines, 'debug_wrapper', None)
+cdef aio_AbstractChildWatcher = asyncio.AbstractChildWatcher
+cdef aio_Transport = asyncio.Transport
+cdef aio_FlowControlMixin = asyncio.transports._FlowControlMixin
+
+cdef col_deque = collections.deque
+cdef col_Iterable = collections.abc.Iterable
+cdef col_Counter = collections.Counter
+cdef col_OrderedDict = collections.OrderedDict
+
+cdef cc_ThreadPoolExecutor = concurrent.futures.ThreadPoolExecutor
+cdef cc_Future = concurrent.futures.Future
+
+cdef errno_EBADF = errno.EBADF
+cdef errno_EINVAL = errno.EINVAL
+
+cdef ft_partial = functools.partial
+
+cdef gc_disable = gc.disable
+
+cdef iter_chain = itertools.chain
+cdef inspect_isgenerator = inspect.isgenerator
+
+cdef int has_IPV6_V6ONLY = hasattr(socket, 'IPV6_V6ONLY')
+cdef int IPV6_V6ONLY = getattr(socket, 'IPV6_V6ONLY', -1)
+cdef int has_SO_REUSEPORT = hasattr(socket, 'SO_REUSEPORT')
+cdef int SO_REUSEPORT = getattr(socket, 'SO_REUSEPORT', 0)
+cdef int SO_BROADCAST = getattr(socket, 'SO_BROADCAST')
+cdef int SOCK_NONBLOCK = getattr(socket, 'SOCK_NONBLOCK', -1)
+cdef int socket_AI_CANONNAME = getattr(socket, 'AI_CANONNAME')
+
+cdef socket_gaierror = socket.gaierror
+cdef socket_error = socket.error
+cdef socket_timeout = socket.timeout
+cdef socket_socket = socket.socket
+cdef socket_socketpair = socket.socketpair
+cdef socket_getservbyname = socket.getservbyname
+cdef socket_AddressFamily = socket.AddressFamily
+cdef socket_SocketKind = socket.SocketKind
+
+cdef int socket_EAI_ADDRFAMILY = getattr(socket, 'EAI_ADDRFAMILY', -1)
+cdef int socket_EAI_AGAIN      = getattr(socket, 'EAI_AGAIN', -1)
+cdef int socket_EAI_BADFLAGS   = getattr(socket, 'EAI_BADFLAGS', -1)
+cdef int socket_EAI_BADHINTS   = getattr(socket, 'EAI_BADHINTS', -1)
+cdef int socket_EAI_CANCELED   = getattr(socket, 'EAI_CANCELED', -1)
+cdef int socket_EAI_FAIL       = getattr(socket, 'EAI_FAIL', -1)
+cdef int socket_EAI_FAMILY     = getattr(socket, 'EAI_FAMILY', -1)
+cdef int socket_EAI_MEMORY     = getattr(socket, 'EAI_MEMORY', -1)
+cdef int socket_EAI_NODATA     = getattr(socket, 'EAI_NODATA', -1)
+cdef int socket_EAI_NONAME     = getattr(socket, 'EAI_NONAME', -1)
+cdef int socket_EAI_OVERFLOW   = getattr(socket, 'EAI_OVERFLOW', -1)
+cdef int socket_EAI_PROTOCOL   = getattr(socket, 'EAI_PROTOCOL', -1)
+cdef int socket_EAI_SERVICE    = getattr(socket, 'EAI_SERVICE', -1)
+cdef int socket_EAI_SOCKTYPE   = getattr(socket, 'EAI_SOCKTYPE', -1)
+
+
+cdef str os_name = os.name
+cdef os_environ = os.environ
+cdef os_dup = os.dup
+cdef os_set_inheritable = os.set_inheritable
+cdef os_get_inheritable = os.get_inheritable
+cdef os_close = os.close
+cdef os_open = os.open
+cdef os_devnull = os.devnull
+cdef os_O_RDWR = os.O_RDWR
+cdef os_pipe = os.pipe
+cdef os_read = os.read
+cdef os_remove = os.remove
+cdef os_stat = os.stat
+cdef os_unlink = os.unlink
+cdef os_fspath = os.fspath
+
+cdef stat_S_ISSOCK = stat.S_ISSOCK
+
+cdef sys_ignore_environment = sys.flags.ignore_environment
+cdef sys_dev_mode = sys.flags.dev_mode
+cdef sys_exc_info = sys.exc_info
+cdef sys_set_coroutine_wrapper = getattr(sys, 'set_coroutine_wrapper', None)
+cdef sys_get_coroutine_wrapper = getattr(sys, 'get_coroutine_wrapper', None)
+cdef sys_getframe = sys._getframe
+cdef sys_version_info = sys.version_info
+cdef sys_getfilesystemencoding = sys.getfilesystemencoding
+cdef str sys_platform = sys.platform
+
+cdef ssl_SSLContext = ssl.SSLContext
+cdef ssl_MemoryBIO = ssl.MemoryBIO
+cdef ssl_create_default_context = ssl.create_default_context
+cdef ssl_SSLError = ssl.SSLError
+cdef ssl_SSLAgainErrors = (ssl.SSLWantReadError, ssl.SSLSyscallError)
+cdef ssl_SSLZeroReturnError = ssl.SSLZeroReturnError
+cdef ssl_CertificateError = ssl.CertificateError
+cdef int ssl_SSL_ERROR_WANT_READ = ssl.SSL_ERROR_WANT_READ
+cdef int ssl_SSL_ERROR_WANT_WRITE = ssl.SSL_ERROR_WANT_WRITE
+cdef int ssl_SSL_ERROR_SYSCALL = ssl.SSL_ERROR_SYSCALL
+
+cdef threading_Thread = threading.Thread
+cdef threading_main_thread = threading.main_thread
+
+cdef int subprocess_PIPE = subprocess.PIPE
+cdef int subprocess_STDOUT = subprocess.STDOUT
+cdef int subprocess_DEVNULL = subprocess.DEVNULL
+cdef subprocess_SubprocessError = subprocess.SubprocessError
+
+cdef int signal_NSIG = signal.NSIG
+cdef signal_signal = signal.signal
+cdef signal_siginterrupt = signal.siginterrupt
+cdef signal_set_wakeup_fd = signal.set_wakeup_fd
+cdef signal_default_int_handler = signal.default_int_handler
+cdef signal_SIG_DFL = signal.SIG_DFL
+
+cdef time_sleep = time.sleep
+cdef time_monotonic = time.monotonic
+
+cdef tb_StackSummary = traceback.StackSummary
+cdef tb_walk_stack = traceback.walk_stack
+cdef tb_format_list = traceback.format_list
+
+cdef warnings_warn = warnings.warn
+
+cdef weakref_WeakValueDictionary = weakref.WeakValueDictionary
+cdef weakref_WeakSet = weakref.WeakSet
+
+cdef py_inf = float('inf')
+
+
+# Cython doesn't clean-up imported objects properly in Py3 mode,
+# so we delete refs to all modules manually (except sys)
+del asyncio, concurrent, collections, errno
+del functools, inspect, itertools, socket, os, threading
+del signal, subprocess, ssl
+del time, traceback, warnings, weakref
diff --git a/lib/python3.12/site-packages/uvloop/includes/system.pxd b/lib/python3.12/site-packages/uvloop/includes/system.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..367fedd1811b0978cd3431b89bbb0ab922166e48
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/includes/system.pxd
@@ -0,0 +1,96 @@
+from libc.stdint cimport int8_t, uint64_t
+
+cdef extern from "arpa/inet.h" nogil:
+
+    int ntohl(int)
+    int htonl(int)
+    int ntohs(int)
+
+
+cdef extern from "sys/socket.h" nogil:
+
+    struct sockaddr:
+        unsigned short sa_family
+        char           sa_data[14]
+
+    struct addrinfo:
+        int            ai_flags
+        int            ai_family
+        int            ai_socktype
+        int            ai_protocol
+        size_t         ai_addrlen
+        sockaddr*      ai_addr
+        char*          ai_canonname
+        addrinfo*      ai_next
+
+    struct sockaddr_in:
+        unsigned short sin_family
+        unsigned short sin_port
+        # ...
+
+    struct sockaddr_in6:
+        unsigned short sin6_family
+        unsigned short sin6_port
+        unsigned long  sin6_flowinfo
+        # ...
+        unsigned long  sin6_scope_id
+
+    struct sockaddr_storage:
+        unsigned short ss_family
+        # ...
+
+    const char *gai_strerror(int errcode)
+
+    int socketpair(int domain, int type, int protocol, int socket_vector[2])
+
+    int setsockopt(int socket, int level, int option_name,
+                   const void *option_value, int option_len)
+
+
+cdef extern from "sys/un.h" nogil:
+
+    struct sockaddr_un:
+        unsigned short sun_family
+        char*          sun_path
+        # ...
+
+
+cdef extern from "unistd.h" nogil:
+
+    ssize_t write(int fd, const void *buf, size_t count)
+    void _exit(int status)
+
+
+cdef extern from "pthread.h":
+
+    int pthread_atfork(
+        void (*prepare)(),
+        void (*parent)(),
+        void (*child)())
+
+
+cdef extern from "includes/compat.h" nogil:
+
+    cdef int EWOULDBLOCK
+
+    cdef int PLATFORM_IS_APPLE
+    cdef int PLATFORM_IS_LINUX
+
+    struct epoll_event:
+        # We don't use the fields
+        pass
+
+    int EPOLL_CTL_DEL
+    int epoll_ctl(int epfd, int op, int fd, epoll_event *event)
+    object MakeUnixSockPyAddr(sockaddr_un *addr)
+
+
+cdef extern from "includes/fork_handler.h":
+
+    uint64_t MAIN_THREAD_ID
+    int8_t MAIN_THREAD_ID_SET
+    ctypedef void (*OnForkHandler)()
+    void handleAtFork()
+    void setForkHandler(OnForkHandler handler)
+    void resetForkHandler()
+    void setMainThreadID(uint64_t id)
diff --git a/lib/python3.12/site-packages/uvloop/includes/uv.pxd b/lib/python3.12/site-packages/uvloop/includes/uv.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..510b14988ed20fd911d618adb9dd5ee42faed5c0
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/includes/uv.pxd
@@ -0,0 +1,506 @@
+from libc.stdint cimport uint16_t, uint32_t, uint64_t, int64_t
+from posix.types cimport gid_t, uid_t
+from posix.unistd cimport getuid
+
+from . cimport system
+
+# This is an internal enum UV_HANDLE_READABLE from uv-common.h, used only by
+# handles/pipe.pyx to temporarily workaround a libuv issue libuv/libuv#2058,
+# before there is a proper fix in libuv. In short, libuv disallowed feeding a
+# write-only pipe to uv_read_start(), which was needed by uvloop to detect a
+# broken pipe without having to send anything on the write-only end. We're
+# setting UV_HANDLE_READABLE on pipe_t to workaround this limitation
+# temporarily, please see also #317.
+cdef enum:
+    UV_INTERNAL_HANDLE_READABLE = 0x00004000
+
+cdef extern from "uv.h" nogil:
+    cdef int UV_TCP_IPV6ONLY
+
+    cdef int UV_EACCES
+    cdef int UV_EAGAIN
+    cdef int UV_EALREADY
+    cdef int UV_EBUSY
+    cdef int UV_ECONNABORTED
+    cdef int UV_ECONNREFUSED
+    cdef int UV_ECONNRESET
+    cdef int UV_ECANCELED
+    cdef int UV_EEXIST
+    cdef int UV_EINTR
+    cdef int UV_EINVAL
+    cdef int UV_EISDIR
+    cdef int UV_ENOENT
+    cdef int UV_EOF
+    cdef int UV_EPERM
+    cdef int UV_EPIPE
+    cdef int UV_ESHUTDOWN
+    cdef int UV_ESRCH
+    cdef int UV_ETIMEDOUT
+    cdef int UV_EBADF
+    cdef int UV_ENOBUFS
+
+    cdef int UV_EAI_ADDRFAMILY
+    cdef int UV_EAI_AGAIN
+    cdef int UV_EAI_BADFLAGS
+    cdef int UV_EAI_BADHINTS
+    cdef int UV_EAI_CANCELED
+    cdef int UV_EAI_FAIL
+    cdef int UV_EAI_FAMILY
+    cdef int UV_EAI_MEMORY
+    cdef int UV_EAI_NODATA
+    cdef int UV_EAI_NONAME
+    cdef int UV_EAI_OVERFLOW
+    cdef int UV_EAI_PROTOCOL
+    cdef int UV_EAI_SERVICE
+    cdef int UV_EAI_SOCKTYPE
+
+    cdef int SOL_SOCKET
+    cdef int SO_ERROR
+    cdef int SO_REUSEADDR
+    # use has_SO_REUSEPORT and SO_REUSEPORT in stdlib.pxi instead
+    cdef int AF_INET
+    cdef int AF_INET6
+    cdef int AF_UNIX
+    cdef int AF_UNSPEC
+    cdef int AI_PASSIVE
+    cdef int AI_NUMERICHOST
+    cdef int INET6_ADDRSTRLEN
+    cdef int IPPROTO_IPV6
+    cdef int SOCK_STREAM
+    cdef int SOCK_DGRAM
+    cdef int IPPROTO_TCP
+    cdef int IPPROTO_UDP
+
+    cdef int SIGINT
+    cdef int SIGHUP
+    cdef int SIGCHLD
+    cdef int SIGKILL
+    cdef int SIGTERM
+
+    ctypedef int uv_os_sock_t
+    ctypedef int uv_file
+    ctypedef int uv_os_fd_t
+
+    ctypedef struct uv_buf_t:
+        char* base
+        size_t len
+
+    ctypedef struct uv_loop_t:
+        void* data
+        # ...
+
+    ctypedef struct uv_handle_t:
+        void* data
+        uv_loop_t* loop
+        unsigned int flags
+        # ...
+
+    ctypedef struct uv_idle_t:
+        void* data
+        uv_loop_t* loop
+        # ...
+
+    ctypedef struct uv_check_t:
+        void* data
+        uv_loop_t* loop
+        # ...
+
+    ctypedef struct uv_signal_t:
+        void* data
+        uv_loop_t* loop
+        # ...
+
+    ctypedef struct uv_async_t:
+        void* data
+        uv_loop_t* loop
+        # ...
+
+    ctypedef struct uv_timer_t:
+        void* data
+        uv_loop_t* loop
+        # ...
+
+    ctypedef struct uv_stream_t:
+        void* data
+        size_t write_queue_size
+        uv_loop_t* loop
+        # ...
+
+    ctypedef struct uv_tcp_t:
+        void* data
+        uv_loop_t* loop
+        # ...
+
+    ctypedef struct uv_pipe_t:
+        void* data
+        uv_loop_t* loop
+        # ...
+
+    ctypedef struct uv_udp_t:
+        void* data
+        uv_loop_t* loop
+        size_t send_queue_size
+        size_t send_queue_count
+        # ...
+
+    ctypedef struct uv_udp_send_t:
+        void* data
+        uv_udp_t* handle
+
+    ctypedef struct uv_poll_t:
+        void* data
+        uv_loop_t* loop
+        # ...
+
+    ctypedef struct uv_req_t:
+        # Only cancellation of uv_fs_t, uv_getaddrinfo_t,
+        # uv_getnameinfo_t and uv_work_t requests is
+        # currently supported.
+        void* data
+        uv_req_type type
+        # ...
+
+    ctypedef struct uv_connect_t:
+        void* data
+
+    ctypedef struct uv_getaddrinfo_t:
+        void* data
+        # ...
+
+    ctypedef struct uv_getnameinfo_t:
+        void* data
+        # ...
+
+    ctypedef struct uv_write_t:
+        void* data
+        # ...
+
+    ctypedef struct uv_shutdown_t:
+        void* data
+        # ...
+
+    ctypedef struct uv_process_t:
+        void* data
+        int pid
+        # ...
+
+    ctypedef struct uv_fs_event_t:
+        void* data
+        # ...
+
+    ctypedef enum uv_req_type:
+        UV_UNKNOWN_REQ = 0,
+        UV_REQ,
+        UV_CONNECT,
+        UV_WRITE,
+        UV_SHUTDOWN,
+        UV_UDP_SEND,
+        UV_FS,
+        UV_WORK,
+        UV_GETADDRINFO,
+        UV_GETNAMEINFO,
+        UV_REQ_TYPE_PRIVATE,
+        UV_REQ_TYPE_MAX
+
+    ctypedef enum uv_run_mode:
+        UV_RUN_DEFAULT = 0,
+        UV_RUN_ONCE,
+        UV_RUN_NOWAIT
+
+    ctypedef enum uv_poll_event:
+        UV_READABLE = 1,
+        UV_WRITABLE = 2,
+        UV_DISCONNECT = 4
+
+    ctypedef enum uv_udp_flags:
+        UV_UDP_IPV6ONLY = 1,
+        UV_UDP_PARTIAL = 2
+
+    ctypedef enum uv_membership:
+        UV_LEAVE_GROUP = 0,
+        UV_JOIN_GROUP
+
+    cdef enum uv_fs_event:
+        UV_RENAME = 1,
+        UV_CHANGE = 2
+
+    const char* uv_strerror(int err)
+    const char* uv_err_name(int err)
+
+    ctypedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg) with gil
+
+    ctypedef void (*uv_close_cb)(uv_handle_t* handle) with gil
+    ctypedef void (*uv_idle_cb)(uv_idle_t* handle) with gil
+    ctypedef void (*uv_check_cb)(uv_check_t* handle) with gil
+    ctypedef void (*uv_signal_cb)(uv_signal_t* handle, int signum) with gil
+    ctypedef void (*uv_async_cb)(uv_async_t* handle) with gil
+    ctypedef void (*uv_timer_cb)(uv_timer_t* handle) with gil
+    ctypedef void (*uv_connection_cb)(uv_stream_t* server, int status) with gil
+    ctypedef void (*uv_alloc_cb)(uv_handle_t* handle,
+                                 size_t suggested_size,
+                                 uv_buf_t* buf) with gil
+    ctypedef void (*uv_read_cb)(uv_stream_t* stream,
+                                ssize_t nread,
+                                const uv_buf_t* buf) with gil
+    ctypedef void (*uv_write_cb)(uv_write_t* req, int status) with gil
+    ctypedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req,
+                                       int status,
+                                       system.addrinfo* res) with gil
+    ctypedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
+                                       int status,
+                                       const char* hostname,
+                                       const char* service) with gil
+    ctypedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status) with gil
+    ctypedef void (*uv_poll_cb)(uv_poll_t* handle,
+                                int status, int events) with gil
+
+    ctypedef void (*uv_connect_cb)(uv_connect_t* req, int status) with gil
+
+    ctypedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status) with gil
+    ctypedef void (*uv_udp_recv_cb)(uv_udp_t* handle,
+                                    ssize_t nread,
+                                    const uv_buf_t* buf,
+                                    const system.sockaddr* addr,
+                                    unsigned flags) with gil
+    ctypedef void (*uv_fs_event_cb)(uv_fs_event_t* handle,
+                                    const char *filename,
+                                    int events,
+                                    int status) with gil
+
+    # Generic request functions
+    int uv_cancel(uv_req_t* req)
+
+    # Generic handler functions
+    int uv_is_active(const uv_handle_t* handle)
+    void uv_close(uv_handle_t* handle, uv_close_cb close_cb)
+    int uv_is_closing(const uv_handle_t* handle)
+    int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd)
+    void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg)
+
+    # Loop functions
+    int uv_loop_init(uv_loop_t* loop)
+    int uv_loop_close(uv_loop_t* loop)
+    int uv_loop_alive(uv_loop_t* loop)
+    int uv_loop_fork(uv_loop_t* loop)
+    uv_os_fd_t uv_backend_fd(uv_loop_t* loop)
+
+    void uv_update_time(uv_loop_t* loop)
+    uint64_t uv_now(const uv_loop_t*)
+
+    int uv_run(uv_loop_t*, uv_run_mode mode) nogil
+    void uv_stop(uv_loop_t*)
+
+    # Idle handler
+    int uv_idle_init(uv_loop_t*, uv_idle_t* idle)
+    int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb)
+    int uv_idle_stop(uv_idle_t* idle)
+
+    # Check handler
+    int uv_check_init(uv_loop_t*, uv_check_t* idle)
+    int uv_check_start(uv_check_t* check, uv_check_cb cb)
+    int uv_check_stop(uv_check_t* check)
+
+    # Signal handler
+    int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle)
+    int uv_signal_start(uv_signal_t* handle,
+                        uv_signal_cb signal_cb,
+                        int signum)
+    int uv_signal_stop(uv_signal_t* handle)
+
+    # Async handler
+    int uv_async_init(uv_loop_t*,
+                      uv_async_t* async_,
+                      uv_async_cb async_cb)
+    int uv_async_send(uv_async_t* async_)
+
+    # Timer handler
+    int uv_timer_init(uv_loop_t*, uv_timer_t* handle)
+    int uv_timer_start(uv_timer_t* handle,
+                       uv_timer_cb cb,
+                       uint64_t timeout,
+                       uint64_t repeat)
+    int uv_timer_stop(uv_timer_t* handle)
+
+    # DNS
+    int uv_getaddrinfo(uv_loop_t* loop,
+                       uv_getaddrinfo_t* req,
+                       uv_getaddrinfo_cb getaddrinfo_cb,
+                       const char* node,
+                       const char* service,
+                       const system.addrinfo* hints)
+
+    void uv_freeaddrinfo(system.addrinfo* ai)
+
+    int uv_getnameinfo(uv_loop_t* loop,
+                       uv_getnameinfo_t* req,
+                       uv_getnameinfo_cb getnameinfo_cb,
+                       const system.sockaddr* addr,
+                       int flags)
+
+    int uv_ip4_name(const system.sockaddr_in* src, char* dst, size_t size)
+    int uv_ip6_name(const system.sockaddr_in6* src, char* dst, size_t size)
+
+    # Streams
+
+    int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb)
+    int uv_accept(uv_stream_t* server, uv_stream_t* client)
+    int uv_read_start(uv_stream_t* stream,
+                      uv_alloc_cb alloc_cb,
+                      uv_read_cb read_cb)
+    int uv_read_stop(uv_stream_t*)
+    int uv_write(uv_write_t* req, uv_stream_t* handle,
+                 uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb)
+
+    int uv_try_write(uv_stream_t* handle, uv_buf_t bufs[], unsigned int nbufs)
+
+    int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb)
+
+    int uv_is_readable(const uv_stream_t* handle)
+    int uv_is_writable(const uv_stream_t* handle)
+
+    # TCP
+
+    int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags)
+    int uv_tcp_nodelay(uv_tcp_t* handle, int enable)
+    int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay)
+    int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock)
+    int uv_tcp_bind(uv_tcp_t* handle, system.sockaddr* addr,
+                    unsigned int flags)
+
+    int uv_tcp_getsockname(const uv_tcp_t* handle, system.sockaddr* name,
+                           int* namelen)
+    int uv_tcp_getpeername(const uv_tcp_t* handle, system.sockaddr* name,
+                           int* namelen)
+
+    int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
+                       const system.sockaddr* addr, uv_connect_cb cb)
+
+    # Pipes
+
+    int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc)
+    int uv_pipe_open(uv_pipe_t* handle, uv_os_fd_t file)
+    int uv_pipe_bind(uv_pipe_t* handle, const char* name)
+
+    void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
+                         const char* name, uv_connect_cb cb)
+
+    # UDP
+
+    int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags)
+    int uv_udp_connect(uv_udp_t* handle, const system.sockaddr* addr)
+    int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock)
+    int uv_udp_bind(uv_udp_t* handle, const system.sockaddr* addr,
+                    unsigned int flags)
+    int uv_udp_send(uv_udp_send_t* req, uv_udp_t* handle,
+                    const uv_buf_t bufs[], unsigned int nbufs,
+                    const system.sockaddr* addr, uv_udp_send_cb send_cb)
+    int uv_udp_try_send(uv_udp_t* handle,
+                        const uv_buf_t bufs[], unsigned int nbufs,
+                        const system.sockaddr* addr)
+    int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
+                          uv_udp_recv_cb recv_cb)
+    int uv_udp_recv_stop(uv_udp_t* handle)
+    int uv_udp_set_broadcast(uv_udp_t* handle, int on)
+
+    # Polling
+
+    int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd)
+    int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+                            uv_os_sock_t socket)
+    int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb)
+    int uv_poll_stop(uv_poll_t* poll)
+
+    # FS Event
+
+    int uv_fs_event_init(uv_loop_t *loop, uv_fs_event_t *handle)
+    int uv_fs_event_start(uv_fs_event_t *handle, uv_fs_event_cb cb,
+                          const char *path, unsigned int flags)
+    int uv_fs_event_stop(uv_fs_event_t *handle)
+
+    # Misc
+
+    ctypedef struct uv_timeval_t:
+        long tv_sec
+        long tv_usec
+
+    ctypedef struct uv_rusage_t:
+        uv_timeval_t ru_utime   # user CPU time used
+        uv_timeval_t ru_stime   # system CPU time used
+        uint64_t ru_maxrss      # maximum resident set size
+        uint64_t ru_ixrss       # integral shared memory size
+        uint64_t ru_idrss       # integral unshared data size
+        uint64_t ru_isrss       # integral unshared stack size
+        uint64_t ru_minflt      # page reclaims (soft page faults)
+        uint64_t ru_majflt      # page faults (hard page faults)
+        uint64_t ru_nswap       # swaps
+        uint64_t ru_inblock     # block input operations
+        uint64_t ru_oublock     # block output operations
+        uint64_t ru_msgsnd      # IPC messages sent
+        uint64_t ru_msgrcv      # IPC messages received
+        uint64_t ru_nsignals    # signals received
+        uint64_t ru_nvcsw       # voluntary context switches
+        uint64_t ru_nivcsw      # involuntary context switches
+
+    int uv_getrusage(uv_rusage_t* rusage)
+
+    int uv_ip4_addr(const char* ip, int port, system.sockaddr_in* addr)
+    int uv_ip6_addr(const char* ip, int port, system.sockaddr_in6* addr)
+
+    # Memory Allocation
+
+    ctypedef void* (*uv_malloc_func)(size_t size)
+    ctypedef void* (*uv_realloc_func)(void* ptr, size_t size)
+    ctypedef void* (*uv_calloc_func)(size_t count, size_t size)
+    ctypedef void (*uv_free_func)(void* ptr)
+
+    int uv_replace_allocator(uv_malloc_func malloc_func,
+                             uv_realloc_func realloc_func,
+                             uv_calloc_func calloc_func,
+                             uv_free_func free_func)
+
+    # Process
+
+    ctypedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status,
+                                int term_signal) with gil
+
+    ctypedef enum uv_process_flags:
+        UV_PROCESS_SETUID = 1,
+        UV_PROCESS_SETGID = 2,
+        UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = 4,
+        UV_PROCESS_DETACHED = 8,
+        UV_PROCESS_WINDOWS_HIDE = 16
+
+    ctypedef enum uv_stdio_flags:
+        UV_IGNORE = 0x00,
+        UV_CREATE_PIPE = 0x01,
+        UV_INHERIT_FD = 0x02,
+        UV_INHERIT_STREAM = 0x04,
+        UV_READABLE_PIPE = 0x10,
+        UV_WRITABLE_PIPE = 0x20
+
+    ctypedef union uv_stdio_container_data_u:
+        uv_stream_t* stream
+        int fd
+
+    ctypedef struct uv_stdio_container_t:
+        uv_stdio_flags flags
+        uv_stdio_container_data_u data
+
+    ctypedef struct uv_process_options_t:
+        uv_exit_cb exit_cb
+        char* file
+        char** args
+        char** env
+        char* cwd
+        unsigned int flags
+        int stdio_count
+        uv_stdio_container_t* stdio
+        uid_t uid
+        gid_t gid
+
+    int uv_spawn(uv_loop_t* loop, uv_process_t* handle,
+                 const uv_process_options_t* options)
+
+    int uv_process_kill(uv_process_t* handle, int signum)
+
+    unsigned int uv_version()
diff --git a/lib/python3.12/site-packages/uvloop/loop.pxd b/lib/python3.12/site-packages/uvloop/loop.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..01e39ae12e24acfabfc6631acbbef55e32c473ce
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/loop.pxd
@@ -0,0 +1,230 @@
+# cython: language_level=3
+
+
+from .includes cimport uv
+from .includes cimport system
+
+from libc.stdint cimport uint64_t, uint32_t, int64_t
+
+
+include "includes/consts.pxi"
+
+
+cdef extern from *:
+    ctypedef int vint "volatile int"
+
+
+cdef class UVHandle
+cdef class UVSocketHandle(UVHandle)
+
+cdef class UVAsync(UVHandle)
+cdef class UVTimer(UVHandle)
+cdef class UVIdle(UVHandle)
+
+cdef class UVBaseTransport(UVSocketHandle)
+
+ctypedef object (*method_t)(object)
+ctypedef object (*method1_t)(object, object)
+ctypedef object (*method2_t)(object, object, object)
+ctypedef object (*method3_t)(object, object, object, object)
+
+
+cdef class Loop:
+    cdef:
+        uv.uv_loop_t *uvloop
+
+        bint _coroutine_debug_set
+        int _coroutine_origin_tracking_saved_depth
+
+        public slow_callback_duration
+
+        readonly bint _closed
+        bint _debug
+        bint _running
+        bint _stopping
+
+        uint64_t _thread_id
+
+        object _task_factory
+        object _exception_handler
+        object _default_executor
+        object _ready
+        set _queued_streams, _executing_streams
+        Py_ssize_t _ready_len
+
+        set _servers
+
+        object _transports
+        set _processes
+        dict _fd_to_reader_fileobj
+        dict _fd_to_writer_fileobj
+        dict _unix_server_sockets
+
+        set _signals
+        dict _signal_handlers
+        object _ssock
+        object _csock
+        bint _listening_signals
+        int _old_signal_wakeup_id
+
+        set _timers
+        dict _polls
+
+        UVProcess active_process_handler
+
+        UVAsync handler_async
+        UVIdle handler_idle
+        UVCheck handler_check__exec_writes
+
+        object _last_error
+
+        cdef object __weakref__
+
+        object _asyncgens
+        bint _asyncgens_shutdown_called
+
+        bint _executor_shutdown_called
+
+        char _recv_buffer[UV_STREAM_RECV_BUF_SIZE]
+        bint _recv_buffer_in_use
+
+        # DEBUG fields
+        # True when compiled with DEBUG.
+        # Used only in unittests.
+        readonly bint _debug_cc
+
+        readonly object _debug_handles_total
+        readonly object _debug_handles_closed
+        readonly object _debug_handles_current
+
+        readonly uint64_t _debug_uv_handles_total
+        readonly uint64_t _debug_uv_handles_freed
+
+        readonly uint64_t _debug_cb_handles_total
+        readonly uint64_t _debug_cb_handles_count
+        readonly uint64_t _debug_cb_timer_handles_total
+        readonly uint64_t _debug_cb_timer_handles_count
+
+        readonly uint64_t _debug_stream_shutdown_errors_total
+        readonly uint64_t _debug_stream_listen_errors_total
+
+        readonly uint64_t _debug_stream_read_cb_total
+        readonly uint64_t _debug_stream_read_cb_errors_total
+        readonly uint64_t _debug_stream_read_eof_total
+        readonly uint64_t _debug_stream_read_eof_cb_errors_total
+        readonly uint64_t _debug_stream_read_errors_total
+
+        readonly uint64_t _debug_stream_write_tries
+        readonly uint64_t _debug_stream_write_errors_total
+        readonly uint64_t _debug_stream_write_ctx_total
+        readonly uint64_t _debug_stream_write_ctx_cnt
+        readonly uint64_t _debug_stream_write_cb_errors_total
+
+        readonly uint64_t _poll_read_events_total
+        readonly uint64_t _poll_read_cb_errors_total
+        readonly uint64_t _poll_write_events_total
+        readonly uint64_t _poll_write_cb_errors_total
+
+        readonly uint64_t _sock_try_write_total
+
+        readonly uint64_t _debug_exception_handler_cnt
+
+    cdef _init_debug_fields(self)
+
+    cdef _on_wake(self)
+    cdef _on_idle(self)
+
+    cdef __run(self, uv.uv_run_mode)
+    cdef _run(self, uv.uv_run_mode)
+
+    cdef _close(self)
+    cdef _stop(self, exc)
+    cdef uint64_t _time(self)
+
+    cdef inline _queue_write(self, UVStream stream)
+    cdef _exec_queued_writes(self)
+
+    cdef inline _call_soon(self, object callback, object args, object context)
+    cdef inline _append_ready_handle(self, Handle handle)
+    cdef inline _call_soon_handle(self, Handle handle)
+
+    cdef _call_later(self, uint64_t delay, object callback, object args,
+                     object context)
+
+    cdef void _handle_exception(self, object ex)
+
+    cdef inline _is_main_thread(self)
+
+    cdef inline _new_future(self)
+    cdef inline _check_signal(self, sig)
+    cdef inline _check_closed(self)
+    cdef inline _check_thread(self)
+
+    cdef _getaddrinfo(self, object host, object port,
+                      int family, int type,
+                      int proto, int flags,
+                      int unpack)
+
+    cdef _getnameinfo(self, system.sockaddr *addr, int flags)
+
+    cdef _track_transport(self, UVBaseTransport transport)
+    cdef _fileobj_to_fd(self, fileobj)
+    cdef _ensure_fd_no_transport(self, fd)
+
+    cdef _track_process(self, UVProcess proc)
+    cdef _untrack_process(self, UVProcess proc)
+
+    cdef _add_reader(self, fd, Handle handle)
+    cdef _has_reader(self, fd)
+    cdef _remove_reader(self, fd)
+
+    cdef _add_writer(self, fd, Handle handle)
+    cdef _has_writer(self, fd)
+    cdef _remove_writer(self, fd)
+
+    cdef _sock_recv(self, fut, sock, n)
+    cdef _sock_recv_into(self, fut, sock, buf)
+    cdef _sock_sendall(self, fut, sock, data)
+    cdef _sock_accept(self, fut, sock)
+
+    cdef _sock_connect(self, sock, address)
+    cdef _sock_connect_cb(self, fut, sock, address)
+
+    cdef _sock_set_reuseport(self, int fd)
+
+    cdef _setup_or_resume_signals(self)
+    cdef _shutdown_signals(self)
+    cdef _pause_signals(self)
+
+    cdef _handle_signal(self, sig)
+    cdef _read_from_self(self)
+    cdef inline _ceval_process_signals(self)
+    cdef _invoke_signals(self, bytes data)
+
+    cdef _set_coroutine_debug(self, bint enabled)
+
+    cdef _print_debug_info(self)
+
+
+include "cbhandles.pxd"
+
+include "handles/handle.pxd"
+include "handles/async_.pxd"
+include "handles/idle.pxd"
+include "handles/check.pxd"
+include "handles/timer.pxd"
+include "handles/poll.pxd"
+include "handles/basetransport.pxd"
+include "handles/stream.pxd"
+include "handles/streamserver.pxd"
+include "handles/tcp.pxd"
+include "handles/pipe.pxd"
+include "handles/process.pxd"
+include "handles/fsevent.pxd"
+
+include "request.pxd"
+include "sslproto.pxd"
+
+include "handles/udp.pxd"
+
+include "server.pxd"
diff --git a/lib/python3.12/site-packages/uvloop/loop.pyi b/lib/python3.12/site-packages/uvloop/loop.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..9c8c46239f8256e93f709ec81524345420ce1b85
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/loop.pyi
@@ -0,0 +1,297 @@
+import asyncio
+import ssl
+import sys
+from socket import AddressFamily, SocketKind, _Address, _RetAddress, socket
+from typing import (
+    IO,
+    Any,
+    Awaitable,
+    Callable,
+    Dict,
+    Generator,
+    List,
+    Optional,
+    Sequence,
+    Tuple,
+    TypeVar,
+    Union,
+    overload,
+)
+
+_T = TypeVar('_T')
+_Context = Dict[str, Any]
+_ExceptionHandler = Callable[[asyncio.AbstractEventLoop, _Context], Any]
+_SSLContext = Union[bool, None, ssl.SSLContext]
+_ProtocolT = TypeVar("_ProtocolT", bound=asyncio.BaseProtocol)
+
+class Loop:
+    def call_soon(
+        self, callback: Callable[..., Any], *args: Any, context: Optional[Any] = ...
+    ) -> asyncio.Handle: ...
+    def call_soon_threadsafe(
+        self, callback: Callable[..., Any], *args: Any, context: Optional[Any] = ...
+    ) -> asyncio.Handle: ...
+    def call_later(
+        self, delay: float, callback: Callable[..., Any], *args: Any, context: Optional[Any] = ...
+    ) -> asyncio.TimerHandle: ...
+    def call_at(
+        self, when: float, callback: Callable[..., Any], *args: Any, context: Optional[Any] = ...
+    ) -> asyncio.TimerHandle: ...
+    def time(self) -> float: ...
+    def stop(self) -> None: ...
+    def run_forever(self) -> None: ...
+    def close(self) -> None: ...
+    def get_debug(self) -> bool: ...
+    def set_debug(self, enabled: bool) -> None: ...
+    def is_running(self) -> bool: ...
+    def is_closed(self) -> bool: ...
+    def create_future(self) -> asyncio.Future[Any]: ...
+    def create_task(
+        self,
+        coro: Union[Awaitable[_T], Generator[Any, None, _T]],
+        *,
+        name: Optional[str] = ...,
+    ) -> asyncio.Task[_T]: ...
+    def set_task_factory(
+        self,
+        factory: Optional[
+            Callable[[asyncio.AbstractEventLoop, Generator[Any, None, _T]], asyncio.Future[_T]]
+        ],
+    ) -> None: ...
+    def get_task_factory(
+        self,
+    ) -> Optional[
+        Callable[[asyncio.AbstractEventLoop, Generator[Any, None, _T]], asyncio.Future[_T]]
+    ]: ...
+    @overload
+    def run_until_complete(self, future: Generator[Any, None, _T]) -> _T: ...
+    @overload
+    def run_until_complete(self, future: Awaitable[_T]) -> _T: ...
+    async def getaddrinfo(
+        self,
+        host: Optional[Union[str, bytes]],
+        port: Optional[Union[str, bytes, int]],
+        *,
+        family: int = ...,
+        type: int = ...,
+        proto: int = ...,
+        flags: int = ...,
+    ) -> List[
+        Tuple[
+            AddressFamily,
+            SocketKind,
+            int,
+            str,
+            Union[Tuple[str, int], Tuple[str, int, int, int]],
+        ]
+    ]: ...
+    async def getnameinfo(
+        self,
+        sockaddr: Union[
+            Tuple[str, int],
+            Tuple[str, int, int],
+            Tuple[str, int, int, int]
+        ],
+        flags: int = ...,
+    ) -> Tuple[str, str]: ...
+    async def start_tls(
+        self,
+        transport: asyncio.BaseTransport,
+        protocol: asyncio.BaseProtocol,
+        sslcontext: ssl.SSLContext,
+        *,
+        server_side: bool = ...,
+        server_hostname: Optional[str] = ...,
+        ssl_handshake_timeout: Optional[float] = ...,
+        ssl_shutdown_timeout: Optional[float] = ...,
+    ) -> asyncio.BaseTransport: ...
+    @overload
+    async def create_server(
+        self,
+        protocol_factory: asyncio.events._ProtocolFactory,
+        host: Optional[Union[str, Sequence[str]]] = ...,
+        port: int = ...,
+        *,
+        family: int = ...,
+        flags: int = ...,
+        sock: None = ...,
+        backlog: int = ...,
+        ssl: _SSLContext = ...,
+        reuse_address: Optional[bool] = ...,
+        reuse_port: Optional[bool] = ...,
+        ssl_handshake_timeout: Optional[float] = ...,
+        ssl_shutdown_timeout: Optional[float] = ...,
+        start_serving: bool = ...,
+    ) -> asyncio.AbstractServer: ...
+    @overload
+    async def create_server(
+        self,
+        protocol_factory: asyncio.events._ProtocolFactory,
+        host: None = ...,
+        port: None = ...,
+        *,
+        family: int = ...,
+        flags: int = ...,
+        sock: socket = ...,
+        backlog: int = ...,
+        ssl: _SSLContext = ...,
+        reuse_address: Optional[bool] = ...,
+        reuse_port: Optional[bool] = ...,
+        ssl_handshake_timeout: Optional[float] = ...,
+        ssl_shutdown_timeout: Optional[float] = ...,
+        start_serving: bool = ...,
+    ) -> asyncio.AbstractServer: ...
+    @overload
+    async def create_connection(
+        self,
+        protocol_factory: Callable[[], _ProtocolT],
+        host: str = ...,
+        port: int = ...,
+        *,
+        ssl: _SSLContext = ...,
+        family: int = ...,
+        proto: int = ...,
+        flags: int = ...,
+        sock: None = ...,
+        local_addr: Optional[Tuple[str, int]] = ...,
+        server_hostname: Optional[str] = ...,
+        ssl_handshake_timeout: Optional[float] = ...,
+        ssl_shutdown_timeout: Optional[float] = ...,
+    ) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
+    @overload
+    async def create_connection(
+        self,
+        protocol_factory: Callable[[], _ProtocolT],
+        host: None = ...,
+        port: None = ...,
+        *,
+        ssl: _SSLContext = ...,
+        family: int = ...,
+        proto: int = ...,
+        flags: int = ...,
+        sock: socket,
+        local_addr: None = ...,
+        server_hostname: Optional[str] = ...,
+        ssl_handshake_timeout: Optional[float] = ...,
+        ssl_shutdown_timeout: Optional[float] = ...,
+    ) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
+    async def create_unix_server(
+        self,
+        protocol_factory: asyncio.events._ProtocolFactory,
+        path: Optional[str] = ...,
+        *,
+        backlog: int = ...,
+        sock: Optional[socket] = ...,
+        ssl: _SSLContext = ...,
+        ssl_handshake_timeout: Optional[float] = ...,
+        ssl_shutdown_timeout: Optional[float] = ...,
+        start_serving: bool = ...,
+    ) -> asyncio.AbstractServer: ...
+    async def create_unix_connection(
+        self,
+        protocol_factory: Callable[[], _ProtocolT],
+        path: Optional[str] = ...,
+        *,
+        ssl: _SSLContext = ...,
+        sock: Optional[socket] = ...,
+        server_hostname: Optional[str] = ...,
+        ssl_handshake_timeout: Optional[float] = ...,
+        ssl_shutdown_timeout: Optional[float] = ...,
+    ) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
+    def default_exception_handler(self, context: _Context) -> None: ...
+    def get_exception_handler(self) -> Optional[_ExceptionHandler]: ...
+    def set_exception_handler(self, handler: Optional[_ExceptionHandler]) -> None: ...
+    def call_exception_handler(self, context: _Context) -> None: ...
+    def add_reader(self, fd: Any, callback: Callable[..., Any], *args: Any) -> None: ...
+    def remove_reader(self, fd: Any) -> None: ...
+    def add_writer(self, fd: Any, callback: Callable[..., Any], *args: Any) -> None: ...
+    def remove_writer(self, fd: Any) -> None: ...
+    async def sock_recv(self, sock: socket, nbytes: int) -> bytes: ...
+    async def sock_recv_into(self, sock: socket, buf: bytearray) -> int: ...
+    async def sock_sendall(self, sock: socket, data: bytes) -> None: ...
+    async def sock_accept(self, sock: socket) -> Tuple[socket, _RetAddress]: ...
+    async def sock_connect(self, sock: socket, address: _Address) -> None: ...
+    async def sock_recvfrom(self, sock: socket, bufsize: int) -> bytes: ...
+    async def sock_recvfrom_into(self, sock: socket, buf: bytearray, nbytes: int = ...) -> int: ...
+    async def sock_sendto(self, sock: socket, data: bytes, address: _Address) -> None: ...
+    async def connect_accepted_socket(
+        self,
+        protocol_factory: Callable[[], _ProtocolT],
+        sock: socket,
+        *,
+        ssl: _SSLContext = ...,
+        ssl_handshake_timeout: Optional[float] = ...,
+        ssl_shutdown_timeout: Optional[float] = ...,
+    ) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
+    async def run_in_executor(
+        self, executor: Any, func: Callable[..., _T], *args: Any
+    ) -> _T: ...
+    def set_default_executor(self, executor: Any) -> None: ...
+    async def subprocess_shell(
+        self,
+        protocol_factory: Callable[[], _ProtocolT],
+        cmd: Union[bytes, str],
+        *,
+        stdin: Any = ...,
+        stdout: Any = ...,
+        stderr: Any = ...,
+        **kwargs: Any,
+    ) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
+    async def subprocess_exec(
+        self,
+        protocol_factory: Callable[[], _ProtocolT],
+        *args: Any,
+        stdin: Any = ...,
+        stdout: Any = ...,
+        stderr: Any = ...,
+        **kwargs: Any,
+    ) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
+    async def connect_read_pipe(
+        self, protocol_factory: Callable[[], _ProtocolT], pipe: Any
+    ) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
+    async def connect_write_pipe(
+        self, protocol_factory: Callable[[], _ProtocolT], pipe: Any
+    ) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
+    def add_signal_handler(
+        self, sig: int, callback: Callable[..., Any], *args: Any
+    ) -> None: ...
+    def remove_signal_handler(self, sig: int) -> bool: ...
+    async def create_datagram_endpoint(
+        self,
+        protocol_factory: Callable[[], _ProtocolT],
+        local_addr: Optional[Tuple[str, int]] = ...,
+        remote_addr: Optional[Tuple[str, int]] = ...,
+        *,
+        family: int = ...,
+        proto: int = ...,
+        flags: int = ...,
+        reuse_address: Optional[bool] = ...,
+        reuse_port: Optional[bool] = ...,
+        allow_broadcast: Optional[bool] = ...,
+        sock: Optional[socket] = ...,
+    ) -> tuple[asyncio.BaseProtocol, _ProtocolT]: ...
+    async def shutdown_asyncgens(self) -> None: ...
+    async def shutdown_default_executor(
+        self,
+        timeout: Optional[float] = ...,
+    ) -> None: ...
+    # Loop doesn't implement these, but since they are marked as abstract in typeshed,
+    # we have to put them in so mypy thinks the base methods are overridden
+    async def sendfile(
+        self,
+        transport: asyncio.BaseTransport,
+        file: IO[bytes],
+        offset: int = ...,
+        count: Optional[int] = ...,
+        *,
+        fallback: bool = ...,
+    ) -> int: ...
+    async def sock_sendfile(
+        self,
+        sock: socket,
+        file: IO[bytes],
+        offset: int = ...,
+        count: Optional[int] = ...,
+        *,
+        fallback: bool = ...
+    ) -> int: ...
diff --git a/lib/python3.12/site-packages/uvloop/loop.pyx b/lib/python3.12/site-packages/uvloop/loop.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..f9a5a23916bb44122edb1320e6801dc3c55d91c4
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/loop.pyx
@@ -0,0 +1,3424 @@
+# cython: language_level=3, embedsignature=True
+
+import asyncio
+cimport cython
+
+from .includes.debug cimport UVLOOP_DEBUG
+from .includes cimport uv
+from .includes cimport system
+from .includes.python cimport (
+    PY_VERSION_HEX,
+    PyMem_RawMalloc, PyMem_RawFree,
+    PyMem_RawCalloc, PyMem_RawRealloc,
+    PyUnicode_EncodeFSDefault,
+    PyErr_SetInterrupt,
+    _Py_RestoreSignals,
+    Context_CopyCurrent,
+    Context_Enter,
+    Context_Exit,
+    PyMemoryView_FromMemory, PyBUF_WRITE,
+    PyMemoryView_FromObject, PyMemoryView_Check,
+    PyOS_AfterFork_Parent, PyOS_AfterFork_Child,
+    PyOS_BeforeFork,
+    PyUnicode_FromString
+)
+from .includes.flowcontrol cimport add_flowcontrol_defaults
+
+from libc.stdint cimport uint64_t
+from libc.string cimport memset, strerror, memcpy
+from libc cimport errno
+
+from cpython cimport PyObject
+from cpython cimport PyErr_CheckSignals, PyErr_Occurred
+from cpython cimport PyThread_get_thread_ident
+from cpython cimport Py_INCREF, Py_DECREF, Py_XDECREF, Py_XINCREF
+from cpython cimport (
+    PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE,
+    Py_buffer, PyBytes_AsString, PyBytes_CheckExact,
+    PyBytes_AsStringAndSize,
+    Py_SIZE, PyBytes_AS_STRING, PyBUF_WRITABLE
+)
+from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer
+
+from . import _noop
+
+
+include "includes/stdlib.pxi"
+
+include "errors.pyx"
+
+cdef:
+    int PY39 = PY_VERSION_HEX >= 0x03090000
+    int PY311 = PY_VERSION_HEX >= 0x030b0000
+    int PY313 = PY_VERSION_HEX >= 0x030d0000
+    uint64_t MAX_SLEEP = 3600 * 24 * 365 * 100
+
+
+cdef _is_sock_stream(sock_type):
+    if SOCK_NONBLOCK == -1:
+        return sock_type == uv.SOCK_STREAM
+    else:
+        # Linux's socket.type is a bitmask that can include extra info
+        # about socket (like SOCK_NONBLOCK bit), therefore we can't do simple
+        # `sock_type == socket.SOCK_STREAM`, see
+        # https://github.com/torvalds/linux/blob/v4.13/include/linux/net.h#L77
+        # for more details.
+        return (sock_type & 0xF) == uv.SOCK_STREAM
+
+
+cdef _is_sock_dgram(sock_type):
+    if SOCK_NONBLOCK == -1:
+        return sock_type == uv.SOCK_DGRAM
+    else:
+        # Read the comment in `_is_sock_stream`.
+        return (sock_type & 0xF) == uv.SOCK_DGRAM
+
+
+cdef isfuture(obj):
+    if aio_isfuture is None:
+        return isinstance(obj, aio_Future)
+    else:
+        return aio_isfuture(obj)
+
+
+cdef inline socket_inc_io_ref(sock):
+    if isinstance(sock, socket_socket):
+        sock._io_refs += 1
+
+
+cdef inline socket_dec_io_ref(sock):
+    if isinstance(sock, socket_socket):
+        sock._decref_socketios()
+
+
+cdef inline run_in_context(context, method):
+    # This method is internally used to workaround a reference issue that in
+    # certain circumstances, inlined context.run() will not hold a reference to
+    # the given method instance, which - if deallocated - will cause segfault.
+    # See also: edgedb/edgedb#2222
+    Py_INCREF(method)
+    try:
+        return context.run(method)
+    finally:
+        Py_DECREF(method)
+
+
+cdef inline run_in_context1(context, method, arg):
+    Py_INCREF(method)
+    try:
+        return context.run(method, arg)
+    finally:
+        Py_DECREF(method)
+
+
+cdef inline run_in_context2(context, method, arg1, arg2):
+    Py_INCREF(method)
+    try:
+        return context.run(method, arg1, arg2)
+    finally:
+        Py_DECREF(method)
+
+
+# Used for deprecation and removal of `loop.create_datagram_endpoint()`'s
+# *reuse_address* parameter
+_unset = object()
+
+
+@cython.no_gc_clear
+cdef class Loop:
+    def __cinit__(self):
+        cdef int err
+
+        # Install PyMem* memory allocators if they aren't installed yet.
+        __install_pymem()
+
+        # Install pthread_atfork handlers
+        __install_atfork()
+
+        self.uvloop = PyMem_RawMalloc(sizeof(uv.uv_loop_t))
+        if self.uvloop is NULL:
+            raise MemoryError()
+
+        self.slow_callback_duration = 0.1
+
+        self._closed = 0
+        self._debug = 0
+        self._thread_id = 0
+        self._running = 0
+        self._stopping = 0
+
+        self._transports = weakref_WeakValueDictionary()
+        self._processes = set()
+
+        # Used to keep a reference (and hence keep the fileobj alive)
+        # for as long as its registered by add_reader or add_writer.
+        # This is how the selector module and hence asyncio behaves.
+        self._fd_to_reader_fileobj = {}
+        self._fd_to_writer_fileobj = {}
+
+        self._unix_server_sockets = {}
+
+        self._timers = set()
+        self._polls = {}
+
+        self._recv_buffer_in_use = 0
+
+        err = uv.uv_loop_init(self.uvloop)
+        if err < 0:
+            raise convert_error(err)
+        self.uvloop.data =  self
+
+        self._init_debug_fields()
+
+        self.active_process_handler = None
+
+        self._last_error = None
+
+        self._task_factory = None
+        self._exception_handler = None
+        self._default_executor = None
+
+        self._queued_streams = set()
+        self._executing_streams = set()
+        self._ready = col_deque()
+        self._ready_len = 0
+
+        self.handler_async = UVAsync.new(
+            self, self._on_wake, self)
+
+        self.handler_idle = UVIdle.new(
+            self,
+            new_MethodHandle(
+                self, "loop._on_idle", self._on_idle, None, self))
+
+        # Needed to call `UVStream._exec_write` for writes scheduled
+        # during `Protocol.data_received`.
+        self.handler_check__exec_writes = UVCheck.new(
+            self,
+            new_MethodHandle(
+                self, "loop._exec_queued_writes",
+                self._exec_queued_writes, None, self))
+
+        self._signals = set()
+        self._ssock = self._csock = None
+        self._signal_handlers = {}
+        self._listening_signals = False
+        self._old_signal_wakeup_id = -1
+
+        self._coroutine_debug_set = False
+
+        # A weak set of all asynchronous generators that are
+        # being iterated by the loop.
+        self._asyncgens = weakref_WeakSet()
+
+        # Set to True when `loop.shutdown_asyncgens` is called.
+        self._asyncgens_shutdown_called = False
+        # Set to True when `loop.shutdown_default_executor` is called.
+        self._executor_shutdown_called = False
+
+        self._servers = set()
+
+    cdef inline _is_main_thread(self):
+        cdef uint64_t main_thread_id = system.MAIN_THREAD_ID
+        if system.MAIN_THREAD_ID_SET == 0:
+            main_thread_id = threading_main_thread().ident
+            system.setMainThreadID(main_thread_id)
+        return main_thread_id == PyThread_get_thread_ident()
+
+    def __init__(self):
+        self.set_debug(
+            sys_dev_mode or (not sys_ignore_environment
+                             and bool(os_environ.get('PYTHONASYNCIODEBUG'))))
+
+    def __dealloc__(self):
+        if self._running == 1:
+            raise RuntimeError('deallocating a running event loop!')
+        if self._closed == 0:
+            aio_logger.error("deallocating an open event loop")
+            return
+        PyMem_RawFree(self.uvloop)
+        self.uvloop = NULL
+
+    cdef _init_debug_fields(self):
+        self._debug_cc = bool(UVLOOP_DEBUG)
+
+        if UVLOOP_DEBUG:
+            self._debug_handles_current = col_Counter()
+            self._debug_handles_closed = col_Counter()
+            self._debug_handles_total = col_Counter()
+        else:
+            self._debug_handles_current = None
+            self._debug_handles_closed = None
+            self._debug_handles_total = None
+
+        self._debug_uv_handles_total = 0
+        self._debug_uv_handles_freed = 0
+
+        self._debug_stream_read_cb_total = 0
+        self._debug_stream_read_eof_total = 0
+        self._debug_stream_read_errors_total = 0
+        self._debug_stream_read_cb_errors_total = 0
+        self._debug_stream_read_eof_cb_errors_total = 0
+
+        self._debug_stream_shutdown_errors_total = 0
+        self._debug_stream_listen_errors_total = 0
+
+        self._debug_stream_write_tries = 0
+        self._debug_stream_write_errors_total = 0
+        self._debug_stream_write_ctx_total = 0
+        self._debug_stream_write_ctx_cnt = 0
+        self._debug_stream_write_cb_errors_total = 0
+
+        self._debug_cb_handles_total = 0
+        self._debug_cb_handles_count = 0
+
+        self._debug_cb_timer_handles_total = 0
+        self._debug_cb_timer_handles_count = 0
+
+        self._poll_read_events_total = 0
+        self._poll_read_cb_errors_total = 0
+        self._poll_write_events_total = 0
+        self._poll_write_cb_errors_total = 0
+
+        self._sock_try_write_total = 0
+
+        self._debug_exception_handler_cnt = 0
+
+    cdef _setup_or_resume_signals(self):
+        if not self._is_main_thread():
+            return
+
+        if self._listening_signals:
+            raise RuntimeError('signals handling has been already setup')
+
+        if self._ssock is not None:
+            raise RuntimeError('self-pipe exists before loop run')
+
+        # Create a self-pipe and call set_signal_wakeup_fd() with one
+        # of its ends.  This is needed so that libuv knows that it needs
+        # to wakeup on ^C (no matter if the SIGINT handler is still the
+        # standard Python's one or or user set their own.)
+
+        self._ssock, self._csock = socket_socketpair()
+        try:
+            self._ssock.setblocking(False)
+            self._csock.setblocking(False)
+
+            fileno = self._csock.fileno()
+
+            self._old_signal_wakeup_id = _set_signal_wakeup_fd(fileno)
+        except Exception:
+            # Out of all statements in the try block, only the
+            # "_set_signal_wakeup_fd()" call can fail, but it shouldn't,
+            # as we ensure that the current thread is the main thread.
+            # Still, if something goes horribly wrong we want to clean up
+            # the socket pair.
+            self._ssock.close()
+            self._csock.close()
+            self._ssock = None
+            self._csock = None
+            raise
+
+        self._add_reader(
+            self._ssock,
+            new_MethodHandle(
+                self,
+                "Loop._read_from_self",
+                self._read_from_self,
+                None,
+                self))
+
+        self._listening_signals = True
+
+    cdef _pause_signals(self):
+        if not self._is_main_thread():
+            if self._listening_signals:
+                raise RuntimeError(
+                    'cannot pause signals handling; no longer running in '
+                    'the main thread')
+            else:
+                return
+
+        if not self._listening_signals:
+            raise RuntimeError('signals handling has not been setup')
+
+        self._listening_signals = False
+
+        _set_signal_wakeup_fd(self._old_signal_wakeup_id)
+
+        self._remove_reader(self._ssock)
+        self._ssock.close()
+        self._csock.close()
+        self._ssock = None
+        self._csock = None
+
+    cdef _shutdown_signals(self):
+        if not self._is_main_thread():
+            if self._signal_handlers:
+                aio_logger.warning(
+                    'cannot cleanup signal handlers: closing the event loop '
+                    'in a non-main OS thread')
+            return
+
+        if self._listening_signals:
+            raise RuntimeError(
+                'cannot shutdown signals handling as it has not been paused')
+
+        if self._ssock:
+            raise RuntimeError(
+                'self-pipe was not cleaned up after loop was run')
+
+        for sig in list(self._signal_handlers):
+            self.remove_signal_handler(sig)
+
+    def __sighandler(self, signum, frame):
+        self._signals.add(signum)
+
+    cdef inline _ceval_process_signals(self):
+        # Invoke CPython eval loop to let process signals.
+        PyErr_CheckSignals()
+        # Calling a pure-Python function will invoke
+        # _PyEval_EvalFrameDefault which will process
+        # pending signal callbacks.
+        _noop.noop()  # Might raise ^C
+
+    cdef _read_from_self(self):
+        cdef bytes sigdata
+        sigdata = b''
+        while True:
+            try:
+                data = self._ssock.recv(65536)
+                if not data:
+                    break
+                sigdata += data
+            except InterruptedError:
+                continue
+            except BlockingIOError:
+                break
+        if sigdata:
+            self._invoke_signals(sigdata)
+
+    cdef _invoke_signals(self, bytes data):
+        cdef set sigs
+
+        self._ceval_process_signals()
+
+        sigs = self._signals.copy()
+        self._signals.clear()
+        for signum in data:
+            if not signum:
+                # ignore null bytes written by set_wakeup_fd()
+                continue
+            sigs.discard(signum)
+            self._handle_signal(signum)
+
+        for signum in sigs:
+            # Since not all signals are registered by add_signal_handler()
+            # (for instance, we use the default SIGINT handler) not all
+            # signals will trigger loop.__sighandler() callback.  Therefore
+            # we combine two datasources: one is self-pipe, one is data
+            # from __sighandler; this ensures that signals shouldn't be
+            # lost even if set_wakeup_fd() couldn't write to the self-pipe.
+            self._handle_signal(signum)
+
+    cdef _handle_signal(self, sig):
+        cdef Handle handle
+
+        try:
+            handle = (self._signal_handlers[sig])
+        except KeyError:
+            handle = None
+
+        if handle is None:
+            self._ceval_process_signals()
+            return
+
+        if handle._cancelled:
+            self.remove_signal_handler(sig)  # Remove it properly.
+        else:
+            self._append_ready_handle(handle)
+            self.handler_async.send()
+
+    cdef _on_wake(self):
+        if ((self._ready_len > 0 or self._stopping) and
+                not self.handler_idle.running):
+            self.handler_idle.start()
+
+    cdef _on_idle(self):
+        cdef:
+            int i, ntodo
+            object popleft = self._ready.popleft
+            Handle handler
+
+        ntodo = len(self._ready)
+        if self._debug:
+            for i from 0 <= i < ntodo:
+                handler =  popleft()
+                if handler._cancelled == 0:
+                    try:
+                        started = time_monotonic()
+                        handler._run()
+                    except BaseException as ex:
+                        self._stop(ex)
+                        return
+                    else:
+                        delta = time_monotonic() - started
+                        if delta > self.slow_callback_duration:
+                            aio_logger.warning(
+                                'Executing %s took %.3f seconds',
+                                handler._format_handle(), delta)
+
+        else:
+            for i from 0 <= i < ntodo:
+                handler =  popleft()
+                if handler._cancelled == 0:
+                    try:
+                        handler._run()
+                    except BaseException as ex:
+                        self._stop(ex)
+                        return
+
+        if len(self._queued_streams):
+            self._exec_queued_writes()
+
+        self._ready_len = len(self._ready)
+        if self._ready_len == 0 and self.handler_idle.running:
+            self.handler_idle.stop()
+
+        if self._stopping:
+            uv.uv_stop(self.uvloop)  # void
+
+    cdef _stop(self, exc):
+        if exc is not None:
+            self._last_error = exc
+        if self._stopping == 1:
+            return
+        self._stopping = 1
+        if not self.handler_idle.running:
+            self.handler_idle.start()
+
+    cdef __run(self, uv.uv_run_mode mode):
+        # Although every UVHandle holds a reference to the loop,
+        # we want to do everything to ensure that the loop will
+        # never deallocate during the run -- so we do some
+        # manual refs management.
+        Py_INCREF(self)
+        with nogil:
+            err = uv.uv_run(self.uvloop, mode)
+        Py_DECREF(self)
+
+        if err < 0:
+            raise convert_error(err)
+
+    cdef _run(self, uv.uv_run_mode mode):
+        cdef int err
+
+        if self._closed == 1:
+            raise RuntimeError('unable to start the loop; it was closed')
+
+        if self._running == 1:
+            raise RuntimeError('this event loop is already running.')
+
+        if (aio_get_running_loop is not None and
+                aio_get_running_loop() is not None):
+            raise RuntimeError(
+                'Cannot run the event loop while another loop is running')
+
+        # reset _last_error
+        self._last_error = None
+
+        self._thread_id = PyThread_get_thread_ident()
+        self._running = 1
+
+        self.handler_check__exec_writes.start()
+        self.handler_idle.start()
+
+        self._setup_or_resume_signals()
+
+        if aio_set_running_loop is not None:
+            aio_set_running_loop(self)
+        try:
+            self.__run(mode)
+        finally:
+            if aio_set_running_loop is not None:
+                aio_set_running_loop(None)
+
+            self.handler_check__exec_writes.stop()
+            self.handler_idle.stop()
+
+            self._pause_signals()
+
+            self._thread_id = 0
+            self._running = 0
+            self._stopping = 0
+
+        if self._last_error is not None:
+            # The loop was stopped with an error with 'loop._stop(error)' call
+            raise self._last_error
+
+    cdef _close(self):
+        cdef int err
+
+        if self._running == 1:
+            raise RuntimeError("Cannot close a running event loop")
+
+        if self._closed == 1:
+            return
+
+        self._closed = 1
+
+        for cb_handle in self._ready:
+            cb_handle.cancel()
+        self._ready.clear()
+        self._ready_len = 0
+
+        if self._polls:
+            for poll_handle in self._polls.values():
+                (poll_handle)._close()
+
+            self._polls.clear()
+
+        if self._timers:
+            for timer_cbhandle in tuple(self._timers):
+                timer_cbhandle.cancel()
+
+        # Close all remaining handles
+        self.handler_async._close()
+        self.handler_idle._close()
+        self.handler_check__exec_writes._close()
+        __close_all_handles(self)
+        self._shutdown_signals()
+        # During this run there should be no open handles,
+        # so it should finish right away
+        self.__run(uv.UV_RUN_DEFAULT)
+
+        if self._fd_to_writer_fileobj:
+            for fileobj in self._fd_to_writer_fileobj.values():
+                socket_dec_io_ref(fileobj)
+            self._fd_to_writer_fileobj.clear()
+
+        if self._fd_to_reader_fileobj:
+            for fileobj in self._fd_to_reader_fileobj.values():
+                socket_dec_io_ref(fileobj)
+            self._fd_to_reader_fileobj.clear()
+
+        if self._timers:
+            raise RuntimeError(
+                f"new timers were queued during loop closing: {self._timers}")
+
+        if self._polls:
+            raise RuntimeError(
+                f"new poll handles were queued during loop closing: "
+                f"{self._polls}")
+
+        if self._ready:
+            raise RuntimeError(
+                f"new callbacks were queued during loop closing: "
+                f"{self._ready}")
+
+        err = uv.uv_loop_close(self.uvloop)
+        if err < 0:
+            raise convert_error(err)
+
+        self.handler_async = None
+        self.handler_idle = None
+        self.handler_check__exec_writes = None
+
+        self._executor_shutdown_called = True
+        executor = self._default_executor
+        if executor is not None:
+            self._default_executor = None
+            executor.shutdown(wait=False)
+
+    cdef uint64_t _time(self):
+        # asyncio doesn't have a time cache, neither should uvloop.
+        uv.uv_update_time(self.uvloop)  # void
+        return uv.uv_now(self.uvloop)
+
+    cdef inline _queue_write(self, UVStream stream):
+        self._queued_streams.add(stream)
+        if not self.handler_check__exec_writes.running:
+            self.handler_check__exec_writes.start()
+
+    cdef _exec_queued_writes(self):
+        if len(self._queued_streams) == 0:
+            if self.handler_check__exec_writes.running:
+                self.handler_check__exec_writes.stop()
+            return
+
+        cdef:
+            UVStream stream
+
+        streams = self._queued_streams
+        self._queued_streams = self._executing_streams
+        self._executing_streams = streams
+        try:
+            for pystream in streams:
+                stream = pystream
+                stream._exec_write()
+        finally:
+            streams.clear()
+
+        if self.handler_check__exec_writes.running:
+            if len(self._queued_streams) == 0:
+                self.handler_check__exec_writes.stop()
+
+    cdef inline _call_soon(self, object callback, object args, object context):
+        cdef Handle handle
+        handle = new_Handle(self, callback, args, context)
+        self._call_soon_handle(handle)
+        return handle
+
+    cdef inline _append_ready_handle(self, Handle handle):
+        self._check_closed()
+        self._ready.append(handle)
+        self._ready_len += 1
+
+    cdef inline _call_soon_handle(self, Handle handle):
+        self._append_ready_handle(handle)
+        if not self.handler_idle.running:
+            self.handler_idle.start()
+
+    cdef _call_later(self, uint64_t delay, object callback, object args,
+                     object context):
+        return TimerHandle(self, callback, args, delay, context)
+
+    cdef void _handle_exception(self, object ex):
+        if isinstance(ex, Exception):
+            self.call_exception_handler({'exception': ex})
+        else:
+            # BaseException
+            self._last_error = ex
+            # Exit ASAP
+            self._stop(None)
+
+    cdef inline _check_signal(self, sig):
+        if not isinstance(sig, int):
+            raise TypeError('sig must be an int, not {!r}'.format(sig))
+
+        if not (1 <= sig < signal_NSIG):
+            raise ValueError(
+                'sig {} out of range(1, {})'.format(sig, signal_NSIG))
+
+    cdef inline _check_closed(self):
+        if self._closed == 1:
+            raise RuntimeError('Event loop is closed')
+
+    cdef inline _check_thread(self):
+        if self._thread_id == 0:
+            return
+
+        cdef uint64_t thread_id
+        thread_id = PyThread_get_thread_ident()
+
+        if thread_id != self._thread_id:
+            raise RuntimeError(
+                "Non-thread-safe operation invoked on an event loop other "
+                "than the current one")
+
+    cdef inline _new_future(self):
+        return aio_Future(loop=self)
+
+    cdef _track_transport(self, UVBaseTransport transport):
+        self._transports[transport._fileno()] = transport
+
+    cdef _track_process(self, UVProcess proc):
+        self._processes.add(proc)
+
+    cdef _untrack_process(self, UVProcess proc):
+        self._processes.discard(proc)
+
+    cdef _fileobj_to_fd(self, fileobj):
+        """Return a file descriptor from a file object.
+
+        Parameters:
+        fileobj -- file object or file descriptor
+
+        Returns:
+        corresponding file descriptor
+
+        Raises:
+        ValueError if the object is invalid
+        """
+        # Copy of the `selectors._fileobj_to_fd()` function.
+        if isinstance(fileobj, int):
+            fd = fileobj
+        else:
+            try:
+                fd = int(fileobj.fileno())
+            except (AttributeError, TypeError, ValueError):
+                raise ValueError("Invalid file object: "
+                                 "{!r}".format(fileobj)) from None
+        if fd < 0:
+            raise ValueError("Invalid file descriptor: {}".format(fd))
+        return fd
+
+    cdef _ensure_fd_no_transport(self, fd):
+        cdef UVBaseTransport tr
+        try:
+            tr = (self._transports[fd])
+        except KeyError:
+            pass
+        else:
+            if tr._is_alive():
+                raise RuntimeError(
+                    'File descriptor {!r} is used by transport {!r}'.format(
+                        fd, tr))
+
+    cdef _add_reader(self, fileobj, Handle handle):
+        cdef:
+            UVPoll poll
+
+        self._check_closed()
+        fd = self._fileobj_to_fd(fileobj)
+        self._ensure_fd_no_transport(fd)
+
+        try:
+            poll = (self._polls[fd])
+        except KeyError:
+            poll = UVPoll.new(self, fd)
+            self._polls[fd] = poll
+
+        poll.start_reading(handle)
+
+        old_fileobj = self._fd_to_reader_fileobj.pop(fd, None)
+        if old_fileobj is not None:
+            socket_dec_io_ref(old_fileobj)
+
+        self._fd_to_reader_fileobj[fd] = fileobj
+        socket_inc_io_ref(fileobj)
+
+    cdef _remove_reader(self, fileobj):
+        cdef:
+            UVPoll poll
+
+        fd = self._fileobj_to_fd(fileobj)
+        self._ensure_fd_no_transport(fd)
+
+        mapped_fileobj = self._fd_to_reader_fileobj.pop(fd, None)
+        if mapped_fileobj is not None:
+            socket_dec_io_ref(mapped_fileobj)
+
+        if self._closed == 1:
+            return False
+
+        try:
+            poll = (self._polls[fd])
+        except KeyError:
+            return False
+
+        result = poll.stop_reading()
+        if not poll.is_active():
+            del self._polls[fd]
+            poll._close()
+
+        return result
+
+    cdef _has_reader(self, fileobj):
+        cdef:
+            UVPoll poll
+
+        self._check_closed()
+        fd = self._fileobj_to_fd(fileobj)
+
+        try:
+            poll = (self._polls[fd])
+        except KeyError:
+            return False
+
+        return poll.is_reading()
+
+    cdef _add_writer(self, fileobj, Handle handle):
+        cdef:
+            UVPoll poll
+
+        self._check_closed()
+        fd = self._fileobj_to_fd(fileobj)
+        self._ensure_fd_no_transport(fd)
+
+        try:
+            poll = (self._polls[fd])
+        except KeyError:
+            poll = UVPoll.new(self, fd)
+            self._polls[fd] = poll
+
+        poll.start_writing(handle)
+
+        old_fileobj = self._fd_to_writer_fileobj.pop(fd, None)
+        if old_fileobj is not None:
+            socket_dec_io_ref(old_fileobj)
+
+        self._fd_to_writer_fileobj[fd] = fileobj
+        socket_inc_io_ref(fileobj)
+
+    cdef _remove_writer(self, fileobj):
+        cdef:
+            UVPoll poll
+
+        fd = self._fileobj_to_fd(fileobj)
+        self._ensure_fd_no_transport(fd)
+
+        mapped_fileobj = self._fd_to_writer_fileobj.pop(fd, None)
+        if mapped_fileobj is not None:
+            socket_dec_io_ref(mapped_fileobj)
+
+        if self._closed == 1:
+            return False
+
+        try:
+            poll = (self._polls[fd])
+        except KeyError:
+            return False
+
+        result = poll.stop_writing()
+        if not poll.is_active():
+            del self._polls[fd]
+            poll._close()
+
+        return result
+
+    cdef _has_writer(self, fileobj):
+        cdef:
+            UVPoll poll
+
+        self._check_closed()
+        fd = self._fileobj_to_fd(fileobj)
+
+        try:
+            poll = (self._polls[fd])
+        except KeyError:
+            return False
+
+        return poll.is_writing()
+
+    cdef _getaddrinfo(self, object host, object port,
+                      int family, int type,
+                      int proto, int flags,
+                      int unpack):
+
+        if isinstance(port, str):
+            port = port.encode()
+        elif isinstance(port, int):
+            port = str(port).encode()
+        if port is not None and not isinstance(port, bytes):
+            raise TypeError('port must be a str, bytes or int')
+
+        if isinstance(host, str):
+            host = host.encode('idna')
+        if host is not None:
+            if not isinstance(host, bytes):
+                raise TypeError('host must be a str or bytes')
+
+        fut = self._new_future()
+
+        def callback(result):
+            if AddrInfo.isinstance(result):
+                try:
+                    if unpack == 0:
+                        data = result
+                    else:
+                        data = (result).unpack()
+                except (KeyboardInterrupt, SystemExit):
+                    raise
+                except BaseException as ex:
+                    if not fut.cancelled():
+                        fut.set_exception(ex)
+                else:
+                    if not fut.cancelled():
+                        fut.set_result(data)
+            else:
+                if not fut.cancelled():
+                    fut.set_exception(result)
+
+        AddrInfoRequest(self, host, port, family, type, proto, flags, callback)
+        return fut
+
+    cdef _getnameinfo(self, system.sockaddr *addr, int flags):
+        cdef NameInfoRequest nr
+        fut = self._new_future()
+
+        def callback(result):
+            if isinstance(result, tuple):
+                fut.set_result(result)
+            else:
+                fut.set_exception(result)
+
+        nr = NameInfoRequest(self, callback)
+        nr.query(addr, flags)
+        return fut
+
+    cdef _sock_recv(self, fut, sock, n):
+        if UVLOOP_DEBUG:
+            if fut.cancelled():
+                # Shouldn't happen with _SyncSocketReaderFuture.
+                raise RuntimeError(
+                    f'_sock_recv is called on a cancelled Future')
+
+            if not self._has_reader(sock):
+                raise RuntimeError(
+                    f'socket {sock!r} does not have a reader '
+                    f'in the _sock_recv callback')
+
+        try:
+            data = sock.recv(n)
+        except (BlockingIOError, InterruptedError):
+            # No need to re-add the reader, let's just wait until
+            # the poll handler calls this callback again.
+            pass
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException as exc:
+            fut.set_exception(exc)
+            self._remove_reader(sock)
+        else:
+            fut.set_result(data)
+            self._remove_reader(sock)
+
+    cdef _sock_recv_into(self, fut, sock, buf):
+        if UVLOOP_DEBUG:
+            if fut.cancelled():
+                # Shouldn't happen with _SyncSocketReaderFuture.
+                raise RuntimeError(
+                    f'_sock_recv_into is called on a cancelled Future')
+
+            if not self._has_reader(sock):
+                raise RuntimeError(
+                    f'socket {sock!r} does not have a reader '
+                    f'in the _sock_recv_into callback')
+
+        try:
+            data = sock.recv_into(buf)
+        except (BlockingIOError, InterruptedError):
+            # No need to re-add the reader, let's just wait until
+            # the poll handler calls this callback again.
+            pass
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException as exc:
+            fut.set_exception(exc)
+            self._remove_reader(sock)
+        else:
+            fut.set_result(data)
+            self._remove_reader(sock)
+
+    cdef _sock_sendall(self, fut, sock, data):
+        cdef:
+            Handle handle
+            int n
+
+        if UVLOOP_DEBUG:
+            if fut.cancelled():
+                # Shouldn't happen with _SyncSocketWriterFuture.
+                raise RuntimeError(
+                    f'_sock_sendall is called on a cancelled Future')
+
+            if not self._has_writer(sock):
+                raise RuntimeError(
+                    f'socket {sock!r} does not have a writer '
+                    f'in the _sock_sendall callback')
+
+        try:
+            n = sock.send(data)
+        except (BlockingIOError, InterruptedError):
+            # Try next time.
+            return
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException as exc:
+            fut.set_exception(exc)
+            self._remove_writer(sock)
+            return
+
+        self._remove_writer(sock)
+
+        if n == len(data):
+            fut.set_result(None)
+        else:
+            if n:
+                if not isinstance(data, memoryview):
+                    data = memoryview(data)
+                data = data[n:]
+
+            handle = new_MethodHandle3(
+                self,
+                "Loop._sock_sendall",
+                self._sock_sendall,
+                None,
+                self,
+                fut, sock, data)
+
+            self._add_writer(sock, handle)
+
+    cdef _sock_accept(self, fut, sock):
+        try:
+            conn, address = sock.accept()
+            conn.setblocking(False)
+        except (BlockingIOError, InterruptedError):
+            # There is an active reader for _sock_accept, so
+            # do nothing, it will be called again.
+            pass
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException as exc:
+            fut.set_exception(exc)
+            self._remove_reader(sock)
+        else:
+            fut.set_result((conn, address))
+            self._remove_reader(sock)
+
+    cdef _sock_connect(self, sock, address):
+        cdef:
+            Handle handle
+
+        try:
+            sock.connect(address)
+        except (BlockingIOError, InterruptedError):
+            pass
+        else:
+            return
+
+        fut = _SyncSocketWriterFuture(sock, self)
+        handle = new_MethodHandle3(
+            self,
+            "Loop._sock_connect",
+            self._sock_connect_cb,
+            None,
+            self,
+            fut, sock, address)
+
+        self._add_writer(sock, handle)
+        return fut
+
+    cdef _sock_connect_cb(self, fut, sock, address):
+        if UVLOOP_DEBUG:
+            if fut.cancelled():
+                # Shouldn't happen with _SyncSocketWriterFuture.
+                raise RuntimeError(
+                    f'_sock_connect_cb is called on a cancelled Future')
+
+            if not self._has_writer(sock):
+                raise RuntimeError(
+                    f'socket {sock!r} does not have a writer '
+                    f'in the _sock_connect_cb callback')
+
+        try:
+            err = sock.getsockopt(uv.SOL_SOCKET, uv.SO_ERROR)
+            if err != 0:
+                # Jump to any except clause below.
+                raise OSError(err, 'Connect call failed %s' % (address,))
+        except (BlockingIOError, InterruptedError):
+            # socket is still registered, the callback will be retried later
+            pass
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException as exc:
+            fut.set_exception(exc)
+            self._remove_writer(sock)
+        else:
+            fut.set_result(None)
+            self._remove_writer(sock)
+
+    cdef _sock_set_reuseport(self, int fd):
+        cdef:
+            int err = 0
+            int reuseport_flag = 1
+
+        err = system.setsockopt(
+            fd,
+            uv.SOL_SOCKET,
+            SO_REUSEPORT,
+            &reuseport_flag,
+            sizeof(reuseport_flag))
+
+        if err < 0:
+            raise convert_error(-errno.errno)
+
+    cdef _set_coroutine_debug(self, bint enabled):
+        enabled = bool(enabled)
+        if self._coroutine_debug_set == enabled:
+            return
+
+        if enabled:
+            self._coroutine_origin_tracking_saved_depth = (
+                sys.get_coroutine_origin_tracking_depth())
+            sys.set_coroutine_origin_tracking_depth(
+                DEBUG_STACK_DEPTH)
+        else:
+            sys.set_coroutine_origin_tracking_depth(
+                self._coroutine_origin_tracking_saved_depth)
+
+        self._coroutine_debug_set = enabled
+
+    def _get_backend_id(self):
+        """This method is used by uvloop tests and is not part of the API."""
+        return uv.uv_backend_fd(self.uvloop)
+
+    cdef _print_debug_info(self):
+        cdef:
+            int err
+            uv.uv_rusage_t rusage
+
+        err = uv.uv_getrusage(&rusage)
+        if err < 0:
+            raise convert_error(err)
+
+        # OS
+
+        print('---- Process info: -----')
+        print('Process memory:            {}'.format(rusage.ru_maxrss))
+        print('Number of signals:         {}'.format(rusage.ru_nsignals))
+        print('')
+
+        # Loop
+
+        print('--- Loop debug info: ---')
+        print('Loop time:                 {}'.format(self.time()))
+        print('Errors logged:             {}'.format(
+            self._debug_exception_handler_cnt))
+        print()
+        print('Callback handles:          {: <8} | {}'.format(
+            self._debug_cb_handles_count,
+            self._debug_cb_handles_total))
+        print('Timer handles:             {: <8} | {}'.format(
+            self._debug_cb_timer_handles_count,
+            self._debug_cb_timer_handles_total))
+        print()
+
+        print('                        alive  | closed  |')
+        print('UVHandles               python | libuv   | total')
+        print('                        objs   | handles |')
+        print('-------------------------------+---------+---------')
+        for name in sorted(self._debug_handles_total):
+            print('    {: <18} {: >7} | {: >7} | {: >7}'.format(
+                name,
+                self._debug_handles_current[name],
+                self._debug_handles_closed[name],
+                self._debug_handles_total[name]))
+        print()
+
+        print('uv_handle_t (current: {}; freed: {}; total: {})'.format(
+            self._debug_uv_handles_total - self._debug_uv_handles_freed,
+            self._debug_uv_handles_freed,
+            self._debug_uv_handles_total))
+        print()
+
+        print('--- Streams debug info: ---')
+        print('Write errors:              {}'.format(
+            self._debug_stream_write_errors_total))
+        print('Write without poll:        {}'.format(
+            self._debug_stream_write_tries))
+        print('Write contexts:            {: <8} | {}'.format(
+            self._debug_stream_write_ctx_cnt,
+            self._debug_stream_write_ctx_total))
+        print('Write failed callbacks:    {}'.format(
+            self._debug_stream_write_cb_errors_total))
+        print()
+        print('Read errors:               {}'.format(
+            self._debug_stream_read_errors_total))
+        print('Read callbacks:            {}'.format(
+            self._debug_stream_read_cb_total))
+        print('Read failed callbacks:     {}'.format(
+            self._debug_stream_read_cb_errors_total))
+        print('Read EOFs:                 {}'.format(
+            self._debug_stream_read_eof_total))
+        print('Read EOF failed callbacks: {}'.format(
+            self._debug_stream_read_eof_cb_errors_total))
+        print()
+        print('Listen errors:             {}'.format(
+            self._debug_stream_listen_errors_total))
+        print('Shutdown errors            {}'.format(
+            self._debug_stream_shutdown_errors_total))
+        print()
+
+        print('--- Polls debug info: ---')
+        print('Read events:               {}'.format(
+            self._poll_read_events_total))
+        print('Read callbacks failed:     {}'.format(
+            self._poll_read_cb_errors_total))
+        print('Write events:              {}'.format(
+            self._poll_write_events_total))
+        print('Write callbacks failed:    {}'.format(
+            self._poll_write_cb_errors_total))
+        print()
+
+        print('--- Sock ops successful on 1st try: ---')
+        print('Socket try-writes:         {}'.format(
+            self._sock_try_write_total))
+
+        print(flush=True)
+
+    property print_debug_info:
+        def __get__(self):
+            if UVLOOP_DEBUG:
+                return lambda: self._print_debug_info()
+            else:
+                raise AttributeError('print_debug_info')
+
+    # Public API
+
+    def __repr__(self):
+        return '<{}.{} running={} closed={} debug={}>'.format(
+            self.__class__.__module__,
+            self.__class__.__name__,
+            self.is_running(),
+            self.is_closed(),
+            self.get_debug()
+        )
+
+    def call_soon(self, callback, *args, context=None):
+        """Arrange for a callback to be called as soon as possible.
+
+        This operates as a FIFO queue: callbacks are called in the
+        order in which they are registered.  Each callback will be
+        called exactly once.
+
+        Any positional arguments after the callback will be passed to
+        the callback when it is called.
+        """
+        if self._debug == 1:
+            self._check_thread()
+        if args:
+            return self._call_soon(callback, args, context)
+        else:
+            return self._call_soon(callback, None, context)
+
+    def call_soon_threadsafe(self, callback, *args, context=None):
+        """Like call_soon(), but thread-safe."""
+        if not args:
+            args = None
+        cdef Handle handle = new_Handle(self, callback, args, context)
+        self._append_ready_handle(handle)  # deque append is atomic
+        # libuv async handler is thread-safe while the idle handler is not -
+        # we only set the async handler here, which will start the idle handler
+        # in _on_wake() from the loop and eventually call the callback.
+        self.handler_async.send()
+        return handle
+
+    def call_later(self, delay, callback, *args, context=None):
+        """Arrange for a callback to be called at a given time.
+
+        Return a Handle: an opaque object with a cancel() method that
+        can be used to cancel the call.
+
+        The delay can be an int or float, expressed in seconds.  It is
+        always relative to the current time.
+
+        Each callback will be called exactly once.  If two callbacks
+        are scheduled for exactly the same time, it undefined which
+        will be called first.
+
+        Any positional arguments after the callback will be passed to
+        the callback when it is called.
+        """
+        cdef uint64_t when
+
+        self._check_closed()
+        if self._debug == 1:
+            self._check_thread()
+
+        if delay < 0:
+            delay = 0
+        elif delay == py_inf or delay > MAX_SLEEP:
+            # ~100 years sounds like a good approximation of
+            # infinity for a Python application.
+            delay = MAX_SLEEP
+
+        when = round(delay * 1000)
+        if not args:
+            args = None
+        if when == 0:
+            return self._call_soon(callback, args, context)
+        else:
+            return self._call_later(when, callback, args, context)
+
+    def call_at(self, when, callback, *args, context=None):
+        """Like call_later(), but uses an absolute time.
+
+        Absolute time corresponds to the event loop's time() method.
+        """
+        return self.call_later(
+            when - self.time(), callback, *args, context=context)
+
+    def time(self):
+        """Return the time according to the event loop's clock.
+
+        This is a float expressed in seconds since an epoch, but the
+        epoch, precision, accuracy and drift are unspecified and may
+        differ per event loop.
+        """
+        return self._time() / 1000
+
+    def stop(self):
+        """Stop running the event loop.
+
+        Every callback already scheduled will still run.  This simply informs
+        run_forever to stop looping after a complete iteration.
+        """
+        self._call_soon_handle(
+            new_MethodHandle1(
+                self,
+                "Loop._stop",
+                self._stop,
+                None,
+                self,
+                None))
+
+    def run_forever(self):
+        """Run the event loop until stop() is called."""
+        self._check_closed()
+        mode = uv.UV_RUN_DEFAULT
+        if self._stopping:
+            # loop.stop() was called right before loop.run_forever().
+            # This is how asyncio loop behaves.
+            mode = uv.UV_RUN_NOWAIT
+        self._set_coroutine_debug(self._debug)
+        old_agen_hooks = sys.get_asyncgen_hooks()
+        sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook,
+                               finalizer=self._asyncgen_finalizer_hook)
+        try:
+            self._run(mode)
+        finally:
+            self._set_coroutine_debug(False)
+            sys.set_asyncgen_hooks(*old_agen_hooks)
+
+    def close(self):
+        """Close the event loop.
+
+        The event loop must not be running.
+
+        This is idempotent and irreversible.
+
+        No other methods should be called after this one.
+        """
+        self._close()
+
+    def get_debug(self):
+        return bool(self._debug)
+
+    def set_debug(self, enabled):
+        self._debug = bool(enabled)
+        if self.is_running():
+             self.call_soon_threadsafe(self._set_coroutine_debug, self._debug)
+
+    def is_running(self):
+        """Return whether the event loop is currently running."""
+        return bool(self._running)
+
+    def is_closed(self):
+        """Returns True if the event loop was closed."""
+        return bool(self._closed)
+
+    def create_future(self):
+        """Create a Future object attached to the loop."""
+        return self._new_future()
+
+    def create_task(self, coro, *, name=None, context=None):
+        """Schedule a coroutine object.
+
+        Return a task object.
+
+        If name is not None, task.set_name(name) will be called if the task
+        object has the set_name attribute, true for default Task in CPython.
+
+        An optional keyword-only context argument allows specifying a custom
+        contextvars.Context for the coro to run in. The current context copy is
+        created when no context is provided.
+        """
+        self._check_closed()
+        if PY311:
+            if self._task_factory is None:
+                task = aio_Task(coro, loop=self, context=context)
+            else:
+                task = self._task_factory(self, coro, context=context)
+        else:
+            if context is None:
+                if self._task_factory is None:
+                    task = aio_Task(coro, loop=self)
+                else:
+                    task = self._task_factory(self, coro)
+            else:
+                if self._task_factory is None:
+                    task = context.run(aio_Task, coro, self)
+                else:
+                    task = context.run(self._task_factory, self, coro)
+
+        # copied from asyncio.tasks._set_task_name (bpo-34270)
+        if name is not None:
+            try:
+                set_name = task.set_name
+            except AttributeError:
+                pass
+            else:
+                set_name(name)
+
+        return task
+
+    def set_task_factory(self, factory):
+        """Set a task factory that will be used by loop.create_task().
+
+        If factory is None the default task factory will be set.
+
+        If factory is a callable, it should have a signature matching
+        '(loop, coro)', where 'loop' will be a reference to the active
+        event loop, 'coro' will be a coroutine object.  The callable
+        must return a Future.
+        """
+        if factory is not None and not callable(factory):
+            raise TypeError('task factory must be a callable or None')
+        self._task_factory = factory
+
+    def get_task_factory(self):
+        """Return a task factory, or None if the default one is in use."""
+        return self._task_factory
+
+    def run_until_complete(self, future):
+        """Run until the Future is done.
+
+        If the argument is a coroutine, it is wrapped in a Task.
+
+        WARNING: It would be disastrous to call run_until_complete()
+        with the same coroutine twice -- it would wrap it in two
+        different Tasks and that can't be good.
+
+        Return the Future's result, or raise its exception.
+        """
+        self._check_closed()
+
+        new_task = not isfuture(future)
+        future = aio_ensure_future(future, loop=self)
+        if new_task:
+            # An exception is raised if the future didn't complete, so there
+            # is no need to log the "destroy pending task" message
+            future._log_destroy_pending = False
+
+        def done_cb(fut):
+            if not fut.cancelled():
+                exc = fut.exception()
+                if isinstance(exc, (SystemExit, KeyboardInterrupt)):
+                    # Issue #336: run_forever() already finished,
+                    # no need to stop it.
+                    return
+            self.stop()
+
+        future.add_done_callback(done_cb)
+        try:
+            self.run_forever()
+        except BaseException:
+            if new_task and future.done() and not future.cancelled():
+                # The coroutine raised a BaseException. Consume the exception
+                # to not log a warning, the caller doesn't have access to the
+                # local task.
+                future.exception()
+            raise
+        finally:
+            future.remove_done_callback(done_cb)
+        if not future.done():
+            raise RuntimeError('Event loop stopped before Future completed.')
+
+        return future.result()
+
+    @cython.iterable_coroutine
+    async def getaddrinfo(self, object host, object port, *,
+                          int family=0, int type=0, int proto=0, int flags=0):
+
+        addr = __static_getaddrinfo_pyaddr(host, port, family,
+                                           type, proto, flags)
+        if addr is not None:
+            return [addr]
+
+        return await self._getaddrinfo(
+            host, port, family, type, proto, flags, 1)
+
+    @cython.iterable_coroutine
+    async def getnameinfo(self, sockaddr, int flags=0):
+        cdef:
+            AddrInfo ai_cnt
+            system.addrinfo *ai
+            system.sockaddr_in6 *sin6
+
+        if not isinstance(sockaddr, tuple):
+            raise TypeError('getnameinfo() argument 1 must be a tuple')
+
+        sl = len(sockaddr)
+
+        if sl < 2 or sl > 4:
+            raise ValueError('sockaddr must be a tuple of 2, 3 or 4 values')
+
+        if sl > 2:
+            flowinfo = sockaddr[2]
+            if flowinfo < 0 or flowinfo > 0xfffff:
+                raise OverflowError(
+                    'getnameinfo(): flowinfo must be 0-1048575.')
+        else:
+            flowinfo = 0
+
+        if sl > 3:
+            scope_id = sockaddr[3]
+            if scope_id < 0 or scope_id > 2 ** 32:
+                raise OverflowError(
+                    'getsockaddrarg: scope_id must be unsigned 32 bit integer')
+        else:
+            scope_id = 0
+
+        ai_cnt = await self._getaddrinfo(
+            sockaddr[0], sockaddr[1],
+            uv.AF_UNSPEC,         # family
+            uv.SOCK_DGRAM,        # type
+            0,                    # proto
+            uv.AI_NUMERICHOST,    # flags
+            0)                    # unpack
+
+        ai = ai_cnt.data
+
+        if ai.ai_next:
+            raise OSError("sockaddr resolved to multiple addresses")
+
+        if ai.ai_family == uv.AF_INET:
+            if sl > 2:
+                raise OSError("IPv4 sockaddr must be 2 tuple")
+        elif ai.ai_family == uv.AF_INET6:
+            # Modify some fields in `ai`
+            sin6 =  ai.ai_addr
+            sin6.sin6_flowinfo = system.htonl(flowinfo)
+            sin6.sin6_scope_id = scope_id
+
+        return await self._getnameinfo(ai.ai_addr, flags)
+
+    @cython.iterable_coroutine
+    async def start_tls(self, transport, protocol, sslcontext, *,
+                        server_side=False,
+                        server_hostname=None,
+                        ssl_handshake_timeout=None,
+                        ssl_shutdown_timeout=None):
+        """Upgrade transport to TLS.
+
+        Return a new transport that *protocol* should start using
+        immediately.
+        """
+        if not isinstance(sslcontext, ssl_SSLContext):
+            raise TypeError(
+                f'sslcontext is expected to be an instance of ssl.SSLContext, '
+                f'got {sslcontext!r}')
+
+        if isinstance(transport, (TCPTransport, UnixTransport)):
+            context = (transport).context
+        elif isinstance(transport, _SSLProtocolTransport):
+            context = (<_SSLProtocolTransport>transport).context
+        else:
+            raise TypeError(
+                f'transport {transport!r} is not supported by start_tls()')
+
+        waiter = self._new_future()
+        ssl_protocol = SSLProtocol(
+            self, protocol, sslcontext, waiter,
+            server_side, server_hostname,
+            ssl_handshake_timeout=ssl_handshake_timeout,
+            ssl_shutdown_timeout=ssl_shutdown_timeout,
+            call_connection_made=False)
+
+        # Pause early so that "ssl_protocol.data_received()" doesn't
+        # have a chance to get called before "ssl_protocol.connection_made()".
+        transport.pause_reading()
+
+        transport.set_protocol(ssl_protocol)
+        conmade_cb = self.call_soon(ssl_protocol.connection_made, transport,
+                                    context=context)
+        # transport.resume_reading() will use the right context
+        # (transport.context) to call e.g. data_received()
+        resume_cb = self.call_soon(transport.resume_reading)
+        app_transport = ssl_protocol._get_app_transport(context)
+
+        try:
+            await waiter
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException:
+            app_transport.close()
+            conmade_cb.cancel()
+            resume_cb.cancel()
+            raise
+
+        return app_transport
+
+    @cython.iterable_coroutine
+    async def create_server(self, protocol_factory, host=None, port=None,
+                            *,
+                            int family=uv.AF_UNSPEC,
+                            int flags=uv.AI_PASSIVE,
+                            sock=None,
+                            backlog=100,
+                            ssl=None,
+                            reuse_address=None,
+                            reuse_port=None,
+                            ssl_handshake_timeout=None,
+                            ssl_shutdown_timeout=None,
+                            start_serving=True):
+        """A coroutine which creates a TCP server bound to host and port.
+
+        The return value is a Server object which can be used to stop
+        the service.
+
+        If host is an empty string or None all interfaces are assumed
+        and a list of multiple sockets will be returned (most likely
+        one for IPv4 and another one for IPv6). The host parameter can also be
+        a sequence (e.g. list) of hosts to bind to.
+
+        family can be set to either AF_INET or AF_INET6 to force the
+        socket to use IPv4 or IPv6. If not set it will be determined
+        from host (defaults to AF_UNSPEC).
+
+        flags is a bitmask for getaddrinfo().
+
+        sock can optionally be specified in order to use a preexisting
+        socket object.
+
+        backlog is the maximum number of queued connections passed to
+        listen() (defaults to 100).
+
+        ssl can be set to an SSLContext to enable SSL over the
+        accepted connections.
+
+        reuse_address tells the kernel to reuse a local socket in
+        TIME_WAIT state, without waiting for its natural timeout to
+        expire. If not specified will automatically be set to True on
+        UNIX.
+
+        reuse_port tells the kernel to allow this endpoint to be bound to
+        the same port as other existing endpoints are bound to, so long as
+        they all set this flag when being created. This option is not
+        supported on Windows.
+
+        ssl_handshake_timeout is the time in seconds that an SSL server
+        will wait for completion of the SSL handshake before aborting the
+        connection. Default is 60s.
+
+        ssl_shutdown_timeout is the time in seconds that an SSL server
+        will wait for completion of the SSL shutdown before aborting the
+        connection. Default is 30s.
+        """
+        cdef:
+            TCPServer tcp
+            system.addrinfo *addrinfo
+            Server server
+
+        if sock is not None and sock.family == uv.AF_UNIX:
+            if host is not None or port is not None:
+                raise ValueError(
+                    'host/port and sock can not be specified at the same time')
+            return await self.create_unix_server(
+                protocol_factory, sock=sock, backlog=backlog, ssl=ssl,
+                start_serving=start_serving,
+                # asyncio won't clean up socket file using create_server() API
+                cleanup_socket=False,
+            )
+
+        server = Server(self)
+
+        if ssl is not None:
+            if not isinstance(ssl, ssl_SSLContext):
+                raise TypeError('ssl argument must be an SSLContext or None')
+        else:
+            if ssl_handshake_timeout is not None:
+                raise ValueError(
+                    'ssl_handshake_timeout is only meaningful with ssl')
+            if ssl_shutdown_timeout is not None:
+                raise ValueError(
+                    'ssl_shutdown_timeout is only meaningful with ssl')
+
+        if host is not None or port is not None:
+            if sock is not None:
+                raise ValueError(
+                    'host/port and sock can not be specified at the same time')
+
+            if reuse_address is None:
+                reuse_address = os_name == 'posix' and sys_platform != 'cygwin'
+            reuse_port = bool(reuse_port)
+            if reuse_port and not has_SO_REUSEPORT:
+                raise ValueError(
+                    'reuse_port not supported by socket module')
+
+            if host == '':
+                hosts = [None]
+            elif (isinstance(host, str) or not isinstance(host, col_Iterable)):
+                hosts = [host]
+            else:
+                hosts = host
+
+            fs = [self._getaddrinfo(host, port, family,
+                                    uv.SOCK_STREAM, 0, flags,
+                                    0) for host in hosts]
+
+            infos = await aio_gather(*fs)
+
+            completed = False
+            sock = None
+            try:
+                for info in infos:
+                    addrinfo = (info).data
+                    while addrinfo != NULL:
+                        if addrinfo.ai_family == uv.AF_UNSPEC:
+                            raise RuntimeError('AF_UNSPEC in DNS results')
+
+                        try:
+                            sock = socket_socket(addrinfo.ai_family,
+                                                 addrinfo.ai_socktype,
+                                                 addrinfo.ai_protocol)
+                        except socket_error:
+                            # Assume it's a bad family/type/protocol
+                            # combination.
+                            if self._debug:
+                                aio_logger.warning(
+                                    'create_server() failed to create '
+                                    'socket.socket(%r, %r, %r)',
+                                    addrinfo.ai_family,
+                                    addrinfo.ai_socktype,
+                                    addrinfo.ai_protocol, exc_info=True)
+                            addrinfo = addrinfo.ai_next
+                            continue
+
+                        if reuse_address:
+                            sock.setsockopt(uv.SOL_SOCKET, uv.SO_REUSEADDR, 1)
+                        if reuse_port:
+                            sock.setsockopt(uv.SOL_SOCKET, SO_REUSEPORT, 1)
+                        # Disable IPv4/IPv6 dual stack support (enabled by
+                        # default on Linux) which makes a single socket
+                        # listen on both address families.
+                        if (addrinfo.ai_family == uv.AF_INET6 and
+                                has_IPV6_V6ONLY):
+                            sock.setsockopt(uv.IPPROTO_IPV6, IPV6_V6ONLY, 1)
+
+                        pyaddr = __convert_sockaddr_to_pyaddr(addrinfo.ai_addr)
+                        try:
+                            sock.bind(pyaddr)
+                        except OSError as err:
+                            raise OSError(
+                                err.errno, 'error while attempting '
+                                'to bind on address %r: %s'
+                                % (pyaddr, err.strerror.lower())) from None
+
+                        tcp = TCPServer.new(self, protocol_factory, server,
+                                            uv.AF_UNSPEC, backlog,
+                                            ssl, ssl_handshake_timeout,
+                                            ssl_shutdown_timeout)
+
+                        try:
+                            tcp._open(sock.fileno())
+                        except (KeyboardInterrupt, SystemExit):
+                            raise
+                        except BaseException:
+                            tcp._close()
+                            raise
+
+                        server._add_server(tcp)
+                        sock.detach()
+                        sock = None
+
+                        addrinfo = addrinfo.ai_next
+
+                completed = True
+            finally:
+                if not completed:
+                    if sock is not None:
+                        sock.close()
+                    server.close()
+        else:
+            if sock is None:
+                raise ValueError('Neither host/port nor sock were specified')
+            if not _is_sock_stream(sock.type):
+                raise ValueError(
+                    'A Stream Socket was expected, got {!r}'.format(sock))
+
+            # libuv will set the socket to non-blocking mode, but
+            # we want Python socket object to notice that.
+            sock.setblocking(False)
+
+            tcp = TCPServer.new(self, protocol_factory, server,
+                                uv.AF_UNSPEC, backlog,
+                                ssl, ssl_handshake_timeout,
+                                ssl_shutdown_timeout)
+
+            try:
+                tcp._open(sock.fileno())
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                tcp._close()
+                raise
+
+            tcp._attach_fileobj(sock)
+            server._add_server(tcp)
+
+        if start_serving:
+            server._start_serving()
+
+        server._ref()
+        return server
+
+    @cython.iterable_coroutine
+    async def create_connection(self, protocol_factory, host=None, port=None,
+                                *,
+                                ssl=None,
+                                family=0, proto=0, flags=0, sock=None,
+                                local_addr=None, server_hostname=None,
+                                ssl_handshake_timeout=None,
+                                ssl_shutdown_timeout=None):
+        """Connect to a TCP server.
+
+        Create a streaming transport connection to a given Internet host and
+        port: socket family AF_INET or socket.AF_INET6 depending on host (or
+        family if specified), socket type SOCK_STREAM. protocol_factory must be
+        a callable returning a protocol instance.
+
+        This method is a coroutine which will try to establish the connection
+        in the background.  When successful, the coroutine returns a
+        (transport, protocol) pair.
+        """
+        cdef:
+            AddrInfo ai_local = None
+            AddrInfo ai_remote
+            TCPTransport tr
+
+            system.addrinfo *rai = NULL
+            system.addrinfo *lai = NULL
+
+            system.addrinfo *rai_iter = NULL
+            system.addrinfo *lai_iter = NULL
+
+            system.addrinfo rai_static
+            system.sockaddr_storage rai_addr_static
+            system.addrinfo lai_static
+            system.sockaddr_storage lai_addr_static
+
+            object app_protocol
+            object app_transport
+            object protocol
+            object ssl_waiter
+
+        if sock is not None and sock.family == uv.AF_UNIX:
+            if host is not None or port is not None:
+                raise ValueError(
+                    'host/port and sock can not be specified at the same time')
+            return await self.create_unix_connection(
+                protocol_factory, None,
+                sock=sock, ssl=ssl, server_hostname=server_hostname)
+
+        app_protocol = protocol = protocol_factory()
+        ssl_waiter = None
+        context = Context_CopyCurrent()
+        if ssl:
+            if server_hostname is None:
+                if not host:
+                    raise ValueError('You must set server_hostname '
+                                     'when using ssl without a host')
+                server_hostname = host
+
+            ssl_waiter = self._new_future()
+            sslcontext = None if isinstance(ssl, bool) else ssl
+            protocol = SSLProtocol(
+                self, app_protocol, sslcontext, ssl_waiter,
+                False, server_hostname,
+                ssl_handshake_timeout=ssl_handshake_timeout,
+                ssl_shutdown_timeout=ssl_shutdown_timeout)
+        else:
+            if server_hostname is not None:
+                raise ValueError('server_hostname is only meaningful with ssl')
+            if ssl_handshake_timeout is not None:
+                raise ValueError(
+                    'ssl_handshake_timeout is only meaningful with ssl')
+            if ssl_shutdown_timeout is not None:
+                raise ValueError(
+                    'ssl_shutdown_timeout is only meaningful with ssl')
+
+        if host is not None or port is not None:
+            if sock is not None:
+                raise ValueError(
+                    'host/port and sock can not be specified at the same time')
+
+            fs = []
+            f1 = f2 = None
+
+            addr = __static_getaddrinfo(
+                host, port, family, uv.SOCK_STREAM,
+                proto, &rai_addr_static)
+
+            if addr is None:
+                f1 = self._getaddrinfo(
+                    host, port, family,
+                    uv.SOCK_STREAM, proto, flags,
+                    0)  # 0 == don't unpack
+
+                fs.append(f1)
+            else:
+                rai_static.ai_addr = &rai_addr_static
+                rai_static.ai_next = NULL
+                rai = &rai_static
+
+            if local_addr is not None:
+                if not isinstance(local_addr, (tuple, list)) or \
+                        len(local_addr) != 2:
+                    raise ValueError(
+                        'local_addr must be a tuple of host and port')
+
+                addr = __static_getaddrinfo(
+                    local_addr[0], local_addr[1],
+                    family, uv.SOCK_STREAM,
+                    proto, &lai_addr_static)
+                if addr is None:
+                    f2 = self._getaddrinfo(
+                        local_addr[0], local_addr[1], family,
+                        uv.SOCK_STREAM, proto, flags,
+                        0)  # 0 == don't unpack
+
+                    fs.append(f2)
+                else:
+                    lai_static.ai_addr = &lai_addr_static
+                    lai_static.ai_next = NULL
+                    lai = &lai_static
+
+            if len(fs):
+                await aio_wait(fs)
+
+            if rai is NULL:
+                ai_remote = f1.result()
+                if ai_remote.data is NULL:
+                    raise OSError('getaddrinfo() returned empty list')
+                rai = ai_remote.data
+
+            if lai is NULL and f2 is not None:
+                ai_local = f2.result()
+                if ai_local.data is NULL:
+                    raise OSError(
+                        'getaddrinfo() returned empty list for local_addr')
+                lai = ai_local.data
+
+            exceptions = []
+            rai_iter = rai
+            while rai_iter is not NULL:
+                tr = None
+                try:
+                    waiter = self._new_future()
+                    tr = TCPTransport.new(self, protocol, None, waiter,
+                                          context)
+
+                    if lai is not NULL:
+                        lai_iter = lai
+                        while lai_iter is not NULL:
+                            try:
+                                tr.bind(lai_iter.ai_addr)
+                                break
+                            except OSError as exc:
+                                exceptions.append(exc)
+                            lai_iter = lai_iter.ai_next
+                        else:
+                            tr._close()
+                            tr = None
+
+                            rai_iter = rai_iter.ai_next
+                            continue
+
+                    tr.connect(rai_iter.ai_addr)
+                    await waiter
+
+                except OSError as exc:
+                    if tr is not None:
+                        tr._close()
+                        tr = None
+                    exceptions.append(exc)
+                except (KeyboardInterrupt, SystemExit):
+                    raise
+                except BaseException:
+                    if tr is not None:
+                        tr._close()
+                        tr = None
+                    raise
+                else:
+                    break
+
+                rai_iter = rai_iter.ai_next
+
+            else:
+                # If they all have the same str(), raise one.
+                model = str(exceptions[0])
+                if all(str(exc) == model for exc in exceptions):
+                    raise exceptions[0]
+                # Raise a combined exception so the user can see all
+                # the various error messages.
+                raise OSError('Multiple exceptions: {}'.format(
+                    ', '.join(str(exc) for exc in exceptions)))
+        else:
+            if sock is None:
+                raise ValueError(
+                    'host and port was not specified and no sock specified')
+            if not _is_sock_stream(sock.type):
+                raise ValueError(
+                    'A Stream Socket was expected, got {!r}'.format(sock))
+
+            # libuv will set the socket to non-blocking mode, but
+            # we want Python socket object to notice that.
+            sock.setblocking(False)
+
+            waiter = self._new_future()
+            tr = TCPTransport.new(self, protocol, None, waiter, context)
+            try:
+                # libuv will make socket non-blocking
+                tr._open(sock.fileno())
+                tr._init_protocol()
+                await waiter
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                # It's OK to call `_close()` here, as opposed to
+                # `_force_close()` or `close()` as we want to terminate the
+                # transport immediately.  The `waiter` can only be waken
+                # up in `Transport._call_connection_made()`, and calling
+                # `_close()` before it is fine.
+                tr._close()
+                raise
+
+            tr._attach_fileobj(sock)
+
+        if ssl:
+            app_transport = protocol._get_app_transport(context)
+            try:
+                await ssl_waiter
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                app_transport.close()
+                raise
+            return app_transport, app_protocol
+        else:
+            return tr, protocol
+
+    @cython.iterable_coroutine
+    async def create_unix_server(self, protocol_factory, path=None,
+                                 *, backlog=100, sock=None, ssl=None,
+                                 ssl_handshake_timeout=None,
+                                 ssl_shutdown_timeout=None,
+                                 start_serving=True, cleanup_socket=PY313):
+        """A coroutine which creates a UNIX Domain Socket server.
+
+        The return value is a Server object, which can be used to stop
+        the service.
+
+        path is a str, representing a file systsem path to bind the
+        server socket to.
+
+        sock can optionally be specified in order to use a preexisting
+        socket object.
+
+        backlog is the maximum number of queued connections passed to
+        listen() (defaults to 100).
+
+        ssl can be set to an SSLContext to enable SSL over the
+        accepted connections.
+
+        ssl_handshake_timeout is the time in seconds that an SSL server
+        will wait for completion of the SSL handshake before aborting the
+        connection. Default is 60s.
+
+        ssl_shutdown_timeout is the time in seconds that an SSL server
+        will wait for completion of the SSL shutdown before aborting the
+        connection. Default is 30s.
+
+        If *cleanup_socket* is true then the Unix socket will automatically
+        be removed from the filesystem when the server is closed, unless the
+        socket has been replaced after the server has been created.
+        This defaults to True on Python 3.13 and above, or False otherwise.
+        """
+        cdef:
+            UnixServer pipe
+            Server server = Server(self)
+
+        if ssl is not None:
+            if not isinstance(ssl, ssl_SSLContext):
+                raise TypeError('ssl argument must be an SSLContext or None')
+        else:
+            if ssl_handshake_timeout is not None:
+                raise ValueError(
+                    'ssl_handshake_timeout is only meaningful with ssl')
+            if ssl_shutdown_timeout is not None:
+                raise ValueError(
+                    'ssl_shutdown_timeout is only meaningful with ssl')
+
+        if path is not None:
+            if sock is not None:
+                raise ValueError(
+                    'path and sock can not be specified at the same time')
+            orig_path = path
+
+            path = os_fspath(path)
+
+            if isinstance(path, str):
+                path = PyUnicode_EncodeFSDefault(path)
+
+            # Check for abstract socket.
+            if path[0] != 0:
+                try:
+                    if stat_S_ISSOCK(os_stat(path).st_mode):
+                        os_remove(path)
+                except FileNotFoundError:
+                    pass
+                except OSError as err:
+                    # Directory may have permissions only to create socket.
+                    aio_logger.error(
+                        'Unable to check or remove stale UNIX socket %r: %r',
+                        orig_path, err)
+
+            # We use Python sockets to create a UNIX server socket because
+            # when UNIX sockets are created by libuv, libuv removes the path
+            # they were bound to.  This is different from asyncio, which
+            # doesn't cleanup the socket path.
+            sock = socket_socket(uv.AF_UNIX)
+
+            try:
+                sock.bind(path)
+            except OSError as exc:
+                sock.close()
+                if exc.errno == errno.EADDRINUSE:
+                    # Let's improve the error message by adding
+                    # with what exact address it occurs.
+                    msg = 'Address {!r} is already in use'.format(orig_path)
+                    raise OSError(errno.EADDRINUSE, msg) from None
+                else:
+                    raise
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                sock.close()
+                raise
+
+        else:
+            if sock is None:
+                raise ValueError(
+                    'path was not specified, and no sock specified')
+
+            if sock.family != uv.AF_UNIX or not _is_sock_stream(sock.type):
+                raise ValueError(
+                    'A UNIX Domain Stream Socket was expected, got {!r}'
+                    .format(sock))
+
+            # libuv will set the socket to non-blocking mode, but
+            # we want Python socket object to notice that.
+            sock.setblocking(False)
+
+        if cleanup_socket:
+            path = sock.getsockname()
+            # Check for abstract socket. `str` and `bytes` paths are supported.
+            if path[0] not in (0, '\x00'):
+                try:
+                    self._unix_server_sockets[sock] = os_stat(path).st_ino
+                except FileNotFoundError:
+                    pass
+
+        pipe = UnixServer.new(
+            self, protocol_factory, server, backlog,
+            ssl, ssl_handshake_timeout, ssl_shutdown_timeout)
+
+        try:
+            pipe._open(sock.fileno())
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException:
+            pipe._close()
+            sock.close()
+            raise
+
+        pipe._attach_fileobj(sock)
+        server._add_server(pipe)
+
+        if start_serving:
+            server._start_serving()
+
+        return server
+
+    @cython.iterable_coroutine
+    async def create_unix_connection(self, protocol_factory, path=None, *,
+                                     ssl=None, sock=None,
+                                     server_hostname=None,
+                                     ssl_handshake_timeout=None,
+                                     ssl_shutdown_timeout=None):
+
+        cdef:
+            UnixTransport tr
+            object app_protocol
+            object app_transport
+            object protocol
+            object ssl_waiter
+
+        app_protocol = protocol = protocol_factory()
+        ssl_waiter = None
+        context = Context_CopyCurrent()
+        if ssl:
+            if server_hostname is None:
+                raise ValueError('You must set server_hostname '
+                                 'when using ssl without a host')
+
+            ssl_waiter = self._new_future()
+            sslcontext = None if isinstance(ssl, bool) else ssl
+            protocol = SSLProtocol(
+                self, app_protocol, sslcontext, ssl_waiter,
+                False, server_hostname,
+                ssl_handshake_timeout=ssl_handshake_timeout,
+                ssl_shutdown_timeout=ssl_shutdown_timeout)
+        else:
+            if server_hostname is not None:
+                raise ValueError('server_hostname is only meaningful with ssl')
+            if ssl_handshake_timeout is not None:
+                raise ValueError(
+                    'ssl_handshake_timeout is only meaningful with ssl')
+            if ssl_shutdown_timeout is not None:
+                raise ValueError(
+                    'ssl_shutdown_timeout is only meaningful with ssl')
+
+        if path is not None:
+            if sock is not None:
+                raise ValueError(
+                    'path and sock can not be specified at the same time')
+
+            path = os_fspath(path)
+
+            if isinstance(path, str):
+                path = PyUnicode_EncodeFSDefault(path)
+
+            waiter = self._new_future()
+            tr = UnixTransport.new(self, protocol, None, waiter, context)
+            tr.connect(path)
+            try:
+                await waiter
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                tr._close()
+                raise
+
+        else:
+            if sock is None:
+                raise ValueError('no path and sock were specified')
+
+            if sock.family != uv.AF_UNIX or not _is_sock_stream(sock.type):
+                raise ValueError(
+                    'A UNIX Domain Stream Socket was expected, got {!r}'
+                    .format(sock))
+
+            # libuv will set the socket to non-blocking mode, but
+            # we want Python socket object to notice that.
+            sock.setblocking(False)
+
+            waiter = self._new_future()
+            tr = UnixTransport.new(self, protocol, None, waiter, context)
+            try:
+                tr._open(sock.fileno())
+                tr._init_protocol()
+                await waiter
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                tr._close()
+                raise
+
+            tr._attach_fileobj(sock)
+
+        if ssl:
+            app_transport = protocol._get_app_transport(Context_CopyCurrent())
+            try:
+                await ssl_waiter
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                app_transport.close()
+                raise
+            return app_transport, app_protocol
+        else:
+            return tr, protocol
+
+    def default_exception_handler(self, context):
+        """Default exception handler.
+
+        This is called when an exception occurs and no exception
+        handler is set, and can be called by a custom exception
+        handler that wants to defer to the default behavior.
+
+        The context parameter has the same meaning as in
+        `call_exception_handler()`.
+        """
+        message = context.get('message')
+        if not message:
+            message = 'Unhandled exception in event loop'
+
+        exception = context.get('exception')
+        if exception is not None:
+            exc_info = (type(exception), exception, exception.__traceback__)
+        else:
+            exc_info = False
+
+        log_lines = [message]
+        for key in sorted(context):
+            if key in {'message', 'exception'}:
+                continue
+            value = context[key]
+            if key == 'source_traceback':
+                tb = ''.join(tb_format_list(value))
+                value = 'Object created at (most recent call last):\n'
+                value += tb.rstrip()
+            else:
+                try:
+                    value = repr(value)
+                except (KeyboardInterrupt, SystemExit):
+                    raise
+                except BaseException as ex:
+                    value = ('Exception in __repr__ {!r}; '
+                             'value type: {!r}'.format(ex, type(value)))
+            log_lines.append('{}: {}'.format(key, value))
+
+        aio_logger.error('\n'.join(log_lines), exc_info=exc_info)
+
+    def get_exception_handler(self):
+        """Return an exception handler, or None if the default one is in use.
+        """
+        return self._exception_handler
+
+    def set_exception_handler(self, handler):
+        """Set handler as the new event loop exception handler.
+
+        If handler is None, the default exception handler will
+        be set.
+
+        If handler is a callable object, it should have a
+        signature matching '(loop, context)', where 'loop'
+        will be a reference to the active event loop, 'context'
+        will be a dict object (see `call_exception_handler()`
+        documentation for details about context).
+        """
+        if handler is not None and not callable(handler):
+            raise TypeError('A callable object or None is expected, '
+                            'got {!r}'.format(handler))
+        self._exception_handler = handler
+
+    def call_exception_handler(self, context):
+        """Call the current event loop's exception handler.
+
+        The context argument is a dict containing the following keys:
+
+        - 'message': Error message;
+        - 'exception' (optional): Exception object;
+        - 'future' (optional): Future instance;
+        - 'handle' (optional): Handle instance;
+        - 'protocol' (optional): Protocol instance;
+        - 'transport' (optional): Transport instance;
+        - 'socket' (optional): Socket instance.
+
+        New keys maybe introduced in the future.
+
+        Note: do not overload this method in an event loop subclass.
+        For custom exception handling, use the
+        `set_exception_handler()` method.
+        """
+        if UVLOOP_DEBUG:
+            self._debug_exception_handler_cnt += 1
+
+        if self._exception_handler is None:
+            try:
+                self.default_exception_handler(context)
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                # Second protection layer for unexpected errors
+                # in the default implementation, as well as for subclassed
+                # event loops with overloaded "default_exception_handler".
+                aio_logger.error('Exception in default exception handler',
+                                 exc_info=True)
+        else:
+            try:
+                self._exception_handler(self, context)
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException as exc:
+                # Exception in the user set custom exception handler.
+                try:
+                    # Let's try default handler.
+                    self.default_exception_handler({
+                        'message': 'Unhandled error in exception handler',
+                        'exception': exc,
+                        'context': context,
+                    })
+                except (KeyboardInterrupt, SystemExit):
+                    raise
+                except BaseException:
+                    # Guard 'default_exception_handler' in case it is
+                    # overloaded.
+                    aio_logger.error('Exception in default exception handler '
+                                     'while handling an unexpected error '
+                                     'in custom exception handler',
+                                     exc_info=True)
+
+    def add_reader(self, fileobj, callback, *args):
+        """Add a reader callback."""
+        if len(args) == 0:
+            args = None
+        self._add_reader(fileobj, new_Handle(self, callback, args, None))
+
+    def remove_reader(self, fileobj):
+        """Remove a reader callback."""
+        self._remove_reader(fileobj)
+
+    def add_writer(self, fileobj, callback, *args):
+        """Add a writer callback.."""
+        if len(args) == 0:
+            args = None
+        self._add_writer(fileobj, new_Handle(self, callback, args, None))
+
+    def remove_writer(self, fileobj):
+        """Remove a writer callback."""
+        self._remove_writer(fileobj)
+
+    @cython.iterable_coroutine
+    async def sock_recv(self, sock, n):
+        """Receive data from the socket.
+
+        The return value is a bytes object representing the data received.
+        The maximum amount of data to be received at once is specified by
+        nbytes.
+
+        This method is a coroutine.
+        """
+        cdef:
+            Handle handle
+
+        if self._debug and sock.gettimeout() != 0:
+            raise ValueError("the socket must be non-blocking")
+
+        fut = _SyncSocketReaderFuture(sock, self)
+        handle = new_MethodHandle3(
+            self,
+            "Loop._sock_recv",
+            self._sock_recv,
+            None,
+            self,
+            fut, sock, n)
+
+        self._add_reader(sock, handle)
+        return await fut
+
+    @cython.iterable_coroutine
+    async def sock_recv_into(self, sock, buf):
+        """Receive data from the socket.
+
+        The received data is written into *buf* (a writable buffer).
+        The return value is the number of bytes written.
+
+        This method is a coroutine.
+        """
+        cdef:
+            Handle handle
+
+        if self._debug and sock.gettimeout() != 0:
+            raise ValueError("the socket must be non-blocking")
+
+        fut = _SyncSocketReaderFuture(sock, self)
+        handle = new_MethodHandle3(
+            self,
+            "Loop._sock_recv_into",
+            self._sock_recv_into,
+            None,
+            self,
+            fut, sock, buf)
+
+        self._add_reader(sock, handle)
+        return await fut
+
+    @cython.iterable_coroutine
+    async def sock_sendall(self, sock, data):
+        """Send data to the socket.
+
+        The socket must be connected to a remote socket. This method continues
+        to send data from data until either all data has been sent or an
+        error occurs. None is returned on success. On error, an exception is
+        raised, and there is no way to determine how much data, if any, was
+        successfully processed by the receiving end of the connection.
+
+        This method is a coroutine.
+        """
+        cdef:
+            Handle handle
+            ssize_t n
+
+        if self._debug and sock.gettimeout() != 0:
+            raise ValueError("the socket must be non-blocking")
+
+        if not data:
+            return
+
+        socket_inc_io_ref(sock)
+        try:
+            try:
+                n = sock.send(data)
+            except (BlockingIOError, InterruptedError):
+                pass
+            else:
+                if UVLOOP_DEBUG:
+                    # This can be a partial success, i.e. only part
+                    # of the data was sent
+                    self._sock_try_write_total += 1
+
+                if n == len(data):
+                    return
+                if not isinstance(data, memoryview):
+                    data = memoryview(data)
+                data = data[n:]
+
+            fut = _SyncSocketWriterFuture(sock, self)
+            handle = new_MethodHandle3(
+                self,
+                "Loop._sock_sendall",
+                self._sock_sendall,
+                None,
+                self,
+                fut, sock, data)
+
+            self._add_writer(sock, handle)
+            return await fut
+        finally:
+            socket_dec_io_ref(sock)
+
+    @cython.iterable_coroutine
+    async def sock_accept(self, sock):
+        """Accept a connection.
+
+        The socket must be bound to an address and listening for connections.
+        The return value is a pair (conn, address) where conn is a new socket
+        object usable to send and receive data on the connection, and address
+        is the address bound to the socket on the other end of the connection.
+
+        This method is a coroutine.
+        """
+        cdef:
+            Handle handle
+
+        if self._debug and sock.gettimeout() != 0:
+            raise ValueError("the socket must be non-blocking")
+
+        fut = _SyncSocketReaderFuture(sock, self)
+        handle = new_MethodHandle2(
+            self,
+            "Loop._sock_accept",
+            self._sock_accept,
+            None,
+            self,
+            fut, sock)
+
+        self._add_reader(sock, handle)
+        return await fut
+
+    @cython.iterable_coroutine
+    async def sock_connect(self, sock, address):
+        """Connect to a remote socket at address.
+
+        This method is a coroutine.
+        """
+        if self._debug and sock.gettimeout() != 0:
+            raise ValueError("the socket must be non-blocking")
+
+        socket_inc_io_ref(sock)
+        try:
+            if sock.family == uv.AF_UNIX:
+                fut = self._sock_connect(sock, address)
+            else:
+                addrs = await self.getaddrinfo(
+                    *address[:2], family=sock.family)
+
+                _, _, _, _, address = addrs[0]
+                fut = self._sock_connect(sock, address)
+            if fut is not None:
+                await fut
+        finally:
+            socket_dec_io_ref(sock)
+
+    @cython.iterable_coroutine
+    async def sock_recvfrom(self, sock, bufsize):
+        raise NotImplementedError
+
+    @cython.iterable_coroutine
+    async def sock_recvfrom_into(self, sock, buf, nbytes=0):
+        raise NotImplementedError
+
+    @cython.iterable_coroutine
+    async def sock_sendto(self, sock, data, address):
+        raise NotImplementedError
+
+    @cython.iterable_coroutine
+    async def connect_accepted_socket(self, protocol_factory, sock, *,
+                                      ssl=None,
+                                      ssl_handshake_timeout=None,
+                                      ssl_shutdown_timeout=None):
+        """Handle an accepted connection.
+
+        This is used by servers that accept connections outside of
+        asyncio but that use asyncio to handle connections.
+
+        This method is a coroutine.  When completed, the coroutine
+        returns a (transport, protocol) pair.
+        """
+
+        cdef:
+            UVStream transport = None
+
+        if ssl is not None:
+            if not isinstance(ssl, ssl_SSLContext):
+                raise TypeError('ssl argument must be an SSLContext or None')
+        else:
+            if ssl_handshake_timeout is not None:
+                raise ValueError(
+                    'ssl_handshake_timeout is only meaningful with ssl')
+            if ssl_shutdown_timeout is not None:
+                raise ValueError(
+                    'ssl_shutdown_timeout is only meaningful with ssl')
+
+        if not _is_sock_stream(sock.type):
+            raise ValueError(
+                'A Stream Socket was expected, got {!r}'.format(sock))
+
+        app_protocol = protocol_factory()
+        waiter = self._new_future()
+        transport_waiter = None
+        context = Context_CopyCurrent()
+
+        if ssl is None:
+            protocol = app_protocol
+            transport_waiter = waiter
+        else:
+            protocol = SSLProtocol(
+                self, app_protocol, ssl, waiter,
+                server_side=True,
+                server_hostname=None,
+                ssl_handshake_timeout=ssl_handshake_timeout,
+                ssl_shutdown_timeout=ssl_shutdown_timeout)
+            transport_waiter = None
+
+        if sock.family == uv.AF_UNIX:
+            transport = UnixTransport.new(
+                self, protocol, None, transport_waiter, context)
+        elif sock.family in (uv.AF_INET, uv.AF_INET6):
+            transport = TCPTransport.new(
+                self, protocol, None, transport_waiter, context)
+
+        if transport is None:
+            raise ValueError(
+                'invalid socket family, expected AF_UNIX, AF_INET or AF_INET6')
+
+        transport._open(sock.fileno())
+        transport._init_protocol()
+        transport._attach_fileobj(sock)
+
+        if ssl:
+            app_transport = protocol._get_app_transport(context)
+            try:
+                await waiter
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                app_transport.close()
+                raise
+            return app_transport, protocol
+        else:
+            try:
+                await waiter
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException:
+                transport._close()
+                raise
+            return transport, protocol
+
+    def run_in_executor(self, executor, func, *args):
+        if aio_iscoroutine(func) or aio_iscoroutinefunction(func):
+            raise TypeError("coroutines cannot be used with run_in_executor()")
+
+        self._check_closed()
+
+        if executor is None:
+            executor = self._default_executor
+            # Only check when the default executor is being used
+            self._check_default_executor()
+            if executor is None:
+                executor = cc_ThreadPoolExecutor()
+                self._default_executor = executor
+
+        return aio_wrap_future(executor.submit(func, *args), loop=self)
+
+    def set_default_executor(self, executor):
+        self._default_executor = executor
+
+    @cython.iterable_coroutine
+    async def __subprocess_run(self, protocol_factory, args,
+                               stdin=subprocess_PIPE,
+                               stdout=subprocess_PIPE,
+                               stderr=subprocess_PIPE,
+                               universal_newlines=False,
+                               shell=True,
+                               bufsize=0,
+                               preexec_fn=None,
+                               close_fds=None,
+                               cwd=None,
+                               env=None,
+                               startupinfo=None,
+                               creationflags=0,
+                               restore_signals=True,
+                               start_new_session=False,
+                               executable=None,
+                               pass_fds=(),
+                               **kwargs):
+
+        # TODO: Implement close_fds (might not be very important in
+        # Python 3.5, since all FDs aren't inheritable by default.)
+
+        cdef:
+            int debug_flags = 0
+
+        if universal_newlines:
+            raise ValueError("universal_newlines must be False")
+        if bufsize != 0:
+            raise ValueError("bufsize must be 0")
+        if startupinfo is not None:
+            raise ValueError('startupinfo is not supported')
+        if creationflags != 0:
+            raise ValueError('creationflags is not supported')
+
+        if executable is not None:
+            args[0] = executable
+
+        # For tests only! Do not use in your code. Ever.
+        if kwargs.pop("__uvloop_sleep_after_fork", False):
+            debug_flags |= __PROCESS_DEBUG_SLEEP_AFTER_FORK
+        if kwargs:
+            raise ValueError(
+                'unexpected kwargs: {}'.format(', '.join(kwargs.keys())))
+
+        waiter = self._new_future()
+        protocol = protocol_factory()
+        proc = UVProcessTransport.new(self, protocol,
+                                      args, env, cwd, start_new_session,
+                                      stdin, stdout, stderr, pass_fds,
+                                      waiter,
+                                      debug_flags,
+                                      preexec_fn,
+                                      restore_signals)
+
+        try:
+            await waiter
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException:
+            proc.close()
+            raise
+
+        return proc, protocol
+
+    @cython.iterable_coroutine
+    async def subprocess_shell(self, protocol_factory, cmd, *,
+                               shell=True,
+                               **kwargs):
+
+        if not shell:
+            raise ValueError("shell must be True")
+
+        args = [cmd]
+        if shell:
+            args = [b'/bin/sh', b'-c'] + args
+
+        return await self.__subprocess_run(protocol_factory, args, shell=True,
+                                           **kwargs)
+
+    @cython.iterable_coroutine
+    async def subprocess_exec(self, protocol_factory, program, *args,
+                              shell=False, **kwargs):
+
+        if shell:
+            raise ValueError("shell must be False")
+
+        args = list((program,) + args)
+
+        return await self.__subprocess_run(protocol_factory, args, shell=False,
+                                           **kwargs)
+
+    @cython.iterable_coroutine
+    async def connect_read_pipe(self, proto_factory, pipe):
+        """Register read pipe in event loop. Set the pipe to non-blocking mode.
+
+        protocol_factory should instantiate object with Protocol interface.
+        pipe is a file-like object.
+        Return pair (transport, protocol), where transport supports the
+        ReadTransport interface."""
+        cdef:
+            ReadUnixTransport transp
+
+        waiter = self._new_future()
+        proto = proto_factory()
+        transp = ReadUnixTransport.new(self, proto, None, waiter)
+        transp._add_extra_info('pipe', pipe)
+        try:
+            transp._open(pipe.fileno())
+            transp._init_protocol()
+            await waiter
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException:
+            transp._close()
+            raise
+        transp._attach_fileobj(pipe)
+        return transp, proto
+
+    @cython.iterable_coroutine
+    async def connect_write_pipe(self, proto_factory, pipe):
+        """Register write pipe in event loop.
+
+        protocol_factory should instantiate object with BaseProtocol interface.
+        Pipe is file-like object already switched to nonblocking.
+        Return pair (transport, protocol), where transport support
+        WriteTransport interface."""
+        cdef:
+            WriteUnixTransport transp
+
+        waiter = self._new_future()
+        proto = proto_factory()
+        transp = WriteUnixTransport.new(self, proto, None, waiter)
+        transp._add_extra_info('pipe', pipe)
+        try:
+            transp._open(pipe.fileno())
+            transp._init_protocol()
+            await waiter
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except BaseException:
+            transp._close()
+            raise
+        transp._attach_fileobj(pipe)
+        return transp, proto
+
+    def add_signal_handler(self, sig, callback, *args):
+        """Add a handler for a signal.  UNIX only.
+
+        Raise ValueError if the signal number is invalid or uncatchable.
+        Raise RuntimeError if there is a problem setting up the handler.
+        """
+        cdef:
+            Handle h
+
+        if not self._is_main_thread():
+            raise ValueError(
+                'add_signal_handler() can only be called from '
+                'the main thread')
+
+        if (aio_iscoroutine(callback)
+                or aio_iscoroutinefunction(callback)):
+            raise TypeError(
+                "coroutines cannot be used with add_signal_handler()")
+
+        if sig == uv.SIGCHLD:
+            if (hasattr(callback, '__self__') and
+                    isinstance(callback.__self__, aio_AbstractChildWatcher)):
+
+                warnings_warn(
+                    "!!! asyncio is trying to install its ChildWatcher for "
+                    "SIGCHLD signal !!!\n\nThis is probably because a uvloop "
+                    "instance is used with asyncio.set_event_loop(). "
+                    "The correct way to use uvloop is to install its policy: "
+                    "`asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())`"
+                    "\n\n", RuntimeWarning, source=self)
+
+                # TODO: ideally we should always raise an error here,
+                # but that would be a backwards incompatible change,
+                # because we recommended using "asyncio.set_event_loop()"
+                # in our README.  Need to start a deprecation period
+                # at some point to turn this warning into an error.
+                return
+
+            raise RuntimeError(
+                'cannot add a signal handler for SIGCHLD: it is used '
+                'by the event loop to track subprocesses')
+
+        self._check_signal(sig)
+        self._check_closed()
+
+        h = new_Handle(self, callback, args or None, None)
+        self._signal_handlers[sig] = h
+
+        try:
+            # Register a dummy signal handler to ask Python to write the signal
+            # number in the wakeup file descriptor.
+            signal_signal(sig, self.__sighandler)
+
+            # Set SA_RESTART to limit EINTR occurrences.
+            signal_siginterrupt(sig, False)
+        except OSError as exc:
+            del self._signal_handlers[sig]
+            if not self._signal_handlers:
+                try:
+                    signal_set_wakeup_fd(-1)
+                except (ValueError, OSError) as nexc:
+                    aio_logger.info('set_wakeup_fd(-1) failed: %s', nexc)
+
+            if exc.errno == errno_EINVAL:
+                raise RuntimeError('sig {} cannot be caught'.format(sig))
+            else:
+                raise
+
+    def remove_signal_handler(self, sig):
+        """Remove a handler for a signal.  UNIX only.
+
+        Return True if a signal handler was removed, False if not.
+        """
+
+        if not self._is_main_thread():
+            raise ValueError(
+                'remove_signal_handler() can only be called from '
+                'the main thread')
+
+        self._check_signal(sig)
+
+        if not self._listening_signals:
+            return False
+
+        try:
+            del self._signal_handlers[sig]
+        except KeyError:
+            return False
+
+        if sig == uv.SIGINT:
+            handler = signal_default_int_handler
+        else:
+            handler = signal_SIG_DFL
+
+        try:
+            signal_signal(sig, handler)
+        except OSError as exc:
+            if exc.errno == errno_EINVAL:
+                raise RuntimeError('sig {} cannot be caught'.format(sig))
+            else:
+                raise
+
+        return True
+
+    @cython.iterable_coroutine
+    async def create_datagram_endpoint(self, protocol_factory,
+                                       local_addr=None, remote_addr=None, *,
+                                       family=0, proto=0, flags=0,
+                                       reuse_address=_unset, reuse_port=None,
+                                       allow_broadcast=None, sock=None):
+        """A coroutine which creates a datagram endpoint.
+
+        This method will try to establish the endpoint in the background.
+        When successful, the coroutine returns a (transport, protocol) pair.
+
+        protocol_factory must be a callable returning a protocol instance.
+
+        socket family AF_INET or socket.AF_INET6 depending on host (or
+        family if specified), socket type SOCK_DGRAM.
+
+        reuse_port tells the kernel to allow this endpoint to be bound to
+        the same port as other existing endpoints are bound to, so long as
+        they all set this flag when being created. This option is not
+        supported on Windows and some UNIX's. If the
+        :py:data:`~socket.SO_REUSEPORT` constant is not defined then this
+        capability is unsupported.
+
+        allow_broadcast tells the kernel to allow this endpoint to send
+        messages to the broadcast address.
+
+        sock can optionally be specified in order to use a preexisting
+        socket object.
+        """
+        cdef:
+            UDPTransport udp = None
+            system.addrinfo * lai
+            system.addrinfo * rai
+
+        if sock is not None:
+            if not _is_sock_dgram(sock.type):
+                raise ValueError(
+                    'A UDP Socket was expected, got {!r}'.format(sock))
+            if (local_addr or remote_addr or
+                    family or proto or flags or
+                    reuse_port or allow_broadcast):
+                # show the problematic kwargs in exception msg
+                opts = dict(local_addr=local_addr, remote_addr=remote_addr,
+                            family=family, proto=proto, flags=flags,
+                            reuse_address=reuse_address, reuse_port=reuse_port,
+                            allow_broadcast=allow_broadcast)
+                problems = ', '.join(
+                    '{}={}'.format(k, v) for k, v in opts.items() if v)
+                raise ValueError(
+                    'socket modifier keyword arguments can not be used '
+                    'when sock is specified. ({})'.format(problems))
+            sock.setblocking(False)
+            udp = UDPTransport.__new__(UDPTransport)
+            udp._init(self, uv.AF_UNSPEC)
+            udp.open(sock.family, sock.fileno())
+            udp._attach_fileobj(sock)
+        else:
+            if reuse_address is not _unset:
+                if reuse_address:
+                    raise ValueError("Passing `reuse_address=True` is no "
+                                     "longer supported, as the usage of "
+                                     "SO_REUSEPORT in UDP poses a significant "
+                                     "security concern.")
+                else:
+                    warnings_warn("The *reuse_address* parameter has been "
+                                  "deprecated as of 0.15.", DeprecationWarning,
+                                  stacklevel=2)
+            reuse_port = bool(reuse_port)
+            if reuse_port and not has_SO_REUSEPORT:
+                raise ValueError(
+                    'reuse_port not supported by socket module')
+
+            lads = None
+            if local_addr is not None:
+                if (not isinstance(local_addr, (tuple, list)) or
+                        len(local_addr) != 2):
+                    raise TypeError(
+                        'local_addr must be a tuple of (host, port)')
+                lads = await self._getaddrinfo(
+                    local_addr[0], local_addr[1],
+                    family, uv.SOCK_DGRAM, proto, flags,
+                    0)
+
+            rads = None
+            if remote_addr is not None:
+                if (not isinstance(remote_addr, (tuple, list)) or
+                        len(remote_addr) != 2):
+                    raise TypeError(
+                        'remote_addr must be a tuple of (host, port)')
+                rads = await self._getaddrinfo(
+                    remote_addr[0], remote_addr[1],
+                    family, uv.SOCK_DGRAM, proto, flags,
+                    0)
+
+            excs = []
+            if lads is None:
+                if rads is not None:
+                    udp = UDPTransport.__new__(UDPTransport)
+                    rai = (rads).data
+                    udp._init(self, rai.ai_family)
+                    udp._connect(rai.ai_addr, rai.ai_addrlen)
+                    udp._set_address(rai)
+                else:
+                    if family not in (uv.AF_INET, uv.AF_INET6):
+                        raise ValueError('unexpected address family')
+                    udp = UDPTransport.__new__(UDPTransport)
+                    udp._init(self, family)
+
+                if reuse_port:
+                    self._sock_set_reuseport(udp._fileno())
+
+            else:
+                lai = (lads).data
+                while lai is not NULL:
+                    try:
+                        udp = UDPTransport.__new__(UDPTransport)
+                        udp._init(self, lai.ai_family)
+                        if reuse_port:
+                            self._sock_set_reuseport(udp._fileno())
+                        udp._bind(lai.ai_addr)
+                    except (KeyboardInterrupt, SystemExit):
+                        raise
+                    except BaseException as ex:
+                        lai = lai.ai_next
+                        excs.append(ex)
+                        continue
+                    else:
+                        break
+                else:
+                    ctx = None
+                    if len(excs):
+                        ctx = excs[0]
+                    raise OSError('could not bind to local_addr {}'.format(
+                        local_addr)) from ctx
+
+                if rads is not None:
+                    rai = (rads).data
+                    while rai is not NULL:
+                        if rai.ai_family != lai.ai_family:
+                            rai = rai.ai_next
+                            continue
+                        if rai.ai_protocol != lai.ai_protocol:
+                            rai = rai.ai_next
+                            continue
+                        udp._connect(rai.ai_addr, rai.ai_addrlen)
+                        udp._set_address(rai)
+                        break
+                    else:
+                        raise OSError(
+                            'could not bind to remote_addr {}'.format(
+                                remote_addr))
+
+        if allow_broadcast:
+            udp._set_broadcast(1)
+
+        protocol = protocol_factory()
+        waiter = self._new_future()
+        assert udp is not None
+        udp._set_protocol(protocol)
+        udp._set_waiter(waiter)
+        udp._init_protocol()
+
+        await waiter
+        return udp, protocol
+
+    def _monitor_fs(self, path: str, callback) -> asyncio.Handle:
+        cdef:
+            UVFSEvent fs_handle
+            char* c_str_path
+
+        self._check_closed()
+        fs_handle = UVFSEvent.new(self, callback, None)
+        p_bytes = path.encode('UTF-8')
+        c_str_path = p_bytes
+        flags = 0
+        fs_handle.start(c_str_path, flags)
+        return fs_handle
+
+    def _check_default_executor(self):
+        if self._executor_shutdown_called:
+            raise RuntimeError('Executor shutdown has been called')
+
+    def _asyncgen_finalizer_hook(self, agen):
+        self._asyncgens.discard(agen)
+        if not self.is_closed():
+            self.call_soon_threadsafe(self.create_task, agen.aclose())
+
+    def _asyncgen_firstiter_hook(self, agen):
+        if self._asyncgens_shutdown_called:
+            warnings_warn(
+                "asynchronous generator {!r} was scheduled after "
+                "loop.shutdown_asyncgens() call".format(agen),
+                ResourceWarning, source=self)
+
+        self._asyncgens.add(agen)
+
+    @cython.iterable_coroutine
+    async def shutdown_asyncgens(self):
+        """Shutdown all active asynchronous generators."""
+        self._asyncgens_shutdown_called = True
+
+        if not len(self._asyncgens):
+            return
+
+        closing_agens = list(self._asyncgens)
+        self._asyncgens.clear()
+
+        shutdown_coro = aio_gather(
+            *[ag.aclose() for ag in closing_agens],
+            return_exceptions=True)
+
+        results = await shutdown_coro
+        for result, agen in zip(results, closing_agens):
+            if isinstance(result, Exception):
+                self.call_exception_handler({
+                    'message': 'an error occurred during closing of '
+                               'asynchronous generator {!r}'.format(agen),
+                    'exception': result,
+                    'asyncgen': agen
+                })
+
+    @cython.iterable_coroutine
+    async def shutdown_default_executor(self, timeout=None):
+        """Schedule the shutdown of the default executor.
+
+        The timeout parameter specifies the amount of time the executor will
+        be given to finish joining. The default value is None, which means
+        that the executor will be given an unlimited amount of time.
+        """
+        self._executor_shutdown_called = True
+        if self._default_executor is None:
+            return
+        future = self.create_future()
+        thread = threading_Thread(target=self._do_shutdown, args=(future,))
+        thread.start()
+        try:
+            await future
+        finally:
+            thread.join(timeout)
+
+        if thread.is_alive():
+            warnings_warn(
+                "The executor did not finishing joining "
+                f"its threads within {timeout} seconds.",
+                RuntimeWarning,
+                stacklevel=2
+            )
+            self._default_executor.shutdown(wait=False)
+
+    def _do_shutdown(self, future):
+        try:
+            self._default_executor.shutdown(wait=True)
+            self.call_soon_threadsafe(future.set_result, None)
+        except Exception as ex:
+            self.call_soon_threadsafe(future.set_exception, ex)
+
+
+# Expose pointer for integration with other C-extensions
+def libuv_get_loop_t_ptr(loop):
+    return PyCapsule_New((loop).uvloop, NULL, NULL)
+
+
+def libuv_get_version():
+    return uv.uv_version()
+
+
+def _testhelper_unwrap_capsuled_pointer(obj):
+    return PyCapsule_GetPointer(obj, NULL)
+
+
+cdef void __loop_alloc_buffer(
+    uv.uv_handle_t* uvhandle,
+    size_t suggested_size,
+    uv.uv_buf_t* buf
+) noexcept with gil:
+    cdef:
+        Loop loop = (uvhandle.data)._loop
+
+    if loop._recv_buffer_in_use == 1:
+        buf.len = 0
+        exc = RuntimeError('concurrent allocations')
+        loop._handle_exception(exc)
+        return
+
+    loop._recv_buffer_in_use = 1
+    buf.base = loop._recv_buffer
+    buf.len = sizeof(loop._recv_buffer)
+
+
+cdef inline void __loop_free_buffer(Loop loop):
+    loop._recv_buffer_in_use = 0
+
+
+class _SyncSocketReaderFuture(aio_Future):
+
+    def __init__(self, sock, loop):
+        aio_Future.__init__(self, loop=loop)
+        self.__sock = sock
+        self.__loop = loop
+
+    def __remove_reader(self):
+        if self.__sock is not None and self.__sock.fileno() != -1:
+            self.__loop.remove_reader(self.__sock)
+            self.__sock = None
+
+    if PY39:
+        def cancel(self, msg=None):
+            self.__remove_reader()
+            aio_Future.cancel(self, msg=msg)
+
+    else:
+        def cancel(self):
+            self.__remove_reader()
+            aio_Future.cancel(self)
+
+
+class _SyncSocketWriterFuture(aio_Future):
+
+    def __init__(self, sock, loop):
+        aio_Future.__init__(self, loop=loop)
+        self.__sock = sock
+        self.__loop = loop
+
+    def __remove_writer(self):
+        if self.__sock is not None and self.__sock.fileno() != -1:
+            self.__loop.remove_writer(self.__sock)
+            self.__sock = None
+
+    if PY39:
+        def cancel(self, msg=None):
+            self.__remove_writer()
+            aio_Future.cancel(self, msg=msg)
+
+    else:
+        def cancel(self):
+            self.__remove_writer()
+            aio_Future.cancel(self)
+
+
+include "cbhandles.pyx"
+include "pseudosock.pyx"
+include "lru.pyx"
+
+include "handles/handle.pyx"
+include "handles/async_.pyx"
+include "handles/idle.pyx"
+include "handles/check.pyx"
+include "handles/timer.pyx"
+include "handles/poll.pyx"
+include "handles/basetransport.pyx"
+include "handles/stream.pyx"
+include "handles/streamserver.pyx"
+include "handles/tcp.pyx"
+include "handles/pipe.pyx"
+include "handles/process.pyx"
+include "handles/fsevent.pyx"
+
+include "request.pyx"
+include "dns.pyx"
+include "sslproto.pyx"
+
+include "handles/udp.pyx"
+
+include "server.pyx"
+
+
+# Used in UVProcess
+cdef vint __atfork_installed = 0
+cdef vint __forking = 0
+cdef Loop __forking_loop = None
+
+
+cdef void __get_fork_handler() noexcept nogil:
+    with gil:
+        if (__forking and __forking_loop is not None and
+                __forking_loop.active_process_handler is not None):
+            __forking_loop.active_process_handler._after_fork()
+
+cdef __install_atfork():
+    global __atfork_installed
+
+    if __atfork_installed:
+        return
+    __atfork_installed = 1
+
+    cdef int err
+
+    err = system.pthread_atfork(NULL, NULL, &system.handleAtFork)
+    if err:
+        __atfork_installed = 0
+        raise convert_error(-err)
+
+
+# Install PyMem* memory allocators
+cdef vint __mem_installed = 0
+cdef __install_pymem():
+    global __mem_installed
+    if __mem_installed:
+        return
+    __mem_installed = 1
+
+    cdef int err
+    err = uv.uv_replace_allocator(PyMem_RawMalloc,
+                                  PyMem_RawRealloc,
+                                  PyMem_RawCalloc,
+                                  PyMem_RawFree)
+    if err < 0:
+        __mem_installed = 0
+        raise convert_error(err)
+
+
+cdef _set_signal_wakeup_fd(fd):
+    if fd >= 0:
+        return signal_set_wakeup_fd(fd, warn_on_full_buffer=False)
+    else:
+        return signal_set_wakeup_fd(fd)
+
+
+# Helpers for tests
+
+@cython.iterable_coroutine
+async def _test_coroutine_1():
+    return 42
diff --git a/lib/python3.12/site-packages/uvloop/lru.pyx b/lib/python3.12/site-packages/uvloop/lru.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..cc7ea1dbc8aade8807a511daf6ea89521a07a13f
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/lru.pyx
@@ -0,0 +1,79 @@
+cdef object _LRU_MARKER = object()
+
+
+@cython.final
+cdef class LruCache:
+
+    cdef:
+        object _dict
+        int _maxsize
+        object _dict_move_to_end
+        object _dict_get
+
+    # We use an OrderedDict for LRU implementation.  Operations:
+    #
+    # * We use a simple `__setitem__` to push a new entry:
+    #       `entries[key] = new_entry`
+    #   That will push `new_entry` to the *end* of the entries dict.
+    #
+    # * When we have a cache hit, we call
+    #       `entries.move_to_end(key, last=True)`
+    #   to move the entry to the *end* of the entries dict.
+    #
+    # * When we need to remove entries to maintain `max_size`, we call
+    #       `entries.popitem(last=False)`
+    #   to remove an entry from the *beginning* of the entries dict.
+    #
+    # So new entries and hits are always promoted to the end of the
+    # entries dict, whereas the unused one will group in the
+    # beginning of it.
+
+    def __init__(self, *, maxsize):
+        if maxsize <= 0:
+            raise ValueError(
+                f'maxsize is expected to be greater than 0, got {maxsize}')
+
+        self._dict = col_OrderedDict()
+        self._dict_move_to_end = self._dict.move_to_end
+        self._dict_get = self._dict.get
+        self._maxsize = maxsize
+
+    cdef get(self, key, default):
+        o = self._dict_get(key, _LRU_MARKER)
+        if o is _LRU_MARKER:
+            return default
+        self._dict_move_to_end(key)  # last=True
+        return o
+
+    cdef inline needs_cleanup(self):
+        return len(self._dict) > self._maxsize
+
+    cdef inline cleanup_one(self):
+        k, _ = self._dict.popitem(last=False)
+        return k
+
+    def __getitem__(self, key):
+        o = self._dict[key]
+        self._dict_move_to_end(key)  # last=True
+        return o
+
+    def __setitem__(self, key, o):
+        if key in self._dict:
+            self._dict[key] = o
+            self._dict_move_to_end(key)  # last=True
+        else:
+            self._dict[key] = o
+        while self.needs_cleanup():
+            self.cleanup_one()
+
+    def __delitem__(self, key):
+        del self._dict[key]
+
+    def __contains__(self, key):
+        return key in self._dict
+
+    def __len__(self):
+        return len(self._dict)
+
+    def __iter__(self):
+        return iter(self._dict)
diff --git a/lib/python3.12/site-packages/uvloop/pseudosock.pyx b/lib/python3.12/site-packages/uvloop/pseudosock.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..10a1ad602e8307e655aa9247c4d2eef045bbe6b2
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/pseudosock.pyx
@@ -0,0 +1,209 @@
+cdef class PseudoSocket:
+    cdef:
+        int _family
+        int _type
+        int _proto
+        int _fd
+        object _peername
+        object _sockname
+
+    def __init__(self, int family, int type, int proto, int fd):
+        self._family = family
+        self._type = type
+        self._proto = proto
+        self._fd = fd
+        self._peername = None
+        self._sockname = None
+
+    cdef _na(self, what):
+        raise TypeError('transport sockets do not support {}'.format(what))
+
+    cdef _make_sock(self):
+        return socket_socket(self._family, self._type, self._proto, self._fd)
+
+    property family:
+        def __get__(self):
+            try:
+                return socket_AddressFamily(self._family)
+            except ValueError:
+                return self._family
+
+    property type:
+        def __get__(self):
+            try:
+                return socket_SocketKind(self._type)
+            except ValueError:
+                return self._type
+
+    property proto:
+        def __get__(self):
+            return self._proto
+
+    def __repr__(self):
+        s = ("self.request.data is not self:
+                raise RuntimeError(
+                    '{}.cancel: .request.data is not UVRequest'.format(
+                        self.__class__.__name__))
+
+        # We only can cancel pending requests.  Let's try.
+        err = uv.uv_cancel(self.request)
+        if err < 0:
+            if err == uv.UV_EBUSY:
+                # Can't close the request -- it's executing (see the first
+                # comment).  Loop will have to wait until the callback
+                # fires.
+                pass
+            elif err == uv.UV_EINVAL:
+                # From libuv docs:
+                #
+                #     Only cancellation of uv_fs_t, uv_getaddrinfo_t,
+                #     uv_getnameinfo_t and uv_work_t requests is currently
+                #     supported.
+                return
+            else:
+                ex = convert_error(err)
+                self.loop._handle_exception(ex)
diff --git a/lib/python3.12/site-packages/uvloop/server.pxd b/lib/python3.12/site-packages/uvloop/server.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..ef10f8131014516df68ef1a669811fbd63ff5b5b
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/server.pxd
@@ -0,0 +1,19 @@
+cdef class Server:
+    cdef:
+        list _servers
+        list _waiters
+        int _active_count
+        Loop _loop
+        bint _serving
+        object _serving_forever_fut
+        object __weakref__
+
+    cdef _add_server(self, UVStreamServer srv)
+    cdef _start_serving(self)
+    cdef _wakeup(self)
+
+    cdef _attach(self)
+    cdef _detach(self)
+
+    cdef _ref(self)
+    cdef _unref(self)
diff --git a/lib/python3.12/site-packages/uvloop/server.pyx b/lib/python3.12/site-packages/uvloop/server.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..845bcfda451ebae9a0ac4c62dbca8f62443d0a59
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/server.pyx
@@ -0,0 +1,136 @@
+import asyncio
+
+
+cdef class Server:
+    def __cinit__(self, Loop loop):
+        self._loop = loop
+        self._servers = []
+        self._waiters = []
+        self._active_count = 0
+        self._serving_forever_fut = None
+
+    cdef _add_server(self, UVStreamServer srv):
+        self._servers.append(srv)
+
+    cdef _start_serving(self):
+        if self._serving:
+            return
+
+        self._serving = 1
+        for server in self._servers:
+            (server).listen()
+
+    cdef _wakeup(self):
+        cdef list waiters
+
+        waiters = self._waiters
+        self._waiters = None
+        for waiter in waiters:
+            if not waiter.done():
+                waiter.set_result(waiter)
+
+    cdef _attach(self):
+        assert self._servers is not None
+        self._active_count += 1
+
+    cdef _detach(self):
+        assert self._active_count > 0
+        self._active_count -= 1
+        if self._active_count == 0 and self._servers is None:
+            self._wakeup()
+
+    cdef _ref(self):
+        # Keep the server object alive while it's not explicitly closed.
+        self._loop._servers.add(self)
+
+    cdef _unref(self):
+        self._loop._servers.discard(self)
+
+    # Public API
+
+    @cython.iterable_coroutine
+    async def __aenter__(self):
+        return self
+
+    @cython.iterable_coroutine
+    async def __aexit__(self, *exc):
+        self.close()
+        await self.wait_closed()
+
+    def __repr__(self):
+        return '<%s sockets=%r>' % (self.__class__.__name__, self.sockets)
+
+    def get_loop(self):
+        return self._loop
+
+    @cython.iterable_coroutine
+    async def wait_closed(self):
+        # Do not remove `self._servers is None` below
+        # because close() method only closes server sockets
+        # and existing client connections are left open.
+        if self._servers is None or self._waiters is None:
+            return
+        waiter = self._loop._new_future()
+        self._waiters.append(waiter)
+        await waiter
+
+    def close(self):
+        cdef list servers
+
+        if self._servers is None:
+            return
+
+        try:
+            servers = self._servers
+            self._servers = None
+            self._serving = 0
+
+            for server in servers:
+                (server)._close()
+
+            if self._active_count == 0:
+                self._wakeup()
+        finally:
+            self._unref()
+
+    def is_serving(self):
+        return self._serving
+
+    @cython.iterable_coroutine
+    async def start_serving(self):
+        self._start_serving()
+
+    @cython.iterable_coroutine
+    async def serve_forever(self):
+        if self._serving_forever_fut is not None:
+            raise RuntimeError(
+                f'server {self!r} is already being awaited on serve_forever()')
+        if self._servers is None:
+            raise RuntimeError(f'server {self!r} is closed')
+
+        self._start_serving()
+        self._serving_forever_fut = self._loop.create_future()
+
+        try:
+            await self._serving_forever_fut
+        except asyncio.CancelledError:
+            try:
+                self.close()
+                await self.wait_closed()
+            finally:
+                raise
+        finally:
+            self._serving_forever_fut = None
+
+    property sockets:
+        def __get__(self):
+            cdef list sockets = []
+
+            # Guard against `self._servers is None`
+            if self._servers:
+                for server in self._servers:
+                    sockets.append(
+                        (server)._get_socket()
+                    )
+
+            return sockets
diff --git a/lib/python3.12/site-packages/uvloop/sslproto.pxd b/lib/python3.12/site-packages/uvloop/sslproto.pxd
new file mode 100644
index 0000000000000000000000000000000000000000..3da10f00cf56ee227c7cda6212f73ca0acd34a1b
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/sslproto.pxd
@@ -0,0 +1,138 @@
+cdef enum SSLProtocolState:
+    UNWRAPPED = 0
+    DO_HANDSHAKE = 1
+    WRAPPED = 2
+    FLUSHING = 3
+    SHUTDOWN = 4
+
+
+cdef enum AppProtocolState:
+    # This tracks the state of app protocol (https://git.io/fj59P):
+    #
+    #     INIT -cm-> CON_MADE [-dr*->] [-er-> EOF?] -cl-> CON_LOST
+    #
+    # * cm: connection_made()
+    # * dr: data_received()
+    # * er: eof_received()
+    # * cl: connection_lost()
+
+    STATE_INIT = 0
+    STATE_CON_MADE = 1
+    STATE_EOF = 2
+    STATE_CON_LOST = 3
+
+
+cdef class _SSLProtocolTransport:
+    cdef:
+        Loop _loop
+        SSLProtocol _ssl_protocol
+        bint _closed
+        object context
+
+
+cdef class SSLProtocol:
+    cdef:
+        bint _server_side
+        str _server_hostname
+        object _sslcontext
+
+        object _extra
+
+        object _write_backlog
+        size_t _write_buffer_size
+
+        object _waiter
+        Loop _loop
+        _SSLProtocolTransport _app_transport
+        bint _app_transport_created
+
+        object _transport
+        object _ssl_handshake_timeout
+        object _ssl_shutdown_timeout
+
+        object _sslobj
+        object _sslobj_read
+        object _sslobj_write
+        object _incoming
+        object _incoming_write
+        object _outgoing
+        object _outgoing_read
+        char* _ssl_buffer
+        size_t _ssl_buffer_len
+        object _ssl_buffer_view
+        SSLProtocolState _state
+        size_t _conn_lost
+        AppProtocolState _app_state
+
+        bint _ssl_writing_paused
+        bint _app_reading_paused
+
+        size_t _incoming_high_water
+        size_t _incoming_low_water
+        bint _ssl_reading_paused
+
+        bint _app_writing_paused
+        size_t _outgoing_high_water
+        size_t _outgoing_low_water
+
+        object _app_protocol
+        bint _app_protocol_is_buffer
+        object _app_protocol_get_buffer
+        object _app_protocol_buffer_updated
+
+        object _handshake_start_time
+        object _handshake_timeout_handle
+        object _shutdown_timeout_handle
+
+    cdef _set_app_protocol(self, app_protocol)
+    cdef _wakeup_waiter(self, exc=*)
+    cdef _get_extra_info(self, name, default=*)
+    cdef _set_state(self, SSLProtocolState new_state)
+
+    # Handshake flow
+
+    cdef _start_handshake(self)
+    cdef _check_handshake_timeout(self)
+    cdef _do_handshake(self)
+    cdef _on_handshake_complete(self, handshake_exc)
+
+    # Shutdown flow
+
+    cdef _start_shutdown(self, object context=*)
+    cdef _check_shutdown_timeout(self)
+    cdef _do_read_into_void(self, object context)
+    cdef _do_flush(self, object context=*)
+    cdef _do_shutdown(self, object context=*)
+    cdef _on_shutdown_complete(self, shutdown_exc)
+    cdef _abort(self, exc)
+
+    # Outgoing flow
+
+    cdef _write_appdata(self, list_of_data, object context)
+    cdef _do_write(self)
+    cdef _process_outgoing(self)
+
+    # Incoming flow
+
+    cdef _do_read(self)
+    cdef _do_read__buffered(self)
+    cdef _do_read__copied(self)
+    cdef _call_eof_received(self, object context=*)
+
+    # Flow control for writes from APP socket
+
+    cdef _control_app_writing(self, object context=*)
+    cdef size_t _get_write_buffer_size(self)
+    cdef _set_write_buffer_limits(self, high=*, low=*)
+
+    # Flow control for reads to APP socket
+
+    cdef _pause_reading(self)
+    cdef _resume_reading(self, object context)
+
+    # Flow control for reads from SSL socket
+
+    cdef _control_ssl_reading(self)
+    cdef _set_read_buffer_limits(self, high=*, low=*)
+    cdef size_t _get_read_buffer_size(self)
+    cdef _fatal_error(self, exc, message=*)
diff --git a/lib/python3.12/site-packages/uvloop/sslproto.pyx b/lib/python3.12/site-packages/uvloop/sslproto.pyx
new file mode 100644
index 0000000000000000000000000000000000000000..42bb76447ce9b36506a7f494ce6b0825503d389a
--- /dev/null
+++ b/lib/python3.12/site-packages/uvloop/sslproto.pyx
@@ -0,0 +1,950 @@
+cdef _create_transport_context(server_side, server_hostname):
+    if server_side:
+        raise ValueError('Server side SSL needs a valid SSLContext')
+
+    # Client side may pass ssl=True to use a default
+    # context; in that case the sslcontext passed is None.
+    # The default is secure for client connections.
+    # Python 3.4+: use up-to-date strong settings.
+    sslcontext = ssl_create_default_context()
+    if not server_hostname:
+        sslcontext.check_hostname = False
+    return sslcontext
+
+
+cdef class _SSLProtocolTransport:
+
+    # TODO:
+    # _sendfile_compatible = constants._SendfileMode.FALLBACK
+
+    def __cinit__(self, Loop loop, ssl_protocol, context):
+        self._loop = loop
+        # SSLProtocol instance
+        self._ssl_protocol = ssl_protocol
+        self._closed = False
+        if context is None:
+            context = Context_CopyCurrent()
+        self.context = context
+
+    def get_extra_info(self, name, default=None):
+        """Get optional transport information."""
+        return self._ssl_protocol._get_extra_info(name, default)
+
+    def set_protocol(self, protocol):
+        self._ssl_protocol._set_app_protocol(protocol)
+
+    def get_protocol(self):
+        return self._ssl_protocol._app_protocol
+
+    def is_closing(self):
+        return self._closed
+
+    def close(self):
+        """Close the transport.
+
+        Buffered data will be flushed asynchronously.  No more data
+        will be received.  After all buffered data is flushed, the
+        protocol's connection_lost() method will (eventually) called
+        with None as its argument.
+        """
+        self._closed = True
+        self._ssl_protocol._start_shutdown(self.context.copy())
+
+    def __dealloc__(self):
+        if not self._closed:
+            self._closed = True
+            warnings_warn(
+                "unclosed transport ", ResourceWarning)
+
+    def is_reading(self):
+        return not self._ssl_protocol._app_reading_paused
+
+    def pause_reading(self):
+        """Pause the receiving end.
+
+        No data will be passed to the protocol's data_received()
+        method until resume_reading() is called.
+        """
+        self._ssl_protocol._pause_reading()
+
+    def resume_reading(self):
+        """Resume the receiving end.
+
+        Data received will once again be passed to the protocol's
+        data_received() method.
+        """
+        self._ssl_protocol._resume_reading(self.context.copy())
+
+    def set_write_buffer_limits(self, high=None, low=None):
+        """Set the high- and low-water limits for write flow control.
+
+        These two values control when to call the protocol's
+        pause_writing() and resume_writing() methods.  If specified,
+        the low-water limit must be less than or equal to the
+        high-water limit.  Neither value can be negative.
+
+        The defaults are implementation-specific.  If only the
+        high-water limit is given, the low-water limit defaults to an
+        implementation-specific value less than or equal to the
+        high-water limit.  Setting high to zero forces low to zero as
+        well, and causes pause_writing() to be called whenever the
+        buffer becomes non-empty.  Setting low to zero causes
+        resume_writing() to be called only once the buffer is empty.
+        Use of zero for either limit is generally sub-optimal as it
+        reduces opportunities for doing I/O and computation
+        concurrently.
+        """
+        self._ssl_protocol._set_write_buffer_limits(high, low)
+        self._ssl_protocol._control_app_writing(self.context.copy())
+
+    def get_write_buffer_limits(self):
+        return (self._ssl_protocol._outgoing_low_water,
+                self._ssl_protocol._outgoing_high_water)
+
+    def get_write_buffer_size(self):
+        """Return the current size of the write buffers."""
+        return self._ssl_protocol._get_write_buffer_size()
+
+    def set_read_buffer_limits(self, high=None, low=None):
+        """Set the high- and low-water limits for read flow control.
+
+        These two values control when to call the upstream transport's
+        pause_reading() and resume_reading() methods.  If specified,
+        the low-water limit must be less than or equal to the
+        high-water limit.  Neither value can be negative.
+
+        The defaults are implementation-specific.  If only the
+        high-water limit is given, the low-water limit defaults to an
+        implementation-specific value less than or equal to the
+        high-water limit.  Setting high to zero forces low to zero as
+        well, and causes pause_reading() to be called whenever the
+        buffer becomes non-empty.  Setting low to zero causes
+        resume_reading() to be called only once the buffer is empty.
+        Use of zero for either limit is generally sub-optimal as it
+        reduces opportunities for doing I/O and computation
+        concurrently.
+        """
+        self._ssl_protocol._set_read_buffer_limits(high, low)
+        self._ssl_protocol._control_ssl_reading()
+
+    def get_read_buffer_limits(self):
+        return (self._ssl_protocol._incoming_low_water,
+                self._ssl_protocol._incoming_high_water)
+
+    def get_read_buffer_size(self):
+        """Return the current size of the read buffer."""
+        return self._ssl_protocol._get_read_buffer_size()
+
+    @property
+    def _protocol_paused(self):
+        # Required for sendfile fallback pause_writing/resume_writing logic
+        return self._ssl_protocol._app_writing_paused
+
+    def write(self, data):
+        """Write some data bytes to the transport.
+
+        This does not block; it buffers the data and arranges for it
+        to be sent out asynchronously.
+        """
+        if not isinstance(data, (bytes, bytearray, memoryview)):
+            raise TypeError(f"data: expecting a bytes-like instance, "
+                            f"got {type(data).__name__}")
+        if not data:
+            return
+        self._ssl_protocol._write_appdata((data,), self.context.copy())
+
+    def writelines(self, list_of_data):
+        """Write a list (or any iterable) of data bytes to the transport.
+
+        The default implementation concatenates the arguments and
+        calls write() on the result.
+        """
+        self._ssl_protocol._write_appdata(list_of_data, self.context.copy())
+
+    def write_eof(self):
+        """Close the write end after flushing buffered data.
+
+        This raises :exc:`NotImplementedError` right now.
+        """
+        raise NotImplementedError
+
+    def can_write_eof(self):
+        """Return True if this transport supports write_eof(), False if not."""
+        return False
+
+    def abort(self):
+        """Close the transport immediately.
+
+        Buffered data will be lost.  No more data will be received.
+        The protocol's connection_lost() method will (eventually) be
+        called with None as its argument.
+        """
+        self._force_close(None)
+
+    def _force_close(self, exc):
+        self._closed = True
+        self._ssl_protocol._abort(exc)
+
+    def _test__append_write_backlog(self, data):
+        # for test only
+        self._ssl_protocol._write_backlog.append(data)
+        self._ssl_protocol._write_buffer_size += len(data)
+
+
+cdef class SSLProtocol:
+    """SSL protocol.
+
+    Implementation of SSL on top of a socket using incoming and outgoing
+    buffers which are ssl.MemoryBIO objects.
+    """
+
+    def __cinit__(self, *args, **kwargs):
+        self._ssl_buffer_len = SSL_READ_MAX_SIZE
+        self._ssl_buffer = PyMem_RawMalloc(self._ssl_buffer_len)
+        if not self._ssl_buffer:
+            raise MemoryError()
+        self._ssl_buffer_view = PyMemoryView_FromMemory(
+            self._ssl_buffer, self._ssl_buffer_len, PyBUF_WRITE)
+
+    def __dealloc__(self):
+        self._ssl_buffer_view = None
+        PyMem_RawFree(self._ssl_buffer)
+        self._ssl_buffer = NULL
+        self._ssl_buffer_len = 0
+
+    def __init__(self, loop, app_protocol, sslcontext, waiter,
+                 server_side=False, server_hostname=None,
+                 call_connection_made=True,
+                 ssl_handshake_timeout=None,
+                 ssl_shutdown_timeout=None):
+        if ssl_handshake_timeout is None:
+            ssl_handshake_timeout = SSL_HANDSHAKE_TIMEOUT
+        elif ssl_handshake_timeout <= 0:
+            raise ValueError(
+                f"ssl_handshake_timeout should be a positive number, "
+                f"got {ssl_handshake_timeout}")
+        if ssl_shutdown_timeout is None:
+            ssl_shutdown_timeout = SSL_SHUTDOWN_TIMEOUT
+        elif ssl_shutdown_timeout <= 0:
+            raise ValueError(
+                f"ssl_shutdown_timeout should be a positive number, "
+                f"got {ssl_shutdown_timeout}")
+
+        if not sslcontext:
+            sslcontext = _create_transport_context(
+                server_side, server_hostname)
+
+        self._server_side = server_side
+        if server_hostname and not server_side:
+            self._server_hostname = server_hostname
+        else:
+            self._server_hostname = None
+        self._sslcontext = sslcontext
+        # SSL-specific extra info. More info are set when the handshake
+        # completes.
+        self._extra = dict(sslcontext=sslcontext)
+
+        # App data write buffering
+        self._write_backlog = col_deque()
+        self._write_buffer_size = 0
+
+        self._waiter = waiter
+        self._loop = loop
+        self._set_app_protocol(app_protocol)
+        self._app_transport = None
+        self._app_transport_created = False
+        # transport, ex: SelectorSocketTransport
+        self._transport = None
+        self._ssl_handshake_timeout = ssl_handshake_timeout
+        self._ssl_shutdown_timeout = ssl_shutdown_timeout
+        # SSL and state machine
+        self._sslobj = None
+        self._incoming = ssl_MemoryBIO()
+        self._incoming_write = self._incoming.write
+        self._outgoing = ssl_MemoryBIO()
+        self._outgoing_read = self._outgoing.read
+        self._state = UNWRAPPED
+        self._conn_lost = 0  # Set when connection_lost called
+        if call_connection_made:
+            self._app_state = STATE_INIT
+        else:
+            self._app_state = STATE_CON_MADE
+
+        # Flow Control
+
+        self._ssl_writing_paused = False
+
+        self._app_reading_paused = False
+
+        self._ssl_reading_paused = False
+        self._incoming_high_water = 0
+        self._incoming_low_water = 0
+        self._set_read_buffer_limits()
+
+        self._app_writing_paused = False
+        self._outgoing_high_water = 0
+        self._outgoing_low_water = 0
+        self._set_write_buffer_limits()
+
+    cdef _set_app_protocol(self, app_protocol):
+        self._app_protocol = app_protocol
+        if (hasattr(app_protocol, 'get_buffer') and
+                not isinstance(app_protocol, aio_Protocol)):
+            self._app_protocol_get_buffer = app_protocol.get_buffer
+            self._app_protocol_buffer_updated = app_protocol.buffer_updated
+            self._app_protocol_is_buffer = True
+        else:
+            self._app_protocol_is_buffer = False
+
+    cdef _wakeup_waiter(self, exc=None):
+        if self._waiter is None:
+            return
+        if not self._waiter.cancelled():
+            if exc is not None:
+                self._waiter.set_exception(exc)
+            else:
+                self._waiter.set_result(None)
+        self._waiter = None
+
+    def _get_app_transport(self, context=None):
+        if self._app_transport is None:
+            if self._app_transport_created:
+                raise RuntimeError('Creating _SSLProtocolTransport twice')
+            self._app_transport = _SSLProtocolTransport(self._loop, self,
+                                                        context)
+            self._app_transport_created = True
+        return self._app_transport
+
+    def connection_made(self, transport):
+        """Called when the low-level connection is made.
+
+        Start the SSL handshake.
+        """
+        self._transport = transport
+        self._start_handshake()
+
+    def connection_lost(self, exc):
+        """Called when the low-level connection is lost or closed.
+
+        The argument is an exception object or None (the latter
+        meaning a regular EOF is received or the connection was
+        aborted or closed).
+        """
+        self._write_backlog.clear()
+        self._outgoing_read()
+        self._conn_lost += 1
+
+        # Just mark the app transport as closed so that its __dealloc__
+        # doesn't complain.
+        if self._app_transport is not None:
+            self._app_transport._closed = True
+
+        if self._state != DO_HANDSHAKE:
+            if self._app_state == STATE_CON_MADE or \
+                    self._app_state == STATE_EOF:
+                self._app_state = STATE_CON_LOST
+                self._loop.call_soon(self._app_protocol.connection_lost, exc)
+        self._set_state(UNWRAPPED)
+        self._transport = None
+        self._app_transport = None
+        self._app_protocol = None
+        self._wakeup_waiter(exc)
+
+        if self._shutdown_timeout_handle:
+            self._shutdown_timeout_handle.cancel()
+            self._shutdown_timeout_handle = None
+        if self._handshake_timeout_handle:
+            self._handshake_timeout_handle.cancel()
+            self._handshake_timeout_handle = None
+
+    def get_buffer(self, n):
+        cdef size_t want = n
+        if want > SSL_READ_MAX_SIZE:
+            want = SSL_READ_MAX_SIZE
+        if self._ssl_buffer_len < want:
+            self._ssl_buffer = PyMem_RawRealloc(self._ssl_buffer, want)
+            if not self._ssl_buffer:
+                raise MemoryError()
+            self._ssl_buffer_len = want
+            self._ssl_buffer_view = PyMemoryView_FromMemory(
+                self._ssl_buffer, want, PyBUF_WRITE)
+        return self._ssl_buffer_view
+
+    def buffer_updated(self, nbytes):
+        self._incoming_write(PyMemoryView_FromMemory(
+            self._ssl_buffer, nbytes, PyBUF_WRITE))
+
+        if self._state == DO_HANDSHAKE:
+            self._do_handshake()
+
+        elif self._state == WRAPPED:
+            self._do_read()
+
+        elif self._state == FLUSHING:
+            self._do_flush()
+
+        elif self._state == SHUTDOWN:
+            self._do_shutdown()
+
+    def eof_received(self):
+        """Called when the other end of the low-level stream
+        is half-closed.
+
+        If this returns a false value (including None), the transport
+        will close itself.  If it returns a true value, closing the
+        transport is up to the protocol.
+        """
+        try:
+            if self._loop.get_debug():
+                aio_logger.debug("%r received EOF", self)
+
+            if self._state == DO_HANDSHAKE:
+                self._on_handshake_complete(ConnectionResetError)
+
+            elif self._state == WRAPPED or self._state == FLUSHING:
+                # We treat a low-level EOF as a critical situation similar to a
+                # broken connection - just send whatever is in the buffer and
+                # close. No application level eof_received() is called -
+                # because we don't want the user to think that this is a
+                # graceful shutdown triggered by SSL "close_notify".
+                self._set_state(SHUTDOWN)
+                self._on_shutdown_complete(None)
+
+            elif self._state == SHUTDOWN:
+                self._on_shutdown_complete(None)
+
+        except Exception:
+            self._transport.close()
+            raise
+
+    cdef _get_extra_info(self, name, default=None):
+        if name == 'uvloop.sslproto':
+            return self
+        elif name in self._extra:
+            return self._extra[name]
+        elif self._transport is not None:
+            return self._transport.get_extra_info(name, default)
+        else:
+            return default
+
+    cdef _set_state(self, SSLProtocolState new_state):
+        cdef bint allowed = False
+
+        if new_state == UNWRAPPED:
+            allowed = True
+
+        elif self._state == UNWRAPPED and new_state == DO_HANDSHAKE:
+            allowed = True
+
+        elif self._state == DO_HANDSHAKE and new_state == WRAPPED:
+            allowed = True
+
+        elif self._state == WRAPPED and new_state == FLUSHING:
+            allowed = True
+
+        elif self._state == WRAPPED and new_state == SHUTDOWN:
+            allowed = True
+
+        elif self._state == FLUSHING and new_state == SHUTDOWN:
+            allowed = True
+
+        if allowed:
+            self._state = new_state
+
+        else:
+            raise RuntimeError(
+                'cannot switch state from {} to {}'.format(
+                    self._state, new_state))
+
+    # Handshake flow
+
+    cdef _start_handshake(self):
+        if self._loop.get_debug():
+            aio_logger.debug("%r starts SSL handshake", self)
+            self._handshake_start_time = self._loop.time()
+        else:
+            self._handshake_start_time = None
+
+        self._set_state(DO_HANDSHAKE)
+
+        # start handshake timeout count down
+        self._handshake_timeout_handle = \
+            self._loop.call_later(self._ssl_handshake_timeout,
+                                  lambda: self._check_handshake_timeout())
+
+        try:
+            self._sslobj = self._sslcontext.wrap_bio(
+                self._incoming, self._outgoing,
+                server_side=self._server_side,
+                server_hostname=self._server_hostname)
+            self._sslobj_read = self._sslobj.read
+            self._sslobj_write = self._sslobj.write
+        except Exception as ex:
+            self._on_handshake_complete(ex)
+        else:
+            self._do_handshake()
+
+    cdef _check_handshake_timeout(self):
+        if self._state == DO_HANDSHAKE:
+            msg = (
+                f"SSL handshake is taking longer than "
+                f"{self._ssl_handshake_timeout} seconds: "
+                f"aborting the connection"
+            )
+            self._fatal_error(ConnectionAbortedError(msg))
+
+    cdef _do_handshake(self):
+        try:
+            self._sslobj.do_handshake()
+        except ssl_SSLAgainErrors as exc:
+            self._process_outgoing()
+        except ssl_SSLError as exc:
+            self._on_handshake_complete(exc)
+        else:
+            self._on_handshake_complete(None)
+
+    cdef _on_handshake_complete(self, handshake_exc):
+        if self._handshake_timeout_handle is not None:
+            self._handshake_timeout_handle.cancel()
+            self._handshake_timeout_handle = None
+
+        sslobj = self._sslobj
+        try:
+            if handshake_exc is None:
+                self._set_state(WRAPPED)
+            else:
+                raise handshake_exc
+
+            peercert = sslobj.getpeercert()
+        except Exception as exc:
+            self._set_state(UNWRAPPED)
+            if isinstance(exc, ssl_CertificateError):
+                msg = 'SSL handshake failed on verifying the certificate'
+            else:
+                msg = 'SSL handshake failed'
+            self._fatal_error(exc, msg)
+            self._wakeup_waiter(exc)
+            return
+
+        if self._loop.get_debug():
+            dt = self._loop.time() - self._handshake_start_time
+            aio_logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3)
+
+        # Add extra info that becomes available after handshake.
+        self._extra.update(peercert=peercert,
+                           cipher=sslobj.cipher(),
+                           compression=sslobj.compression(),
+                           ssl_object=sslobj)
+        if self._app_state == STATE_INIT:
+            self._app_state = STATE_CON_MADE
+            self._app_protocol.connection_made(self._get_app_transport())
+        self._wakeup_waiter()
+
+        # We should wakeup user code before sending the first data below. In
+        # case of `start_tls()`, the user can only get the SSLTransport in the
+        # wakeup callback, because `connection_made()` is not called again.
+        # We should schedule the first data later than the wakeup callback so
+        # that the user get a chance to e.g. check ALPN with the transport
+        # before having to handle the first data.
+        self._loop._call_soon_handle(
+            new_MethodHandle(self._loop,
+                             "SSLProtocol._do_read",
+                              self._do_read,
+                             None,  # current context is good
+                             self))
+
+    # Shutdown flow
+
+    cdef _start_shutdown(self, object context=None):
+        if self._state in (FLUSHING, SHUTDOWN, UNWRAPPED):
+            return
+        # we don't need the context for _abort or the timeout, because
+        # TCP transport._force_close() should be able to call
+        # connection_lost() in the right context
+        if self._app_transport is not None:
+            self._app_transport._closed = True
+        if self._state == DO_HANDSHAKE:
+            self._abort(None)
+        else:
+            self._set_state(FLUSHING)
+            self._shutdown_timeout_handle = \
+                self._loop.call_later(self._ssl_shutdown_timeout,
+                                      lambda: self._check_shutdown_timeout())
+            self._do_flush(context)
+
+    cdef _check_shutdown_timeout(self):
+        if self._state in (FLUSHING, SHUTDOWN):
+            self._transport._force_close(
+                aio_TimeoutError('SSL shutdown timed out'))
+
+    cdef _do_read_into_void(self, object context):
+        """Consume and discard incoming application data.
+
+        If close_notify is received for the first time, call eof_received.
+        """
+        cdef:
+            bint close_notify = False
+        try:
+            while True:
+                if not self._sslobj_read(SSL_READ_MAX_SIZE):
+                    close_notify = True
+                    break
+        except ssl_SSLAgainErrors as exc:
+            pass
+        except ssl_SSLZeroReturnError:
+            close_notify = True
+        if close_notify:
+            self._call_eof_received(context)
+
+    cdef _do_flush(self, object context=None):
+        """Flush the write backlog, discarding new data received.
+
+        We don't send close_notify in FLUSHING because we still want to send
+        the remaining data over SSL, even if we received a close_notify. Also,
+        no application-level resume_writing() or pause_writing() will be called
+        in FLUSHING, as we could fully manage the flow control internally.
+        """
+        try:
+            self._do_read_into_void(context)
+            self._do_write()
+            self._process_outgoing()
+            self._control_ssl_reading()
+        except Exception as ex:
+            self._on_shutdown_complete(ex)
+        else:
+            if not self._get_write_buffer_size():
+                self._set_state(SHUTDOWN)
+                self._do_shutdown(context)
+
+    cdef _do_shutdown(self, object context=None):
+        """Send close_notify and wait for the same from the peer."""
+        try:
+            # we must skip all application data (if any) before unwrap
+            self._do_read_into_void(context)
+            try:
+                self._sslobj.unwrap()
+            except ssl_SSLAgainErrors as exc:
+                self._process_outgoing()
+            else:
+                self._process_outgoing()
+                if not self._get_write_buffer_size():
+                    self._on_shutdown_complete(None)
+        except Exception as ex:
+            self._on_shutdown_complete(ex)
+
+    cdef _on_shutdown_complete(self, shutdown_exc):
+        if self._shutdown_timeout_handle is not None:
+            self._shutdown_timeout_handle.cancel()
+            self._shutdown_timeout_handle = None
+
+        # we don't need the context here because TCP transport.close() should
+        # be able to call connection_made() in the right context
+        if shutdown_exc:
+            self._fatal_error(shutdown_exc, 'Error occurred during shutdown')
+        else:
+            self._transport.close()
+
+    cdef _abort(self, exc):
+        self._set_state(UNWRAPPED)
+        if self._transport is not None:
+            self._transport._force_close(exc)
+
+    # Outgoing flow
+
+    cdef _write_appdata(self, list_of_data, object context):
+        if self._state in (FLUSHING, SHUTDOWN, UNWRAPPED):
+            if self._conn_lost >= LOG_THRESHOLD_FOR_CONNLOST_WRITES:
+                aio_logger.warning('SSL connection is closed')
+            self._conn_lost += 1
+            return
+
+        for data in list_of_data:
+            self._write_backlog.append(data)
+            self._write_buffer_size += len(data)
+
+        try:
+            if self._state == WRAPPED:
+                self._do_write()
+                self._process_outgoing()
+                self._control_app_writing(context)
+
+        except Exception as ex:
+            self._fatal_error(ex, 'Fatal error on SSL protocol')
+
+    cdef _do_write(self):
+        """Do SSL write, consumes write backlog and fills outgoing BIO."""
+        cdef size_t data_len, count
+        try:
+            while self._write_backlog:
+                data = self._write_backlog[0]
+                count = self._sslobj_write(data)
+                data_len = len(data)
+                if count < data_len:
+                    if not PyMemoryView_Check(data):
+                        data = PyMemoryView_FromObject(data)
+                    self._write_backlog[0] = data[count:]
+                    self._write_buffer_size -= count
+                else:
+                    del self._write_backlog[0]
+                    self._write_buffer_size -= data_len
+        except ssl_SSLAgainErrors as exc:
+            pass
+
+    cdef _process_outgoing(self):
+        """Send bytes from the outgoing BIO."""
+        if not self._ssl_writing_paused:
+            data = self._outgoing_read()
+            if len(data):
+                self._transport.write(data)
+
+    # Incoming flow
+
+    cdef _do_read(self):
+        if self._state != WRAPPED:
+            return
+        try:
+            if not self._app_reading_paused:
+                if self._app_protocol_is_buffer:
+                    self._do_read__buffered()
+                else:
+                    self._do_read__copied()
+                if self._write_backlog:
+                    self._do_write()
+                self._process_outgoing()
+                self._control_app_writing()
+            self._control_ssl_reading()
+        except Exception as ex:
+            self._fatal_error(ex, 'Fatal error on SSL protocol')
+
+    cdef _do_read__buffered(self):
+        cdef:
+            Py_buffer pybuf
+            bint pybuf_inited = False
+            size_t wants, offset = 0
+            int count = 1
+            object buf
+
+        buf = self._app_protocol_get_buffer(self._get_read_buffer_size())
+        wants = len(buf)
+
+        try:
+            count = self._sslobj_read(wants, buf)
+
+            if count > 0:
+                offset = count
+                if offset < wants:
+                    PyObject_GetBuffer(buf, &pybuf, PyBUF_WRITABLE)
+                    pybuf_inited = True
+                while offset < wants:
+                    buf = PyMemoryView_FromMemory(
+                        (pybuf.buf) + offset,
+                        wants - offset,
+                        PyBUF_WRITE)
+                    count = self._sslobj_read(wants - offset, buf)
+                    if count > 0:
+                        offset += count
+                    else:
+                        break
+                else:
+                    self._loop._call_soon_handle(
+                        new_MethodHandle(self._loop,
+                                         "SSLProtocol._do_read",
+                                         self._do_read,
+                                         None,  # current context is good
+                                         self))
+        except ssl_SSLAgainErrors as exc:
+            pass
+        finally:
+            if pybuf_inited:
+                PyBuffer_Release(&pybuf)
+        if offset > 0:
+            self._app_protocol_buffer_updated(offset)
+        if not count:
+            # close_notify
+            self._call_eof_received()
+            self._start_shutdown()
+
+    cdef _do_read__copied(self):
+        cdef:
+            list data
+            bytes first, chunk = b'1'
+            bint zero = True, one = False
+
+        try:
+            while True:
+                chunk = self._sslobj_read(SSL_READ_MAX_SIZE)
+                if not chunk:
+                    break
+                if zero:
+                    zero = False
+                    one = True
+                    first = chunk
+                elif one:
+                    one = False
+                    data = [first, chunk]
+                else:
+                    data.append(chunk)
+        except ssl_SSLAgainErrors as exc:
+            pass
+        if one:
+            self._app_protocol.data_received(first)
+        elif not zero:
+            self._app_protocol.data_received(b''.join(data))
+        if not chunk:
+            # close_notify
+            self._call_eof_received()
+            self._start_shutdown()
+
+    cdef _call_eof_received(self, object context=None):
+        if self._app_state == STATE_CON_MADE:
+            self._app_state = STATE_EOF
+            try:
+                if context is None:
+                    # If the caller didn't provide a context, we assume the
+                    # caller is already in the right context, which is usually
+                    # inside the upstream callbacks like buffer_updated()
+                    keep_open = self._app_protocol.eof_received()
+                else:
+                    keep_open = run_in_context(
+                        context, self._app_protocol.eof_received,
+                    )
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException as ex:
+                self._fatal_error(ex, 'Error calling eof_received()')
+            else:
+                if keep_open:
+                    aio_logger.warning('returning true from eof_received() '
+                                       'has no effect when using ssl')
+
+    # Flow control for writes from APP socket
+
+    cdef _control_app_writing(self, object context=None):
+        cdef size_t size = self._get_write_buffer_size()
+        if size >= self._outgoing_high_water and not self._app_writing_paused:
+            self._app_writing_paused = True
+            try:
+                if context is None:
+                    # If the caller didn't provide a context, we assume the
+                    # caller is already in the right context, which is usually
+                    # inside the upstream callbacks like buffer_updated()
+                    self._app_protocol.pause_writing()
+                else:
+                    run_in_context(context, self._app_protocol.pause_writing)
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException as exc:
+                self._loop.call_exception_handler({
+                    'message': 'protocol.pause_writing() failed',
+                    'exception': exc,
+                    'transport': self._app_transport,
+                    'protocol': self,
+                })
+        elif size <= self._outgoing_low_water and self._app_writing_paused:
+            self._app_writing_paused = False
+            try:
+                if context is None:
+                    # If the caller didn't provide a context, we assume the
+                    # caller is already in the right context, which is usually
+                    # inside the upstream callbacks like resume_writing()
+                    self._app_protocol.resume_writing()
+                else:
+                    run_in_context(context, self._app_protocol.resume_writing)
+            except (KeyboardInterrupt, SystemExit):
+                raise
+            except BaseException as exc:
+                self._loop.call_exception_handler({
+                    'message': 'protocol.resume_writing() failed',
+                    'exception': exc,
+                    'transport': self._app_transport,
+                    'protocol': self,
+                })
+
+    cdef size_t _get_write_buffer_size(self):
+        return self._outgoing.pending + self._write_buffer_size
+
+    cdef _set_write_buffer_limits(self, high=None, low=None):
+        high, low = add_flowcontrol_defaults(
+            high, low, FLOW_CONTROL_HIGH_WATER_SSL_WRITE)
+        self._outgoing_high_water = high
+        self._outgoing_low_water = low
+
+    # Flow control for reads to APP socket
+
+    cdef _pause_reading(self):
+        self._app_reading_paused = True
+
+    cdef _resume_reading(self, object context):
+        if self._app_reading_paused:
+            self._app_reading_paused = False
+            if self._state == WRAPPED:
+                self._loop._call_soon_handle(
+                    new_MethodHandle(self._loop,
+                                     "SSLProtocol._do_read",
+                                     self._do_read,
+                                     context,
+                                     self))
+
+    # Flow control for reads from SSL socket
+
+    cdef _control_ssl_reading(self):
+        cdef size_t size = self._get_read_buffer_size()
+        if size >= self._incoming_high_water and not self._ssl_reading_paused:
+            self._ssl_reading_paused = True
+            self._transport.pause_reading()
+        elif size <= self._incoming_low_water and self._ssl_reading_paused:
+            self._ssl_reading_paused = False
+            self._transport.resume_reading()
+
+    cdef _set_read_buffer_limits(self, high=None, low=None):
+        high, low = add_flowcontrol_defaults(
+            high, low, FLOW_CONTROL_HIGH_WATER_SSL_READ)
+        self._incoming_high_water = high
+        self._incoming_low_water = low
+
+    cdef size_t _get_read_buffer_size(self):
+        return self._incoming.pending
+
+    # Flow control for writes to SSL socket
+
+    def pause_writing(self):
+        """Called when the low-level transport's buffer goes over
+        the high-water mark.
+        """
+        assert not self._ssl_writing_paused
+        self._ssl_writing_paused = True
+
+    def resume_writing(self):
+        """Called when the low-level transport's buffer drains below
+        the low-water mark.
+        """
+        assert self._ssl_writing_paused
+        self._ssl_writing_paused = False
+
+        if self._state == WRAPPED:
+            self._process_outgoing()
+            self._control_app_writing()
+
+        elif self._state == FLUSHING:
+            self._do_flush()
+
+        elif self._state == SHUTDOWN:
+            self._do_shutdown()
+
+    cdef _fatal_error(self, exc, message='Fatal error on transport'):
+        if self._app_transport:
+            self._app_transport._force_close(exc)
+        elif self._transport:
+            self._transport._force_close(exc)
+
+        if isinstance(exc, OSError):
+            if self._loop.get_debug():
+                aio_logger.debug("%r: %s", self, message, exc_info=True)
+        elif not isinstance(exc, aio_CancelledError):
+            self._loop.call_exception_handler({
+                'message': message,
+                'exception': exc,
+                'transport': self._transport,
+                'protocol': self,
+            })
diff --git a/lib/python3.12/site-packages/wcwidth/__init__.py b/lib/python3.12/site-packages/wcwidth/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..ffb13207b61838ca291c0a6ae6653fae4ce0f918
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/__init__.py
@@ -0,0 +1,43 @@
+"""
+Wcwidth module.
+
+https://github.com/jquast/wcwidth
+"""
+# re-export all functions & definitions, even private ones, from top-level
+# module path, to allow for 'from wcwidth import _private_func'.  Of course,
+# user beware that any _private functions or variables not exported by __all__
+# may disappear or change signature at any future version.
+
+# local
+from .wcwidth import ZERO_WIDTH  # noqa
+from .wcwidth import (WIDE_EASTASIAN,
+                      AMBIGUOUS_EASTASIAN,
+                      VS16_NARROW_TO_WIDE,
+                      clip,
+                      ljust,
+                      rjust,
+                      width,
+                      center,
+                      wcwidth,
+                      wcswidth,
+                      list_versions,
+                      iter_sequences,
+                      strip_sequences,
+                      _wcmatch_version,
+                      _wcversion_value)
+from .bisearch import bisearch as _bisearch
+from .grapheme import grapheme_boundary_before  # noqa
+from .grapheme import iter_graphemes, iter_graphemes_reverse
+from .textwrap import SequenceTextWrapper, wrap
+from .sgr_state import propagate_sgr
+
+# The __all__ attribute defines the items exported from statement,
+# 'from wcwidth import *', but also to say, "This is the public API".
+__all__ = ('wcwidth', 'wcswidth', 'width', 'iter_sequences', 'iter_graphemes',
+           'iter_graphemes_reverse', 'grapheme_boundary_before',
+           'ljust', 'rjust', 'center', 'wrap', 'clip', 'strip_sequences',
+           'list_versions', 'propagate_sgr')
+
+# Using 'hatchling', it does not seem to provide the pyproject.toml nicety, "dynamic = ['version']"
+# like flit_core, maybe there is some better way but for now we have to duplicate it in both places
+__version__ = '0.5.3'
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/__init__.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d34680aab30b68c43270a79c26ae8b113568cc88
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/__init__.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/bisearch.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/bisearch.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ed40fa85f959b85956fa6a905938c505c7f92f46
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/bisearch.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/control_codes.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/control_codes.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c0227bff80893c66e94712ef6bcc0e482c90d0c7
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/control_codes.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/escape_sequences.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/escape_sequences.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9b9ea1dda169cf53f556acfbad3478ee72b0806a
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/escape_sequences.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/grapheme.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/grapheme.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..20219d5436f41b5e675a1841fcb4b6cd4aba85b1
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/grapheme.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/sgr_state.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/sgr_state.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..18716d9268f97c6bcec326bc9b9cd9cb0696122b
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/sgr_state.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/table_ambiguous.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/table_ambiguous.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..26c831996aa5cafc7f48f681648d17d557e03dc4
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/table_ambiguous.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/table_grapheme.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/table_grapheme.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c6c1a617d004b2ce53373c13f2f425e77c2799a0
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/table_grapheme.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/table_mc.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/table_mc.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f2c91fdc08011a548b607dc4df21381d6f021da2
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/table_mc.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/table_vs16.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/table_vs16.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..eb9fbe03708c459d65a75512003de1c028543d5b
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/table_vs16.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/table_zero.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/table_zero.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..fd7b819e1198a044207e5a9e82862193ee1e00ce
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/table_zero.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/textwrap.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/textwrap.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dbc341848c449a5e4701a4c0f5cadb04d433958d
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/textwrap.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/unicode_versions.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/unicode_versions.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..962474f24b74633de2b4fdbb37732e7091152b90
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/unicode_versions.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/__pycache__/wcwidth.cpython-312.pyc b/lib/python3.12/site-packages/wcwidth/__pycache__/wcwidth.cpython-312.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c730bcf2b2f1ffaa5c1bc15700ce3e3fa5fd0590
Binary files /dev/null and b/lib/python3.12/site-packages/wcwidth/__pycache__/wcwidth.cpython-312.pyc differ
diff --git a/lib/python3.12/site-packages/wcwidth/bisearch.py b/lib/python3.12/site-packages/wcwidth/bisearch.py
new file mode 100644
index 0000000000000000000000000000000000000000..becfe86a9d12d1788f0c8f3593d49122452d83f9
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/bisearch.py
@@ -0,0 +1,29 @@
+"""Binary search function for Unicode interval tables."""
+from __future__ import annotations
+
+
+def bisearch(ucs: int, table: tuple[tuple[int, int], ...]) -> int:
+    """
+    Binary search in interval table.
+
+    :param ucs: Ordinal value of unicode character.
+    :param table: Tuple of starting and ending ranges of ordinal values,
+        in form of ``((start, end), ...)``.
+    :returns: 1 if ordinal value ucs is found within lookup table, else 0.
+    """
+    lbound = 0
+    ubound = len(table) - 1
+
+    if ucs < table[0][0] or ucs > table[ubound][1]:
+        return 0
+
+    while ubound >= lbound:
+        mid = (lbound + ubound) // 2
+        if ucs > table[mid][1]:
+            lbound = mid + 1
+        elif ucs < table[mid][0]:
+            ubound = mid - 1
+        else:
+            return 1
+
+    return 0
diff --git a/lib/python3.12/site-packages/wcwidth/control_codes.py b/lib/python3.12/site-packages/wcwidth/control_codes.py
new file mode 100644
index 0000000000000000000000000000000000000000..3a6fff76386241c07f760391aa320fd4dddb068b
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/control_codes.py
@@ -0,0 +1,46 @@
+"""
+Control character sets for terminal handling.
+
+This module provides the control character sets used by the width() function to handle terminal
+control characters.
+"""
+
+# Illegal C0/C1 control characters.
+# These raise ValueError in 'strict' mode.
+ILLEGAL_CTRL = frozenset(
+    chr(c) for c in (
+        list(range(0x01, 0x07)) +    # SOH, STX, ETX (^C), EOT (^D), ENQ, ACK
+        list(range(0x10, 0x1b)) +    # DLE through SUB (^Z)
+        list(range(0x1c, 0x20)) +    # FS, GS, RS, US
+        [0x7f] +                      # DEL
+        list(range(0x80, 0xa0))       # C1 control characters
+    )
+)
+
+# Vertical movement control characters.
+# These raise ValueError in 'strict' mode (indeterminate horizontal position).
+VERTICAL_CTRL = frozenset({
+    '\x0a',  # LF (line feed)
+    '\x0b',  # VT (vertical tab)
+    '\x0c',  # FF (form feed)
+})
+
+# Horizontal movement control characters.
+# These affect cursor position and are tracked in 'strict' and 'parse' modes.
+HORIZONTAL_CTRL = frozenset({
+    '\x08',  # BS (backspace) - cursor left 1
+    '\x09',  # HT (horizontal tab) - advance to next tab stop
+    '\x0d',  # CR (carriage return) - cursor to column 0
+})
+
+# Terminal-valid zero-width control characters.
+# These are allowed in all modes (zero-width, no movement).
+ZERO_WIDTH_CTRL = frozenset({
+    '\x00',  # NUL
+    '\x07',  # BEL (bell)
+    '\x0e',  # SO (shift out)
+    '\x0f',  # SI (shift in)
+})
+
+# All control characters that need special handling (not regular printable).
+ALL_CTRL = ILLEGAL_CTRL | VERTICAL_CTRL | HORIZONTAL_CTRL | ZERO_WIDTH_CTRL | {'\x1b'}
diff --git a/lib/python3.12/site-packages/wcwidth/escape_sequences.py b/lib/python3.12/site-packages/wcwidth/escape_sequences.py
new file mode 100644
index 0000000000000000000000000000000000000000..d4ac6cc36db740a1c42178b7b51b2774253eeb7e
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/escape_sequences.py
@@ -0,0 +1,69 @@
+r"""
+Terminal escape sequence patterns.
+
+This module provides regex patterns for matching terminal escape sequences. All patterns match
+sequences that begin with ESC (``\x1b``). Before calling re.match with these patterns, callers
+should first check that the character at the current position is ESC for optimal performance.
+"""
+# std imports
+import re
+
+# Zero-width escape sequences (SGR, OSC, CSI, etc.). This table, like INDETERMINATE_EFFECT_SEQUENCE,
+# originated from the 'blessed' library.
+ZERO_WIDTH_PATTERN = re.compile(
+    # CSI sequences
+    r'\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]|'
+    # OSC sequences
+    r'\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|'
+    # APC sequences
+    r'\x1b_[^\x1b\x07]*(?:\x07|\x1b\\)|'
+    # DCS sequences
+    r'\x1bP[^\x1b\x07]*(?:\x07|\x1b\\)|'
+    # PM sequences
+    r'\x1b\^[^\x1b\x07]*(?:\x07|\x1b\\)|'
+    # Character set designation
+    r'\x1b[()].|'
+    # Fe sequences
+    r'\x1b[\x40-\x5f]|'
+    # Fp sequences
+    r'\x1b[78=>g]'
+)
+
+# Cursor right movement: CSI [n] C, parameter may be parsed by width()
+CURSOR_RIGHT_SEQUENCE = re.compile(r'\x1b\[(\d*)C')
+
+# Cursor left movement: CSI [n] D, parameter may be parsed by width()
+CURSOR_LEFT_SEQUENCE = re.compile(r'\x1b\[(\d*)D')
+
+# Indeterminate effect sequences - raise ValueError in 'strict' mode. The effects of these sequences
+# are likely to be undesirable, moving the cursor vertically or to any unknown position, and
+# otherwise not managed by the 'width' method of this library.
+#
+# This table was created initially with code generation by extraction of termcap library with
+# techniques used at 'blessed' library runtime for 'xterm', 'alacritty', 'kitty', ghostty',
+# 'screen', 'tmux', and others. Then, these common capabilities were merged into the list below.
+INDETERMINATE_EFFECT_SEQUENCE = re.compile(
+    '|'.join(f'(?:{_pattern})' for _pattern in (
+        r'\x1b\[\d+;\d+r',           # change_scroll_region
+        r'\x1b\[\d*K',               # erase_in_line (clr_eol, clr_bol)
+        r'\x1b\[\d*J',               # erase_in_display (clr_eos, erase_display)
+        r'\x1b\[\d*G',               # column_address
+        r'\x1b\[\d+;\d+H',           # cursor_address
+        r'\x1b\[\d*H',               # cursor_home
+        r'\x1b\[\d*A',               # cursor_up
+        r'\x1b\[\d*B',               # cursor_down
+        r'\x1b\[\d*P',               # delete_character
+        r'\x1b\[\d*M',               # delete_line
+        r'\x1b\[\d*L',               # insert_line
+        r'\x1b\[\d*@',               # insert_character
+        r'\x1b\[\d+X',               # erase_chars
+        r'\x1b\[\d*S',               # scroll_up (parm_index)
+        r'\x1b\[\d*T',               # scroll_down (parm_rindex)
+        r'\x1b\[\d*d',               # row_address
+        r'\x1b\[\?1049[hl]',         # alternate screen buffer
+        r'\x1b\[\?47[hl]',           # alternate screen (legacy)
+        r'\x1b8',                    # restore_cursor
+        r'\x1bD',                    # scroll_forward (index)
+        r'\x1bM',                    # scroll_reverse (reverse index)
+    ))
+)
diff --git a/lib/python3.12/site-packages/wcwidth/grapheme.py b/lib/python3.12/site-packages/wcwidth/grapheme.py
new file mode 100644
index 0000000000000000000000000000000000000000..7befc92052ed94f700de8d269d7cedc4b0f72516
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/grapheme.py
@@ -0,0 +1,428 @@
+"""
+Grapheme cluster segmentation following Unicode Standard Annex #29.
+
+This module provides pure-Python implementation of the grapheme cluster boundary algorithm as
+defined in UAX #29: Unicode Text Segmentation.
+
+https://www.unicode.org/reports/tr29/
+"""
+
+from __future__ import annotations
+
+# std imports
+from enum import IntEnum
+from functools import lru_cache
+
+from typing import TYPE_CHECKING, NamedTuple
+
+# local
+from .bisearch import bisearch as _bisearch
+from .table_grapheme import (GRAPHEME_L,
+                             GRAPHEME_T,
+                             GRAPHEME_V,
+                             GRAPHEME_LV,
+                             INCB_EXTEND,
+                             INCB_LINKER,
+                             GRAPHEME_LVT,
+                             INCB_CONSONANT,
+                             GRAPHEME_EXTEND,
+                             GRAPHEME_CONTROL,
+                             GRAPHEME_PREPEND,
+                             GRAPHEME_SPACINGMARK,
+                             EXTENDED_PICTOGRAPHIC,
+                             GRAPHEME_REGIONAL_INDICATOR)
+
+if TYPE_CHECKING:  # pragma: no cover
+    # std imports
+    from collections.abc import Iterator
+
+# Maximum backward scan distance when finding grapheme cluster boundaries.
+# Covers all known Unicode grapheme clusters with margin; longer sequences are pathological.
+MAX_GRAPHEME_SCAN = 32
+
+
+class GCB(IntEnum):
+    """Grapheme Cluster Break property values."""
+
+    OTHER = 0
+    CR = 1
+    LF = 2
+    CONTROL = 3
+    EXTEND = 4
+    ZWJ = 5
+    REGIONAL_INDICATOR = 6
+    PREPEND = 7
+    SPACING_MARK = 8
+    L = 9
+    V = 10
+    T = 11
+    LV = 12
+    LVT = 13
+
+
+# All lru_cache sizes in this file use maxsize=1024, chosen by benchmarking UDHR data (500+
+# languages) and considering typical process-long sessions: western scripts need ~64 unique
+# codepoints, but CJK could reach ~2000 -- but likely not.
+@lru_cache(maxsize=1024)
+def _grapheme_cluster_break(ucs: int) -> GCB:
+    # pylint: disable=too-many-branches,too-complex
+    """Return the Grapheme_Cluster_Break property for a codepoint."""
+    # Single codepoint matches
+    if ucs == 0x000d:
+        return GCB.CR
+    if ucs == 0x000a:
+        return GCB.LF
+    if ucs == 0x200d:
+        return GCB.ZWJ
+    # Matching by codepoint ranges, requiring binary search
+    if _bisearch(ucs, GRAPHEME_CONTROL):
+        return GCB.CONTROL
+    if _bisearch(ucs, GRAPHEME_EXTEND):
+        return GCB.EXTEND
+    if _bisearch(ucs, GRAPHEME_REGIONAL_INDICATOR):
+        return GCB.REGIONAL_INDICATOR
+    if _bisearch(ucs, GRAPHEME_PREPEND):
+        return GCB.PREPEND
+    if _bisearch(ucs, GRAPHEME_SPACINGMARK):
+        return GCB.SPACING_MARK
+    if _bisearch(ucs, GRAPHEME_L):
+        return GCB.L
+    if _bisearch(ucs, GRAPHEME_V):
+        return GCB.V
+    if _bisearch(ucs, GRAPHEME_T):
+        return GCB.T
+    if _bisearch(ucs, GRAPHEME_LV):
+        return GCB.LV
+    if _bisearch(ucs, GRAPHEME_LVT):
+        return GCB.LVT
+    return GCB.OTHER
+
+
+@lru_cache(maxsize=1024)
+def _is_extended_pictographic(ucs: int) -> bool:
+    """Check if codepoint has Extended_Pictographic property."""
+    return bool(_bisearch(ucs, EXTENDED_PICTOGRAPHIC))
+
+
+@lru_cache(maxsize=1024)
+def _is_incb_linker(ucs: int) -> bool:
+    """Check if codepoint has InCB=Linker property."""
+    return bool(_bisearch(ucs, INCB_LINKER))
+
+
+@lru_cache(maxsize=1024)
+def _is_incb_consonant(ucs: int) -> bool:
+    """Check if codepoint has InCB=Consonant property."""
+    return bool(_bisearch(ucs, INCB_CONSONANT))
+
+
+@lru_cache(maxsize=1024)
+def _is_incb_extend(ucs: int) -> bool:
+    """Check if codepoint has InCB=Extend property."""
+    return bool(_bisearch(ucs, INCB_EXTEND))
+
+
+class BreakResult(NamedTuple):
+    """Result of grapheme cluster break decision."""
+
+    should_break: bool
+    ri_count: int
+
+
+@lru_cache(maxsize=1024)
+def _simple_break_check(prev_gcb: GCB, curr_gcb: GCB) -> BreakResult | None:
+    """
+    Check simple GCB-pair-based break rules (cacheable).
+
+    Returns BreakResult for rules that can be determined from GCB properties alone, or None if
+    complex lookback rules (GB9c, GB11) need to be checked.
+    """
+    # GB3: CR x LF
+    if prev_gcb == GCB.CR and curr_gcb == GCB.LF:
+        return BreakResult(should_break=False, ri_count=0)
+
+    # GB4: (Control|CR|LF) ÷
+    if prev_gcb in (GCB.CONTROL, GCB.CR, GCB.LF):
+        return BreakResult(should_break=True, ri_count=0)
+
+    # GB5: ÷ (Control|CR|LF)
+    if curr_gcb in (GCB.CONTROL, GCB.CR, GCB.LF):
+        return BreakResult(should_break=True, ri_count=0)
+
+    # GB6: L x (L|V|LV|LVT)
+    if prev_gcb == GCB.L and curr_gcb in (GCB.L, GCB.V, GCB.LV, GCB.LVT):
+        return BreakResult(should_break=False, ri_count=0)
+
+    # GB7: (LV|V) x (V|T)
+    if prev_gcb in (GCB.LV, GCB.V) and curr_gcb in (GCB.V, GCB.T):
+        return BreakResult(should_break=False, ri_count=0)
+
+    # GB8: (LVT|T) x T
+    if prev_gcb in (GCB.LVT, GCB.T) and curr_gcb == GCB.T:
+        return BreakResult(should_break=False, ri_count=0)
+
+    # GB9: x (Extend|ZWJ) - but ZWJ needs GB11 check, so only handle Extend here
+    if curr_gcb == GCB.EXTEND:
+        return BreakResult(should_break=False, ri_count=0)
+
+    # GB9a: x SpacingMark
+    if curr_gcb == GCB.SPACING_MARK:
+        return BreakResult(should_break=False, ri_count=0)
+
+    # GB9b: Prepend x
+    if prev_gcb == GCB.PREPEND:
+        return BreakResult(should_break=False, ri_count=0)
+
+    # GB9c and GB11 need lookback - return None to signal complex check needed
+    # GB12/13 (RI pairs) need ri_count state - also handled in main function
+    return None
+
+
+def _should_break(
+    prev_gcb: GCB,
+    curr_gcb: GCB,
+    text: str,
+    curr_idx: int,
+    ri_count: int,
+) -> BreakResult:
+    # pylint: disable=too-many-branches,too-complex
+    """
+    Determine if there should be a grapheme cluster break between prev and curr.
+
+    Implements UAX #29 grapheme cluster boundary rules.
+    """
+    # Try cached simple rules first
+    result = _simple_break_check(prev_gcb, curr_gcb)
+    if result is not None:
+        return result
+
+    # GB9: x ZWJ (not cached because GB11 needs lookback when prev is ZWJ)
+    if curr_gcb == GCB.ZWJ:
+        return BreakResult(should_break=False, ri_count=0)
+
+    # GB9c: Indic conjunct cluster
+    # \p{InCB=Consonant} [\p{InCB=Extend}\p{InCB=Linker}]* \p{InCB=Linker}
+    #     [\p{InCB=Extend}\p{InCB=Linker}]* x \p{InCB=Consonant}
+    curr_ucs = ord(text[curr_idx])
+    if _is_incb_consonant(curr_ucs):
+        has_linker = False
+        i = curr_idx - 1
+        while i >= 0:
+            prev_ucs = ord(text[i])
+            if _is_incb_linker(prev_ucs):
+                has_linker = True
+                i -= 1
+            elif _is_incb_extend(prev_ucs):
+                i -= 1
+            elif _is_incb_consonant(prev_ucs):
+                if has_linker:
+                    return BreakResult(should_break=False, ri_count=0)
+                break
+            else:
+                break
+
+    # GB11: ExtPict Extend* ZWJ x ExtPict
+    if prev_gcb == GCB.ZWJ and _is_extended_pictographic(curr_ucs):
+        i = curr_idx - 2  # Skip the ZWJ at curr_idx - 1
+        while i >= 0:
+            prev_ucs = ord(text[i])
+            prev_prop = _grapheme_cluster_break(prev_ucs)
+            if prev_prop == GCB.EXTEND:
+                i -= 1
+            elif _is_extended_pictographic(prev_ucs):
+                return BreakResult(should_break=False, ri_count=0)
+            else:
+                break
+
+    # GB12/GB13: RI x RI (pair matching)
+    if prev_gcb == GCB.REGIONAL_INDICATOR and curr_gcb == GCB.REGIONAL_INDICATOR:
+        if ri_count % 2 == 1:
+            return BreakResult(should_break=False, ri_count=ri_count + 1)
+        return BreakResult(should_break=True, ri_count=1)
+
+    # GB999: Any ÷ Any
+    ri_count = 1 if curr_gcb == GCB.REGIONAL_INDICATOR else 0
+    return BreakResult(should_break=True, ri_count=ri_count)
+
+
+def iter_graphemes(
+    unistr: str,
+    start: int = 0,
+    end: int | None = None,
+) -> Iterator[str]:
+    r"""
+    Iterate over grapheme clusters in a Unicode string.
+
+    Grapheme clusters are "user-perceived characters" - what a user would
+    consider a single character, which may consist of multiple Unicode
+    codepoints (e.g., a base character with combining marks, emoji sequences).
+
+    :param unistr: The Unicode string to segment.
+    :param start: Starting index (default 0).
+    :param end: Ending index (default len(unistr)).
+    :yields: Grapheme cluster substrings.
+
+    Example::
+
+        >>> list(iter_graphemes('cafe\u0301'))
+        ['c', 'a', 'f', 'e\u0301']
+        >>> list(iter_graphemes('\U0001F468\u200D\U0001F469\u200D\U0001F467'))
+        ['o', 'k', '\U0001F468\u200D\U0001F469\u200D\U0001F467']
+        >>> list(iter_graphemes('\U0001F1FA\U0001F1F8'))
+        ['o', 'k', '\U0001F1FA\U0001F1F8']
+
+    .. versionadded:: 0.3.0
+    """
+    if not unistr:
+        return
+
+    length = len(unistr)
+
+    if end is None:
+        end = length
+
+    if start >= end or start >= length:
+        return
+
+    end = min(end, length)
+
+    # Track state for grapheme cluster boundaries
+    cluster_start = start
+    ri_count = 0
+
+    # Get GCB for first character
+    prev_gcb = _grapheme_cluster_break(ord(unistr[start]))
+
+    # Handle Regional Indicator count initialization
+    if prev_gcb == GCB.REGIONAL_INDICATOR:
+        ri_count = 1
+
+    for idx in range(start + 1, end):
+        curr_gcb = _grapheme_cluster_break(ord(unistr[idx]))
+
+        result = _should_break(prev_gcb, curr_gcb, unistr, idx, ri_count)
+        ri_count = result.ri_count
+
+        if result.should_break:
+            yield unistr[cluster_start:idx]
+            cluster_start = idx
+
+        prev_gcb = curr_gcb
+
+    # Yield the final cluster
+    yield unistr[cluster_start:end]
+
+
+def _find_cluster_start(text: str, pos: int) -> int:
+    """
+    Find the start of the grapheme cluster containing the character before pos.
+
+    Scans backwards from pos to find a safe starting point, then iterates forward using standard
+    break rules to find the actual cluster boundary.
+
+    :param text: The Unicode string.
+    :param pos: Position to search before (exclusive).
+    :returns: Start position of the grapheme cluster.
+    """
+    target_cp = ord(text[pos - 1])
+
+    # GB3: CR x LF - LF after CR is part of same cluster
+    if target_cp == 0x0A and pos >= 2 and text[pos - 2] == '\r':
+        return pos - 2
+
+    # Fast path: ASCII (except LF) starts its own cluster
+    if target_cp < 0x80:
+        # GB9b: Check for preceding PREPEND (rare: Arabic/Brahmic)
+        if pos >= 2 and target_cp >= 0x20:
+            prev_cp = ord(text[pos - 2])
+            if prev_cp >= 0x80 and _grapheme_cluster_break(prev_cp) == GCB.PREPEND:
+                return _find_cluster_start(text, pos - 1)
+        return pos - 1
+
+    # Scan backward to find a safe starting point
+    safe_start = pos - 1
+    while safe_start > 0 and (pos - safe_start) < MAX_GRAPHEME_SCAN:
+        cp = ord(text[safe_start])
+        if 0x20 <= cp < 0x80:  # ASCII always starts a cluster
+            break
+        if _grapheme_cluster_break(cp) == GCB.CONTROL:  # GB4
+            break
+        safe_start -= 1
+
+    # Verify forward to find the actual cluster boundary
+    cluster_start = safe_start
+    left_gcb = _grapheme_cluster_break(ord(text[safe_start]))
+    ri_count = 1 if left_gcb == GCB.REGIONAL_INDICATOR else 0
+
+    for i in range(safe_start + 1, pos):
+        right_gcb = _grapheme_cluster_break(ord(text[i]))
+        result = _should_break(left_gcb, right_gcb, text, i, ri_count)
+        ri_count = result.ri_count
+        if result.should_break:
+            cluster_start = i
+        left_gcb = right_gcb
+
+    return cluster_start
+
+
+def grapheme_boundary_before(unistr: str, pos: int) -> int:
+    r"""
+    Find the grapheme cluster boundary immediately before a position.
+
+    :param unistr: The Unicode string to search.
+    :param pos: Position in the string (0 < pos <= len(unistr)).
+    :returns: Start index of the grapheme cluster containing the character at pos-1.
+
+    Example::
+
+        >>> grapheme_boundary_before('Hello \U0001F44B\U0001F3FB', 8)
+        6
+        >>> grapheme_boundary_before('a\r\nb', 3)
+        1
+
+    .. versionadded:: 0.3.6
+    """
+    if pos <= 0:
+        return 0
+    return _find_cluster_start(unistr, min(pos, len(unistr)))
+
+
+def iter_graphemes_reverse(
+    unistr: str,
+    start: int = 0,
+    end: int | None = None,
+) -> Iterator[str]:
+    r"""
+    Iterate over grapheme clusters in reverse order (last to first).
+
+    :param unistr: The Unicode string to segment.
+    :param start: Starting index (default 0).
+    :param end: Ending index (default len(unistr)).
+    :yields: Grapheme cluster substrings in reverse order.
+
+    Example::
+
+        >>> list(iter_graphemes_reverse('cafe\u0301'))
+        ['e\u0301', 'f', 'a', 'c']
+
+    .. versionadded:: 0.3.6
+    """
+    if not unistr:
+        return
+
+    length = len(unistr)
+
+    end = length if end is None else min(end, length)
+    start = max(start, 0)
+
+    if start >= end or start >= length:
+        return
+
+    pos = end
+    while pos > start:
+        cluster_start = _find_cluster_start(unistr, pos)
+        # Don't yield partial graphemes that extend before start
+        if cluster_start < start:
+            break
+        yield unistr[cluster_start:pos]
+        pos = cluster_start
diff --git a/lib/python3.12/site-packages/wcwidth/py.typed b/lib/python3.12/site-packages/wcwidth/py.typed
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/wcwidth/sgr_state.py b/lib/python3.12/site-packages/wcwidth/sgr_state.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0c8648437e61cff1692ec9e2550b33ebcd43ea9
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/sgr_state.py
@@ -0,0 +1,338 @@
+"""
+SGR (Select Graphic Rendition) state tracking for terminal escape sequences.
+
+This module provides functions for tracking and propagating terminal styling (bold, italic, colors,
+etc.) via public API propagate_sgr(), and its dependent functions, cut() and wrap(). It only has
+attributes necessary to perform its functions, eg 'RED' and 'BLUE' attributes are not defined.
+"""
+from __future__ import annotations
+
+# std imports
+import re
+from enum import IntEnum
+
+from typing import TYPE_CHECKING, Iterator, NamedTuple
+
+if TYPE_CHECKING:  # pragma: no cover
+    from typing import Sequence
+
+
+class _SGR(IntEnum):
+    """
+    SGR (Select Graphic Rendition) parameter codes.
+
+    References:
+    - https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+    - https://github.com/tehmaze/ansi/tree/master/ansi/colour
+    """
+
+    RESET = 0
+    BOLD = 1
+    DIM = 2
+    ITALIC = 3
+    UNDERLINE = 4
+    BLINK = 5
+    RAPID_BLINK = 6
+    INVERSE = 7
+    HIDDEN = 8
+    STRIKETHROUGH = 9
+    DOUBLE_UNDERLINE = 21
+    BOLD_DIM_OFF = 22
+    ITALIC_OFF = 23
+    UNDERLINE_OFF = 24
+    BLINK_OFF = 25
+    INVERSE_OFF = 27
+    HIDDEN_OFF = 28
+    STRIKETHROUGH_OFF = 29
+    FG_BLACK = 30
+    FG_WHITE = 37
+    FG_EXTENDED = 38
+    FG_DEFAULT = 39
+    BG_BLACK = 40
+    BG_WHITE = 47
+    BG_EXTENDED = 48
+    BG_DEFAULT = 49
+    FG_BRIGHT_BLACK = 90
+    FG_BRIGHT_WHITE = 97
+    BG_BRIGHT_BLACK = 100
+    BG_BRIGHT_WHITE = 107
+
+
+# SGR sequence pattern: CSI followed by params (digits, semicolons, colons) ending with 'm'
+# Colons are used in ITU T.416 (ISO 8613-6) extended color format: 38:2::R:G:B
+# This colon format is less common than semicolon (38;2;R;G;B) but supported by kitty,
+# iTerm2, and newer VTE-based terminals.
+_SGR_PATTERN = re.compile(r'\x1b\[([\d;:]*)m')
+
+# Fast path: quick check if any SGR sequence exists
+_SGR_QUICK_CHECK = re.compile(r'\x1b\[[\d;:]*m')
+
+# Reset sequence
+_SGR_RESET = '\x1b[0m'
+
+
+class _SGRState(NamedTuple):
+    """
+    Track active SGR terminal attributes by category (immutable).
+
+    :param bold: Bold attribute (SGR 1).
+    :param dim: Dim/faint attribute (SGR 2).
+    :param italic: Italic attribute (SGR 3).
+    :param underline: Underline attribute (SGR 4).
+    :param blink: Slow blink attribute (SGR 5).
+    :param rapid_blink: Rapid blink attribute (SGR 6).
+    :param inverse: Inverse/reverse attribute (SGR 7).
+    :param hidden: Hidden/invisible attribute (SGR 8).
+    :param strikethrough: Strikethrough attribute (SGR 9).
+    :param double_underline: Double underline attribute (SGR 21).
+    :param foreground: Foreground color as tuple of SGR params, or None for default.
+    :param background: Background color as tuple of SGR params, or None for default.
+    """
+
+    bold: bool = False
+    dim: bool = False
+    italic: bool = False
+    underline: bool = False
+    blink: bool = False
+    rapid_blink: bool = False
+    inverse: bool = False
+    hidden: bool = False
+    strikethrough: bool = False
+    double_underline: bool = False
+    foreground: tuple[int, ...] | None = None
+    background: tuple[int, ...] | None = None
+
+
+# Default state with no attributes set
+_SGR_STATE_DEFAULT = _SGRState()
+
+
+def _sgr_state_is_active(state: _SGRState) -> bool:
+    """
+    Return True if any attributes are set.
+
+    :param state: The SGR state to check.
+    :returns: True if any attribute differs from default.
+    """
+    return (state.bold or state.dim or state.italic or state.underline
+            or state.blink or state.rapid_blink or state.inverse or state.hidden
+            or state.strikethrough or state.double_underline
+            or state.foreground is not None or state.background is not None)
+
+
+def _sgr_state_to_sequence(state: _SGRState) -> str:
+    """
+    Generate minimal SGR sequence to restore this state from reset.
+
+    :param state: The SGR state to convert.
+    :returns: SGR escape sequence string, or empty string if no attributes set.
+    """
+    if not _sgr_state_is_active(state):
+        return ''
+
+    # Map boolean attributes to their SGR codes
+    bool_attrs = [
+        (state.bold, '1'), (state.dim, '2'), (state.italic, '3'),
+        (state.underline, '4'), (state.blink, '5'), (state.rapid_blink, '6'),
+        (state.inverse, '7'), (state.hidden, '8'), (state.strikethrough, '9'),
+        (state.double_underline, '21'),
+    ]
+    params = [code for active, code in bool_attrs if active]
+
+    # Add color params (already formatted as tuples)
+    if state.foreground is not None:
+        params.append(';'.join(str(p) for p in state.foreground))
+    if state.background is not None:
+        params.append(';'.join(str(p) for p in state.background))
+
+    return f'\x1b[{";".join(params)}m'
+
+
+def _parse_sgr_params(sequence: str) -> list[int | tuple[int, ...]]:
+    r"""
+    Parse SGR sequence and return list of parameter values.
+
+    Handles compound sequences like ``\x1b[1;31;4m`` -> [1, 31, 4].
+    Empty params (e.g., ``\x1b[m``) are treated as [0] (reset).
+    Colon-separated extended colors like ``\x1b[38:2::255:0:0m`` are returned
+    as tuples: [(38, 2, 255, 0, 0)].
+
+    :param sequence: SGR escape sequence string.
+    :returns: List of integer parameters or tuples for colon-separated colors.
+    """
+    match = _SGR_PATTERN.match(sequence)
+    if not match:
+        return []
+    params_str = match.group(1)
+    if not params_str:
+        return [0]  # \x1b[m is equivalent to \x1b[0m
+    result: list[int | tuple[int, ...]] = []
+    for param in params_str.split(';'):
+        if ':' in param:
+            # Colon-separated extended color (ITU T.416 format)
+            # e.g., "38:2::255:0:0" or "38:2:1:255:0:0" (with colorspace)
+            parts = [int(p) if p else 0 for p in param.split(':')]
+            result.append(tuple(parts))
+        else:
+            result.append(int(param) if param else 0)
+    return result
+
+
+def _parse_extended_color(
+    params: Iterator[int | tuple[int, ...]], base: int
+) -> tuple[int, ...] | None:
+    """
+    Parse extended color (256-color or RGB) from parameter iterator.
+
+    :param params: Iterator of remaining SGR parameters (semicolon-separated format).
+    :param base: Base code (38 for foreground, 48 for background).
+    :returns: Color tuple like (38, 5, N) or (38, 2, R, G, B), or None if malformed.
+    """
+    try:
+        mode = next(params)
+        if isinstance(mode, tuple):
+            return None  # Unexpected tuple, colon format handled separately
+        if mode == 5:  # 256-color
+            n = next(params)
+            if isinstance(n, tuple):
+                return None
+            return (int(base), 5, n)
+        if mode == 2:  # RGB
+            r, g, b = next(params), next(params), next(params)
+            if isinstance(r, tuple) or isinstance(g, tuple) or isinstance(b, tuple):
+                return None
+            return (int(base), 2, r, g, b)
+    except StopIteration:
+        pass
+    return None
+
+
+def _sgr_state_update(state: _SGRState, sequence: str) -> _SGRState:
+    # pylint: disable=too-many-branches,too-complex,too-many-statements
+    # NOTE: When minimum Python version is 3.10+, this can be simplified using match/case.
+    """
+    Parse SGR sequence and return new state with updates applied.
+
+    :param state: Current SGR state.
+    :param sequence: SGR escape sequence string.
+    :returns: New SGRState with updates applied.
+    """
+    params_list = _parse_sgr_params(sequence)
+    params = iter(params_list)
+    for p in params:
+        # Handle colon-separated extended colors (ITU T.416 format)
+        if isinstance(p, tuple):
+            if len(p) >= 2 and p[0] == _SGR.FG_EXTENDED:
+                # Foreground: (38, 2, [colorspace,] R, G, B) or (38, 5, N)
+                state = state._replace(foreground=p)
+            elif len(p) >= 2 and p[0] == _SGR.BG_EXTENDED:
+                # Background: (48, 2, [colorspace,] R, G, B) or (48, 5, N)
+                state = state._replace(background=p)
+            continue
+        if p == _SGR.RESET:
+            state = _SGR_STATE_DEFAULT
+        # Attribute ON codes
+        elif p == _SGR.BOLD:
+            state = state._replace(bold=True)
+        elif p == _SGR.DIM:
+            state = state._replace(dim=True)
+        elif p == _SGR.ITALIC:
+            state = state._replace(italic=True)
+        elif p == _SGR.UNDERLINE:
+            state = state._replace(underline=True)
+        elif p == _SGR.BLINK:
+            state = state._replace(blink=True)
+        elif p == _SGR.RAPID_BLINK:
+            state = state._replace(rapid_blink=True)
+        elif p == _SGR.INVERSE:
+            state = state._replace(inverse=True)
+        elif p == _SGR.HIDDEN:
+            state = state._replace(hidden=True)
+        elif p == _SGR.STRIKETHROUGH:
+            state = state._replace(strikethrough=True)
+        elif p == _SGR.DOUBLE_UNDERLINE:
+            state = state._replace(double_underline=True)
+        # Attribute OFF codes
+        elif p == _SGR.BOLD_DIM_OFF:
+            state = state._replace(bold=False, dim=False)
+        elif p == _SGR.ITALIC_OFF:
+            state = state._replace(italic=False)
+        elif p == _SGR.UNDERLINE_OFF:
+            state = state._replace(underline=False, double_underline=False)
+        elif p == _SGR.BLINK_OFF:
+            state = state._replace(blink=False, rapid_blink=False)
+        elif p == _SGR.INVERSE_OFF:
+            state = state._replace(inverse=False)
+        elif p == _SGR.HIDDEN_OFF:
+            state = state._replace(hidden=False)
+        elif p == _SGR.STRIKETHROUGH_OFF:
+            state = state._replace(strikethrough=False)
+        # Basic colors (30-37, 40-47 standard; 90-97, 100-107 bright)
+        elif (_SGR.FG_BLACK <= p <= _SGR.FG_WHITE
+              or _SGR.FG_BRIGHT_BLACK <= p <= _SGR.FG_BRIGHT_WHITE):
+            state = state._replace(foreground=(p,))
+        elif (_SGR.BG_BLACK <= p <= _SGR.BG_WHITE
+              or _SGR.BG_BRIGHT_BLACK <= p <= _SGR.BG_BRIGHT_WHITE):
+            state = state._replace(background=(p,))
+        elif p == _SGR.FG_DEFAULT:
+            state = state._replace(foreground=None)
+        elif p == _SGR.BG_DEFAULT:
+            state = state._replace(background=None)
+        # Extended colors (semicolon-separated format)
+        elif p == _SGR.FG_EXTENDED:
+            if color := _parse_extended_color(params, _SGR.FG_EXTENDED):
+                state = state._replace(foreground=color)
+        elif p == _SGR.BG_EXTENDED:
+            if color := _parse_extended_color(params, _SGR.BG_EXTENDED):
+                state = state._replace(background=color)
+    return state
+
+
+def propagate_sgr(lines: Sequence[str]) -> list[str]:
+    r"""
+    Propagate SGR codes across wrapped lines.
+
+    When text with SGR styling is wrapped across multiple lines, each line
+    needs to be self-contained for proper display. This function:
+
+    - Ends each line with ``\x1b[0m`` if styles are active (prevents bleeding)
+    - Starts each subsequent line with the active style restored
+
+    :param lines: List of text lines, possibly containing SGR sequences.
+    :returns: List of lines with SGR codes propagated.
+
+    Example::
+
+        >>> propagate_sgr(['\x1b[31mhello', 'world\x1b[0m'])
+        ['\x1b[31mhello\x1b[0m', '\x1b[31mworld\x1b[0m']
+
+    This is useful in cases of making special editors and viewers, and is used for the
+    default modes (propagate_sgr=True) of :func:`wcwidth.width` and :func:`wcwidth.clip`.
+
+    When wrapping and clipping text containing SGR sequences, maybe a previous line enabled the BLUE
+    color--if we are viewing *only* the line following, we would want the carry over the BLUE color,
+    and all lines with sequences should end with terminating reset (``\x1b[0m``).
+    """
+    # Fast path: check if any line contains SGR sequences
+    if not any(_SGR_QUICK_CHECK.search(line) for line in lines) or not lines:
+        return list(lines)
+
+    result: list[str] = []
+    state = _SGR_STATE_DEFAULT
+
+    for line in lines:
+        # Prefix with restoration sequence if state is active
+        prefix = _sgr_state_to_sequence(state)
+
+        # Update state by processing all SGR sequences in this line
+        for match in _SGR_PATTERN.finditer(line):
+            state = _sgr_state_update(state, match.group())
+
+        # Build output line
+        output_line = prefix + line if prefix else line
+        if _sgr_state_is_active(state):
+            output_line = output_line + _SGR_RESET
+
+        result.append(output_line)
+
+    return result
diff --git a/lib/python3.12/site-packages/wcwidth/table_ambiguous.py b/lib/python3.12/site-packages/wcwidth/table_ambiguous.py
new file mode 100644
index 0000000000000000000000000000000000000000..e3dc0b1c3de9f2160190cfe71b2e717b7dcd2a1c
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/table_ambiguous.py
@@ -0,0 +1,189 @@
+"""
+Exports AMBIGUOUS_EASTASIAN table keyed by supporting unicode version level.
+
+This code generated by wcwidth/bin/update-tables.py on 2026-01-18 23:27:15 UTC.
+"""
+# pylint: disable=duplicate-code
+AMBIGUOUS_EASTASIAN = {
+    '17.0.0': (
+        # Source: EastAsianWidth-17.0.0.txt
+        # Date: 2025-07-24, 00:12:54 GMT
+        #
+        (0x000a1, 0x000a1,),  # Inverted Exclamation Mark
+        (0x000a4, 0x000a4,),  # Currency Sign
+        (0x000a7, 0x000a8,),  # Section Sign            ..Diaeresis
+        (0x000aa, 0x000aa,),  # Feminine Ordinal Indicator
+        (0x000ad, 0x000ae,),  # Soft Hyphen             ..Registered Sign
+        (0x000b0, 0x000b4,),  # Degree Sign             ..Acute Accent
+        (0x000b6, 0x000ba,),  # Pilcrow Sign            ..Masculine Ordinal Indica
+        (0x000bc, 0x000bf,),  # Vulgar Fraction One Quar..Inverted Question Mark
+        (0x000c6, 0x000c6,),  # Latin Capital Letter Ae
+        (0x000d0, 0x000d0,),  # Latin Capital Letter Eth
+        (0x000d7, 0x000d8,),  # Multiplication Sign     ..Latin Capital Letter O W
+        (0x000de, 0x000e1,),  # Latin Capital Letter Tho..Latin Small Letter A Wit
+        (0x000e6, 0x000e6,),  # Latin Small Letter Ae
+        (0x000e8, 0x000ea,),  # Latin Small Letter E Wit..Latin Small Letter E Wit
+        (0x000ec, 0x000ed,),  # Latin Small Letter I Wit..Latin Small Letter I Wit
+        (0x000f0, 0x000f0,),  # Latin Small Letter Eth
+        (0x000f2, 0x000f3,),  # Latin Small Letter O Wit..Latin Small Letter O Wit
+        (0x000f7, 0x000fa,),  # Division Sign           ..Latin Small Letter U Wit
+        (0x000fc, 0x000fc,),  # Latin Small Letter U With Diaeresis
+        (0x000fe, 0x000fe,),  # Latin Small Letter Thorn
+        (0x00101, 0x00101,),  # Latin Small Letter A With Macron
+        (0x00111, 0x00111,),  # Latin Small Letter D With Stroke
+        (0x00113, 0x00113,),  # Latin Small Letter E With Macron
+        (0x0011b, 0x0011b,),  # Latin Small Letter E With Caron
+        (0x00126, 0x00127,),  # Latin Capital Letter H W..Latin Small Letter H Wit
+        (0x0012b, 0x0012b,),  # Latin Small Letter I With Macron
+        (0x00131, 0x00133,),  # Latin Small Letter Dotle..Latin Small Ligature Ij
+        (0x00138, 0x00138,),  # Latin Small Letter Kra
+        (0x0013f, 0x00142,),  # Latin Capital Letter L W..Latin Small Letter L Wit
+        (0x00144, 0x00144,),  # Latin Small Letter N With Acute
+        (0x00148, 0x0014b,),  # Latin Small Letter N Wit..Latin Small Letter Eng
+        (0x0014d, 0x0014d,),  # Latin Small Letter O With Macron
+        (0x00152, 0x00153,),  # Latin Capital Ligature O..Latin Small Ligature Oe
+        (0x00166, 0x00167,),  # Latin Capital Letter T W..Latin Small Letter T Wit
+        (0x0016b, 0x0016b,),  # Latin Small Letter U With Macron
+        (0x001ce, 0x001ce,),  # Latin Small Letter A With Caron
+        (0x001d0, 0x001d0,),  # Latin Small Letter I With Caron
+        (0x001d2, 0x001d2,),  # Latin Small Letter O With Caron
+        (0x001d4, 0x001d4,),  # Latin Small Letter U With Caron
+        (0x001d6, 0x001d6,),  # Latin Small Letter U With Diaeresis And Macron
+        (0x001d8, 0x001d8,),  # Latin Small Letter U With Diaeresis And Acute
+        (0x001da, 0x001da,),  # Latin Small Letter U With Diaeresis And Caron
+        (0x001dc, 0x001dc,),  # Latin Small Letter U With Diaeresis And Grave
+        (0x00251, 0x00251,),  # Latin Small Letter Alpha
+        (0x00261, 0x00261,),  # Latin Small Letter Script G
+        (0x002c4, 0x002c4,),  # Modifier Letter Up Arrowhead
+        (0x002c7, 0x002c7,),  # Caron
+        (0x002c9, 0x002cb,),  # Modifier Letter Macron  ..Modifier Letter Grave Ac
+        (0x002cd, 0x002cd,),  # Modifier Letter Low Macron
+        (0x002d0, 0x002d0,),  # Modifier Letter Triangular Colon
+        (0x002d8, 0x002db,),  # Breve                   ..Ogonek
+        (0x002dd, 0x002dd,),  # Double Acute Accent
+        (0x002df, 0x002df,),  # Modifier Letter Cross Accent
+        (0x00391, 0x003a1,),  # Greek Capital Letter Alp..Greek Capital Letter Rho
+        (0x003a3, 0x003a9,),  # Greek Capital Letter Sig..Greek Capital Letter Ome
+        (0x003b1, 0x003c1,),  # Greek Small Letter Alpha..Greek Small Letter Rho
+        (0x003c3, 0x003c9,),  # Greek Small Letter Sigma..Greek Small Letter Omega
+        (0x00401, 0x00401,),  # Cyrillic Capital Letter Io
+        (0x00410, 0x0044f,),  # Cyrillic Capital Letter ..Cyrillic Small Letter Ya
+        (0x00451, 0x00451,),  # Cyrillic Small Letter Io
+        (0x02010, 0x02010,),  # Hyphen
+        (0x02013, 0x02016,),  # En Dash                 ..Double Vertical Line
+        (0x02018, 0x02019,),  # Left Single Quotation Ma..Right Single Quotation M
+        (0x0201c, 0x0201d,),  # Left Double Quotation Ma..Right Double Quotation M
+        (0x02020, 0x02022,),  # Dagger                  ..Bullet
+        (0x02024, 0x02027,),  # One Dot Leader          ..Hyphenation Point
+        (0x02030, 0x02030,),  # Per Mille Sign
+        (0x02032, 0x02033,),  # Prime                   ..Double Prime
+        (0x02035, 0x02035,),  # Reversed Prime
+        (0x0203b, 0x0203b,),  # Reference Mark
+        (0x0203e, 0x0203e,),  # Overline
+        (0x02074, 0x02074,),  # Superscript Four
+        (0x0207f, 0x0207f,),  # Superscript Latin Small Letter N
+        (0x02081, 0x02084,),  # Subscript One           ..Subscript Four
+        (0x020ac, 0x020ac,),  # Euro Sign
+        (0x02103, 0x02103,),  # Degree Celsius
+        (0x02105, 0x02105,),  # Care Of
+        (0x02109, 0x02109,),  # Degree Fahrenheit
+        (0x02113, 0x02113,),  # Script Small L
+        (0x02116, 0x02116,),  # Numero Sign
+        (0x02121, 0x02122,),  # Telephone Sign          ..Trade Mark Sign
+        (0x02126, 0x02126,),  # Ohm Sign
+        (0x0212b, 0x0212b,),  # Angstrom Sign
+        (0x02153, 0x02154,),  # Vulgar Fraction One Thir..Vulgar Fraction Two Thir
+        (0x0215b, 0x0215e,),  # Vulgar Fraction One Eigh..Vulgar Fraction Seven Ei
+        (0x02160, 0x0216b,),  # Roman Numeral One       ..Roman Numeral Twelve
+        (0x02170, 0x02179,),  # Small Roman Numeral One ..Small Roman Numeral Ten
+        (0x02189, 0x02189,),  # Vulgar Fraction Zero Thirds
+        (0x02190, 0x02199,),  # Leftwards Arrow         ..South West Arrow
+        (0x021b8, 0x021b9,),  # North West Arrow To Long..Leftwards Arrow To Bar O
+        (0x021d2, 0x021d2,),  # Rightwards Double Arrow
+        (0x021d4, 0x021d4,),  # Left Right Double Arrow
+        (0x021e7, 0x021e7,),  # Upwards White Arrow
+        (0x02200, 0x02200,),  # For All
+        (0x02202, 0x02203,),  # Partial Differential    ..There Exists
+        (0x02207, 0x02208,),  # Nabla                   ..Element Of
+        (0x0220b, 0x0220b,),  # Contains As Member
+        (0x0220f, 0x0220f,),  # N-ary Product
+        (0x02211, 0x02211,),  # N-ary Summation
+        (0x02215, 0x02215,),  # Division Slash
+        (0x0221a, 0x0221a,),  # Square Root
+        (0x0221d, 0x02220,),  # Proportional To         ..Angle
+        (0x02223, 0x02223,),  # Divides
+        (0x02225, 0x02225,),  # Parallel To
+        (0x02227, 0x0222c,),  # Logical And             ..Double Integral
+        (0x0222e, 0x0222e,),  # Contour Integral
+        (0x02234, 0x02237,),  # Therefore               ..Proportion
+        (0x0223c, 0x0223d,),  # Tilde Operator          ..Reversed Tilde
+        (0x02248, 0x02248,),  # Almost Equal To
+        (0x0224c, 0x0224c,),  # All Equal To
+        (0x02252, 0x02252,),  # Approximately Equal To Or The Image Of
+        (0x02260, 0x02261,),  # Not Equal To            ..Identical To
+        (0x02264, 0x02267,),  # Less-than Or Equal To   ..Greater-than Over Equal
+        (0x0226a, 0x0226b,),  # Much Less-than          ..Much Greater-than
+        (0x0226e, 0x0226f,),  # Not Less-than           ..Not Greater-than
+        (0x02282, 0x02283,),  # Subset Of               ..Superset Of
+        (0x02286, 0x02287,),  # Subset Of Or Equal To   ..Superset Of Or Equal To
+        (0x02295, 0x02295,),  # Circled Plus
+        (0x02299, 0x02299,),  # Circled Dot Operator
+        (0x022a5, 0x022a5,),  # Up Tack
+        (0x022bf, 0x022bf,),  # Right Triangle
+        (0x02312, 0x02312,),  # Arc
+        (0x02460, 0x024e9,),  # Circled Digit One       ..Circled Latin Small Lett
+        (0x024eb, 0x0254b,),  # Negative Circled Number ..Box Drawings Heavy Verti
+        (0x02550, 0x02573,),  # Box Drawings Double Hori..Box Drawings Light Diago
+        (0x02580, 0x0258f,),  # Upper Half Block        ..Left One Eighth Block
+        (0x02592, 0x02595,),  # Medium Shade            ..Right One Eighth Block
+        (0x025a0, 0x025a1,),  # Black Square            ..White Square
+        (0x025a3, 0x025a9,),  # White Square Containing ..Square With Diagonal Cro
+        (0x025b2, 0x025b3,),  # Black Up-pointing Triang..White Up-pointing Triang
+        (0x025b6, 0x025b7,),  # Black Right-pointing Tri..White Right-pointing Tri
+        (0x025bc, 0x025bd,),  # Black Down-pointing Tria..White Down-pointing Tria
+        (0x025c0, 0x025c1,),  # Black Left-pointing Tria..White Left-pointing Tria
+        (0x025c6, 0x025c8,),  # Black Diamond           ..White Diamond Containing
+        (0x025cb, 0x025cb,),  # White Circle
+        (0x025ce, 0x025d1,),  # Bullseye                ..Circle With Right Half B
+        (0x025e2, 0x025e5,),  # Black Lower Right Triang..Black Upper Right Triang
+        (0x025ef, 0x025ef,),  # Large Circle
+        (0x02605, 0x02606,),  # Black Star              ..White Star
+        (0x02609, 0x02609,),  # Sun
+        (0x0260e, 0x0260f,),  # Black Telephone         ..White Telephone
+        (0x0261c, 0x0261c,),  # White Left Pointing Index
+        (0x0261e, 0x0261e,),  # White Right Pointing Index
+        (0x02640, 0x02640,),  # Female Sign
+        (0x02642, 0x02642,),  # Male Sign
+        (0x02660, 0x02661,),  # Black Spade Suit        ..White Heart Suit
+        (0x02663, 0x02665,),  # Black Club Suit         ..Black Heart Suit
+        (0x02667, 0x0266a,),  # White Club Suit         ..Eighth Note
+        (0x0266c, 0x0266d,),  # Beamed Sixteenth Notes  ..Music Flat Sign
+        (0x0266f, 0x0266f,),  # Music Sharp Sign
+        (0x0269e, 0x0269f,),  # Three Lines Converging R..Three Lines Converging L
+        (0x026bf, 0x026bf,),  # Squared Key
+        (0x026c6, 0x026cd,),  # Rain                    ..Disabled Car
+        (0x026cf, 0x026d3,),  # Pick                    ..Chains
+        (0x026d5, 0x026e1,),  # Alternate One-way Left W..Restricted Left Entry-2
+        (0x026e3, 0x026e3,),  # Heavy Circle With Stroke And Two Dots Above
+        (0x026e8, 0x026e9,),  # Black Cross On Shield   ..Shinto Shrine
+        (0x026eb, 0x026f1,),  # Castle                  ..Umbrella On Ground
+        (0x026f4, 0x026f4,),  # Ferry
+        (0x026f6, 0x026f9,),  # Square Four Corners     ..Person With Ball
+        (0x026fb, 0x026fc,),  # Japanese Bank Symbol    ..Headstone Graveyard Symb
+        (0x026fe, 0x026ff,),  # Cup On Black Square     ..White Flag With Horizont
+        (0x0273d, 0x0273d,),  # Heavy Teardrop-spoked Asterisk
+        (0x02776, 0x0277f,),  # Dingbat Negative Circled..Dingbat Negative Circled
+        (0x02b56, 0x02b59,),  # Heavy Oval With Oval Ins..Heavy Circled Saltire
+        (0x03248, 0x0324f,),  # Circled Number Ten On Bl..Circled Number Eighty On
+        (0x0e000, 0x0f8ff,),  # (nil)
+        (0x0fffd, 0x0fffd,),  # Replacement Character
+        (0x1f100, 0x1f10a,),  # Digit Zero Full Stop    ..Digit Nine Comma
+        (0x1f110, 0x1f12d,),  # Parenthesized Latin Capi..Circled Cd
+        (0x1f130, 0x1f169,),  # Squared Latin Capital Le..Negative Circled Latin C
+        (0x1f170, 0x1f18d,),  # Negative Squared Latin C..Negative Squared Sa
+        (0x1f18f, 0x1f190,),  # Negative Squared Wc     ..Square Dj
+        (0x1f19b, 0x1f1ac,),  # Squared Three D         ..Squared Vod
+        (0xf0000, 0xffffd,),  # (nil)
+        (0x100000, 0x10fffd,),  # (nil)
+    ),
+}
diff --git a/lib/python3.12/site-packages/wcwidth/table_grapheme.py b/lib/python3.12/site-packages/wcwidth/table_grapheme.py
new file mode 100644
index 0000000000000000000000000000000000000000..42fd19e03dfd3cc5f7a86e55eb1796bc5eb2eef5
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/table_grapheme.py
@@ -0,0 +1,2294 @@
+"""
+Exports grapheme cluster break property tables for Unicode version 17.0.0.
+
+This module provides lookup tables for Unicode grapheme cluster break properties as defined in UAX
+#29: Unicode Text Segmentation.
+
+This code generated by wcwidth/bin/update-tables.py on 2026-01-29 23:33:42 UTC.
+"""
+# pylint: disable=duplicate-code
+
+GRAPHEME_CR = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x0000d, 0x0000d,),  # (nil)
+)
+
+GRAPHEME_LF = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x0000a, 0x0000a,),  # (nil)
+)
+
+GRAPHEME_CONTROL = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x00000, 0x00009,),  # (nil)
+    (0x0000b, 0x0000c,),  # (nil)
+    (0x0000e, 0x0001f,),  # (nil)
+    (0x0007f, 0x0009f,),  # (nil)
+    (0x000ad, 0x000ad,),  # Soft Hyphen
+    (0x0061c, 0x0061c,),  # Arabic Letter Mark
+    (0x0180e, 0x0180e,),  # Mongolian Vowel Separator
+    (0x0200b, 0x0200b,),  # Zero Width Space
+    (0x0200e, 0x0200f,),  # Left-to-right Mark      ..Right-to-left Mark
+    (0x02028, 0x0202e,),  # Line Separator          ..Right-to-left Override
+    (0x02060, 0x0206f,),  # Word Joiner             ..Nominal Digit Shapes
+    (0x0feff, 0x0feff,),  # Zero Width No-break Space
+    (0x0fff0, 0x0fffb,),  # (nil)                   ..Interlinear Annotation T
+    (0x13430, 0x1343f,),  # Egyptian Hieroglyph Vert..Egyptian Hieroglyph End
+    (0x1bca0, 0x1bca3,),  # Shorthand Format Letter ..Shorthand Format Up Step
+    (0x1d173, 0x1d17a,),  # Musical Symbol Begin Bea..Musical Symbol End Phras
+    (0xe0000, 0xe001f,),  # (nil)
+    (0xe0080, 0xe00ff,),  # (nil)
+    (0xe01f0, 0xe0fff,),  # (nil)
+)
+
+GRAPHEME_EXTEND = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x00300, 0x0036f,),  # Combining Grave Accent  ..Combining Latin Small Le
+    (0x00483, 0x00489,),  # Combining Cyrillic Titlo..Combining Cyrillic Milli
+    (0x00591, 0x005bd,),  # Hebrew Accent Etnahta   ..Hebrew Point Meteg
+    (0x005bf, 0x005bf,),  # Hebrew Point Rafe
+    (0x005c1, 0x005c2,),  # Hebrew Point Shin Dot   ..Hebrew Point Sin Dot
+    (0x005c4, 0x005c5,),  # Hebrew Mark Upper Dot   ..Hebrew Mark Lower Dot
+    (0x005c7, 0x005c7,),  # Hebrew Point Qamats Qatan
+    (0x00610, 0x0061a,),  # Arabic Sign Sallallahou ..Arabic Small Kasra
+    (0x0064b, 0x0065f,),  # Arabic Fathatan         ..Arabic Wavy Hamza Below
+    (0x00670, 0x00670,),  # Arabic Letter Superscript Alef
+    (0x006d6, 0x006dc,),  # Arabic Small High Ligatu..Arabic Small High Seen
+    (0x006df, 0x006e4,),  # Arabic Small High Rounde..Arabic Small High Madda
+    (0x006e7, 0x006e8,),  # Arabic Small High Yeh   ..Arabic Small High Noon
+    (0x006ea, 0x006ed,),  # Arabic Empty Centre Low ..Arabic Small Low Meem
+    (0x00711, 0x00711,),  # Syriac Letter Superscript Alaph
+    (0x00730, 0x0074a,),  # Syriac Pthaha Above     ..Syriac Barrekh
+    (0x007a6, 0x007b0,),  # Thaana Abafili          ..Thaana Sukun
+    (0x007eb, 0x007f3,),  # Nko Combining Short High..Nko Combining Double Dot
+    (0x007fd, 0x007fd,),  # Nko Dantayalan
+    (0x00816, 0x00819,),  # Samaritan Mark In       ..Samaritan Mark Dagesh
+    (0x0081b, 0x00823,),  # Samaritan Mark Epentheti..Samaritan Vowel Sign A
+    (0x00825, 0x00827,),  # Samaritan Vowel Sign Sho..Samaritan Vowel Sign U
+    (0x00829, 0x0082d,),  # Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa
+    (0x00859, 0x0085b,),  # Mandaic Affrication Mark..Mandaic Gemination Mark
+    (0x00897, 0x0089f,),  # Arabic Pepet            ..Arabic Half Madda Over M
+    (0x008ca, 0x008e1,),  # Arabic Small High Farsi ..Arabic Small High Sign S
+    (0x008e3, 0x00902,),  # Arabic Turned Damma Belo..Devanagari Sign Anusvara
+    (0x0093a, 0x0093a,),  # Devanagari Vowel Sign Oe
+    (0x0093c, 0x0093c,),  # Devanagari Sign Nukta
+    (0x00941, 0x00948,),  # Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai
+    (0x0094d, 0x0094d,),  # Devanagari Sign Virama
+    (0x00951, 0x00957,),  # Devanagari Stress Sign U..Devanagari Vowel Sign Uu
+    (0x00962, 0x00963,),  # Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo
+    (0x00981, 0x00981,),  # Bengali Sign Candrabindu
+    (0x009bc, 0x009bc,),  # Bengali Sign Nukta
+    (0x009be, 0x009be,),  # Bengali Vowel Sign Aa
+    (0x009c1, 0x009c4,),  # Bengali Vowel Sign U    ..Bengali Vowel Sign Vocal
+    (0x009cd, 0x009cd,),  # Bengali Sign Virama
+    (0x009d7, 0x009d7,),  # Bengali Au Length Mark
+    (0x009e2, 0x009e3,),  # Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal
+    (0x009fe, 0x009fe,),  # Bengali Sandhi Mark
+    (0x00a01, 0x00a02,),  # Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi
+    (0x00a3c, 0x00a3c,),  # Gurmukhi Sign Nukta
+    (0x00a41, 0x00a42,),  # Gurmukhi Vowel Sign U   ..Gurmukhi Vowel Sign Uu
+    (0x00a47, 0x00a48,),  # Gurmukhi Vowel Sign Ee  ..Gurmukhi Vowel Sign Ai
+    (0x00a4b, 0x00a4d,),  # Gurmukhi Vowel Sign Oo  ..Gurmukhi Sign Virama
+    (0x00a51, 0x00a51,),  # Gurmukhi Sign Udaat
+    (0x00a70, 0x00a71,),  # Gurmukhi Tippi          ..Gurmukhi Addak
+    (0x00a75, 0x00a75,),  # Gurmukhi Sign Yakash
+    (0x00a81, 0x00a82,),  # Gujarati Sign Candrabind..Gujarati Sign Anusvara
+    (0x00abc, 0x00abc,),  # Gujarati Sign Nukta
+    (0x00ac1, 0x00ac5,),  # Gujarati Vowel Sign U   ..Gujarati Vowel Sign Cand
+    (0x00ac7, 0x00ac8,),  # Gujarati Vowel Sign E   ..Gujarati Vowel Sign Ai
+    (0x00acd, 0x00acd,),  # Gujarati Sign Virama
+    (0x00ae2, 0x00ae3,),  # Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca
+    (0x00afa, 0x00aff,),  # Gujarati Sign Sukun     ..Gujarati Sign Two-circle
+    (0x00b01, 0x00b01,),  # Oriya Sign Candrabindu
+    (0x00b3c, 0x00b3c,),  # Oriya Sign Nukta
+    (0x00b3e, 0x00b3f,),  # Oriya Vowel Sign Aa     ..Oriya Vowel Sign I
+    (0x00b41, 0x00b44,),  # Oriya Vowel Sign U      ..Oriya Vowel Sign Vocalic
+    (0x00b4d, 0x00b4d,),  # Oriya Sign Virama
+    (0x00b55, 0x00b57,),  # Oriya Sign Overline     ..Oriya Au Length Mark
+    (0x00b62, 0x00b63,),  # Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic
+    (0x00b82, 0x00b82,),  # Tamil Sign Anusvara
+    (0x00bbe, 0x00bbe,),  # Tamil Vowel Sign Aa
+    (0x00bc0, 0x00bc0,),  # Tamil Vowel Sign Ii
+    (0x00bcd, 0x00bcd,),  # Tamil Sign Virama
+    (0x00bd7, 0x00bd7,),  # Tamil Au Length Mark
+    (0x00c00, 0x00c00,),  # Telugu Sign Combining Candrabindu Above
+    (0x00c04, 0x00c04,),  # Telugu Sign Combining Anusvara Above
+    (0x00c3c, 0x00c3c,),  # Telugu Sign Nukta
+    (0x00c3e, 0x00c40,),  # Telugu Vowel Sign Aa    ..Telugu Vowel Sign Ii
+    (0x00c46, 0x00c48,),  # Telugu Vowel Sign E     ..Telugu Vowel Sign Ai
+    (0x00c4a, 0x00c4d,),  # Telugu Vowel Sign O     ..Telugu Sign Virama
+    (0x00c55, 0x00c56,),  # Telugu Length Mark      ..Telugu Ai Length Mark
+    (0x00c62, 0x00c63,),  # Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali
+    (0x00c81, 0x00c81,),  # Kannada Sign Candrabindu
+    (0x00cbc, 0x00cbc,),  # Kannada Sign Nukta
+    (0x00cbf, 0x00cc0,),  # Kannada Vowel Sign I    ..Kannada Vowel Sign Ii
+    (0x00cc2, 0x00cc2,),  # Kannada Vowel Sign Uu
+    (0x00cc6, 0x00cc8,),  # Kannada Vowel Sign E    ..Kannada Vowel Sign Ai
+    (0x00cca, 0x00ccd,),  # Kannada Vowel Sign O    ..Kannada Sign Virama
+    (0x00cd5, 0x00cd6,),  # Kannada Length Mark     ..Kannada Ai Length Mark
+    (0x00ce2, 0x00ce3,),  # Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal
+    (0x00d00, 0x00d01,),  # Malayalam Sign Combining..Malayalam Sign Candrabin
+    (0x00d3b, 0x00d3c,),  # Malayalam Sign Vertical ..Malayalam Sign Circular
+    (0x00d3e, 0x00d3e,),  # Malayalam Vowel Sign Aa
+    (0x00d41, 0x00d44,),  # Malayalam Vowel Sign U  ..Malayalam Vowel Sign Voc
+    (0x00d4d, 0x00d4d,),  # Malayalam Sign Virama
+    (0x00d57, 0x00d57,),  # Malayalam Au Length Mark
+    (0x00d62, 0x00d63,),  # Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc
+    (0x00d81, 0x00d81,),  # Sinhala Sign Candrabindu
+    (0x00dca, 0x00dca,),  # Sinhala Sign Al-lakuna
+    (0x00dcf, 0x00dcf,),  # Sinhala Vowel Sign Aela-pilla
+    (0x00dd2, 0x00dd4,),  # Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti
+    (0x00dd6, 0x00dd6,),  # Sinhala Vowel Sign Diga Paa-pilla
+    (0x00ddf, 0x00ddf,),  # Sinhala Vowel Sign Gayanukitta
+    (0x00e31, 0x00e31,),  # Thai Character Mai Han-akat
+    (0x00e34, 0x00e3a,),  # Thai Character Sara I   ..Thai Character Phinthu
+    (0x00e47, 0x00e4e,),  # Thai Character Maitaikhu..Thai Character Yamakkan
+    (0x00eb1, 0x00eb1,),  # Lao Vowel Sign Mai Kan
+    (0x00eb4, 0x00ebc,),  # Lao Vowel Sign I        ..Lao Semivowel Sign Lo
+    (0x00ec8, 0x00ece,),  # Lao Tone Mai Ek         ..Lao Yamakkan
+    (0x00f18, 0x00f19,),  # Tibetan Astrological Sig..Tibetan Astrological Sig
+    (0x00f35, 0x00f35,),  # Tibetan Mark Ngas Bzung Nyi Zla
+    (0x00f37, 0x00f37,),  # Tibetan Mark Ngas Bzung Sgor Rtags
+    (0x00f39, 0x00f39,),  # Tibetan Mark Tsa -phru
+    (0x00f71, 0x00f7e,),  # Tibetan Vowel Sign Aa   ..Tibetan Sign Rjes Su Nga
+    (0x00f80, 0x00f84,),  # Tibetan Vowel Sign Rever..Tibetan Mark Halanta
+    (0x00f86, 0x00f87,),  # Tibetan Sign Lci Rtags  ..Tibetan Sign Yang Rtags
+    (0x00f8d, 0x00f97,),  # Tibetan Subjoined Sign L..Tibetan Subjoined Letter
+    (0x00f99, 0x00fbc,),  # Tibetan Subjoined Letter..Tibetan Subjoined Letter
+    (0x00fc6, 0x00fc6,),  # Tibetan Symbol Padma Gdan
+    (0x0102d, 0x01030,),  # Myanmar Vowel Sign I    ..Myanmar Vowel Sign Uu
+    (0x01032, 0x01037,),  # Myanmar Vowel Sign Ai   ..Myanmar Sign Dot Below
+    (0x01039, 0x0103a,),  # Myanmar Sign Virama     ..Myanmar Sign Asat
+    (0x0103d, 0x0103e,),  # Myanmar Consonant Sign M..Myanmar Consonant Sign M
+    (0x01058, 0x01059,),  # Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal
+    (0x0105e, 0x01060,),  # Myanmar Consonant Sign M..Myanmar Consonant Sign M
+    (0x01071, 0x01074,),  # Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah
+    (0x01082, 0x01082,),  # Myanmar Consonant Sign Shan Medial Wa
+    (0x01085, 0x01086,),  # Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan
+    (0x0108d, 0x0108d,),  # Myanmar Sign Shan Council Emphatic Tone
+    (0x0109d, 0x0109d,),  # Myanmar Vowel Sign Aiton Ai
+    (0x0135d, 0x0135f,),  # Ethiopic Combining Gemin..Ethiopic Combining Gemin
+    (0x01712, 0x01715,),  # Tagalog Vowel Sign I    ..Tagalog Sign Pamudpod
+    (0x01732, 0x01734,),  # Hanunoo Vowel Sign I    ..Hanunoo Sign Pamudpod
+    (0x01752, 0x01753,),  # Buhid Vowel Sign I      ..Buhid Vowel Sign U
+    (0x01772, 0x01773,),  # Tagbanwa Vowel Sign I   ..Tagbanwa Vowel Sign U
+    (0x017b4, 0x017b5,),  # Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa
+    (0x017b7, 0x017bd,),  # Khmer Vowel Sign I      ..Khmer Vowel Sign Ua
+    (0x017c6, 0x017c6,),  # Khmer Sign Nikahit
+    (0x017c9, 0x017d3,),  # Khmer Sign Muusikatoan  ..Khmer Sign Bathamasat
+    (0x017dd, 0x017dd,),  # Khmer Sign Atthacan
+    (0x0180b, 0x0180d,),  # Mongolian Free Variation..Mongolian Free Variation
+    (0x0180f, 0x0180f,),  # Mongolian Free Variation Selector Four
+    (0x01885, 0x01886,),  # Mongolian Letter Ali Gal..Mongolian Letter Ali Gal
+    (0x018a9, 0x018a9,),  # Mongolian Letter Ali Gali Dagalga
+    (0x01920, 0x01922,),  # Limbu Vowel Sign A      ..Limbu Vowel Sign U
+    (0x01927, 0x01928,),  # Limbu Vowel Sign E      ..Limbu Vowel Sign O
+    (0x01932, 0x01932,),  # Limbu Small Letter Anusvara
+    (0x01939, 0x0193b,),  # Limbu Sign Mukphreng    ..Limbu Sign Sa-i
+    (0x01a17, 0x01a18,),  # Buginese Vowel Sign I   ..Buginese Vowel Sign U
+    (0x01a1b, 0x01a1b,),  # Buginese Vowel Sign Ae
+    (0x01a56, 0x01a56,),  # Tai Tham Consonant Sign Medial La
+    (0x01a58, 0x01a5e,),  # Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign
+    (0x01a60, 0x01a60,),  # Tai Tham Sign Sakot
+    (0x01a62, 0x01a62,),  # Tai Tham Vowel Sign Mai Sat
+    (0x01a65, 0x01a6c,),  # Tai Tham Vowel Sign I   ..Tai Tham Vowel Sign Oa B
+    (0x01a73, 0x01a7c,),  # Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue
+    (0x01a7f, 0x01a7f,),  # Tai Tham Combining Cryptogrammic Dot
+    (0x01ab0, 0x01add,),  # Combining Doubled Circum..Combining Dot-and-ring B
+    (0x01ae0, 0x01aeb,),  # Combining Left Tack Abov..Combining Double Rightwa
+    (0x01b00, 0x01b03,),  # Balinese Sign Ulu Ricem ..Balinese Sign Surang
+    (0x01b34, 0x01b3d,),  # Balinese Sign Rerekan   ..Balinese Vowel Sign La L
+    (0x01b42, 0x01b44,),  # Balinese Vowel Sign Pepe..Balinese Adeg Adeg
+    (0x01b6b, 0x01b73,),  # Balinese Musical Symbol ..Balinese Musical Symbol
+    (0x01b80, 0x01b81,),  # Sundanese Sign Panyecek ..Sundanese Sign Panglayar
+    (0x01ba2, 0x01ba5,),  # Sundanese Consonant Sign..Sundanese Vowel Sign Pan
+    (0x01ba8, 0x01bad,),  # Sundanese Vowel Sign Pam..Sundanese Consonant Sign
+    (0x01be6, 0x01be6,),  # Batak Sign Tompi
+    (0x01be8, 0x01be9,),  # Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee
+    (0x01bed, 0x01bed,),  # Batak Vowel Sign Karo O
+    (0x01bef, 0x01bf3,),  # Batak Vowel Sign U For S..Batak Panongonan
+    (0x01c2c, 0x01c33,),  # Lepcha Vowel Sign E     ..Lepcha Consonant Sign T
+    (0x01c36, 0x01c37,),  # Lepcha Sign Ran         ..Lepcha Sign Nukta
+    (0x01cd0, 0x01cd2,),  # Vedic Tone Karshana     ..Vedic Tone Prenkha
+    (0x01cd4, 0x01ce0,),  # Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash
+    (0x01ce2, 0x01ce8,),  # Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda
+    (0x01ced, 0x01ced,),  # Vedic Sign Tiryak
+    (0x01cf4, 0x01cf4,),  # Vedic Tone Candra Above
+    (0x01cf8, 0x01cf9,),  # Vedic Tone Ring Above   ..Vedic Tone Double Ring A
+    (0x01dc0, 0x01dff,),  # Combining Dotted Grave A..Combining Right Arrowhea
+    (0x0200c, 0x0200c,),  # Zero Width Non-joiner
+    (0x020d0, 0x020f0,),  # Combining Left Harpoon A..Combining Asterisk Above
+    (0x02cef, 0x02cf1,),  # Coptic Combining Ni Abov..Coptic Combining Spiritu
+    (0x02d7f, 0x02d7f,),  # Tifinagh Consonant Joiner
+    (0x02de0, 0x02dff,),  # Combining Cyrillic Lette..Combining Cyrillic Lette
+    (0x0302a, 0x0302f,),  # Ideographic Level Tone M..Hangul Double Dot Tone M
+    (0x03099, 0x0309a,),  # Combining Katakana-hirag..Combining Katakana-hirag
+    (0x0a66f, 0x0a672,),  # Combining Cyrillic Vzmet..Combining Cyrillic Thous
+    (0x0a674, 0x0a67d,),  # Combining Cyrillic Lette..Combining Cyrillic Payer
+    (0x0a69e, 0x0a69f,),  # Combining Cyrillic Lette..Combining Cyrillic Lette
+    (0x0a6f0, 0x0a6f1,),  # Bamum Combining Mark Koq..Bamum Combining Mark Tuk
+    (0x0a802, 0x0a802,),  # Syloti Nagri Sign Dvisvara
+    (0x0a806, 0x0a806,),  # Syloti Nagri Sign Hasanta
+    (0x0a80b, 0x0a80b,),  # Syloti Nagri Sign Anusvara
+    (0x0a825, 0x0a826,),  # Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign
+    (0x0a82c, 0x0a82c,),  # Syloti Nagri Sign Alternate Hasanta
+    (0x0a8c4, 0x0a8c5,),  # Saurashtra Sign Virama  ..Saurashtra Sign Candrabi
+    (0x0a8e0, 0x0a8f1,),  # Combining Devanagari Dig..Combining Devanagari Sig
+    (0x0a8ff, 0x0a8ff,),  # Devanagari Vowel Sign Ay
+    (0x0a926, 0x0a92d,),  # Kayah Li Vowel Ue       ..Kayah Li Tone Calya Plop
+    (0x0a947, 0x0a951,),  # Rejang Vowel Sign I     ..Rejang Consonant Sign R
+    (0x0a953, 0x0a953,),  # Rejang Virama
+    (0x0a980, 0x0a982,),  # Javanese Sign Panyangga ..Javanese Sign Layar
+    (0x0a9b3, 0x0a9b3,),  # Javanese Sign Cecak Telu
+    (0x0a9b6, 0x0a9b9,),  # Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku
+    (0x0a9bc, 0x0a9bd,),  # Javanese Vowel Sign Pepe..Javanese Consonant Sign
+    (0x0a9c0, 0x0a9c0,),  # Javanese Pangkon
+    (0x0a9e5, 0x0a9e5,),  # Myanmar Sign Shan Saw
+    (0x0aa29, 0x0aa2e,),  # Cham Vowel Sign Aa      ..Cham Vowel Sign Oe
+    (0x0aa31, 0x0aa32,),  # Cham Vowel Sign Au      ..Cham Vowel Sign Ue
+    (0x0aa35, 0x0aa36,),  # Cham Consonant Sign La  ..Cham Consonant Sign Wa
+    (0x0aa43, 0x0aa43,),  # Cham Consonant Sign Final Ng
+    (0x0aa4c, 0x0aa4c,),  # Cham Consonant Sign Final M
+    (0x0aa7c, 0x0aa7c,),  # Myanmar Sign Tai Laing Tone-2
+    (0x0aab0, 0x0aab0,),  # Tai Viet Mai Kang
+    (0x0aab2, 0x0aab4,),  # Tai Viet Vowel I        ..Tai Viet Vowel U
+    (0x0aab7, 0x0aab8,),  # Tai Viet Mai Khit       ..Tai Viet Vowel Ia
+    (0x0aabe, 0x0aabf,),  # Tai Viet Vowel Am       ..Tai Viet Tone Mai Ek
+    (0x0aac1, 0x0aac1,),  # Tai Viet Tone Mai Tho
+    (0x0aaec, 0x0aaed,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+    (0x0aaf6, 0x0aaf6,),  # Meetei Mayek Virama
+    (0x0abe5, 0x0abe5,),  # Meetei Mayek Vowel Sign Anap
+    (0x0abe8, 0x0abe8,),  # Meetei Mayek Vowel Sign Unap
+    (0x0abed, 0x0abed,),  # Meetei Mayek Apun Iyek
+    (0x0fb1e, 0x0fb1e,),  # Hebrew Point Judeo-spanish Varika
+    (0x0fe00, 0x0fe0f,),  # Variation Selector-1    ..Variation Selector-16
+    (0x0fe20, 0x0fe2f,),  # Combining Ligature Left ..Combining Cyrillic Titlo
+    (0x0ff9e, 0x0ff9f,),  # Halfwidth Katakana Voice..Halfwidth Katakana Semi-
+    (0x101fd, 0x101fd,),  # Phaistos Disc Sign Combining Oblique Stroke
+    (0x102e0, 0x102e0,),  # Coptic Epact Thousands Mark
+    (0x10376, 0x1037a,),  # Combining Old Permic Let..Combining Old Permic Let
+    (0x10a01, 0x10a03,),  # Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo
+    (0x10a05, 0x10a06,),  # Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O
+    (0x10a0c, 0x10a0f,),  # Kharoshthi Vowel Length ..Kharoshthi Sign Visarga
+    (0x10a38, 0x10a3a,),  # Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo
+    (0x10a3f, 0x10a3f,),  # Kharoshthi Virama
+    (0x10ae5, 0x10ae6,),  # Manichaean Abbreviation ..Manichaean Abbreviation
+    (0x10d24, 0x10d27,),  # Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas
+    (0x10d69, 0x10d6d,),  # Garay Vowel Sign E      ..Garay Consonant Nasaliza
+    (0x10eab, 0x10eac,),  # Yezidi Combining Hamza M..Yezidi Combining Madda M
+    (0x10efa, 0x10eff,),  # Arabic Double Vertical B..Arabic Small Low Word Ma
+    (0x10f46, 0x10f50,),  # Sogdian Combining Dot Be..Sogdian Combining Stroke
+    (0x10f82, 0x10f85,),  # Old Uyghur Combining Dot..Old Uyghur Combining Two
+    (0x11001, 0x11001,),  # Brahmi Sign Anusvara
+    (0x11038, 0x11046,),  # Brahmi Vowel Sign Aa    ..Brahmi Virama
+    (0x11070, 0x11070,),  # Brahmi Sign Old Tamil Virama
+    (0x11073, 0x11074,),  # Brahmi Vowel Sign Old Ta..Brahmi Vowel Sign Old Ta
+    (0x1107f, 0x11081,),  # Brahmi Number Joiner    ..Kaithi Sign Anusvara
+    (0x110b3, 0x110b6,),  # Kaithi Vowel Sign U     ..Kaithi Vowel Sign Ai
+    (0x110b9, 0x110ba,),  # Kaithi Sign Virama      ..Kaithi Sign Nukta
+    (0x110c2, 0x110c2,),  # Kaithi Vowel Sign Vocalic R
+    (0x11100, 0x11102,),  # Chakma Sign Candrabindu ..Chakma Sign Visarga
+    (0x11127, 0x1112b,),  # Chakma Vowel Sign A     ..Chakma Vowel Sign Uu
+    (0x1112d, 0x11134,),  # Chakma Vowel Sign Ai    ..Chakma Maayyaa
+    (0x11173, 0x11173,),  # Mahajani Sign Nukta
+    (0x11180, 0x11181,),  # Sharada Sign Candrabindu..Sharada Sign Anusvara
+    (0x111b6, 0x111be,),  # Sharada Vowel Sign U    ..Sharada Vowel Sign O
+    (0x111c0, 0x111c0,),  # Sharada Sign Virama
+    (0x111c9, 0x111cc,),  # Sharada Sandhi Mark     ..Sharada Extra Short Vowe
+    (0x111cf, 0x111cf,),  # Sharada Sign Inverted Candrabindu
+    (0x1122f, 0x11231,),  # Khojki Vowel Sign U     ..Khojki Vowel Sign Ai
+    (0x11234, 0x11237,),  # Khojki Sign Anusvara    ..Khojki Sign Shadda
+    (0x1123e, 0x1123e,),  # Khojki Sign Sukun
+    (0x11241, 0x11241,),  # Khojki Vowel Sign Vocalic R
+    (0x112df, 0x112df,),  # Khudawadi Sign Anusvara
+    (0x112e3, 0x112ea,),  # Khudawadi Vowel Sign U  ..Khudawadi Sign Virama
+    (0x11300, 0x11301,),  # Grantha Sign Combining A..Grantha Sign Candrabindu
+    (0x1133b, 0x1133c,),  # Combining Bindu Below   ..Grantha Sign Nukta
+    (0x1133e, 0x1133e,),  # Grantha Vowel Sign Aa
+    (0x11340, 0x11340,),  # Grantha Vowel Sign Ii
+    (0x1134d, 0x1134d,),  # Grantha Sign Virama
+    (0x11357, 0x11357,),  # Grantha Au Length Mark
+    (0x11366, 0x1136c,),  # Combining Grantha Digit ..Combining Grantha Digit
+    (0x11370, 0x11374,),  # Combining Grantha Letter..Combining Grantha Letter
+    (0x113b8, 0x113b8,),  # Tulu-tigalari Vowel Sign Aa
+    (0x113bb, 0x113c0,),  # Tulu-tigalari Vowel Sign..Tulu-tigalari Vowel Sign
+    (0x113c2, 0x113c2,),  # Tulu-tigalari Vowel Sign Ee
+    (0x113c5, 0x113c5,),  # Tulu-tigalari Vowel Sign Ai
+    (0x113c7, 0x113c9,),  # Tulu-tigalari Vowel Sign..Tulu-tigalari Au Length
+    (0x113ce, 0x113d0,),  # Tulu-tigalari Sign Viram..Tulu-tigalari Conjoiner
+    (0x113d2, 0x113d2,),  # Tulu-tigalari Gemination Mark
+    (0x113e1, 0x113e2,),  # Tulu-tigalari Vedic Tone..Tulu-tigalari Vedic Tone
+    (0x11438, 0x1143f,),  # Newa Vowel Sign U       ..Newa Vowel Sign Ai
+    (0x11442, 0x11444,),  # Newa Sign Virama        ..Newa Sign Anusvara
+    (0x11446, 0x11446,),  # Newa Sign Nukta
+    (0x1145e, 0x1145e,),  # Newa Sandhi Mark
+    (0x114b0, 0x114b0,),  # Tirhuta Vowel Sign Aa
+    (0x114b3, 0x114b8,),  # Tirhuta Vowel Sign U    ..Tirhuta Vowel Sign Vocal
+    (0x114ba, 0x114ba,),  # Tirhuta Vowel Sign Short E
+    (0x114bd, 0x114bd,),  # Tirhuta Vowel Sign Short O
+    (0x114bf, 0x114c0,),  # Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara
+    (0x114c2, 0x114c3,),  # Tirhuta Sign Virama     ..Tirhuta Sign Nukta
+    (0x115af, 0x115af,),  # Siddham Vowel Sign Aa
+    (0x115b2, 0x115b5,),  # Siddham Vowel Sign U    ..Siddham Vowel Sign Vocal
+    (0x115bc, 0x115bd,),  # Siddham Sign Candrabindu..Siddham Sign Anusvara
+    (0x115bf, 0x115c0,),  # Siddham Sign Virama     ..Siddham Sign Nukta
+    (0x115dc, 0x115dd,),  # Siddham Vowel Sign Alter..Siddham Vowel Sign Alter
+    (0x11633, 0x1163a,),  # Modi Vowel Sign U       ..Modi Vowel Sign Ai
+    (0x1163d, 0x1163d,),  # Modi Sign Anusvara
+    (0x1163f, 0x11640,),  # Modi Sign Virama        ..Modi Sign Ardhacandra
+    (0x116ab, 0x116ab,),  # Takri Sign Anusvara
+    (0x116ad, 0x116ad,),  # Takri Vowel Sign Aa
+    (0x116b0, 0x116b7,),  # Takri Vowel Sign U      ..Takri Sign Nukta
+    (0x1171d, 0x1171d,),  # Ahom Consonant Sign Medial La
+    (0x1171f, 0x1171f,),  # Ahom Consonant Sign Medial Ligating Ra
+    (0x11722, 0x11725,),  # Ahom Vowel Sign I       ..Ahom Vowel Sign Uu
+    (0x11727, 0x1172b,),  # Ahom Vowel Sign Aw      ..Ahom Sign Killer
+    (0x1182f, 0x11837,),  # Dogra Vowel Sign U      ..Dogra Sign Anusvara
+    (0x11839, 0x1183a,),  # Dogra Sign Virama       ..Dogra Sign Nukta
+    (0x11930, 0x11930,),  # Dives Akuru Vowel Sign Aa
+    (0x1193b, 0x1193e,),  # Dives Akuru Sign Anusvar..Dives Akuru Virama
+    (0x11943, 0x11943,),  # Dives Akuru Sign Nukta
+    (0x119d4, 0x119d7,),  # Nandinagari Vowel Sign U..Nandinagari Vowel Sign V
+    (0x119da, 0x119db,),  # Nandinagari Vowel Sign E..Nandinagari Vowel Sign A
+    (0x119e0, 0x119e0,),  # Nandinagari Sign Virama
+    (0x11a01, 0x11a0a,),  # Zanabazar Square Vowel S..Zanabazar Square Vowel L
+    (0x11a33, 0x11a38,),  # Zanabazar Square Final C..Zanabazar Square Sign An
+    (0x11a3b, 0x11a3e,),  # Zanabazar Square Cluster..Zanabazar Square Cluster
+    (0x11a47, 0x11a47,),  # Zanabazar Square Subjoiner
+    (0x11a51, 0x11a56,),  # Soyombo Vowel Sign I    ..Soyombo Vowel Sign Oe
+    (0x11a59, 0x11a5b,),  # Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar
+    (0x11a8a, 0x11a96,),  # Soyombo Final Consonant ..Soyombo Sign Anusvara
+    (0x11a98, 0x11a99,),  # Soyombo Gemination Mark ..Soyombo Subjoiner
+    (0x11b60, 0x11b60,),  # Sharada Vowel Sign Oe
+    (0x11b62, 0x11b64,),  # Sharada Vowel Sign Ue   ..Sharada Vowel Sign Short
+    (0x11b66, 0x11b66,),  # Sharada Vowel Sign Candra E
+    (0x11c30, 0x11c36,),  # Bhaiksuki Vowel Sign I  ..Bhaiksuki Vowel Sign Voc
+    (0x11c38, 0x11c3d,),  # Bhaiksuki Vowel Sign E  ..Bhaiksuki Sign Anusvara
+    (0x11c3f, 0x11c3f,),  # Bhaiksuki Sign Virama
+    (0x11c92, 0x11ca7,),  # Marchen Subjoined Letter..Marchen Subjoined Letter
+    (0x11caa, 0x11cb0,),  # Marchen Subjoined Letter..Marchen Vowel Sign Aa
+    (0x11cb2, 0x11cb3,),  # Marchen Vowel Sign U    ..Marchen Vowel Sign E
+    (0x11cb5, 0x11cb6,),  # Marchen Sign Anusvara   ..Marchen Sign Candrabindu
+    (0x11d31, 0x11d36,),  # Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign
+    (0x11d3a, 0x11d3a,),  # Masaram Gondi Vowel Sign E
+    (0x11d3c, 0x11d3d,),  # Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign
+    (0x11d3f, 0x11d45,),  # Masaram Gondi Vowel Sign..Masaram Gondi Virama
+    (0x11d47, 0x11d47,),  # Masaram Gondi Ra-kara
+    (0x11d90, 0x11d91,),  # Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign
+    (0x11d95, 0x11d95,),  # Gunjala Gondi Sign Anusvara
+    (0x11d97, 0x11d97,),  # Gunjala Gondi Virama
+    (0x11ef3, 0x11ef4,),  # Makasar Vowel Sign I    ..Makasar Vowel Sign U
+    (0x11f00, 0x11f01,),  # Kawi Sign Candrabindu   ..Kawi Sign Anusvara
+    (0x11f36, 0x11f3a,),  # Kawi Vowel Sign I       ..Kawi Vowel Sign Vocalic
+    (0x11f40, 0x11f42,),  # Kawi Vowel Sign Eu      ..Kawi Conjoiner
+    (0x11f5a, 0x11f5a,),  # Kawi Sign Nukta
+    (0x13440, 0x13440,),  # Egyptian Hieroglyph Mirror Horizontally
+    (0x13447, 0x13455,),  # Egyptian Hieroglyph Modi..Egyptian Hieroglyph Modi
+    (0x1611e, 0x16129,),  # Gurung Khema Vowel Sign ..Gurung Khema Vowel Lengt
+    (0x1612d, 0x1612f,),  # Gurung Khema Sign Anusva..Gurung Khema Sign Tholho
+    (0x16af0, 0x16af4,),  # Bassa Vah Combining High..Bassa Vah Combining High
+    (0x16b30, 0x16b36,),  # Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta
+    (0x16f4f, 0x16f4f,),  # Miao Sign Consonant Modifier Bar
+    (0x16f8f, 0x16f92,),  # Miao Tone Right         ..Miao Tone Below
+    (0x16fe4, 0x16fe4,),  # Khitan Small Script Filler
+    (0x16ff0, 0x16ff1,),  # Vietnamese Alternate Rea..Vietnamese Alternate Rea
+    (0x1bc9d, 0x1bc9e,),  # Duployan Thick Letter Se..Duployan Double Mark
+    (0x1cf00, 0x1cf2d,),  # Znamenny Combining Mark ..Znamenny Combining Mark
+    (0x1cf30, 0x1cf46,),  # Znamenny Combining Tonal..Znamenny Priznak Modifie
+    (0x1d165, 0x1d169,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d16d, 0x1d172,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d17b, 0x1d182,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d185, 0x1d18b,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d1aa, 0x1d1ad,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d242, 0x1d244,),  # Combining Greek Musical ..Combining Greek Musical
+    (0x1da00, 0x1da36,),  # Signwriting Head Rim    ..Signwriting Air Sucking
+    (0x1da3b, 0x1da6c,),  # Signwriting Mouth Closed..Signwriting Excitement
+    (0x1da75, 0x1da75,),  # Signwriting Upper Body Tilting From Hip Joints
+    (0x1da84, 0x1da84,),  # Signwriting Location Head Neck
+    (0x1da9b, 0x1da9f,),  # Signwriting Fill Modifie..Signwriting Fill Modifie
+    (0x1daa1, 0x1daaf,),  # Signwriting Rotation Mod..Signwriting Rotation Mod
+    (0x1e000, 0x1e006,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e008, 0x1e018,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e01b, 0x1e021,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e023, 0x1e024,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e026, 0x1e02a,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e08f, 0x1e08f,),  # Combining Cyrillic Small Letter Byelorussian-ukr
+    (0x1e130, 0x1e136,),  # Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T
+    (0x1e2ae, 0x1e2ae,),  # Toto Sign Rising Tone
+    (0x1e2ec, 0x1e2ef,),  # Wancho Tone Tup         ..Wancho Tone Koini
+    (0x1e4ec, 0x1e4ef,),  # Nag Mundari Sign Muhor  ..Nag Mundari Sign Sutuh
+    (0x1e5ee, 0x1e5ef,),  # Ol Onal Sign Mu         ..Ol Onal Sign Ikir
+    (0x1e6e3, 0x1e6e3,),  # Tai Yo Sign Ue
+    (0x1e6e6, 0x1e6e6,),  # Tai Yo Sign Au
+    (0x1e6ee, 0x1e6ef,),  # Tai Yo Sign Ay          ..Tai Yo Sign Ang
+    (0x1e6f5, 0x1e6f5,),  # Tai Yo Sign Om
+    (0x1e8d0, 0x1e8d6,),  # Mende Kikakui Combining ..Mende Kikakui Combining
+    (0x1e944, 0x1e94a,),  # Adlam Alif Lengthener   ..Adlam Nukta
+    (0x1f3fb, 0x1f3ff,),  # Emoji Modifier Fitzpatri..Emoji Modifier Fitzpatri
+    (0xe0020, 0xe007f,),  # Tag Space               ..Cancel Tag
+    (0xe0100, 0xe01ef,),  # Variation Selector-17   ..Variation Selector-256
+)
+
+GRAPHEME_ZWJ = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x0200d, 0x0200d,),  # Zero Width Joiner
+)
+
+GRAPHEME_REGIONAL_INDICATOR = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x1f1e6, 0x1f1ff,),  # Regional Indicator Symbo..Regional Indicator Symbo
+)
+
+GRAPHEME_PREPEND = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x00600, 0x00605,),  # Arabic Number Sign      ..Arabic Number Mark Above
+    (0x006dd, 0x006dd,),  # Arabic End Of Ayah
+    (0x0070f, 0x0070f,),  # Syriac Abbreviation Mark
+    (0x00890, 0x00891,),  # Arabic Pound Mark Above ..Arabic Piastre Mark Abov
+    (0x008e2, 0x008e2,),  # Arabic Disputed End Of Ayah
+    (0x00d4e, 0x00d4e,),  # Malayalam Letter Dot Reph
+    (0x110bd, 0x110bd,),  # Kaithi Number Sign
+    (0x110cd, 0x110cd,),  # Kaithi Number Sign Above
+    (0x111c2, 0x111c3,),  # Sharada Sign Jihvamuliya..Sharada Sign Upadhmaniya
+    (0x113d1, 0x113d1,),  # Tulu-tigalari Repha
+    (0x1193f, 0x1193f,),  # Dives Akuru Prefixed Nasal Sign
+    (0x11941, 0x11941,),  # Dives Akuru Initial Ra
+    (0x11a84, 0x11a89,),  # Soyombo Sign Jihvamuliya..Soyombo Cluster-initial
+    (0x11d46, 0x11d46,),  # Masaram Gondi Repha
+    (0x11f02, 0x11f02,),  # Kawi Sign Repha
+)
+
+GRAPHEME_SPACINGMARK = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x00903, 0x00903,),  # Devanagari Sign Visarga
+    (0x0093b, 0x0093b,),  # Devanagari Vowel Sign Ooe
+    (0x0093e, 0x00940,),  # Devanagari Vowel Sign Aa..Devanagari Vowel Sign Ii
+    (0x00949, 0x0094c,),  # Devanagari Vowel Sign Ca..Devanagari Vowel Sign Au
+    (0x0094e, 0x0094f,),  # Devanagari Vowel Sign Pr..Devanagari Vowel Sign Aw
+    (0x00982, 0x00983,),  # Bengali Sign Anusvara   ..Bengali Sign Visarga
+    (0x009bf, 0x009c0,),  # Bengali Vowel Sign I    ..Bengali Vowel Sign Ii
+    (0x009c7, 0x009c8,),  # Bengali Vowel Sign E    ..Bengali Vowel Sign Ai
+    (0x009cb, 0x009cc,),  # Bengali Vowel Sign O    ..Bengali Vowel Sign Au
+    (0x00a03, 0x00a03,),  # Gurmukhi Sign Visarga
+    (0x00a3e, 0x00a40,),  # Gurmukhi Vowel Sign Aa  ..Gurmukhi Vowel Sign Ii
+    (0x00a83, 0x00a83,),  # Gujarati Sign Visarga
+    (0x00abe, 0x00ac0,),  # Gujarati Vowel Sign Aa  ..Gujarati Vowel Sign Ii
+    (0x00ac9, 0x00ac9,),  # Gujarati Vowel Sign Candra O
+    (0x00acb, 0x00acc,),  # Gujarati Vowel Sign O   ..Gujarati Vowel Sign Au
+    (0x00b02, 0x00b03,),  # Oriya Sign Anusvara     ..Oriya Sign Visarga
+    (0x00b40, 0x00b40,),  # Oriya Vowel Sign Ii
+    (0x00b47, 0x00b48,),  # Oriya Vowel Sign E      ..Oriya Vowel Sign Ai
+    (0x00b4b, 0x00b4c,),  # Oriya Vowel Sign O      ..Oriya Vowel Sign Au
+    (0x00bbf, 0x00bbf,),  # Tamil Vowel Sign I
+    (0x00bc1, 0x00bc2,),  # Tamil Vowel Sign U      ..Tamil Vowel Sign Uu
+    (0x00bc6, 0x00bc8,),  # Tamil Vowel Sign E      ..Tamil Vowel Sign Ai
+    (0x00bca, 0x00bcc,),  # Tamil Vowel Sign O      ..Tamil Vowel Sign Au
+    (0x00c01, 0x00c03,),  # Telugu Sign Candrabindu ..Telugu Sign Visarga
+    (0x00c41, 0x00c44,),  # Telugu Vowel Sign U     ..Telugu Vowel Sign Vocali
+    (0x00c82, 0x00c83,),  # Kannada Sign Anusvara   ..Kannada Sign Visarga
+    (0x00cbe, 0x00cbe,),  # Kannada Vowel Sign Aa
+    (0x00cc1, 0x00cc1,),  # Kannada Vowel Sign U
+    (0x00cc3, 0x00cc4,),  # Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal
+    (0x00cf3, 0x00cf3,),  # Kannada Sign Combining Anusvara Above Right
+    (0x00d02, 0x00d03,),  # Malayalam Sign Anusvara ..Malayalam Sign Visarga
+    (0x00d3f, 0x00d40,),  # Malayalam Vowel Sign I  ..Malayalam Vowel Sign Ii
+    (0x00d46, 0x00d48,),  # Malayalam Vowel Sign E  ..Malayalam Vowel Sign Ai
+    (0x00d4a, 0x00d4c,),  # Malayalam Vowel Sign O  ..Malayalam Vowel Sign Au
+    (0x00d82, 0x00d83,),  # Sinhala Sign Anusvaraya ..Sinhala Sign Visargaya
+    (0x00dd0, 0x00dd1,),  # Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Diga
+    (0x00dd8, 0x00dde,),  # Sinhala Vowel Sign Gaett..Sinhala Vowel Sign Kombu
+    (0x00df2, 0x00df3,),  # Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga
+    (0x00e33, 0x00e33,),  # Thai Character Sara Am
+    (0x00eb3, 0x00eb3,),  # Lao Vowel Sign Am
+    (0x00f3e, 0x00f3f,),  # Tibetan Sign Yar Tshes  ..Tibetan Sign Mar Tshes
+    (0x00f7f, 0x00f7f,),  # Tibetan Sign Rnam Bcad
+    (0x01031, 0x01031,),  # Myanmar Vowel Sign E
+    (0x0103b, 0x0103c,),  # Myanmar Consonant Sign M..Myanmar Consonant Sign M
+    (0x01056, 0x01057,),  # Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal
+    (0x01084, 0x01084,),  # Myanmar Vowel Sign Shan E
+    (0x017b6, 0x017b6,),  # Khmer Vowel Sign Aa
+    (0x017be, 0x017c5,),  # Khmer Vowel Sign Oe     ..Khmer Vowel Sign Au
+    (0x017c7, 0x017c8,),  # Khmer Sign Reahmuk      ..Khmer Sign Yuukaleapintu
+    (0x01923, 0x01926,),  # Limbu Vowel Sign Ee     ..Limbu Vowel Sign Au
+    (0x01929, 0x0192b,),  # Limbu Subjoined Letter Y..Limbu Subjoined Letter W
+    (0x01930, 0x01931,),  # Limbu Small Letter Ka   ..Limbu Small Letter Nga
+    (0x01933, 0x01938,),  # Limbu Small Letter Ta   ..Limbu Small Letter La
+    (0x01a19, 0x01a1a,),  # Buginese Vowel Sign E   ..Buginese Vowel Sign O
+    (0x01a55, 0x01a55,),  # Tai Tham Consonant Sign Medial Ra
+    (0x01a57, 0x01a57,),  # Tai Tham Consonant Sign La Tang Lai
+    (0x01a6d, 0x01a72,),  # Tai Tham Vowel Sign Oy  ..Tai Tham Vowel Sign Tham
+    (0x01b04, 0x01b04,),  # Balinese Sign Bisah
+    (0x01b3e, 0x01b41,),  # Balinese Vowel Sign Tali..Balinese Vowel Sign Tali
+    (0x01b82, 0x01b82,),  # Sundanese Sign Pangwisad
+    (0x01ba1, 0x01ba1,),  # Sundanese Consonant Sign Pamingkal
+    (0x01ba6, 0x01ba7,),  # Sundanese Vowel Sign Pan..Sundanese Vowel Sign Pan
+    (0x01be7, 0x01be7,),  # Batak Vowel Sign E
+    (0x01bea, 0x01bec,),  # Batak Vowel Sign I      ..Batak Vowel Sign O
+    (0x01bee, 0x01bee,),  # Batak Vowel Sign U
+    (0x01c24, 0x01c2b,),  # Lepcha Subjoined Letter ..Lepcha Vowel Sign Uu
+    (0x01c34, 0x01c35,),  # Lepcha Consonant Sign Ny..Lepcha Consonant Sign Ka
+    (0x01ce1, 0x01ce1,),  # Vedic Tone Atharvavedic Independent Svarita
+    (0x01cf7, 0x01cf7,),  # Vedic Sign Atikrama
+    (0x0a823, 0x0a824,),  # Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign
+    (0x0a827, 0x0a827,),  # Syloti Nagri Vowel Sign Oo
+    (0x0a880, 0x0a881,),  # Saurashtra Sign Anusvara..Saurashtra Sign Visarga
+    (0x0a8b4, 0x0a8c3,),  # Saurashtra Consonant Sig..Saurashtra Vowel Sign Au
+    (0x0a952, 0x0a952,),  # Rejang Consonant Sign H
+    (0x0a983, 0x0a983,),  # Javanese Sign Wignyan
+    (0x0a9b4, 0x0a9b5,),  # Javanese Vowel Sign Taru..Javanese Vowel Sign Tolo
+    (0x0a9ba, 0x0a9bb,),  # Javanese Vowel Sign Tali..Javanese Vowel Sign Dirg
+    (0x0a9be, 0x0a9bf,),  # Javanese Consonant Sign ..Javanese Consonant Sign
+    (0x0aa2f, 0x0aa30,),  # Cham Vowel Sign O       ..Cham Vowel Sign Ai
+    (0x0aa33, 0x0aa34,),  # Cham Consonant Sign Ya  ..Cham Consonant Sign Ra
+    (0x0aa4d, 0x0aa4d,),  # Cham Consonant Sign Final H
+    (0x0aaeb, 0x0aaeb,),  # Meetei Mayek Vowel Sign Ii
+    (0x0aaee, 0x0aaef,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+    (0x0aaf5, 0x0aaf5,),  # Meetei Mayek Vowel Sign Visarga
+    (0x0abe3, 0x0abe4,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+    (0x0abe6, 0x0abe7,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+    (0x0abe9, 0x0abea,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+    (0x0abec, 0x0abec,),  # Meetei Mayek Lum Iyek
+    (0x11000, 0x11000,),  # Brahmi Sign Candrabindu
+    (0x11002, 0x11002,),  # Brahmi Sign Visarga
+    (0x11082, 0x11082,),  # Kaithi Sign Visarga
+    (0x110b0, 0x110b2,),  # Kaithi Vowel Sign Aa    ..Kaithi Vowel Sign Ii
+    (0x110b7, 0x110b8,),  # Kaithi Vowel Sign O     ..Kaithi Vowel Sign Au
+    (0x1112c, 0x1112c,),  # Chakma Vowel Sign E
+    (0x11145, 0x11146,),  # Chakma Vowel Sign Aa    ..Chakma Vowel Sign Ei
+    (0x11182, 0x11182,),  # Sharada Sign Visarga
+    (0x111b3, 0x111b5,),  # Sharada Vowel Sign Aa   ..Sharada Vowel Sign Ii
+    (0x111bf, 0x111bf,),  # Sharada Vowel Sign Au
+    (0x111ce, 0x111ce,),  # Sharada Vowel Sign Prishthamatra E
+    (0x1122c, 0x1122e,),  # Khojki Vowel Sign Aa    ..Khojki Vowel Sign Ii
+    (0x11232, 0x11233,),  # Khojki Vowel Sign O     ..Khojki Vowel Sign Au
+    (0x112e0, 0x112e2,),  # Khudawadi Vowel Sign Aa ..Khudawadi Vowel Sign Ii
+    (0x11302, 0x11303,),  # Grantha Sign Anusvara   ..Grantha Sign Visarga
+    (0x1133f, 0x1133f,),  # Grantha Vowel Sign I
+    (0x11341, 0x11344,),  # Grantha Vowel Sign U    ..Grantha Vowel Sign Vocal
+    (0x11347, 0x11348,),  # Grantha Vowel Sign Ee   ..Grantha Vowel Sign Ai
+    (0x1134b, 0x1134c,),  # Grantha Vowel Sign Oo   ..Grantha Vowel Sign Au
+    (0x11362, 0x11363,),  # Grantha Vowel Sign Vocal..Grantha Vowel Sign Vocal
+    (0x113b9, 0x113ba,),  # Tulu-tigalari Vowel Sign..Tulu-tigalari Vowel Sign
+    (0x113ca, 0x113ca,),  # Tulu-tigalari Sign Candra Anunasika
+    (0x113cc, 0x113cd,),  # Tulu-tigalari Sign Anusv..Tulu-tigalari Sign Visar
+    (0x11435, 0x11437,),  # Newa Vowel Sign Aa      ..Newa Vowel Sign Ii
+    (0x11440, 0x11441,),  # Newa Vowel Sign O       ..Newa Vowel Sign Au
+    (0x11445, 0x11445,),  # Newa Sign Visarga
+    (0x114b1, 0x114b2,),  # Tirhuta Vowel Sign I    ..Tirhuta Vowel Sign Ii
+    (0x114b9, 0x114b9,),  # Tirhuta Vowel Sign E
+    (0x114bb, 0x114bc,),  # Tirhuta Vowel Sign Ai   ..Tirhuta Vowel Sign O
+    (0x114be, 0x114be,),  # Tirhuta Vowel Sign Au
+    (0x114c1, 0x114c1,),  # Tirhuta Sign Visarga
+    (0x115b0, 0x115b1,),  # Siddham Vowel Sign I    ..Siddham Vowel Sign Ii
+    (0x115b8, 0x115bb,),  # Siddham Vowel Sign E    ..Siddham Vowel Sign Au
+    (0x115be, 0x115be,),  # Siddham Sign Visarga
+    (0x11630, 0x11632,),  # Modi Vowel Sign Aa      ..Modi Vowel Sign Ii
+    (0x1163b, 0x1163c,),  # Modi Vowel Sign O       ..Modi Vowel Sign Au
+    (0x1163e, 0x1163e,),  # Modi Sign Visarga
+    (0x116ac, 0x116ac,),  # Takri Sign Visarga
+    (0x116ae, 0x116af,),  # Takri Vowel Sign I      ..Takri Vowel Sign Ii
+    (0x1171e, 0x1171e,),  # Ahom Consonant Sign Medial Ra
+    (0x11726, 0x11726,),  # Ahom Vowel Sign E
+    (0x1182c, 0x1182e,),  # Dogra Vowel Sign Aa     ..Dogra Vowel Sign Ii
+    (0x11838, 0x11838,),  # Dogra Sign Visarga
+    (0x11931, 0x11935,),  # Dives Akuru Vowel Sign I..Dives Akuru Vowel Sign E
+    (0x11937, 0x11938,),  # Dives Akuru Vowel Sign A..Dives Akuru Vowel Sign O
+    (0x11940, 0x11940,),  # Dives Akuru Medial Ya
+    (0x11942, 0x11942,),  # Dives Akuru Medial Ra
+    (0x119d1, 0x119d3,),  # Nandinagari Vowel Sign A..Nandinagari Vowel Sign I
+    (0x119dc, 0x119df,),  # Nandinagari Vowel Sign O..Nandinagari Sign Visarga
+    (0x119e4, 0x119e4,),  # Nandinagari Vowel Sign Prishthamatra E
+    (0x11a39, 0x11a39,),  # Zanabazar Square Sign Visarga
+    (0x11a57, 0x11a58,),  # Soyombo Vowel Sign Ai   ..Soyombo Vowel Sign Au
+    (0x11a97, 0x11a97,),  # Soyombo Sign Visarga
+    (0x11b61, 0x11b61,),  # Sharada Vowel Sign Ooe
+    (0x11b65, 0x11b65,),  # Sharada Vowel Sign Short O
+    (0x11b67, 0x11b67,),  # Sharada Vowel Sign Candra O
+    (0x11c2f, 0x11c2f,),  # Bhaiksuki Vowel Sign Aa
+    (0x11c3e, 0x11c3e,),  # Bhaiksuki Sign Visarga
+    (0x11ca9, 0x11ca9,),  # Marchen Subjoined Letter Ya
+    (0x11cb1, 0x11cb1,),  # Marchen Vowel Sign I
+    (0x11cb4, 0x11cb4,),  # Marchen Vowel Sign O
+    (0x11d8a, 0x11d8e,),  # Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign
+    (0x11d93, 0x11d94,),  # Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign
+    (0x11d96, 0x11d96,),  # Gunjala Gondi Sign Visarga
+    (0x11ef5, 0x11ef6,),  # Makasar Vowel Sign E    ..Makasar Vowel Sign O
+    (0x11f03, 0x11f03,),  # Kawi Sign Visarga
+    (0x11f34, 0x11f35,),  # Kawi Vowel Sign Aa      ..Kawi Vowel Sign Alternat
+    (0x11f3e, 0x11f3f,),  # Kawi Vowel Sign E       ..Kawi Vowel Sign Ai
+    (0x1612a, 0x1612c,),  # Gurung Khema Consonant S..Gurung Khema Consonant S
+    (0x16f51, 0x16f87,),  # Miao Sign Aspiration    ..Miao Vowel Sign Ui
+)
+
+GRAPHEME_L = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x01100, 0x0115f,),  # Hangul Choseong Kiyeok  ..Hangul Choseong Filler
+    (0x0a960, 0x0a97c,),  # Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo
+)
+
+GRAPHEME_V = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x01160, 0x011a7,),  # Hangul Jungseong Filler ..Hangul Jungseong O-yae
+    (0x0d7b0, 0x0d7c6,),  # Hangul Jungseong O-yeo  ..Hangul Jungseong Araea-e
+    (0x16d63, 0x16d63,),  # Kirat Rai Vowel Sign Aa
+    (0x16d67, 0x16d6a,),  # Kirat Rai Vowel Sign E  ..Kirat Rai Vowel Sign Au
+)
+
+GRAPHEME_T = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x011a8, 0x011ff,),  # Hangul Jongseong Kiyeok ..Hangul Jongseong Ssangni
+    (0x0d7cb, 0x0d7fb,),  # Hangul Jongseong Nieun-r..Hangul Jongseong Phieuph
+)
+
+GRAPHEME_LV = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x0ac00, 0x0ac00,),  # Hangul Syllable Ga
+    (0x0ac1c, 0x0ac1c,),  # Hangul Syllable Gae
+    (0x0ac38, 0x0ac38,),  # Hangul Syllable Gya
+    (0x0ac54, 0x0ac54,),  # Hangul Syllable Gyae
+    (0x0ac70, 0x0ac70,),  # Hangul Syllable Geo
+    (0x0ac8c, 0x0ac8c,),  # Hangul Syllable Ge
+    (0x0aca8, 0x0aca8,),  # Hangul Syllable Gyeo
+    (0x0acc4, 0x0acc4,),  # Hangul Syllable Gye
+    (0x0ace0, 0x0ace0,),  # Hangul Syllable Go
+    (0x0acfc, 0x0acfc,),  # Hangul Syllable Gwa
+    (0x0ad18, 0x0ad18,),  # Hangul Syllable Gwae
+    (0x0ad34, 0x0ad34,),  # Hangul Syllable Goe
+    (0x0ad50, 0x0ad50,),  # Hangul Syllable Gyo
+    (0x0ad6c, 0x0ad6c,),  # Hangul Syllable Gu
+    (0x0ad88, 0x0ad88,),  # Hangul Syllable Gweo
+    (0x0ada4, 0x0ada4,),  # Hangul Syllable Gwe
+    (0x0adc0, 0x0adc0,),  # Hangul Syllable Gwi
+    (0x0addc, 0x0addc,),  # Hangul Syllable Gyu
+    (0x0adf8, 0x0adf8,),  # Hangul Syllable Geu
+    (0x0ae14, 0x0ae14,),  # Hangul Syllable Gyi
+    (0x0ae30, 0x0ae30,),  # Hangul Syllable Gi
+    (0x0ae4c, 0x0ae4c,),  # Hangul Syllable Gga
+    (0x0ae68, 0x0ae68,),  # Hangul Syllable Ggae
+    (0x0ae84, 0x0ae84,),  # Hangul Syllable Ggya
+    (0x0aea0, 0x0aea0,),  # Hangul Syllable Ggyae
+    (0x0aebc, 0x0aebc,),  # Hangul Syllable Ggeo
+    (0x0aed8, 0x0aed8,),  # Hangul Syllable Gge
+    (0x0aef4, 0x0aef4,),  # Hangul Syllable Ggyeo
+    (0x0af10, 0x0af10,),  # Hangul Syllable Ggye
+    (0x0af2c, 0x0af2c,),  # Hangul Syllable Ggo
+    (0x0af48, 0x0af48,),  # Hangul Syllable Ggwa
+    (0x0af64, 0x0af64,),  # Hangul Syllable Ggwae
+    (0x0af80, 0x0af80,),  # Hangul Syllable Ggoe
+    (0x0af9c, 0x0af9c,),  # Hangul Syllable Ggyo
+    (0x0afb8, 0x0afb8,),  # Hangul Syllable Ggu
+    (0x0afd4, 0x0afd4,),  # Hangul Syllable Ggweo
+    (0x0aff0, 0x0aff0,),  # Hangul Syllable Ggwe
+    (0x0b00c, 0x0b00c,),  # Hangul Syllable Ggwi
+    (0x0b028, 0x0b028,),  # Hangul Syllable Ggyu
+    (0x0b044, 0x0b044,),  # Hangul Syllable Ggeu
+    (0x0b060, 0x0b060,),  # Hangul Syllable Ggyi
+    (0x0b07c, 0x0b07c,),  # Hangul Syllable Ggi
+    (0x0b098, 0x0b098,),  # Hangul Syllable Na
+    (0x0b0b4, 0x0b0b4,),  # Hangul Syllable Nae
+    (0x0b0d0, 0x0b0d0,),  # Hangul Syllable Nya
+    (0x0b0ec, 0x0b0ec,),  # Hangul Syllable Nyae
+    (0x0b108, 0x0b108,),  # Hangul Syllable Neo
+    (0x0b124, 0x0b124,),  # Hangul Syllable Ne
+    (0x0b140, 0x0b140,),  # Hangul Syllable Nyeo
+    (0x0b15c, 0x0b15c,),  # Hangul Syllable Nye
+    (0x0b178, 0x0b178,),  # Hangul Syllable No
+    (0x0b194, 0x0b194,),  # Hangul Syllable Nwa
+    (0x0b1b0, 0x0b1b0,),  # Hangul Syllable Nwae
+    (0x0b1cc, 0x0b1cc,),  # Hangul Syllable Noe
+    (0x0b1e8, 0x0b1e8,),  # Hangul Syllable Nyo
+    (0x0b204, 0x0b204,),  # Hangul Syllable Nu
+    (0x0b220, 0x0b220,),  # Hangul Syllable Nweo
+    (0x0b23c, 0x0b23c,),  # Hangul Syllable Nwe
+    (0x0b258, 0x0b258,),  # Hangul Syllable Nwi
+    (0x0b274, 0x0b274,),  # Hangul Syllable Nyu
+    (0x0b290, 0x0b290,),  # Hangul Syllable Neu
+    (0x0b2ac, 0x0b2ac,),  # Hangul Syllable Nyi
+    (0x0b2c8, 0x0b2c8,),  # Hangul Syllable Ni
+    (0x0b2e4, 0x0b2e4,),  # Hangul Syllable Da
+    (0x0b300, 0x0b300,),  # Hangul Syllable Dae
+    (0x0b31c, 0x0b31c,),  # Hangul Syllable Dya
+    (0x0b338, 0x0b338,),  # Hangul Syllable Dyae
+    (0x0b354, 0x0b354,),  # Hangul Syllable Deo
+    (0x0b370, 0x0b370,),  # Hangul Syllable De
+    (0x0b38c, 0x0b38c,),  # Hangul Syllable Dyeo
+    (0x0b3a8, 0x0b3a8,),  # Hangul Syllable Dye
+    (0x0b3c4, 0x0b3c4,),  # Hangul Syllable Do
+    (0x0b3e0, 0x0b3e0,),  # Hangul Syllable Dwa
+    (0x0b3fc, 0x0b3fc,),  # Hangul Syllable Dwae
+    (0x0b418, 0x0b418,),  # Hangul Syllable Doe
+    (0x0b434, 0x0b434,),  # Hangul Syllable Dyo
+    (0x0b450, 0x0b450,),  # Hangul Syllable Du
+    (0x0b46c, 0x0b46c,),  # Hangul Syllable Dweo
+    (0x0b488, 0x0b488,),  # Hangul Syllable Dwe
+    (0x0b4a4, 0x0b4a4,),  # Hangul Syllable Dwi
+    (0x0b4c0, 0x0b4c0,),  # Hangul Syllable Dyu
+    (0x0b4dc, 0x0b4dc,),  # Hangul Syllable Deu
+    (0x0b4f8, 0x0b4f8,),  # Hangul Syllable Dyi
+    (0x0b514, 0x0b514,),  # Hangul Syllable Di
+    (0x0b530, 0x0b530,),  # Hangul Syllable Dda
+    (0x0b54c, 0x0b54c,),  # Hangul Syllable Ddae
+    (0x0b568, 0x0b568,),  # Hangul Syllable Ddya
+    (0x0b584, 0x0b584,),  # Hangul Syllable Ddyae
+    (0x0b5a0, 0x0b5a0,),  # Hangul Syllable Ddeo
+    (0x0b5bc, 0x0b5bc,),  # Hangul Syllable Dde
+    (0x0b5d8, 0x0b5d8,),  # Hangul Syllable Ddyeo
+    (0x0b5f4, 0x0b5f4,),  # Hangul Syllable Ddye
+    (0x0b610, 0x0b610,),  # Hangul Syllable Ddo
+    (0x0b62c, 0x0b62c,),  # Hangul Syllable Ddwa
+    (0x0b648, 0x0b648,),  # Hangul Syllable Ddwae
+    (0x0b664, 0x0b664,),  # Hangul Syllable Ddoe
+    (0x0b680, 0x0b680,),  # Hangul Syllable Ddyo
+    (0x0b69c, 0x0b69c,),  # Hangul Syllable Ddu
+    (0x0b6b8, 0x0b6b8,),  # Hangul Syllable Ddweo
+    (0x0b6d4, 0x0b6d4,),  # Hangul Syllable Ddwe
+    (0x0b6f0, 0x0b6f0,),  # Hangul Syllable Ddwi
+    (0x0b70c, 0x0b70c,),  # Hangul Syllable Ddyu
+    (0x0b728, 0x0b728,),  # Hangul Syllable Ddeu
+    (0x0b744, 0x0b744,),  # Hangul Syllable Ddyi
+    (0x0b760, 0x0b760,),  # Hangul Syllable Ddi
+    (0x0b77c, 0x0b77c,),  # Hangul Syllable Ra
+    (0x0b798, 0x0b798,),  # Hangul Syllable Rae
+    (0x0b7b4, 0x0b7b4,),  # Hangul Syllable Rya
+    (0x0b7d0, 0x0b7d0,),  # Hangul Syllable Ryae
+    (0x0b7ec, 0x0b7ec,),  # Hangul Syllable Reo
+    (0x0b808, 0x0b808,),  # Hangul Syllable Re
+    (0x0b824, 0x0b824,),  # Hangul Syllable Ryeo
+    (0x0b840, 0x0b840,),  # Hangul Syllable Rye
+    (0x0b85c, 0x0b85c,),  # Hangul Syllable Ro
+    (0x0b878, 0x0b878,),  # Hangul Syllable Rwa
+    (0x0b894, 0x0b894,),  # Hangul Syllable Rwae
+    (0x0b8b0, 0x0b8b0,),  # Hangul Syllable Roe
+    (0x0b8cc, 0x0b8cc,),  # Hangul Syllable Ryo
+    (0x0b8e8, 0x0b8e8,),  # Hangul Syllable Ru
+    (0x0b904, 0x0b904,),  # Hangul Syllable Rweo
+    (0x0b920, 0x0b920,),  # Hangul Syllable Rwe
+    (0x0b93c, 0x0b93c,),  # Hangul Syllable Rwi
+    (0x0b958, 0x0b958,),  # Hangul Syllable Ryu
+    (0x0b974, 0x0b974,),  # Hangul Syllable Reu
+    (0x0b990, 0x0b990,),  # Hangul Syllable Ryi
+    (0x0b9ac, 0x0b9ac,),  # Hangul Syllable Ri
+    (0x0b9c8, 0x0b9c8,),  # Hangul Syllable Ma
+    (0x0b9e4, 0x0b9e4,),  # Hangul Syllable Mae
+    (0x0ba00, 0x0ba00,),  # Hangul Syllable Mya
+    (0x0ba1c, 0x0ba1c,),  # Hangul Syllable Myae
+    (0x0ba38, 0x0ba38,),  # Hangul Syllable Meo
+    (0x0ba54, 0x0ba54,),  # Hangul Syllable Me
+    (0x0ba70, 0x0ba70,),  # Hangul Syllable Myeo
+    (0x0ba8c, 0x0ba8c,),  # Hangul Syllable Mye
+    (0x0baa8, 0x0baa8,),  # Hangul Syllable Mo
+    (0x0bac4, 0x0bac4,),  # Hangul Syllable Mwa
+    (0x0bae0, 0x0bae0,),  # Hangul Syllable Mwae
+    (0x0bafc, 0x0bafc,),  # Hangul Syllable Moe
+    (0x0bb18, 0x0bb18,),  # Hangul Syllable Myo
+    (0x0bb34, 0x0bb34,),  # Hangul Syllable Mu
+    (0x0bb50, 0x0bb50,),  # Hangul Syllable Mweo
+    (0x0bb6c, 0x0bb6c,),  # Hangul Syllable Mwe
+    (0x0bb88, 0x0bb88,),  # Hangul Syllable Mwi
+    (0x0bba4, 0x0bba4,),  # Hangul Syllable Myu
+    (0x0bbc0, 0x0bbc0,),  # Hangul Syllable Meu
+    (0x0bbdc, 0x0bbdc,),  # Hangul Syllable Myi
+    (0x0bbf8, 0x0bbf8,),  # Hangul Syllable Mi
+    (0x0bc14, 0x0bc14,),  # Hangul Syllable Ba
+    (0x0bc30, 0x0bc30,),  # Hangul Syllable Bae
+    (0x0bc4c, 0x0bc4c,),  # Hangul Syllable Bya
+    (0x0bc68, 0x0bc68,),  # Hangul Syllable Byae
+    (0x0bc84, 0x0bc84,),  # Hangul Syllable Beo
+    (0x0bca0, 0x0bca0,),  # Hangul Syllable Be
+    (0x0bcbc, 0x0bcbc,),  # Hangul Syllable Byeo
+    (0x0bcd8, 0x0bcd8,),  # Hangul Syllable Bye
+    (0x0bcf4, 0x0bcf4,),  # Hangul Syllable Bo
+    (0x0bd10, 0x0bd10,),  # Hangul Syllable Bwa
+    (0x0bd2c, 0x0bd2c,),  # Hangul Syllable Bwae
+    (0x0bd48, 0x0bd48,),  # Hangul Syllable Boe
+    (0x0bd64, 0x0bd64,),  # Hangul Syllable Byo
+    (0x0bd80, 0x0bd80,),  # Hangul Syllable Bu
+    (0x0bd9c, 0x0bd9c,),  # Hangul Syllable Bweo
+    (0x0bdb8, 0x0bdb8,),  # Hangul Syllable Bwe
+    (0x0bdd4, 0x0bdd4,),  # Hangul Syllable Bwi
+    (0x0bdf0, 0x0bdf0,),  # Hangul Syllable Byu
+    (0x0be0c, 0x0be0c,),  # Hangul Syllable Beu
+    (0x0be28, 0x0be28,),  # Hangul Syllable Byi
+    (0x0be44, 0x0be44,),  # Hangul Syllable Bi
+    (0x0be60, 0x0be60,),  # Hangul Syllable Bba
+    (0x0be7c, 0x0be7c,),  # Hangul Syllable Bbae
+    (0x0be98, 0x0be98,),  # Hangul Syllable Bbya
+    (0x0beb4, 0x0beb4,),  # Hangul Syllable Bbyae
+    (0x0bed0, 0x0bed0,),  # Hangul Syllable Bbeo
+    (0x0beec, 0x0beec,),  # Hangul Syllable Bbe
+    (0x0bf08, 0x0bf08,),  # Hangul Syllable Bbyeo
+    (0x0bf24, 0x0bf24,),  # Hangul Syllable Bbye
+    (0x0bf40, 0x0bf40,),  # Hangul Syllable Bbo
+    (0x0bf5c, 0x0bf5c,),  # Hangul Syllable Bbwa
+    (0x0bf78, 0x0bf78,),  # Hangul Syllable Bbwae
+    (0x0bf94, 0x0bf94,),  # Hangul Syllable Bboe
+    (0x0bfb0, 0x0bfb0,),  # Hangul Syllable Bbyo
+    (0x0bfcc, 0x0bfcc,),  # Hangul Syllable Bbu
+    (0x0bfe8, 0x0bfe8,),  # Hangul Syllable Bbweo
+    (0x0c004, 0x0c004,),  # Hangul Syllable Bbwe
+    (0x0c020, 0x0c020,),  # Hangul Syllable Bbwi
+    (0x0c03c, 0x0c03c,),  # Hangul Syllable Bbyu
+    (0x0c058, 0x0c058,),  # Hangul Syllable Bbeu
+    (0x0c074, 0x0c074,),  # Hangul Syllable Bbyi
+    (0x0c090, 0x0c090,),  # Hangul Syllable Bbi
+    (0x0c0ac, 0x0c0ac,),  # Hangul Syllable Sa
+    (0x0c0c8, 0x0c0c8,),  # Hangul Syllable Sae
+    (0x0c0e4, 0x0c0e4,),  # Hangul Syllable Sya
+    (0x0c100, 0x0c100,),  # Hangul Syllable Syae
+    (0x0c11c, 0x0c11c,),  # Hangul Syllable Seo
+    (0x0c138, 0x0c138,),  # Hangul Syllable Se
+    (0x0c154, 0x0c154,),  # Hangul Syllable Syeo
+    (0x0c170, 0x0c170,),  # Hangul Syllable Sye
+    (0x0c18c, 0x0c18c,),  # Hangul Syllable So
+    (0x0c1a8, 0x0c1a8,),  # Hangul Syllable Swa
+    (0x0c1c4, 0x0c1c4,),  # Hangul Syllable Swae
+    (0x0c1e0, 0x0c1e0,),  # Hangul Syllable Soe
+    (0x0c1fc, 0x0c1fc,),  # Hangul Syllable Syo
+    (0x0c218, 0x0c218,),  # Hangul Syllable Su
+    (0x0c234, 0x0c234,),  # Hangul Syllable Sweo
+    (0x0c250, 0x0c250,),  # Hangul Syllable Swe
+    (0x0c26c, 0x0c26c,),  # Hangul Syllable Swi
+    (0x0c288, 0x0c288,),  # Hangul Syllable Syu
+    (0x0c2a4, 0x0c2a4,),  # Hangul Syllable Seu
+    (0x0c2c0, 0x0c2c0,),  # Hangul Syllable Syi
+    (0x0c2dc, 0x0c2dc,),  # Hangul Syllable Si
+    (0x0c2f8, 0x0c2f8,),  # Hangul Syllable Ssa
+    (0x0c314, 0x0c314,),  # Hangul Syllable Ssae
+    (0x0c330, 0x0c330,),  # Hangul Syllable Ssya
+    (0x0c34c, 0x0c34c,),  # Hangul Syllable Ssyae
+    (0x0c368, 0x0c368,),  # Hangul Syllable Sseo
+    (0x0c384, 0x0c384,),  # Hangul Syllable Sse
+    (0x0c3a0, 0x0c3a0,),  # Hangul Syllable Ssyeo
+    (0x0c3bc, 0x0c3bc,),  # Hangul Syllable Ssye
+    (0x0c3d8, 0x0c3d8,),  # Hangul Syllable Sso
+    (0x0c3f4, 0x0c3f4,),  # Hangul Syllable Sswa
+    (0x0c410, 0x0c410,),  # Hangul Syllable Sswae
+    (0x0c42c, 0x0c42c,),  # Hangul Syllable Ssoe
+    (0x0c448, 0x0c448,),  # Hangul Syllable Ssyo
+    (0x0c464, 0x0c464,),  # Hangul Syllable Ssu
+    (0x0c480, 0x0c480,),  # Hangul Syllable Ssweo
+    (0x0c49c, 0x0c49c,),  # Hangul Syllable Sswe
+    (0x0c4b8, 0x0c4b8,),  # Hangul Syllable Sswi
+    (0x0c4d4, 0x0c4d4,),  # Hangul Syllable Ssyu
+    (0x0c4f0, 0x0c4f0,),  # Hangul Syllable Sseu
+    (0x0c50c, 0x0c50c,),  # Hangul Syllable Ssyi
+    (0x0c528, 0x0c528,),  # Hangul Syllable Ssi
+    (0x0c544, 0x0c544,),  # Hangul Syllable A
+    (0x0c560, 0x0c560,),  # Hangul Syllable Ae
+    (0x0c57c, 0x0c57c,),  # Hangul Syllable Ya
+    (0x0c598, 0x0c598,),  # Hangul Syllable Yae
+    (0x0c5b4, 0x0c5b4,),  # Hangul Syllable Eo
+    (0x0c5d0, 0x0c5d0,),  # Hangul Syllable E
+    (0x0c5ec, 0x0c5ec,),  # Hangul Syllable Yeo
+    (0x0c608, 0x0c608,),  # Hangul Syllable Ye
+    (0x0c624, 0x0c624,),  # Hangul Syllable O
+    (0x0c640, 0x0c640,),  # Hangul Syllable Wa
+    (0x0c65c, 0x0c65c,),  # Hangul Syllable Wae
+    (0x0c678, 0x0c678,),  # Hangul Syllable Oe
+    (0x0c694, 0x0c694,),  # Hangul Syllable Yo
+    (0x0c6b0, 0x0c6b0,),  # Hangul Syllable U
+    (0x0c6cc, 0x0c6cc,),  # Hangul Syllable Weo
+    (0x0c6e8, 0x0c6e8,),  # Hangul Syllable We
+    (0x0c704, 0x0c704,),  # Hangul Syllable Wi
+    (0x0c720, 0x0c720,),  # Hangul Syllable Yu
+    (0x0c73c, 0x0c73c,),  # Hangul Syllable Eu
+    (0x0c758, 0x0c758,),  # Hangul Syllable Yi
+    (0x0c774, 0x0c774,),  # Hangul Syllable I
+    (0x0c790, 0x0c790,),  # Hangul Syllable Ja
+    (0x0c7ac, 0x0c7ac,),  # Hangul Syllable Jae
+    (0x0c7c8, 0x0c7c8,),  # Hangul Syllable Jya
+    (0x0c7e4, 0x0c7e4,),  # Hangul Syllable Jyae
+    (0x0c800, 0x0c800,),  # Hangul Syllable Jeo
+    (0x0c81c, 0x0c81c,),  # Hangul Syllable Je
+    (0x0c838, 0x0c838,),  # Hangul Syllable Jyeo
+    (0x0c854, 0x0c854,),  # Hangul Syllable Jye
+    (0x0c870, 0x0c870,),  # Hangul Syllable Jo
+    (0x0c88c, 0x0c88c,),  # Hangul Syllable Jwa
+    (0x0c8a8, 0x0c8a8,),  # Hangul Syllable Jwae
+    (0x0c8c4, 0x0c8c4,),  # Hangul Syllable Joe
+    (0x0c8e0, 0x0c8e0,),  # Hangul Syllable Jyo
+    (0x0c8fc, 0x0c8fc,),  # Hangul Syllable Ju
+    (0x0c918, 0x0c918,),  # Hangul Syllable Jweo
+    (0x0c934, 0x0c934,),  # Hangul Syllable Jwe
+    (0x0c950, 0x0c950,),  # Hangul Syllable Jwi
+    (0x0c96c, 0x0c96c,),  # Hangul Syllable Jyu
+    (0x0c988, 0x0c988,),  # Hangul Syllable Jeu
+    (0x0c9a4, 0x0c9a4,),  # Hangul Syllable Jyi
+    (0x0c9c0, 0x0c9c0,),  # Hangul Syllable Ji
+    (0x0c9dc, 0x0c9dc,),  # Hangul Syllable Jja
+    (0x0c9f8, 0x0c9f8,),  # Hangul Syllable Jjae
+    (0x0ca14, 0x0ca14,),  # Hangul Syllable Jjya
+    (0x0ca30, 0x0ca30,),  # Hangul Syllable Jjyae
+    (0x0ca4c, 0x0ca4c,),  # Hangul Syllable Jjeo
+    (0x0ca68, 0x0ca68,),  # Hangul Syllable Jje
+    (0x0ca84, 0x0ca84,),  # Hangul Syllable Jjyeo
+    (0x0caa0, 0x0caa0,),  # Hangul Syllable Jjye
+    (0x0cabc, 0x0cabc,),  # Hangul Syllable Jjo
+    (0x0cad8, 0x0cad8,),  # Hangul Syllable Jjwa
+    (0x0caf4, 0x0caf4,),  # Hangul Syllable Jjwae
+    (0x0cb10, 0x0cb10,),  # Hangul Syllable Jjoe
+    (0x0cb2c, 0x0cb2c,),  # Hangul Syllable Jjyo
+    (0x0cb48, 0x0cb48,),  # Hangul Syllable Jju
+    (0x0cb64, 0x0cb64,),  # Hangul Syllable Jjweo
+    (0x0cb80, 0x0cb80,),  # Hangul Syllable Jjwe
+    (0x0cb9c, 0x0cb9c,),  # Hangul Syllable Jjwi
+    (0x0cbb8, 0x0cbb8,),  # Hangul Syllable Jjyu
+    (0x0cbd4, 0x0cbd4,),  # Hangul Syllable Jjeu
+    (0x0cbf0, 0x0cbf0,),  # Hangul Syllable Jjyi
+    (0x0cc0c, 0x0cc0c,),  # Hangul Syllable Jji
+    (0x0cc28, 0x0cc28,),  # Hangul Syllable Ca
+    (0x0cc44, 0x0cc44,),  # Hangul Syllable Cae
+    (0x0cc60, 0x0cc60,),  # Hangul Syllable Cya
+    (0x0cc7c, 0x0cc7c,),  # Hangul Syllable Cyae
+    (0x0cc98, 0x0cc98,),  # Hangul Syllable Ceo
+    (0x0ccb4, 0x0ccb4,),  # Hangul Syllable Ce
+    (0x0ccd0, 0x0ccd0,),  # Hangul Syllable Cyeo
+    (0x0ccec, 0x0ccec,),  # Hangul Syllable Cye
+    (0x0cd08, 0x0cd08,),  # Hangul Syllable Co
+    (0x0cd24, 0x0cd24,),  # Hangul Syllable Cwa
+    (0x0cd40, 0x0cd40,),  # Hangul Syllable Cwae
+    (0x0cd5c, 0x0cd5c,),  # Hangul Syllable Coe
+    (0x0cd78, 0x0cd78,),  # Hangul Syllable Cyo
+    (0x0cd94, 0x0cd94,),  # Hangul Syllable Cu
+    (0x0cdb0, 0x0cdb0,),  # Hangul Syllable Cweo
+    (0x0cdcc, 0x0cdcc,),  # Hangul Syllable Cwe
+    (0x0cde8, 0x0cde8,),  # Hangul Syllable Cwi
+    (0x0ce04, 0x0ce04,),  # Hangul Syllable Cyu
+    (0x0ce20, 0x0ce20,),  # Hangul Syllable Ceu
+    (0x0ce3c, 0x0ce3c,),  # Hangul Syllable Cyi
+    (0x0ce58, 0x0ce58,),  # Hangul Syllable Ci
+    (0x0ce74, 0x0ce74,),  # Hangul Syllable Ka
+    (0x0ce90, 0x0ce90,),  # Hangul Syllable Kae
+    (0x0ceac, 0x0ceac,),  # Hangul Syllable Kya
+    (0x0cec8, 0x0cec8,),  # Hangul Syllable Kyae
+    (0x0cee4, 0x0cee4,),  # Hangul Syllable Keo
+    (0x0cf00, 0x0cf00,),  # Hangul Syllable Ke
+    (0x0cf1c, 0x0cf1c,),  # Hangul Syllable Kyeo
+    (0x0cf38, 0x0cf38,),  # Hangul Syllable Kye
+    (0x0cf54, 0x0cf54,),  # Hangul Syllable Ko
+    (0x0cf70, 0x0cf70,),  # Hangul Syllable Kwa
+    (0x0cf8c, 0x0cf8c,),  # Hangul Syllable Kwae
+    (0x0cfa8, 0x0cfa8,),  # Hangul Syllable Koe
+    (0x0cfc4, 0x0cfc4,),  # Hangul Syllable Kyo
+    (0x0cfe0, 0x0cfe0,),  # Hangul Syllable Ku
+    (0x0cffc, 0x0cffc,),  # Hangul Syllable Kweo
+    (0x0d018, 0x0d018,),  # Hangul Syllable Kwe
+    (0x0d034, 0x0d034,),  # Hangul Syllable Kwi
+    (0x0d050, 0x0d050,),  # Hangul Syllable Kyu
+    (0x0d06c, 0x0d06c,),  # Hangul Syllable Keu
+    (0x0d088, 0x0d088,),  # Hangul Syllable Kyi
+    (0x0d0a4, 0x0d0a4,),  # Hangul Syllable Ki
+    (0x0d0c0, 0x0d0c0,),  # Hangul Syllable Ta
+    (0x0d0dc, 0x0d0dc,),  # Hangul Syllable Tae
+    (0x0d0f8, 0x0d0f8,),  # Hangul Syllable Tya
+    (0x0d114, 0x0d114,),  # Hangul Syllable Tyae
+    (0x0d130, 0x0d130,),  # Hangul Syllable Teo
+    (0x0d14c, 0x0d14c,),  # Hangul Syllable Te
+    (0x0d168, 0x0d168,),  # Hangul Syllable Tyeo
+    (0x0d184, 0x0d184,),  # Hangul Syllable Tye
+    (0x0d1a0, 0x0d1a0,),  # Hangul Syllable To
+    (0x0d1bc, 0x0d1bc,),  # Hangul Syllable Twa
+    (0x0d1d8, 0x0d1d8,),  # Hangul Syllable Twae
+    (0x0d1f4, 0x0d1f4,),  # Hangul Syllable Toe
+    (0x0d210, 0x0d210,),  # Hangul Syllable Tyo
+    (0x0d22c, 0x0d22c,),  # Hangul Syllable Tu
+    (0x0d248, 0x0d248,),  # Hangul Syllable Tweo
+    (0x0d264, 0x0d264,),  # Hangul Syllable Twe
+    (0x0d280, 0x0d280,),  # Hangul Syllable Twi
+    (0x0d29c, 0x0d29c,),  # Hangul Syllable Tyu
+    (0x0d2b8, 0x0d2b8,),  # Hangul Syllable Teu
+    (0x0d2d4, 0x0d2d4,),  # Hangul Syllable Tyi
+    (0x0d2f0, 0x0d2f0,),  # Hangul Syllable Ti
+    (0x0d30c, 0x0d30c,),  # Hangul Syllable Pa
+    (0x0d328, 0x0d328,),  # Hangul Syllable Pae
+    (0x0d344, 0x0d344,),  # Hangul Syllable Pya
+    (0x0d360, 0x0d360,),  # Hangul Syllable Pyae
+    (0x0d37c, 0x0d37c,),  # Hangul Syllable Peo
+    (0x0d398, 0x0d398,),  # Hangul Syllable Pe
+    (0x0d3b4, 0x0d3b4,),  # Hangul Syllable Pyeo
+    (0x0d3d0, 0x0d3d0,),  # Hangul Syllable Pye
+    (0x0d3ec, 0x0d3ec,),  # Hangul Syllable Po
+    (0x0d408, 0x0d408,),  # Hangul Syllable Pwa
+    (0x0d424, 0x0d424,),  # Hangul Syllable Pwae
+    (0x0d440, 0x0d440,),  # Hangul Syllable Poe
+    (0x0d45c, 0x0d45c,),  # Hangul Syllable Pyo
+    (0x0d478, 0x0d478,),  # Hangul Syllable Pu
+    (0x0d494, 0x0d494,),  # Hangul Syllable Pweo
+    (0x0d4b0, 0x0d4b0,),  # Hangul Syllable Pwe
+    (0x0d4cc, 0x0d4cc,),  # Hangul Syllable Pwi
+    (0x0d4e8, 0x0d4e8,),  # Hangul Syllable Pyu
+    (0x0d504, 0x0d504,),  # Hangul Syllable Peu
+    (0x0d520, 0x0d520,),  # Hangul Syllable Pyi
+    (0x0d53c, 0x0d53c,),  # Hangul Syllable Pi
+    (0x0d558, 0x0d558,),  # Hangul Syllable Ha
+    (0x0d574, 0x0d574,),  # Hangul Syllable Hae
+    (0x0d590, 0x0d590,),  # Hangul Syllable Hya
+    (0x0d5ac, 0x0d5ac,),  # Hangul Syllable Hyae
+    (0x0d5c8, 0x0d5c8,),  # Hangul Syllable Heo
+    (0x0d5e4, 0x0d5e4,),  # Hangul Syllable He
+    (0x0d600, 0x0d600,),  # Hangul Syllable Hyeo
+    (0x0d61c, 0x0d61c,),  # Hangul Syllable Hye
+    (0x0d638, 0x0d638,),  # Hangul Syllable Ho
+    (0x0d654, 0x0d654,),  # Hangul Syllable Hwa
+    (0x0d670, 0x0d670,),  # Hangul Syllable Hwae
+    (0x0d68c, 0x0d68c,),  # Hangul Syllable Hoe
+    (0x0d6a8, 0x0d6a8,),  # Hangul Syllable Hyo
+    (0x0d6c4, 0x0d6c4,),  # Hangul Syllable Hu
+    (0x0d6e0, 0x0d6e0,),  # Hangul Syllable Hweo
+    (0x0d6fc, 0x0d6fc,),  # Hangul Syllable Hwe
+    (0x0d718, 0x0d718,),  # Hangul Syllable Hwi
+    (0x0d734, 0x0d734,),  # Hangul Syllable Hyu
+    (0x0d750, 0x0d750,),  # Hangul Syllable Heu
+    (0x0d76c, 0x0d76c,),  # Hangul Syllable Hyi
+    (0x0d788, 0x0d788,),  # Hangul Syllable Hi
+)
+
+GRAPHEME_LVT = (
+    # Source: GraphemeBreakProperty-17.0.0.txt
+    # Date: 2025-06-30, 06:20:23 GMT
+    #
+    (0x0ac01, 0x0ac1b,),  # Hangul Syllable Gag     ..Hangul Syllable Gah
+    (0x0ac1d, 0x0ac37,),  # Hangul Syllable Gaeg    ..Hangul Syllable Gaeh
+    (0x0ac39, 0x0ac53,),  # Hangul Syllable Gyag    ..Hangul Syllable Gyah
+    (0x0ac55, 0x0ac6f,),  # Hangul Syllable Gyaeg   ..Hangul Syllable Gyaeh
+    (0x0ac71, 0x0ac8b,),  # Hangul Syllable Geog    ..Hangul Syllable Geoh
+    (0x0ac8d, 0x0aca7,),  # Hangul Syllable Geg     ..Hangul Syllable Geh
+    (0x0aca9, 0x0acc3,),  # Hangul Syllable Gyeog   ..Hangul Syllable Gyeoh
+    (0x0acc5, 0x0acdf,),  # Hangul Syllable Gyeg    ..Hangul Syllable Gyeh
+    (0x0ace1, 0x0acfb,),  # Hangul Syllable Gog     ..Hangul Syllable Goh
+    (0x0acfd, 0x0ad17,),  # Hangul Syllable Gwag    ..Hangul Syllable Gwah
+    (0x0ad19, 0x0ad33,),  # Hangul Syllable Gwaeg   ..Hangul Syllable Gwaeh
+    (0x0ad35, 0x0ad4f,),  # Hangul Syllable Goeg    ..Hangul Syllable Goeh
+    (0x0ad51, 0x0ad6b,),  # Hangul Syllable Gyog    ..Hangul Syllable Gyoh
+    (0x0ad6d, 0x0ad87,),  # Hangul Syllable Gug     ..Hangul Syllable Guh
+    (0x0ad89, 0x0ada3,),  # Hangul Syllable Gweog   ..Hangul Syllable Gweoh
+    (0x0ada5, 0x0adbf,),  # Hangul Syllable Gweg    ..Hangul Syllable Gweh
+    (0x0adc1, 0x0addb,),  # Hangul Syllable Gwig    ..Hangul Syllable Gwih
+    (0x0addd, 0x0adf7,),  # Hangul Syllable Gyug    ..Hangul Syllable Gyuh
+    (0x0adf9, 0x0ae13,),  # Hangul Syllable Geug    ..Hangul Syllable Geuh
+    (0x0ae15, 0x0ae2f,),  # Hangul Syllable Gyig    ..Hangul Syllable Gyih
+    (0x0ae31, 0x0ae4b,),  # Hangul Syllable Gig     ..Hangul Syllable Gih
+    (0x0ae4d, 0x0ae67,),  # Hangul Syllable Ggag    ..Hangul Syllable Ggah
+    (0x0ae69, 0x0ae83,),  # Hangul Syllable Ggaeg   ..Hangul Syllable Ggaeh
+    (0x0ae85, 0x0ae9f,),  # Hangul Syllable Ggyag   ..Hangul Syllable Ggyah
+    (0x0aea1, 0x0aebb,),  # Hangul Syllable Ggyaeg  ..Hangul Syllable Ggyaeh
+    (0x0aebd, 0x0aed7,),  # Hangul Syllable Ggeog   ..Hangul Syllable Ggeoh
+    (0x0aed9, 0x0aef3,),  # Hangul Syllable Ggeg    ..Hangul Syllable Ggeh
+    (0x0aef5, 0x0af0f,),  # Hangul Syllable Ggyeog  ..Hangul Syllable Ggyeoh
+    (0x0af11, 0x0af2b,),  # Hangul Syllable Ggyeg   ..Hangul Syllable Ggyeh
+    (0x0af2d, 0x0af47,),  # Hangul Syllable Ggog    ..Hangul Syllable Ggoh
+    (0x0af49, 0x0af63,),  # Hangul Syllable Ggwag   ..Hangul Syllable Ggwah
+    (0x0af65, 0x0af7f,),  # Hangul Syllable Ggwaeg  ..Hangul Syllable Ggwaeh
+    (0x0af81, 0x0af9b,),  # Hangul Syllable Ggoeg   ..Hangul Syllable Ggoeh
+    (0x0af9d, 0x0afb7,),  # Hangul Syllable Ggyog   ..Hangul Syllable Ggyoh
+    (0x0afb9, 0x0afd3,),  # Hangul Syllable Ggug    ..Hangul Syllable Gguh
+    (0x0afd5, 0x0afef,),  # Hangul Syllable Ggweog  ..Hangul Syllable Ggweoh
+    (0x0aff1, 0x0b00b,),  # Hangul Syllable Ggweg   ..Hangul Syllable Ggweh
+    (0x0b00d, 0x0b027,),  # Hangul Syllable Ggwig   ..Hangul Syllable Ggwih
+    (0x0b029, 0x0b043,),  # Hangul Syllable Ggyug   ..Hangul Syllable Ggyuh
+    (0x0b045, 0x0b05f,),  # Hangul Syllable Ggeug   ..Hangul Syllable Ggeuh
+    (0x0b061, 0x0b07b,),  # Hangul Syllable Ggyig   ..Hangul Syllable Ggyih
+    (0x0b07d, 0x0b097,),  # Hangul Syllable Ggig    ..Hangul Syllable Ggih
+    (0x0b099, 0x0b0b3,),  # Hangul Syllable Nag     ..Hangul Syllable Nah
+    (0x0b0b5, 0x0b0cf,),  # Hangul Syllable Naeg    ..Hangul Syllable Naeh
+    (0x0b0d1, 0x0b0eb,),  # Hangul Syllable Nyag    ..Hangul Syllable Nyah
+    (0x0b0ed, 0x0b107,),  # Hangul Syllable Nyaeg   ..Hangul Syllable Nyaeh
+    (0x0b109, 0x0b123,),  # Hangul Syllable Neog    ..Hangul Syllable Neoh
+    (0x0b125, 0x0b13f,),  # Hangul Syllable Neg     ..Hangul Syllable Neh
+    (0x0b141, 0x0b15b,),  # Hangul Syllable Nyeog   ..Hangul Syllable Nyeoh
+    (0x0b15d, 0x0b177,),  # Hangul Syllable Nyeg    ..Hangul Syllable Nyeh
+    (0x0b179, 0x0b193,),  # Hangul Syllable Nog     ..Hangul Syllable Noh
+    (0x0b195, 0x0b1af,),  # Hangul Syllable Nwag    ..Hangul Syllable Nwah
+    (0x0b1b1, 0x0b1cb,),  # Hangul Syllable Nwaeg   ..Hangul Syllable Nwaeh
+    (0x0b1cd, 0x0b1e7,),  # Hangul Syllable Noeg    ..Hangul Syllable Noeh
+    (0x0b1e9, 0x0b203,),  # Hangul Syllable Nyog    ..Hangul Syllable Nyoh
+    (0x0b205, 0x0b21f,),  # Hangul Syllable Nug     ..Hangul Syllable Nuh
+    (0x0b221, 0x0b23b,),  # Hangul Syllable Nweog   ..Hangul Syllable Nweoh
+    (0x0b23d, 0x0b257,),  # Hangul Syllable Nweg    ..Hangul Syllable Nweh
+    (0x0b259, 0x0b273,),  # Hangul Syllable Nwig    ..Hangul Syllable Nwih
+    (0x0b275, 0x0b28f,),  # Hangul Syllable Nyug    ..Hangul Syllable Nyuh
+    (0x0b291, 0x0b2ab,),  # Hangul Syllable Neug    ..Hangul Syllable Neuh
+    (0x0b2ad, 0x0b2c7,),  # Hangul Syllable Nyig    ..Hangul Syllable Nyih
+    (0x0b2c9, 0x0b2e3,),  # Hangul Syllable Nig     ..Hangul Syllable Nih
+    (0x0b2e5, 0x0b2ff,),  # Hangul Syllable Dag     ..Hangul Syllable Dah
+    (0x0b301, 0x0b31b,),  # Hangul Syllable Daeg    ..Hangul Syllable Daeh
+    (0x0b31d, 0x0b337,),  # Hangul Syllable Dyag    ..Hangul Syllable Dyah
+    (0x0b339, 0x0b353,),  # Hangul Syllable Dyaeg   ..Hangul Syllable Dyaeh
+    (0x0b355, 0x0b36f,),  # Hangul Syllable Deog    ..Hangul Syllable Deoh
+    (0x0b371, 0x0b38b,),  # Hangul Syllable Deg     ..Hangul Syllable Deh
+    (0x0b38d, 0x0b3a7,),  # Hangul Syllable Dyeog   ..Hangul Syllable Dyeoh
+    (0x0b3a9, 0x0b3c3,),  # Hangul Syllable Dyeg    ..Hangul Syllable Dyeh
+    (0x0b3c5, 0x0b3df,),  # Hangul Syllable Dog     ..Hangul Syllable Doh
+    (0x0b3e1, 0x0b3fb,),  # Hangul Syllable Dwag    ..Hangul Syllable Dwah
+    (0x0b3fd, 0x0b417,),  # Hangul Syllable Dwaeg   ..Hangul Syllable Dwaeh
+    (0x0b419, 0x0b433,),  # Hangul Syllable Doeg    ..Hangul Syllable Doeh
+    (0x0b435, 0x0b44f,),  # Hangul Syllable Dyog    ..Hangul Syllable Dyoh
+    (0x0b451, 0x0b46b,),  # Hangul Syllable Dug     ..Hangul Syllable Duh
+    (0x0b46d, 0x0b487,),  # Hangul Syllable Dweog   ..Hangul Syllable Dweoh
+    (0x0b489, 0x0b4a3,),  # Hangul Syllable Dweg    ..Hangul Syllable Dweh
+    (0x0b4a5, 0x0b4bf,),  # Hangul Syllable Dwig    ..Hangul Syllable Dwih
+    (0x0b4c1, 0x0b4db,),  # Hangul Syllable Dyug    ..Hangul Syllable Dyuh
+    (0x0b4dd, 0x0b4f7,),  # Hangul Syllable Deug    ..Hangul Syllable Deuh
+    (0x0b4f9, 0x0b513,),  # Hangul Syllable Dyig    ..Hangul Syllable Dyih
+    (0x0b515, 0x0b52f,),  # Hangul Syllable Dig     ..Hangul Syllable Dih
+    (0x0b531, 0x0b54b,),  # Hangul Syllable Ddag    ..Hangul Syllable Ddah
+    (0x0b54d, 0x0b567,),  # Hangul Syllable Ddaeg   ..Hangul Syllable Ddaeh
+    (0x0b569, 0x0b583,),  # Hangul Syllable Ddyag   ..Hangul Syllable Ddyah
+    (0x0b585, 0x0b59f,),  # Hangul Syllable Ddyaeg  ..Hangul Syllable Ddyaeh
+    (0x0b5a1, 0x0b5bb,),  # Hangul Syllable Ddeog   ..Hangul Syllable Ddeoh
+    (0x0b5bd, 0x0b5d7,),  # Hangul Syllable Ddeg    ..Hangul Syllable Ddeh
+    (0x0b5d9, 0x0b5f3,),  # Hangul Syllable Ddyeog  ..Hangul Syllable Ddyeoh
+    (0x0b5f5, 0x0b60f,),  # Hangul Syllable Ddyeg   ..Hangul Syllable Ddyeh
+    (0x0b611, 0x0b62b,),  # Hangul Syllable Ddog    ..Hangul Syllable Ddoh
+    (0x0b62d, 0x0b647,),  # Hangul Syllable Ddwag   ..Hangul Syllable Ddwah
+    (0x0b649, 0x0b663,),  # Hangul Syllable Ddwaeg  ..Hangul Syllable Ddwaeh
+    (0x0b665, 0x0b67f,),  # Hangul Syllable Ddoeg   ..Hangul Syllable Ddoeh
+    (0x0b681, 0x0b69b,),  # Hangul Syllable Ddyog   ..Hangul Syllable Ddyoh
+    (0x0b69d, 0x0b6b7,),  # Hangul Syllable Ddug    ..Hangul Syllable Dduh
+    (0x0b6b9, 0x0b6d3,),  # Hangul Syllable Ddweog  ..Hangul Syllable Ddweoh
+    (0x0b6d5, 0x0b6ef,),  # Hangul Syllable Ddweg   ..Hangul Syllable Ddweh
+    (0x0b6f1, 0x0b70b,),  # Hangul Syllable Ddwig   ..Hangul Syllable Ddwih
+    (0x0b70d, 0x0b727,),  # Hangul Syllable Ddyug   ..Hangul Syllable Ddyuh
+    (0x0b729, 0x0b743,),  # Hangul Syllable Ddeug   ..Hangul Syllable Ddeuh
+    (0x0b745, 0x0b75f,),  # Hangul Syllable Ddyig   ..Hangul Syllable Ddyih
+    (0x0b761, 0x0b77b,),  # Hangul Syllable Ddig    ..Hangul Syllable Ddih
+    (0x0b77d, 0x0b797,),  # Hangul Syllable Rag     ..Hangul Syllable Rah
+    (0x0b799, 0x0b7b3,),  # Hangul Syllable Raeg    ..Hangul Syllable Raeh
+    (0x0b7b5, 0x0b7cf,),  # Hangul Syllable Ryag    ..Hangul Syllable Ryah
+    (0x0b7d1, 0x0b7eb,),  # Hangul Syllable Ryaeg   ..Hangul Syllable Ryaeh
+    (0x0b7ed, 0x0b807,),  # Hangul Syllable Reog    ..Hangul Syllable Reoh
+    (0x0b809, 0x0b823,),  # Hangul Syllable Reg     ..Hangul Syllable Reh
+    (0x0b825, 0x0b83f,),  # Hangul Syllable Ryeog   ..Hangul Syllable Ryeoh
+    (0x0b841, 0x0b85b,),  # Hangul Syllable Ryeg    ..Hangul Syllable Ryeh
+    (0x0b85d, 0x0b877,),  # Hangul Syllable Rog     ..Hangul Syllable Roh
+    (0x0b879, 0x0b893,),  # Hangul Syllable Rwag    ..Hangul Syllable Rwah
+    (0x0b895, 0x0b8af,),  # Hangul Syllable Rwaeg   ..Hangul Syllable Rwaeh
+    (0x0b8b1, 0x0b8cb,),  # Hangul Syllable Roeg    ..Hangul Syllable Roeh
+    (0x0b8cd, 0x0b8e7,),  # Hangul Syllable Ryog    ..Hangul Syllable Ryoh
+    (0x0b8e9, 0x0b903,),  # Hangul Syllable Rug     ..Hangul Syllable Ruh
+    (0x0b905, 0x0b91f,),  # Hangul Syllable Rweog   ..Hangul Syllable Rweoh
+    (0x0b921, 0x0b93b,),  # Hangul Syllable Rweg    ..Hangul Syllable Rweh
+    (0x0b93d, 0x0b957,),  # Hangul Syllable Rwig    ..Hangul Syllable Rwih
+    (0x0b959, 0x0b973,),  # Hangul Syllable Ryug    ..Hangul Syllable Ryuh
+    (0x0b975, 0x0b98f,),  # Hangul Syllable Reug    ..Hangul Syllable Reuh
+    (0x0b991, 0x0b9ab,),  # Hangul Syllable Ryig    ..Hangul Syllable Ryih
+    (0x0b9ad, 0x0b9c7,),  # Hangul Syllable Rig     ..Hangul Syllable Rih
+    (0x0b9c9, 0x0b9e3,),  # Hangul Syllable Mag     ..Hangul Syllable Mah
+    (0x0b9e5, 0x0b9ff,),  # Hangul Syllable Maeg    ..Hangul Syllable Maeh
+    (0x0ba01, 0x0ba1b,),  # Hangul Syllable Myag    ..Hangul Syllable Myah
+    (0x0ba1d, 0x0ba37,),  # Hangul Syllable Myaeg   ..Hangul Syllable Myaeh
+    (0x0ba39, 0x0ba53,),  # Hangul Syllable Meog    ..Hangul Syllable Meoh
+    (0x0ba55, 0x0ba6f,),  # Hangul Syllable Meg     ..Hangul Syllable Meh
+    (0x0ba71, 0x0ba8b,),  # Hangul Syllable Myeog   ..Hangul Syllable Myeoh
+    (0x0ba8d, 0x0baa7,),  # Hangul Syllable Myeg    ..Hangul Syllable Myeh
+    (0x0baa9, 0x0bac3,),  # Hangul Syllable Mog     ..Hangul Syllable Moh
+    (0x0bac5, 0x0badf,),  # Hangul Syllable Mwag    ..Hangul Syllable Mwah
+    (0x0bae1, 0x0bafb,),  # Hangul Syllable Mwaeg   ..Hangul Syllable Mwaeh
+    (0x0bafd, 0x0bb17,),  # Hangul Syllable Moeg    ..Hangul Syllable Moeh
+    (0x0bb19, 0x0bb33,),  # Hangul Syllable Myog    ..Hangul Syllable Myoh
+    (0x0bb35, 0x0bb4f,),  # Hangul Syllable Mug     ..Hangul Syllable Muh
+    (0x0bb51, 0x0bb6b,),  # Hangul Syllable Mweog   ..Hangul Syllable Mweoh
+    (0x0bb6d, 0x0bb87,),  # Hangul Syllable Mweg    ..Hangul Syllable Mweh
+    (0x0bb89, 0x0bba3,),  # Hangul Syllable Mwig    ..Hangul Syllable Mwih
+    (0x0bba5, 0x0bbbf,),  # Hangul Syllable Myug    ..Hangul Syllable Myuh
+    (0x0bbc1, 0x0bbdb,),  # Hangul Syllable Meug    ..Hangul Syllable Meuh
+    (0x0bbdd, 0x0bbf7,),  # Hangul Syllable Myig    ..Hangul Syllable Myih
+    (0x0bbf9, 0x0bc13,),  # Hangul Syllable Mig     ..Hangul Syllable Mih
+    (0x0bc15, 0x0bc2f,),  # Hangul Syllable Bag     ..Hangul Syllable Bah
+    (0x0bc31, 0x0bc4b,),  # Hangul Syllable Baeg    ..Hangul Syllable Baeh
+    (0x0bc4d, 0x0bc67,),  # Hangul Syllable Byag    ..Hangul Syllable Byah
+    (0x0bc69, 0x0bc83,),  # Hangul Syllable Byaeg   ..Hangul Syllable Byaeh
+    (0x0bc85, 0x0bc9f,),  # Hangul Syllable Beog    ..Hangul Syllable Beoh
+    (0x0bca1, 0x0bcbb,),  # Hangul Syllable Beg     ..Hangul Syllable Beh
+    (0x0bcbd, 0x0bcd7,),  # Hangul Syllable Byeog   ..Hangul Syllable Byeoh
+    (0x0bcd9, 0x0bcf3,),  # Hangul Syllable Byeg    ..Hangul Syllable Byeh
+    (0x0bcf5, 0x0bd0f,),  # Hangul Syllable Bog     ..Hangul Syllable Boh
+    (0x0bd11, 0x0bd2b,),  # Hangul Syllable Bwag    ..Hangul Syllable Bwah
+    (0x0bd2d, 0x0bd47,),  # Hangul Syllable Bwaeg   ..Hangul Syllable Bwaeh
+    (0x0bd49, 0x0bd63,),  # Hangul Syllable Boeg    ..Hangul Syllable Boeh
+    (0x0bd65, 0x0bd7f,),  # Hangul Syllable Byog    ..Hangul Syllable Byoh
+    (0x0bd81, 0x0bd9b,),  # Hangul Syllable Bug     ..Hangul Syllable Buh
+    (0x0bd9d, 0x0bdb7,),  # Hangul Syllable Bweog   ..Hangul Syllable Bweoh
+    (0x0bdb9, 0x0bdd3,),  # Hangul Syllable Bweg    ..Hangul Syllable Bweh
+    (0x0bdd5, 0x0bdef,),  # Hangul Syllable Bwig    ..Hangul Syllable Bwih
+    (0x0bdf1, 0x0be0b,),  # Hangul Syllable Byug    ..Hangul Syllable Byuh
+    (0x0be0d, 0x0be27,),  # Hangul Syllable Beug    ..Hangul Syllable Beuh
+    (0x0be29, 0x0be43,),  # Hangul Syllable Byig    ..Hangul Syllable Byih
+    (0x0be45, 0x0be5f,),  # Hangul Syllable Big     ..Hangul Syllable Bih
+    (0x0be61, 0x0be7b,),  # Hangul Syllable Bbag    ..Hangul Syllable Bbah
+    (0x0be7d, 0x0be97,),  # Hangul Syllable Bbaeg   ..Hangul Syllable Bbaeh
+    (0x0be99, 0x0beb3,),  # Hangul Syllable Bbyag   ..Hangul Syllable Bbyah
+    (0x0beb5, 0x0becf,),  # Hangul Syllable Bbyaeg  ..Hangul Syllable Bbyaeh
+    (0x0bed1, 0x0beeb,),  # Hangul Syllable Bbeog   ..Hangul Syllable Bbeoh
+    (0x0beed, 0x0bf07,),  # Hangul Syllable Bbeg    ..Hangul Syllable Bbeh
+    (0x0bf09, 0x0bf23,),  # Hangul Syllable Bbyeog  ..Hangul Syllable Bbyeoh
+    (0x0bf25, 0x0bf3f,),  # Hangul Syllable Bbyeg   ..Hangul Syllable Bbyeh
+    (0x0bf41, 0x0bf5b,),  # Hangul Syllable Bbog    ..Hangul Syllable Bboh
+    (0x0bf5d, 0x0bf77,),  # Hangul Syllable Bbwag   ..Hangul Syllable Bbwah
+    (0x0bf79, 0x0bf93,),  # Hangul Syllable Bbwaeg  ..Hangul Syllable Bbwaeh
+    (0x0bf95, 0x0bfaf,),  # Hangul Syllable Bboeg   ..Hangul Syllable Bboeh
+    (0x0bfb1, 0x0bfcb,),  # Hangul Syllable Bbyog   ..Hangul Syllable Bbyoh
+    (0x0bfcd, 0x0bfe7,),  # Hangul Syllable Bbug    ..Hangul Syllable Bbuh
+    (0x0bfe9, 0x0c003,),  # Hangul Syllable Bbweog  ..Hangul Syllable Bbweoh
+    (0x0c005, 0x0c01f,),  # Hangul Syllable Bbweg   ..Hangul Syllable Bbweh
+    (0x0c021, 0x0c03b,),  # Hangul Syllable Bbwig   ..Hangul Syllable Bbwih
+    (0x0c03d, 0x0c057,),  # Hangul Syllable Bbyug   ..Hangul Syllable Bbyuh
+    (0x0c059, 0x0c073,),  # Hangul Syllable Bbeug   ..Hangul Syllable Bbeuh
+    (0x0c075, 0x0c08f,),  # Hangul Syllable Bbyig   ..Hangul Syllable Bbyih
+    (0x0c091, 0x0c0ab,),  # Hangul Syllable Bbig    ..Hangul Syllable Bbih
+    (0x0c0ad, 0x0c0c7,),  # Hangul Syllable Sag     ..Hangul Syllable Sah
+    (0x0c0c9, 0x0c0e3,),  # Hangul Syllable Saeg    ..Hangul Syllable Saeh
+    (0x0c0e5, 0x0c0ff,),  # Hangul Syllable Syag    ..Hangul Syllable Syah
+    (0x0c101, 0x0c11b,),  # Hangul Syllable Syaeg   ..Hangul Syllable Syaeh
+    (0x0c11d, 0x0c137,),  # Hangul Syllable Seog    ..Hangul Syllable Seoh
+    (0x0c139, 0x0c153,),  # Hangul Syllable Seg     ..Hangul Syllable Seh
+    (0x0c155, 0x0c16f,),  # Hangul Syllable Syeog   ..Hangul Syllable Syeoh
+    (0x0c171, 0x0c18b,),  # Hangul Syllable Syeg    ..Hangul Syllable Syeh
+    (0x0c18d, 0x0c1a7,),  # Hangul Syllable Sog     ..Hangul Syllable Soh
+    (0x0c1a9, 0x0c1c3,),  # Hangul Syllable Swag    ..Hangul Syllable Swah
+    (0x0c1c5, 0x0c1df,),  # Hangul Syllable Swaeg   ..Hangul Syllable Swaeh
+    (0x0c1e1, 0x0c1fb,),  # Hangul Syllable Soeg    ..Hangul Syllable Soeh
+    (0x0c1fd, 0x0c217,),  # Hangul Syllable Syog    ..Hangul Syllable Syoh
+    (0x0c219, 0x0c233,),  # Hangul Syllable Sug     ..Hangul Syllable Suh
+    (0x0c235, 0x0c24f,),  # Hangul Syllable Sweog   ..Hangul Syllable Sweoh
+    (0x0c251, 0x0c26b,),  # Hangul Syllable Sweg    ..Hangul Syllable Sweh
+    (0x0c26d, 0x0c287,),  # Hangul Syllable Swig    ..Hangul Syllable Swih
+    (0x0c289, 0x0c2a3,),  # Hangul Syllable Syug    ..Hangul Syllable Syuh
+    (0x0c2a5, 0x0c2bf,),  # Hangul Syllable Seug    ..Hangul Syllable Seuh
+    (0x0c2c1, 0x0c2db,),  # Hangul Syllable Syig    ..Hangul Syllable Syih
+    (0x0c2dd, 0x0c2f7,),  # Hangul Syllable Sig     ..Hangul Syllable Sih
+    (0x0c2f9, 0x0c313,),  # Hangul Syllable Ssag    ..Hangul Syllable Ssah
+    (0x0c315, 0x0c32f,),  # Hangul Syllable Ssaeg   ..Hangul Syllable Ssaeh
+    (0x0c331, 0x0c34b,),  # Hangul Syllable Ssyag   ..Hangul Syllable Ssyah
+    (0x0c34d, 0x0c367,),  # Hangul Syllable Ssyaeg  ..Hangul Syllable Ssyaeh
+    (0x0c369, 0x0c383,),  # Hangul Syllable Sseog   ..Hangul Syllable Sseoh
+    (0x0c385, 0x0c39f,),  # Hangul Syllable Sseg    ..Hangul Syllable Sseh
+    (0x0c3a1, 0x0c3bb,),  # Hangul Syllable Ssyeog  ..Hangul Syllable Ssyeoh
+    (0x0c3bd, 0x0c3d7,),  # Hangul Syllable Ssyeg   ..Hangul Syllable Ssyeh
+    (0x0c3d9, 0x0c3f3,),  # Hangul Syllable Ssog    ..Hangul Syllable Ssoh
+    (0x0c3f5, 0x0c40f,),  # Hangul Syllable Sswag   ..Hangul Syllable Sswah
+    (0x0c411, 0x0c42b,),  # Hangul Syllable Sswaeg  ..Hangul Syllable Sswaeh
+    (0x0c42d, 0x0c447,),  # Hangul Syllable Ssoeg   ..Hangul Syllable Ssoeh
+    (0x0c449, 0x0c463,),  # Hangul Syllable Ssyog   ..Hangul Syllable Ssyoh
+    (0x0c465, 0x0c47f,),  # Hangul Syllable Ssug    ..Hangul Syllable Ssuh
+    (0x0c481, 0x0c49b,),  # Hangul Syllable Ssweog  ..Hangul Syllable Ssweoh
+    (0x0c49d, 0x0c4b7,),  # Hangul Syllable Ssweg   ..Hangul Syllable Ssweh
+    (0x0c4b9, 0x0c4d3,),  # Hangul Syllable Sswig   ..Hangul Syllable Sswih
+    (0x0c4d5, 0x0c4ef,),  # Hangul Syllable Ssyug   ..Hangul Syllable Ssyuh
+    (0x0c4f1, 0x0c50b,),  # Hangul Syllable Sseug   ..Hangul Syllable Sseuh
+    (0x0c50d, 0x0c527,),  # Hangul Syllable Ssyig   ..Hangul Syllable Ssyih
+    (0x0c529, 0x0c543,),  # Hangul Syllable Ssig    ..Hangul Syllable Ssih
+    (0x0c545, 0x0c55f,),  # Hangul Syllable Ag      ..Hangul Syllable Ah
+    (0x0c561, 0x0c57b,),  # Hangul Syllable Aeg     ..Hangul Syllable Aeh
+    (0x0c57d, 0x0c597,),  # Hangul Syllable Yag     ..Hangul Syllable Yah
+    (0x0c599, 0x0c5b3,),  # Hangul Syllable Yaeg    ..Hangul Syllable Yaeh
+    (0x0c5b5, 0x0c5cf,),  # Hangul Syllable Eog     ..Hangul Syllable Eoh
+    (0x0c5d1, 0x0c5eb,),  # Hangul Syllable Eg      ..Hangul Syllable Eh
+    (0x0c5ed, 0x0c607,),  # Hangul Syllable Yeog    ..Hangul Syllable Yeoh
+    (0x0c609, 0x0c623,),  # Hangul Syllable Yeg     ..Hangul Syllable Yeh
+    (0x0c625, 0x0c63f,),  # Hangul Syllable Og      ..Hangul Syllable Oh
+    (0x0c641, 0x0c65b,),  # Hangul Syllable Wag     ..Hangul Syllable Wah
+    (0x0c65d, 0x0c677,),  # Hangul Syllable Waeg    ..Hangul Syllable Waeh
+    (0x0c679, 0x0c693,),  # Hangul Syllable Oeg     ..Hangul Syllable Oeh
+    (0x0c695, 0x0c6af,),  # Hangul Syllable Yog     ..Hangul Syllable Yoh
+    (0x0c6b1, 0x0c6cb,),  # Hangul Syllable Ug      ..Hangul Syllable Uh
+    (0x0c6cd, 0x0c6e7,),  # Hangul Syllable Weog    ..Hangul Syllable Weoh
+    (0x0c6e9, 0x0c703,),  # Hangul Syllable Weg     ..Hangul Syllable Weh
+    (0x0c705, 0x0c71f,),  # Hangul Syllable Wig     ..Hangul Syllable Wih
+    (0x0c721, 0x0c73b,),  # Hangul Syllable Yug     ..Hangul Syllable Yuh
+    (0x0c73d, 0x0c757,),  # Hangul Syllable Eug     ..Hangul Syllable Euh
+    (0x0c759, 0x0c773,),  # Hangul Syllable Yig     ..Hangul Syllable Yih
+    (0x0c775, 0x0c78f,),  # Hangul Syllable Ig      ..Hangul Syllable Ih
+    (0x0c791, 0x0c7ab,),  # Hangul Syllable Jag     ..Hangul Syllable Jah
+    (0x0c7ad, 0x0c7c7,),  # Hangul Syllable Jaeg    ..Hangul Syllable Jaeh
+    (0x0c7c9, 0x0c7e3,),  # Hangul Syllable Jyag    ..Hangul Syllable Jyah
+    (0x0c7e5, 0x0c7ff,),  # Hangul Syllable Jyaeg   ..Hangul Syllable Jyaeh
+    (0x0c801, 0x0c81b,),  # Hangul Syllable Jeog    ..Hangul Syllable Jeoh
+    (0x0c81d, 0x0c837,),  # Hangul Syllable Jeg     ..Hangul Syllable Jeh
+    (0x0c839, 0x0c853,),  # Hangul Syllable Jyeog   ..Hangul Syllable Jyeoh
+    (0x0c855, 0x0c86f,),  # Hangul Syllable Jyeg    ..Hangul Syllable Jyeh
+    (0x0c871, 0x0c88b,),  # Hangul Syllable Jog     ..Hangul Syllable Joh
+    (0x0c88d, 0x0c8a7,),  # Hangul Syllable Jwag    ..Hangul Syllable Jwah
+    (0x0c8a9, 0x0c8c3,),  # Hangul Syllable Jwaeg   ..Hangul Syllable Jwaeh
+    (0x0c8c5, 0x0c8df,),  # Hangul Syllable Joeg    ..Hangul Syllable Joeh
+    (0x0c8e1, 0x0c8fb,),  # Hangul Syllable Jyog    ..Hangul Syllable Jyoh
+    (0x0c8fd, 0x0c917,),  # Hangul Syllable Jug     ..Hangul Syllable Juh
+    (0x0c919, 0x0c933,),  # Hangul Syllable Jweog   ..Hangul Syllable Jweoh
+    (0x0c935, 0x0c94f,),  # Hangul Syllable Jweg    ..Hangul Syllable Jweh
+    (0x0c951, 0x0c96b,),  # Hangul Syllable Jwig    ..Hangul Syllable Jwih
+    (0x0c96d, 0x0c987,),  # Hangul Syllable Jyug    ..Hangul Syllable Jyuh
+    (0x0c989, 0x0c9a3,),  # Hangul Syllable Jeug    ..Hangul Syllable Jeuh
+    (0x0c9a5, 0x0c9bf,),  # Hangul Syllable Jyig    ..Hangul Syllable Jyih
+    (0x0c9c1, 0x0c9db,),  # Hangul Syllable Jig     ..Hangul Syllable Jih
+    (0x0c9dd, 0x0c9f7,),  # Hangul Syllable Jjag    ..Hangul Syllable Jjah
+    (0x0c9f9, 0x0ca13,),  # Hangul Syllable Jjaeg   ..Hangul Syllable Jjaeh
+    (0x0ca15, 0x0ca2f,),  # Hangul Syllable Jjyag   ..Hangul Syllable Jjyah
+    (0x0ca31, 0x0ca4b,),  # Hangul Syllable Jjyaeg  ..Hangul Syllable Jjyaeh
+    (0x0ca4d, 0x0ca67,),  # Hangul Syllable Jjeog   ..Hangul Syllable Jjeoh
+    (0x0ca69, 0x0ca83,),  # Hangul Syllable Jjeg    ..Hangul Syllable Jjeh
+    (0x0ca85, 0x0ca9f,),  # Hangul Syllable Jjyeog  ..Hangul Syllable Jjyeoh
+    (0x0caa1, 0x0cabb,),  # Hangul Syllable Jjyeg   ..Hangul Syllable Jjyeh
+    (0x0cabd, 0x0cad7,),  # Hangul Syllable Jjog    ..Hangul Syllable Jjoh
+    (0x0cad9, 0x0caf3,),  # Hangul Syllable Jjwag   ..Hangul Syllable Jjwah
+    (0x0caf5, 0x0cb0f,),  # Hangul Syllable Jjwaeg  ..Hangul Syllable Jjwaeh
+    (0x0cb11, 0x0cb2b,),  # Hangul Syllable Jjoeg   ..Hangul Syllable Jjoeh
+    (0x0cb2d, 0x0cb47,),  # Hangul Syllable Jjyog   ..Hangul Syllable Jjyoh
+    (0x0cb49, 0x0cb63,),  # Hangul Syllable Jjug    ..Hangul Syllable Jjuh
+    (0x0cb65, 0x0cb7f,),  # Hangul Syllable Jjweog  ..Hangul Syllable Jjweoh
+    (0x0cb81, 0x0cb9b,),  # Hangul Syllable Jjweg   ..Hangul Syllable Jjweh
+    (0x0cb9d, 0x0cbb7,),  # Hangul Syllable Jjwig   ..Hangul Syllable Jjwih
+    (0x0cbb9, 0x0cbd3,),  # Hangul Syllable Jjyug   ..Hangul Syllable Jjyuh
+    (0x0cbd5, 0x0cbef,),  # Hangul Syllable Jjeug   ..Hangul Syllable Jjeuh
+    (0x0cbf1, 0x0cc0b,),  # Hangul Syllable Jjyig   ..Hangul Syllable Jjyih
+    (0x0cc0d, 0x0cc27,),  # Hangul Syllable Jjig    ..Hangul Syllable Jjih
+    (0x0cc29, 0x0cc43,),  # Hangul Syllable Cag     ..Hangul Syllable Cah
+    (0x0cc45, 0x0cc5f,),  # Hangul Syllable Caeg    ..Hangul Syllable Caeh
+    (0x0cc61, 0x0cc7b,),  # Hangul Syllable Cyag    ..Hangul Syllable Cyah
+    (0x0cc7d, 0x0cc97,),  # Hangul Syllable Cyaeg   ..Hangul Syllable Cyaeh
+    (0x0cc99, 0x0ccb3,),  # Hangul Syllable Ceog    ..Hangul Syllable Ceoh
+    (0x0ccb5, 0x0cccf,),  # Hangul Syllable Ceg     ..Hangul Syllable Ceh
+    (0x0ccd1, 0x0cceb,),  # Hangul Syllable Cyeog   ..Hangul Syllable Cyeoh
+    (0x0cced, 0x0cd07,),  # Hangul Syllable Cyeg    ..Hangul Syllable Cyeh
+    (0x0cd09, 0x0cd23,),  # Hangul Syllable Cog     ..Hangul Syllable Coh
+    (0x0cd25, 0x0cd3f,),  # Hangul Syllable Cwag    ..Hangul Syllable Cwah
+    (0x0cd41, 0x0cd5b,),  # Hangul Syllable Cwaeg   ..Hangul Syllable Cwaeh
+    (0x0cd5d, 0x0cd77,),  # Hangul Syllable Coeg    ..Hangul Syllable Coeh
+    (0x0cd79, 0x0cd93,),  # Hangul Syllable Cyog    ..Hangul Syllable Cyoh
+    (0x0cd95, 0x0cdaf,),  # Hangul Syllable Cug     ..Hangul Syllable Cuh
+    (0x0cdb1, 0x0cdcb,),  # Hangul Syllable Cweog   ..Hangul Syllable Cweoh
+    (0x0cdcd, 0x0cde7,),  # Hangul Syllable Cweg    ..Hangul Syllable Cweh
+    (0x0cde9, 0x0ce03,),  # Hangul Syllable Cwig    ..Hangul Syllable Cwih
+    (0x0ce05, 0x0ce1f,),  # Hangul Syllable Cyug    ..Hangul Syllable Cyuh
+    (0x0ce21, 0x0ce3b,),  # Hangul Syllable Ceug    ..Hangul Syllable Ceuh
+    (0x0ce3d, 0x0ce57,),  # Hangul Syllable Cyig    ..Hangul Syllable Cyih
+    (0x0ce59, 0x0ce73,),  # Hangul Syllable Cig     ..Hangul Syllable Cih
+    (0x0ce75, 0x0ce8f,),  # Hangul Syllable Kag     ..Hangul Syllable Kah
+    (0x0ce91, 0x0ceab,),  # Hangul Syllable Kaeg    ..Hangul Syllable Kaeh
+    (0x0cead, 0x0cec7,),  # Hangul Syllable Kyag    ..Hangul Syllable Kyah
+    (0x0cec9, 0x0cee3,),  # Hangul Syllable Kyaeg   ..Hangul Syllable Kyaeh
+    (0x0cee5, 0x0ceff,),  # Hangul Syllable Keog    ..Hangul Syllable Keoh
+    (0x0cf01, 0x0cf1b,),  # Hangul Syllable Keg     ..Hangul Syllable Keh
+    (0x0cf1d, 0x0cf37,),  # Hangul Syllable Kyeog   ..Hangul Syllable Kyeoh
+    (0x0cf39, 0x0cf53,),  # Hangul Syllable Kyeg    ..Hangul Syllable Kyeh
+    (0x0cf55, 0x0cf6f,),  # Hangul Syllable Kog     ..Hangul Syllable Koh
+    (0x0cf71, 0x0cf8b,),  # Hangul Syllable Kwag    ..Hangul Syllable Kwah
+    (0x0cf8d, 0x0cfa7,),  # Hangul Syllable Kwaeg   ..Hangul Syllable Kwaeh
+    (0x0cfa9, 0x0cfc3,),  # Hangul Syllable Koeg    ..Hangul Syllable Koeh
+    (0x0cfc5, 0x0cfdf,),  # Hangul Syllable Kyog    ..Hangul Syllable Kyoh
+    (0x0cfe1, 0x0cffb,),  # Hangul Syllable Kug     ..Hangul Syllable Kuh
+    (0x0cffd, 0x0d017,),  # Hangul Syllable Kweog   ..Hangul Syllable Kweoh
+    (0x0d019, 0x0d033,),  # Hangul Syllable Kweg    ..Hangul Syllable Kweh
+    (0x0d035, 0x0d04f,),  # Hangul Syllable Kwig    ..Hangul Syllable Kwih
+    (0x0d051, 0x0d06b,),  # Hangul Syllable Kyug    ..Hangul Syllable Kyuh
+    (0x0d06d, 0x0d087,),  # Hangul Syllable Keug    ..Hangul Syllable Keuh
+    (0x0d089, 0x0d0a3,),  # Hangul Syllable Kyig    ..Hangul Syllable Kyih
+    (0x0d0a5, 0x0d0bf,),  # Hangul Syllable Kig     ..Hangul Syllable Kih
+    (0x0d0c1, 0x0d0db,),  # Hangul Syllable Tag     ..Hangul Syllable Tah
+    (0x0d0dd, 0x0d0f7,),  # Hangul Syllable Taeg    ..Hangul Syllable Taeh
+    (0x0d0f9, 0x0d113,),  # Hangul Syllable Tyag    ..Hangul Syllable Tyah
+    (0x0d115, 0x0d12f,),  # Hangul Syllable Tyaeg   ..Hangul Syllable Tyaeh
+    (0x0d131, 0x0d14b,),  # Hangul Syllable Teog    ..Hangul Syllable Teoh
+    (0x0d14d, 0x0d167,),  # Hangul Syllable Teg     ..Hangul Syllable Teh
+    (0x0d169, 0x0d183,),  # Hangul Syllable Tyeog   ..Hangul Syllable Tyeoh
+    (0x0d185, 0x0d19f,),  # Hangul Syllable Tyeg    ..Hangul Syllable Tyeh
+    (0x0d1a1, 0x0d1bb,),  # Hangul Syllable Tog     ..Hangul Syllable Toh
+    (0x0d1bd, 0x0d1d7,),  # Hangul Syllable Twag    ..Hangul Syllable Twah
+    (0x0d1d9, 0x0d1f3,),  # Hangul Syllable Twaeg   ..Hangul Syllable Twaeh
+    (0x0d1f5, 0x0d20f,),  # Hangul Syllable Toeg    ..Hangul Syllable Toeh
+    (0x0d211, 0x0d22b,),  # Hangul Syllable Tyog    ..Hangul Syllable Tyoh
+    (0x0d22d, 0x0d247,),  # Hangul Syllable Tug     ..Hangul Syllable Tuh
+    (0x0d249, 0x0d263,),  # Hangul Syllable Tweog   ..Hangul Syllable Tweoh
+    (0x0d265, 0x0d27f,),  # Hangul Syllable Tweg    ..Hangul Syllable Tweh
+    (0x0d281, 0x0d29b,),  # Hangul Syllable Twig    ..Hangul Syllable Twih
+    (0x0d29d, 0x0d2b7,),  # Hangul Syllable Tyug    ..Hangul Syllable Tyuh
+    (0x0d2b9, 0x0d2d3,),  # Hangul Syllable Teug    ..Hangul Syllable Teuh
+    (0x0d2d5, 0x0d2ef,),  # Hangul Syllable Tyig    ..Hangul Syllable Tyih
+    (0x0d2f1, 0x0d30b,),  # Hangul Syllable Tig     ..Hangul Syllable Tih
+    (0x0d30d, 0x0d327,),  # Hangul Syllable Pag     ..Hangul Syllable Pah
+    (0x0d329, 0x0d343,),  # Hangul Syllable Paeg    ..Hangul Syllable Paeh
+    (0x0d345, 0x0d35f,),  # Hangul Syllable Pyag    ..Hangul Syllable Pyah
+    (0x0d361, 0x0d37b,),  # Hangul Syllable Pyaeg   ..Hangul Syllable Pyaeh
+    (0x0d37d, 0x0d397,),  # Hangul Syllable Peog    ..Hangul Syllable Peoh
+    (0x0d399, 0x0d3b3,),  # Hangul Syllable Peg     ..Hangul Syllable Peh
+    (0x0d3b5, 0x0d3cf,),  # Hangul Syllable Pyeog   ..Hangul Syllable Pyeoh
+    (0x0d3d1, 0x0d3eb,),  # Hangul Syllable Pyeg    ..Hangul Syllable Pyeh
+    (0x0d3ed, 0x0d407,),  # Hangul Syllable Pog     ..Hangul Syllable Poh
+    (0x0d409, 0x0d423,),  # Hangul Syllable Pwag    ..Hangul Syllable Pwah
+    (0x0d425, 0x0d43f,),  # Hangul Syllable Pwaeg   ..Hangul Syllable Pwaeh
+    (0x0d441, 0x0d45b,),  # Hangul Syllable Poeg    ..Hangul Syllable Poeh
+    (0x0d45d, 0x0d477,),  # Hangul Syllable Pyog    ..Hangul Syllable Pyoh
+    (0x0d479, 0x0d493,),  # Hangul Syllable Pug     ..Hangul Syllable Puh
+    (0x0d495, 0x0d4af,),  # Hangul Syllable Pweog   ..Hangul Syllable Pweoh
+    (0x0d4b1, 0x0d4cb,),  # Hangul Syllable Pweg    ..Hangul Syllable Pweh
+    (0x0d4cd, 0x0d4e7,),  # Hangul Syllable Pwig    ..Hangul Syllable Pwih
+    (0x0d4e9, 0x0d503,),  # Hangul Syllable Pyug    ..Hangul Syllable Pyuh
+    (0x0d505, 0x0d51f,),  # Hangul Syllable Peug    ..Hangul Syllable Peuh
+    (0x0d521, 0x0d53b,),  # Hangul Syllable Pyig    ..Hangul Syllable Pyih
+    (0x0d53d, 0x0d557,),  # Hangul Syllable Pig     ..Hangul Syllable Pih
+    (0x0d559, 0x0d573,),  # Hangul Syllable Hag     ..Hangul Syllable Hah
+    (0x0d575, 0x0d58f,),  # Hangul Syllable Haeg    ..Hangul Syllable Haeh
+    (0x0d591, 0x0d5ab,),  # Hangul Syllable Hyag    ..Hangul Syllable Hyah
+    (0x0d5ad, 0x0d5c7,),  # Hangul Syllable Hyaeg   ..Hangul Syllable Hyaeh
+    (0x0d5c9, 0x0d5e3,),  # Hangul Syllable Heog    ..Hangul Syllable Heoh
+    (0x0d5e5, 0x0d5ff,),  # Hangul Syllable Heg     ..Hangul Syllable Heh
+    (0x0d601, 0x0d61b,),  # Hangul Syllable Hyeog   ..Hangul Syllable Hyeoh
+    (0x0d61d, 0x0d637,),  # Hangul Syllable Hyeg    ..Hangul Syllable Hyeh
+    (0x0d639, 0x0d653,),  # Hangul Syllable Hog     ..Hangul Syllable Hoh
+    (0x0d655, 0x0d66f,),  # Hangul Syllable Hwag    ..Hangul Syllable Hwah
+    (0x0d671, 0x0d68b,),  # Hangul Syllable Hwaeg   ..Hangul Syllable Hwaeh
+    (0x0d68d, 0x0d6a7,),  # Hangul Syllable Hoeg    ..Hangul Syllable Hoeh
+    (0x0d6a9, 0x0d6c3,),  # Hangul Syllable Hyog    ..Hangul Syllable Hyoh
+    (0x0d6c5, 0x0d6df,),  # Hangul Syllable Hug     ..Hangul Syllable Huh
+    (0x0d6e1, 0x0d6fb,),  # Hangul Syllable Hweog   ..Hangul Syllable Hweoh
+    (0x0d6fd, 0x0d717,),  # Hangul Syllable Hweg    ..Hangul Syllable Hweh
+    (0x0d719, 0x0d733,),  # Hangul Syllable Hwig    ..Hangul Syllable Hwih
+    (0x0d735, 0x0d74f,),  # Hangul Syllable Hyug    ..Hangul Syllable Hyuh
+    (0x0d751, 0x0d76b,),  # Hangul Syllable Heug    ..Hangul Syllable Heuh
+    (0x0d76d, 0x0d787,),  # Hangul Syllable Hyig    ..Hangul Syllable Hyih
+    (0x0d789, 0x0d7a3,),  # Hangul Syllable Hig     ..Hangul Syllable Hih
+)
+
+EXTENDED_PICTOGRAPHIC = (
+    # Source: emoji-data.txt
+    # Date: 2025-07-25, 17:54:31 GMT
+    #
+    (0x000a9, 0x000a9,),  # Copyright Sign
+    (0x000ae, 0x000ae,),  # Registered Sign
+    (0x0203c, 0x0203c,),  # Double Exclamation Mark
+    (0x02049, 0x02049,),  # Exclamation Question Mark
+    (0x02122, 0x02122,),  # Trade Mark Sign
+    (0x02139, 0x02139,),  # Information Source
+    (0x02194, 0x02199,),  # Left Right Arrow        ..South West Arrow
+    (0x021a9, 0x021aa,),  # Leftwards Arrow With Hoo..Rightwards Arrow With Ho
+    (0x0231a, 0x0231b,),  # Watch                   ..Hourglass
+    (0x02328, 0x02328,),  # Keyboard
+    (0x023cf, 0x023cf,),  # Eject Symbol
+    (0x023e9, 0x023f3,),  # Black Right-pointing Dou..Hourglass With Flowing S
+    (0x023f8, 0x023fa,),  # Double Vertical Bar     ..Black Circle For Record
+    (0x024c2, 0x024c2,),  # Circled Latin Capital Letter M
+    (0x025aa, 0x025ab,),  # Black Small Square      ..White Small Square
+    (0x025b6, 0x025b6,),  # Black Right-pointing Triangle
+    (0x025c0, 0x025c0,),  # Black Left-pointing Triangle
+    (0x025fb, 0x025fe,),  # White Medium Square     ..Black Medium Small Squar
+    (0x02600, 0x02604,),  # Black Sun With Rays     ..Comet
+    (0x0260e, 0x0260e,),  # Black Telephone
+    (0x02611, 0x02611,),  # Ballot Box With Check
+    (0x02614, 0x02615,),  # Umbrella With Rain Drops..Hot Beverage
+    (0x02618, 0x02618,),  # Shamrock
+    (0x0261d, 0x0261d,),  # White Up Pointing Index
+    (0x02620, 0x02620,),  # Skull And Crossbones
+    (0x02622, 0x02623,),  # Radioactive Sign        ..Biohazard Sign
+    (0x02626, 0x02626,),  # Orthodox Cross
+    (0x0262a, 0x0262a,),  # Star And Crescent
+    (0x0262e, 0x0262f,),  # Peace Symbol            ..Yin Yang
+    (0x02638, 0x0263a,),  # Wheel Of Dharma         ..White Smiling Face
+    (0x02640, 0x02640,),  # Female Sign
+    (0x02642, 0x02642,),  # Male Sign
+    (0x02648, 0x02653,),  # Aries                   ..Pisces
+    (0x0265f, 0x02660,),  # Black Chess Pawn        ..Black Spade Suit
+    (0x02663, 0x02663,),  # Black Club Suit
+    (0x02665, 0x02666,),  # Black Heart Suit        ..Black Diamond Suit
+    (0x02668, 0x02668,),  # Hot Springs
+    (0x0267b, 0x0267b,),  # Black Universal Recycling Symbol
+    (0x0267e, 0x0267f,),  # Permanent Paper Sign    ..Wheelchair Symbol
+    (0x02692, 0x02697,),  # Hammer And Pick         ..Alembic
+    (0x02699, 0x02699,),  # Gear
+    (0x0269b, 0x0269c,),  # Atom Symbol             ..Fleur-de-lis
+    (0x026a0, 0x026a1,),  # Warning Sign            ..High Voltage Sign
+    (0x026a7, 0x026a7,),  # Male With Stroke And Male And Female Sign
+    (0x026aa, 0x026ab,),  # Medium White Circle     ..Medium Black Circle
+    (0x026b0, 0x026b1,),  # Coffin                  ..Funeral Urn
+    (0x026bd, 0x026be,),  # Soccer Ball             ..Baseball
+    (0x026c4, 0x026c5,),  # Snowman Without Snow    ..Sun Behind Cloud
+    (0x026c8, 0x026c8,),  # Thunder Cloud And Rain
+    (0x026ce, 0x026cf,),  # Ophiuchus               ..Pick
+    (0x026d1, 0x026d1,),  # Helmet With White Cross
+    (0x026d3, 0x026d4,),  # Chains                  ..No Entry
+    (0x026e9, 0x026ea,),  # Shinto Shrine           ..Church
+    (0x026f0, 0x026f5,),  # Mountain                ..Sailboat
+    (0x026f7, 0x026fa,),  # Skier                   ..Tent
+    (0x026fd, 0x026fd,),  # Fuel Pump
+    (0x02702, 0x02702,),  # Black Scissors
+    (0x02705, 0x02705,),  # White Heavy Check Mark
+    (0x02708, 0x0270d,),  # Airplane                ..Writing Hand
+    (0x0270f, 0x0270f,),  # Pencil
+    (0x02712, 0x02712,),  # Black Nib
+    (0x02714, 0x02714,),  # Heavy Check Mark
+    (0x02716, 0x02716,),  # Heavy Multiplication X
+    (0x0271d, 0x0271d,),  # Latin Cross
+    (0x02721, 0x02721,),  # Star Of David
+    (0x02728, 0x02728,),  # Sparkles
+    (0x02733, 0x02734,),  # Eight Spoked Asterisk   ..Eight Pointed Black Star
+    (0x02744, 0x02744,),  # Snowflake
+    (0x02747, 0x02747,),  # Sparkle
+    (0x0274c, 0x0274c,),  # Cross Mark
+    (0x0274e, 0x0274e,),  # Negative Squared Cross Mark
+    (0x02753, 0x02755,),  # Black Question Mark Orna..White Exclamation Mark O
+    (0x02757, 0x02757,),  # Heavy Exclamation Mark Symbol
+    (0x02763, 0x02764,),  # Heavy Heart Exclamation ..Heavy Black Heart
+    (0x02795, 0x02797,),  # Heavy Plus Sign         ..Heavy Division Sign
+    (0x027a1, 0x027a1,),  # Black Rightwards Arrow
+    (0x027b0, 0x027b0,),  # Curly Loop
+    (0x027bf, 0x027bf,),  # Double Curly Loop
+    (0x02934, 0x02935,),  # Arrow Pointing Rightward..Arrow Pointing Rightward
+    (0x02b05, 0x02b07,),  # Leftwards Black Arrow   ..Downwards Black Arrow
+    (0x02b1b, 0x02b1c,),  # Black Large Square      ..White Large Square
+    (0x02b50, 0x02b50,),  # White Medium Star
+    (0x02b55, 0x02b55,),  # Heavy Large Circle
+    (0x03030, 0x03030,),  # Wavy Dash
+    (0x0303d, 0x0303d,),  # Part Alternation Mark
+    (0x03297, 0x03297,),  # Circled Ideograph Congratulation
+    (0x03299, 0x03299,),  # Circled Ideograph Secret
+    (0x1f004, 0x1f004,),  # Mahjong Tile Red Dragon
+    (0x1f02c, 0x1f02f,),  # (nil)
+    (0x1f094, 0x1f09f,),  # (nil)
+    (0x1f0af, 0x1f0b0,),  # (nil)
+    (0x1f0c0, 0x1f0c0,),  # (nil)
+    (0x1f0cf, 0x1f0d0,),  # Playing Card Black Joker..(nil)
+    (0x1f0f6, 0x1f0ff,),  # (nil)
+    (0x1f170, 0x1f171,),  # Negative Squared Latin C..Negative Squared Latin C
+    (0x1f17e, 0x1f17f,),  # Negative Squared Latin C..Negative Squared Latin C
+    (0x1f18e, 0x1f18e,),  # Negative Squared Ab
+    (0x1f191, 0x1f19a,),  # Squared Cl              ..Squared Vs
+    (0x1f1ae, 0x1f1e5,),  # (nil)
+    (0x1f201, 0x1f20f,),  # Squared Katakana Koko   ..(nil)
+    (0x1f21a, 0x1f21a,),  # Squared Cjk Unified Ideograph-7121
+    (0x1f22f, 0x1f22f,),  # Squared Cjk Unified Ideograph-6307
+    (0x1f232, 0x1f23a,),  # Squared Cjk Unified Ideo..Squared Cjk Unified Ideo
+    (0x1f23c, 0x1f23f,),  # (nil)
+    (0x1f249, 0x1f25f,),  # (nil)
+    (0x1f266, 0x1f321,),  # (nil)                   ..Thermometer
+    (0x1f324, 0x1f393,),  # White Sun With Small Clo..Graduation Cap
+    (0x1f396, 0x1f397,),  # Military Medal          ..Reminder Ribbon
+    (0x1f399, 0x1f39b,),  # Studio Microphone       ..Control Knobs
+    (0x1f39e, 0x1f3f0,),  # Film Frames             ..European Castle
+    (0x1f3f3, 0x1f3f5,),  # Waving White Flag       ..Rosette
+    (0x1f3f7, 0x1f3fa,),  # Label                   ..Amphora
+    (0x1f400, 0x1f4fd,),  # Rat                     ..Film Projector
+    (0x1f4ff, 0x1f53d,),  # Prayer Beads            ..Down-pointing Small Red
+    (0x1f549, 0x1f54e,),  # Om Symbol               ..Menorah With Nine Branch
+    (0x1f550, 0x1f567,),  # Clock Face One Oclock   ..Clock Face Twelve-thirty
+    (0x1f56f, 0x1f570,),  # Candle                  ..Mantelpiece Clock
+    (0x1f573, 0x1f57a,),  # Hole                    ..Man Dancing
+    (0x1f587, 0x1f587,),  # Linked Paperclips
+    (0x1f58a, 0x1f58d,),  # Lower Left Ballpoint Pen..Lower Left Crayon
+    (0x1f590, 0x1f590,),  # Raised Hand With Fingers Splayed
+    (0x1f595, 0x1f596,),  # Reversed Hand With Middl..Raised Hand With Part Be
+    (0x1f5a4, 0x1f5a5,),  # Black Heart             ..Desktop Computer
+    (0x1f5a8, 0x1f5a8,),  # Printer
+    (0x1f5b1, 0x1f5b2,),  # Three Button Mouse      ..Trackball
+    (0x1f5bc, 0x1f5bc,),  # Frame With Picture
+    (0x1f5c2, 0x1f5c4,),  # Card Index Dividers     ..File Cabinet
+    (0x1f5d1, 0x1f5d3,),  # Wastebasket             ..Spiral Calendar Pad
+    (0x1f5dc, 0x1f5de,),  # Compression             ..Rolled-up Newspaper
+    (0x1f5e1, 0x1f5e1,),  # Dagger Knife
+    (0x1f5e3, 0x1f5e3,),  # Speaking Head In Silhouette
+    (0x1f5e8, 0x1f5e8,),  # Left Speech Bubble
+    (0x1f5ef, 0x1f5ef,),  # Right Anger Bubble
+    (0x1f5f3, 0x1f5f3,),  # Ballot Box With Ballot
+    (0x1f5fa, 0x1f64f,),  # World Map               ..Person With Folded Hands
+    (0x1f680, 0x1f6c5,),  # Rocket                  ..Left Luggage
+    (0x1f6cb, 0x1f6d2,),  # Couch And Lamp          ..Shopping Trolley
+    (0x1f6d5, 0x1f6e5,),  # Hindu Temple            ..Motor Boat
+    (0x1f6e9, 0x1f6e9,),  # Small Airplane
+    (0x1f6eb, 0x1f6f0,),  # Airplane Departure      ..Satellite
+    (0x1f6f3, 0x1f6ff,),  # Passenger Ship          ..(nil)
+    (0x1f7da, 0x1f7ff,),  # (nil)
+    (0x1f80c, 0x1f80f,),  # (nil)
+    (0x1f848, 0x1f84f,),  # (nil)
+    (0x1f85a, 0x1f85f,),  # (nil)
+    (0x1f888, 0x1f88f,),  # (nil)
+    (0x1f8ae, 0x1f8af,),  # (nil)
+    (0x1f8bc, 0x1f8bf,),  # (nil)
+    (0x1f8c2, 0x1f8cf,),  # (nil)
+    (0x1f8d9, 0x1f8ff,),  # (nil)
+    (0x1f90c, 0x1f93a,),  # Pinched Fingers         ..Fencer
+    (0x1f93c, 0x1f945,),  # Wrestlers               ..Goal Net
+    (0x1f947, 0x1f9ff,),  # First Place Medal       ..Nazar Amulet
+    (0x1fa58, 0x1fa5f,),  # (nil)
+    (0x1fa6e, 0x1faff,),  # (nil)
+    (0x1fc00, 0x1fffd,),  # (nil)
+)
+
+INCB_LINKER = (
+    # Source: DerivedCoreProperties
+    # Date: see file
+    #
+    (0x0094d, 0x0094d,),  # Devanagari Sign Virama
+    (0x009cd, 0x009cd,),  # Bengali Sign Virama
+    (0x00acd, 0x00acd,),  # Gujarati Sign Virama
+    (0x00b4d, 0x00b4d,),  # Oriya Sign Virama
+    (0x00c4d, 0x00c4d,),  # Telugu Sign Virama
+    (0x00d4d, 0x00d4d,),  # Malayalam Sign Virama
+    (0x01039, 0x01039,),  # Myanmar Sign Virama
+    (0x017d2, 0x017d2,),  # Khmer Sign Coeng
+    (0x01a60, 0x01a60,),  # Tai Tham Sign Sakot
+    (0x01b44, 0x01b44,),  # Balinese Adeg Adeg
+    (0x01bab, 0x01bab,),  # Sundanese Sign Virama
+    (0x0a9c0, 0x0a9c0,),  # Javanese Pangkon
+    (0x0aaf6, 0x0aaf6,),  # Meetei Mayek Virama
+    (0x10a3f, 0x10a3f,),  # Kharoshthi Virama
+    (0x11133, 0x11133,),  # Chakma Virama
+    (0x113d0, 0x113d0,),  # Tulu-tigalari Conjoiner
+    (0x1193e, 0x1193e,),  # Dives Akuru Virama
+    (0x11a47, 0x11a47,),  # Zanabazar Square Subjoiner
+    (0x11a99, 0x11a99,),  # Soyombo Subjoiner
+    (0x11f42, 0x11f42,),  # Kawi Conjoiner
+)
+
+INCB_CONSONANT = (
+    # Source: DerivedCoreProperties
+    # Date: see file
+    #
+    (0x00915, 0x00939,),  # Devanagari Letter Ka    ..Devanagari Letter Ha
+    (0x00958, 0x0095f,),  # Devanagari Letter Qa    ..Devanagari Letter Yya
+    (0x00978, 0x0097f,),  # Devanagari Letter Marwar..Devanagari Letter Bba
+    (0x00995, 0x009a8,),  # Bengali Letter Ka       ..Bengali Letter Na
+    (0x009aa, 0x009b0,),  # Bengali Letter Pa       ..Bengali Letter Ra
+    (0x009b2, 0x009b2,),  # Bengali Letter La
+    (0x009b6, 0x009b9,),  # Bengali Letter Sha      ..Bengali Letter Ha
+    (0x009dc, 0x009dd,),  # Bengali Letter Rra      ..Bengali Letter Rha
+    (0x009df, 0x009df,),  # Bengali Letter Yya
+    (0x009f0, 0x009f1,),  # Bengali Letter Ra With M..Bengali Letter Ra With L
+    (0x00a95, 0x00aa8,),  # Gujarati Letter Ka      ..Gujarati Letter Na
+    (0x00aaa, 0x00ab0,),  # Gujarati Letter Pa      ..Gujarati Letter Ra
+    (0x00ab2, 0x00ab3,),  # Gujarati Letter La      ..Gujarati Letter Lla
+    (0x00ab5, 0x00ab9,),  # Gujarati Letter Va      ..Gujarati Letter Ha
+    (0x00af9, 0x00af9,),  # Gujarati Letter Zha
+    (0x00b15, 0x00b28,),  # Oriya Letter Ka         ..Oriya Letter Na
+    (0x00b2a, 0x00b30,),  # Oriya Letter Pa         ..Oriya Letter Ra
+    (0x00b32, 0x00b33,),  # Oriya Letter La         ..Oriya Letter Lla
+    (0x00b35, 0x00b39,),  # Oriya Letter Va         ..Oriya Letter Ha
+    (0x00b5c, 0x00b5d,),  # Oriya Letter Rra        ..Oriya Letter Rha
+    (0x00b5f, 0x00b5f,),  # Oriya Letter Yya
+    (0x00b71, 0x00b71,),  # Oriya Letter Wa
+    (0x00c15, 0x00c28,),  # Telugu Letter Ka        ..Telugu Letter Na
+    (0x00c2a, 0x00c39,),  # Telugu Letter Pa        ..Telugu Letter Ha
+    (0x00c58, 0x00c5a,),  # Telugu Letter Tsa       ..Telugu Letter Rrra
+    (0x00d15, 0x00d3a,),  # Malayalam Letter Ka     ..Malayalam Letter Ttta
+    (0x01000, 0x0102a,),  # Myanmar Letter Ka       ..Myanmar Letter Au
+    (0x0103f, 0x0103f,),  # Myanmar Letter Great Sa
+    (0x01050, 0x01055,),  # Myanmar Letter Sha      ..Myanmar Letter Vocalic L
+    (0x0105a, 0x0105d,),  # Myanmar Letter Mon Nga  ..Myanmar Letter Mon Bbe
+    (0x01061, 0x01061,),  # Myanmar Letter Sgaw Karen Sha
+    (0x01065, 0x01066,),  # Myanmar Letter Western P..Myanmar Letter Western P
+    (0x0106e, 0x01070,),  # Myanmar Letter Eastern P..Myanmar Letter Eastern P
+    (0x01075, 0x01081,),  # Myanmar Letter Shan Ka  ..Myanmar Letter Shan Ha
+    (0x0108e, 0x0108e,),  # Myanmar Letter Rumai Palaung Fa
+    (0x01780, 0x017b3,),  # Khmer Letter Ka         ..Khmer Independent Vowel
+    (0x01a20, 0x01a54,),  # Tai Tham Letter High Ka ..Tai Tham Letter Great Sa
+    (0x01b0b, 0x01b0c,),  # Balinese Letter Ra Repa ..Balinese Letter Ra Repa
+    (0x01b13, 0x01b33,),  # Balinese Letter Ka      ..Balinese Letter Ha
+    (0x01b45, 0x01b4c,),  # Balinese Letter Kaf Sasa..Balinese Letter Archaic
+    (0x01b83, 0x01ba0,),  # Sundanese Letter A      ..Sundanese Letter Ha
+    (0x01bae, 0x01baf,),  # Sundanese Letter Kha    ..Sundanese Letter Sya
+    (0x01bbb, 0x01bbd,),  # Sundanese Letter Reu    ..Sundanese Letter Bha
+    (0x0a989, 0x0a98b,),  # Javanese Letter Pa Cerek..Javanese Letter Nga Lele
+    (0x0a98f, 0x0a9b2,),  # Javanese Letter Ka      ..Javanese Letter Ha
+    (0x0a9e0, 0x0a9e4,),  # Myanmar Letter Shan Gha ..Myanmar Letter Shan Bha
+    (0x0a9e7, 0x0a9ef,),  # Myanmar Letter Tai Laing..Myanmar Letter Tai Laing
+    (0x0a9fa, 0x0a9fe,),  # Myanmar Letter Tai Laing..Myanmar Letter Tai Laing
+    (0x0aa60, 0x0aa6f,),  # Myanmar Letter Khamti Ga..Myanmar Letter Khamti Fa
+    (0x0aa71, 0x0aa73,),  # Myanmar Letter Khamti Xa..Myanmar Letter Khamti Ra
+    (0x0aa7a, 0x0aa7a,),  # Myanmar Letter Aiton Ra
+    (0x0aa7e, 0x0aa7f,),  # Myanmar Letter Shwe Pala..Myanmar Letter Shwe Pala
+    (0x0aae0, 0x0aaea,),  # Meetei Mayek Letter E   ..Meetei Mayek Letter Ssa
+    (0x0abc0, 0x0abda,),  # Meetei Mayek Letter Kok ..Meetei Mayek Letter Bham
+    (0x10a00, 0x10a00,),  # Kharoshthi Letter A
+    (0x10a10, 0x10a13,),  # Kharoshthi Letter Ka    ..Kharoshthi Letter Gha
+    (0x10a15, 0x10a17,),  # Kharoshthi Letter Ca    ..Kharoshthi Letter Ja
+    (0x10a19, 0x10a35,),  # Kharoshthi Letter Nya   ..Kharoshthi Letter Vha
+    (0x11103, 0x11126,),  # Chakma Letter Aa        ..Chakma Letter Haa
+    (0x11144, 0x11144,),  # Chakma Letter Lhaa
+    (0x11147, 0x11147,),  # Chakma Letter Vaa
+    (0x11380, 0x11389,),  # Tulu-tigalari Letter A  ..Tulu-tigalari Letter Voc
+    (0x1138b, 0x1138b,),  # Tulu-tigalari Letter Ee
+    (0x1138e, 0x1138e,),  # Tulu-tigalari Letter Ai
+    (0x11390, 0x113b5,),  # Tulu-tigalari Letter Oo ..Tulu-tigalari Letter Lll
+    (0x11900, 0x11906,),  # Dives Akuru Letter A    ..Dives Akuru Letter E
+    (0x11909, 0x11909,),  # Dives Akuru Letter O
+    (0x1190c, 0x11913,),  # Dives Akuru Letter Ka   ..Dives Akuru Letter Ja
+    (0x11915, 0x11916,),  # Dives Akuru Letter Nya  ..Dives Akuru Letter Tta
+    (0x11918, 0x1192f,),  # Dives Akuru Letter Dda  ..Dives Akuru Letter Za
+    (0x11a00, 0x11a00,),  # Zanabazar Square Letter A
+    (0x11a0b, 0x11a32,),  # Zanabazar Square Letter ..Zanabazar Square Letter
+    (0x11a50, 0x11a50,),  # Soyombo Letter A
+    (0x11a5c, 0x11a83,),  # Soyombo Letter Ka       ..Soyombo Letter Kssa
+    (0x11f04, 0x11f10,),  # Kawi Letter A           ..Kawi Letter O
+    (0x11f12, 0x11f33,),  # Kawi Letter Ka          ..Kawi Letter Jnya
+)
+
+INCB_EXTEND = (
+    # Source: DerivedCoreProperties
+    # Date: see file
+    #
+    (0x00300, 0x0036f,),  # Combining Grave Accent  ..Combining Latin Small Le
+    (0x00483, 0x00489,),  # Combining Cyrillic Titlo..Combining Cyrillic Milli
+    (0x00591, 0x005bd,),  # Hebrew Accent Etnahta   ..Hebrew Point Meteg
+    (0x005bf, 0x005bf,),  # Hebrew Point Rafe
+    (0x005c1, 0x005c2,),  # Hebrew Point Shin Dot   ..Hebrew Point Sin Dot
+    (0x005c4, 0x005c5,),  # Hebrew Mark Upper Dot   ..Hebrew Mark Lower Dot
+    (0x005c7, 0x005c7,),  # Hebrew Point Qamats Qatan
+    (0x00610, 0x0061a,),  # Arabic Sign Sallallahou ..Arabic Small Kasra
+    (0x0064b, 0x0065f,),  # Arabic Fathatan         ..Arabic Wavy Hamza Below
+    (0x00670, 0x00670,),  # Arabic Letter Superscript Alef
+    (0x006d6, 0x006dc,),  # Arabic Small High Ligatu..Arabic Small High Seen
+    (0x006df, 0x006e4,),  # Arabic Small High Rounde..Arabic Small High Madda
+    (0x006e7, 0x006e8,),  # Arabic Small High Yeh   ..Arabic Small High Noon
+    (0x006ea, 0x006ed,),  # Arabic Empty Centre Low ..Arabic Small Low Meem
+    (0x00711, 0x00711,),  # Syriac Letter Superscript Alaph
+    (0x00730, 0x0074a,),  # Syriac Pthaha Above     ..Syriac Barrekh
+    (0x007a6, 0x007b0,),  # Thaana Abafili          ..Thaana Sukun
+    (0x007eb, 0x007f3,),  # Nko Combining Short High..Nko Combining Double Dot
+    (0x007fd, 0x007fd,),  # Nko Dantayalan
+    (0x00816, 0x00819,),  # Samaritan Mark In       ..Samaritan Mark Dagesh
+    (0x0081b, 0x00823,),  # Samaritan Mark Epentheti..Samaritan Vowel Sign A
+    (0x00825, 0x00827,),  # Samaritan Vowel Sign Sho..Samaritan Vowel Sign U
+    (0x00829, 0x0082d,),  # Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa
+    (0x00859, 0x0085b,),  # Mandaic Affrication Mark..Mandaic Gemination Mark
+    (0x00897, 0x0089f,),  # Arabic Pepet            ..Arabic Half Madda Over M
+    (0x008ca, 0x008e1,),  # Arabic Small High Farsi ..Arabic Small High Sign S
+    (0x008e3, 0x00902,),  # Arabic Turned Damma Belo..Devanagari Sign Anusvara
+    (0x0093a, 0x0093a,),  # Devanagari Vowel Sign Oe
+    (0x0093c, 0x0093c,),  # Devanagari Sign Nukta
+    (0x00941, 0x00948,),  # Devanagari Vowel Sign U ..Devanagari Vowel Sign Ai
+    (0x00951, 0x00957,),  # Devanagari Stress Sign U..Devanagari Vowel Sign Uu
+    (0x00962, 0x00963,),  # Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo
+    (0x00981, 0x00981,),  # Bengali Sign Candrabindu
+    (0x009bc, 0x009bc,),  # Bengali Sign Nukta
+    (0x009be, 0x009be,),  # Bengali Vowel Sign Aa
+    (0x009c1, 0x009c4,),  # Bengali Vowel Sign U    ..Bengali Vowel Sign Vocal
+    (0x009d7, 0x009d7,),  # Bengali Au Length Mark
+    (0x009e2, 0x009e3,),  # Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal
+    (0x009fe, 0x009fe,),  # Bengali Sandhi Mark
+    (0x00a01, 0x00a02,),  # Gurmukhi Sign Adak Bindi..Gurmukhi Sign Bindi
+    (0x00a3c, 0x00a3c,),  # Gurmukhi Sign Nukta
+    (0x00a41, 0x00a42,),  # Gurmukhi Vowel Sign U   ..Gurmukhi Vowel Sign Uu
+    (0x00a47, 0x00a48,),  # Gurmukhi Vowel Sign Ee  ..Gurmukhi Vowel Sign Ai
+    (0x00a4b, 0x00a4d,),  # Gurmukhi Vowel Sign Oo  ..Gurmukhi Sign Virama
+    (0x00a51, 0x00a51,),  # Gurmukhi Sign Udaat
+    (0x00a70, 0x00a71,),  # Gurmukhi Tippi          ..Gurmukhi Addak
+    (0x00a75, 0x00a75,),  # Gurmukhi Sign Yakash
+    (0x00a81, 0x00a82,),  # Gujarati Sign Candrabind..Gujarati Sign Anusvara
+    (0x00abc, 0x00abc,),  # Gujarati Sign Nukta
+    (0x00ac1, 0x00ac5,),  # Gujarati Vowel Sign U   ..Gujarati Vowel Sign Cand
+    (0x00ac7, 0x00ac8,),  # Gujarati Vowel Sign E   ..Gujarati Vowel Sign Ai
+    (0x00ae2, 0x00ae3,),  # Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca
+    (0x00afa, 0x00aff,),  # Gujarati Sign Sukun     ..Gujarati Sign Two-circle
+    (0x00b01, 0x00b01,),  # Oriya Sign Candrabindu
+    (0x00b3c, 0x00b3c,),  # Oriya Sign Nukta
+    (0x00b3e, 0x00b3f,),  # Oriya Vowel Sign Aa     ..Oriya Vowel Sign I
+    (0x00b41, 0x00b44,),  # Oriya Vowel Sign U      ..Oriya Vowel Sign Vocalic
+    (0x00b55, 0x00b57,),  # Oriya Sign Overline     ..Oriya Au Length Mark
+    (0x00b62, 0x00b63,),  # Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic
+    (0x00b82, 0x00b82,),  # Tamil Sign Anusvara
+    (0x00bbe, 0x00bbe,),  # Tamil Vowel Sign Aa
+    (0x00bc0, 0x00bc0,),  # Tamil Vowel Sign Ii
+    (0x00bcd, 0x00bcd,),  # Tamil Sign Virama
+    (0x00bd7, 0x00bd7,),  # Tamil Au Length Mark
+    (0x00c00, 0x00c00,),  # Telugu Sign Combining Candrabindu Above
+    (0x00c04, 0x00c04,),  # Telugu Sign Combining Anusvara Above
+    (0x00c3c, 0x00c3c,),  # Telugu Sign Nukta
+    (0x00c3e, 0x00c40,),  # Telugu Vowel Sign Aa    ..Telugu Vowel Sign Ii
+    (0x00c46, 0x00c48,),  # Telugu Vowel Sign E     ..Telugu Vowel Sign Ai
+    (0x00c4a, 0x00c4c,),  # Telugu Vowel Sign O     ..Telugu Vowel Sign Au
+    (0x00c55, 0x00c56,),  # Telugu Length Mark      ..Telugu Ai Length Mark
+    (0x00c62, 0x00c63,),  # Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali
+    (0x00c81, 0x00c81,),  # Kannada Sign Candrabindu
+    (0x00cbc, 0x00cbc,),  # Kannada Sign Nukta
+    (0x00cbf, 0x00cc0,),  # Kannada Vowel Sign I    ..Kannada Vowel Sign Ii
+    (0x00cc2, 0x00cc2,),  # Kannada Vowel Sign Uu
+    (0x00cc6, 0x00cc8,),  # Kannada Vowel Sign E    ..Kannada Vowel Sign Ai
+    (0x00cca, 0x00ccd,),  # Kannada Vowel Sign O    ..Kannada Sign Virama
+    (0x00cd5, 0x00cd6,),  # Kannada Length Mark     ..Kannada Ai Length Mark
+    (0x00ce2, 0x00ce3,),  # Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal
+    (0x00d00, 0x00d01,),  # Malayalam Sign Combining..Malayalam Sign Candrabin
+    (0x00d3b, 0x00d3c,),  # Malayalam Sign Vertical ..Malayalam Sign Circular
+    (0x00d3e, 0x00d3e,),  # Malayalam Vowel Sign Aa
+    (0x00d41, 0x00d44,),  # Malayalam Vowel Sign U  ..Malayalam Vowel Sign Voc
+    (0x00d57, 0x00d57,),  # Malayalam Au Length Mark
+    (0x00d62, 0x00d63,),  # Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc
+    (0x00d81, 0x00d81,),  # Sinhala Sign Candrabindu
+    (0x00dca, 0x00dca,),  # Sinhala Sign Al-lakuna
+    (0x00dcf, 0x00dcf,),  # Sinhala Vowel Sign Aela-pilla
+    (0x00dd2, 0x00dd4,),  # Sinhala Vowel Sign Ketti..Sinhala Vowel Sign Ketti
+    (0x00dd6, 0x00dd6,),  # Sinhala Vowel Sign Diga Paa-pilla
+    (0x00ddf, 0x00ddf,),  # Sinhala Vowel Sign Gayanukitta
+    (0x00e31, 0x00e31,),  # Thai Character Mai Han-akat
+    (0x00e34, 0x00e3a,),  # Thai Character Sara I   ..Thai Character Phinthu
+    (0x00e47, 0x00e4e,),  # Thai Character Maitaikhu..Thai Character Yamakkan
+    (0x00eb1, 0x00eb1,),  # Lao Vowel Sign Mai Kan
+    (0x00eb4, 0x00ebc,),  # Lao Vowel Sign I        ..Lao Semivowel Sign Lo
+    (0x00ec8, 0x00ece,),  # Lao Tone Mai Ek         ..Lao Yamakkan
+    (0x00f18, 0x00f19,),  # Tibetan Astrological Sig..Tibetan Astrological Sig
+    (0x00f35, 0x00f35,),  # Tibetan Mark Ngas Bzung Nyi Zla
+    (0x00f37, 0x00f37,),  # Tibetan Mark Ngas Bzung Sgor Rtags
+    (0x00f39, 0x00f39,),  # Tibetan Mark Tsa -phru
+    (0x00f71, 0x00f7e,),  # Tibetan Vowel Sign Aa   ..Tibetan Sign Rjes Su Nga
+    (0x00f80, 0x00f84,),  # Tibetan Vowel Sign Rever..Tibetan Mark Halanta
+    (0x00f86, 0x00f87,),  # Tibetan Sign Lci Rtags  ..Tibetan Sign Yang Rtags
+    (0x00f8d, 0x00f97,),  # Tibetan Subjoined Sign L..Tibetan Subjoined Letter
+    (0x00f99, 0x00fbc,),  # Tibetan Subjoined Letter..Tibetan Subjoined Letter
+    (0x00fc6, 0x00fc6,),  # Tibetan Symbol Padma Gdan
+    (0x0102d, 0x01030,),  # Myanmar Vowel Sign I    ..Myanmar Vowel Sign Uu
+    (0x01032, 0x01037,),  # Myanmar Vowel Sign Ai   ..Myanmar Sign Dot Below
+    (0x0103a, 0x0103a,),  # Myanmar Sign Asat
+    (0x0103d, 0x0103e,),  # Myanmar Consonant Sign M..Myanmar Consonant Sign M
+    (0x01058, 0x01059,),  # Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal
+    (0x0105e, 0x01060,),  # Myanmar Consonant Sign M..Myanmar Consonant Sign M
+    (0x01071, 0x01074,),  # Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah
+    (0x01082, 0x01082,),  # Myanmar Consonant Sign Shan Medial Wa
+    (0x01085, 0x01086,),  # Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan
+    (0x0108d, 0x0108d,),  # Myanmar Sign Shan Council Emphatic Tone
+    (0x0109d, 0x0109d,),  # Myanmar Vowel Sign Aiton Ai
+    (0x0135d, 0x0135f,),  # Ethiopic Combining Gemin..Ethiopic Combining Gemin
+    (0x01712, 0x01715,),  # Tagalog Vowel Sign I    ..Tagalog Sign Pamudpod
+    (0x01732, 0x01734,),  # Hanunoo Vowel Sign I    ..Hanunoo Sign Pamudpod
+    (0x01752, 0x01753,),  # Buhid Vowel Sign I      ..Buhid Vowel Sign U
+    (0x01772, 0x01773,),  # Tagbanwa Vowel Sign I   ..Tagbanwa Vowel Sign U
+    (0x017b4, 0x017b5,),  # Khmer Vowel Inherent Aq ..Khmer Vowel Inherent Aa
+    (0x017b7, 0x017bd,),  # Khmer Vowel Sign I      ..Khmer Vowel Sign Ua
+    (0x017c6, 0x017c6,),  # Khmer Sign Nikahit
+    (0x017c9, 0x017d1,),  # Khmer Sign Muusikatoan  ..Khmer Sign Viriam
+    (0x017d3, 0x017d3,),  # Khmer Sign Bathamasat
+    (0x017dd, 0x017dd,),  # Khmer Sign Atthacan
+    (0x0180b, 0x0180d,),  # Mongolian Free Variation..Mongolian Free Variation
+    (0x0180f, 0x0180f,),  # Mongolian Free Variation Selector Four
+    (0x01885, 0x01886,),  # Mongolian Letter Ali Gal..Mongolian Letter Ali Gal
+    (0x018a9, 0x018a9,),  # Mongolian Letter Ali Gali Dagalga
+    (0x01920, 0x01922,),  # Limbu Vowel Sign A      ..Limbu Vowel Sign U
+    (0x01927, 0x01928,),  # Limbu Vowel Sign E      ..Limbu Vowel Sign O
+    (0x01932, 0x01932,),  # Limbu Small Letter Anusvara
+    (0x01939, 0x0193b,),  # Limbu Sign Mukphreng    ..Limbu Sign Sa-i
+    (0x01a17, 0x01a18,),  # Buginese Vowel Sign I   ..Buginese Vowel Sign U
+    (0x01a1b, 0x01a1b,),  # Buginese Vowel Sign Ae
+    (0x01a56, 0x01a56,),  # Tai Tham Consonant Sign Medial La
+    (0x01a58, 0x01a5e,),  # Tai Tham Sign Mai Kang L..Tai Tham Consonant Sign
+    (0x01a62, 0x01a62,),  # Tai Tham Vowel Sign Mai Sat
+    (0x01a65, 0x01a6c,),  # Tai Tham Vowel Sign I   ..Tai Tham Vowel Sign Oa B
+    (0x01a73, 0x01a7c,),  # Tai Tham Vowel Sign Oa A..Tai Tham Sign Khuen-lue
+    (0x01a7f, 0x01a7f,),  # Tai Tham Combining Cryptogrammic Dot
+    (0x01ab0, 0x01add,),  # Combining Doubled Circum..Combining Dot-and-ring B
+    (0x01ae0, 0x01aeb,),  # Combining Left Tack Abov..Combining Double Rightwa
+    (0x01b00, 0x01b03,),  # Balinese Sign Ulu Ricem ..Balinese Sign Surang
+    (0x01b34, 0x01b3d,),  # Balinese Sign Rerekan   ..Balinese Vowel Sign La L
+    (0x01b42, 0x01b43,),  # Balinese Vowel Sign Pepe..Balinese Vowel Sign Pepe
+    (0x01b6b, 0x01b73,),  # Balinese Musical Symbol ..Balinese Musical Symbol
+    (0x01b80, 0x01b81,),  # Sundanese Sign Panyecek ..Sundanese Sign Panglayar
+    (0x01ba2, 0x01ba5,),  # Sundanese Consonant Sign..Sundanese Vowel Sign Pan
+    (0x01ba8, 0x01baa,),  # Sundanese Vowel Sign Pam..Sundanese Sign Pamaaeh
+    (0x01bac, 0x01bad,),  # Sundanese Consonant Sign..Sundanese Consonant Sign
+    (0x01be6, 0x01be6,),  # Batak Sign Tompi
+    (0x01be8, 0x01be9,),  # Batak Vowel Sign Pakpak ..Batak Vowel Sign Ee
+    (0x01bed, 0x01bed,),  # Batak Vowel Sign Karo O
+    (0x01bef, 0x01bf3,),  # Batak Vowel Sign U For S..Batak Panongonan
+    (0x01c2c, 0x01c33,),  # Lepcha Vowel Sign E     ..Lepcha Consonant Sign T
+    (0x01c36, 0x01c37,),  # Lepcha Sign Ran         ..Lepcha Sign Nukta
+    (0x01cd0, 0x01cd2,),  # Vedic Tone Karshana     ..Vedic Tone Prenkha
+    (0x01cd4, 0x01ce0,),  # Vedic Sign Yajurvedic Mi..Vedic Tone Rigvedic Kash
+    (0x01ce2, 0x01ce8,),  # Vedic Sign Visarga Svari..Vedic Sign Visarga Anuda
+    (0x01ced, 0x01ced,),  # Vedic Sign Tiryak
+    (0x01cf4, 0x01cf4,),  # Vedic Tone Candra Above
+    (0x01cf8, 0x01cf9,),  # Vedic Tone Ring Above   ..Vedic Tone Double Ring A
+    (0x01dc0, 0x01dff,),  # Combining Dotted Grave A..Combining Right Arrowhea
+    (0x0200d, 0x0200d,),  # Zero Width Joiner
+    (0x020d0, 0x020f0,),  # Combining Left Harpoon A..Combining Asterisk Above
+    (0x02cef, 0x02cf1,),  # Coptic Combining Ni Abov..Coptic Combining Spiritu
+    (0x02d7f, 0x02d7f,),  # Tifinagh Consonant Joiner
+    (0x02de0, 0x02dff,),  # Combining Cyrillic Lette..Combining Cyrillic Lette
+    (0x0302a, 0x0302f,),  # Ideographic Level Tone M..Hangul Double Dot Tone M
+    (0x03099, 0x0309a,),  # Combining Katakana-hirag..Combining Katakana-hirag
+    (0x0a66f, 0x0a672,),  # Combining Cyrillic Vzmet..Combining Cyrillic Thous
+    (0x0a674, 0x0a67d,),  # Combining Cyrillic Lette..Combining Cyrillic Payer
+    (0x0a69e, 0x0a69f,),  # Combining Cyrillic Lette..Combining Cyrillic Lette
+    (0x0a6f0, 0x0a6f1,),  # Bamum Combining Mark Koq..Bamum Combining Mark Tuk
+    (0x0a802, 0x0a802,),  # Syloti Nagri Sign Dvisvara
+    (0x0a806, 0x0a806,),  # Syloti Nagri Sign Hasanta
+    (0x0a80b, 0x0a80b,),  # Syloti Nagri Sign Anusvara
+    (0x0a825, 0x0a826,),  # Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign
+    (0x0a82c, 0x0a82c,),  # Syloti Nagri Sign Alternate Hasanta
+    (0x0a8c4, 0x0a8c5,),  # Saurashtra Sign Virama  ..Saurashtra Sign Candrabi
+    (0x0a8e0, 0x0a8f1,),  # Combining Devanagari Dig..Combining Devanagari Sig
+    (0x0a8ff, 0x0a8ff,),  # Devanagari Vowel Sign Ay
+    (0x0a926, 0x0a92d,),  # Kayah Li Vowel Ue       ..Kayah Li Tone Calya Plop
+    (0x0a947, 0x0a951,),  # Rejang Vowel Sign I     ..Rejang Consonant Sign R
+    (0x0a953, 0x0a953,),  # Rejang Virama
+    (0x0a980, 0x0a982,),  # Javanese Sign Panyangga ..Javanese Sign Layar
+    (0x0a9b3, 0x0a9b3,),  # Javanese Sign Cecak Telu
+    (0x0a9b6, 0x0a9b9,),  # Javanese Vowel Sign Wulu..Javanese Vowel Sign Suku
+    (0x0a9bc, 0x0a9bd,),  # Javanese Vowel Sign Pepe..Javanese Consonant Sign
+    (0x0a9e5, 0x0a9e5,),  # Myanmar Sign Shan Saw
+    (0x0aa29, 0x0aa2e,),  # Cham Vowel Sign Aa      ..Cham Vowel Sign Oe
+    (0x0aa31, 0x0aa32,),  # Cham Vowel Sign Au      ..Cham Vowel Sign Ue
+    (0x0aa35, 0x0aa36,),  # Cham Consonant Sign La  ..Cham Consonant Sign Wa
+    (0x0aa43, 0x0aa43,),  # Cham Consonant Sign Final Ng
+    (0x0aa4c, 0x0aa4c,),  # Cham Consonant Sign Final M
+    (0x0aa7c, 0x0aa7c,),  # Myanmar Sign Tai Laing Tone-2
+    (0x0aab0, 0x0aab0,),  # Tai Viet Mai Kang
+    (0x0aab2, 0x0aab4,),  # Tai Viet Vowel I        ..Tai Viet Vowel U
+    (0x0aab7, 0x0aab8,),  # Tai Viet Mai Khit       ..Tai Viet Vowel Ia
+    (0x0aabe, 0x0aabf,),  # Tai Viet Vowel Am       ..Tai Viet Tone Mai Ek
+    (0x0aac1, 0x0aac1,),  # Tai Viet Tone Mai Tho
+    (0x0aaec, 0x0aaed,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+    (0x0abe5, 0x0abe5,),  # Meetei Mayek Vowel Sign Anap
+    (0x0abe8, 0x0abe8,),  # Meetei Mayek Vowel Sign Unap
+    (0x0abed, 0x0abed,),  # Meetei Mayek Apun Iyek
+    (0x0fb1e, 0x0fb1e,),  # Hebrew Point Judeo-spanish Varika
+    (0x0fe00, 0x0fe0f,),  # Variation Selector-1    ..Variation Selector-16
+    (0x0fe20, 0x0fe2f,),  # Combining Ligature Left ..Combining Cyrillic Titlo
+    (0x0ff9e, 0x0ff9f,),  # Halfwidth Katakana Voice..Halfwidth Katakana Semi-
+    (0x101fd, 0x101fd,),  # Phaistos Disc Sign Combining Oblique Stroke
+    (0x102e0, 0x102e0,),  # Coptic Epact Thousands Mark
+    (0x10376, 0x1037a,),  # Combining Old Permic Let..Combining Old Permic Let
+    (0x10a01, 0x10a03,),  # Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo
+    (0x10a05, 0x10a06,),  # Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O
+    (0x10a0c, 0x10a0f,),  # Kharoshthi Vowel Length ..Kharoshthi Sign Visarga
+    (0x10a38, 0x10a3a,),  # Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo
+    (0x10ae5, 0x10ae6,),  # Manichaean Abbreviation ..Manichaean Abbreviation
+    (0x10d24, 0x10d27,),  # Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas
+    (0x10d69, 0x10d6d,),  # Garay Vowel Sign E      ..Garay Consonant Nasaliza
+    (0x10eab, 0x10eac,),  # Yezidi Combining Hamza M..Yezidi Combining Madda M
+    (0x10efa, 0x10eff,),  # Arabic Double Vertical B..Arabic Small Low Word Ma
+    (0x10f46, 0x10f50,),  # Sogdian Combining Dot Be..Sogdian Combining Stroke
+    (0x10f82, 0x10f85,),  # Old Uyghur Combining Dot..Old Uyghur Combining Two
+    (0x11001, 0x11001,),  # Brahmi Sign Anusvara
+    (0x11038, 0x11046,),  # Brahmi Vowel Sign Aa    ..Brahmi Virama
+    (0x11070, 0x11070,),  # Brahmi Sign Old Tamil Virama
+    (0x11073, 0x11074,),  # Brahmi Vowel Sign Old Ta..Brahmi Vowel Sign Old Ta
+    (0x1107f, 0x11081,),  # Brahmi Number Joiner    ..Kaithi Sign Anusvara
+    (0x110b3, 0x110b6,),  # Kaithi Vowel Sign U     ..Kaithi Vowel Sign Ai
+    (0x110b9, 0x110ba,),  # Kaithi Sign Virama      ..Kaithi Sign Nukta
+    (0x110c2, 0x110c2,),  # Kaithi Vowel Sign Vocalic R
+    (0x11100, 0x11102,),  # Chakma Sign Candrabindu ..Chakma Sign Visarga
+    (0x11127, 0x1112b,),  # Chakma Vowel Sign A     ..Chakma Vowel Sign Uu
+    (0x1112d, 0x11132,),  # Chakma Vowel Sign Ai    ..Chakma Au Mark
+    (0x11134, 0x11134,),  # Chakma Maayyaa
+    (0x11173, 0x11173,),  # Mahajani Sign Nukta
+    (0x11180, 0x11181,),  # Sharada Sign Candrabindu..Sharada Sign Anusvara
+    (0x111b6, 0x111be,),  # Sharada Vowel Sign U    ..Sharada Vowel Sign O
+    (0x111c0, 0x111c0,),  # Sharada Sign Virama
+    (0x111c9, 0x111cc,),  # Sharada Sandhi Mark     ..Sharada Extra Short Vowe
+    (0x111cf, 0x111cf,),  # Sharada Sign Inverted Candrabindu
+    (0x1122f, 0x11231,),  # Khojki Vowel Sign U     ..Khojki Vowel Sign Ai
+    (0x11234, 0x11237,),  # Khojki Sign Anusvara    ..Khojki Sign Shadda
+    (0x1123e, 0x1123e,),  # Khojki Sign Sukun
+    (0x11241, 0x11241,),  # Khojki Vowel Sign Vocalic R
+    (0x112df, 0x112df,),  # Khudawadi Sign Anusvara
+    (0x112e3, 0x112ea,),  # Khudawadi Vowel Sign U  ..Khudawadi Sign Virama
+    (0x11300, 0x11301,),  # Grantha Sign Combining A..Grantha Sign Candrabindu
+    (0x1133b, 0x1133c,),  # Combining Bindu Below   ..Grantha Sign Nukta
+    (0x1133e, 0x1133e,),  # Grantha Vowel Sign Aa
+    (0x11340, 0x11340,),  # Grantha Vowel Sign Ii
+    (0x1134d, 0x1134d,),  # Grantha Sign Virama
+    (0x11357, 0x11357,),  # Grantha Au Length Mark
+    (0x11366, 0x1136c,),  # Combining Grantha Digit ..Combining Grantha Digit
+    (0x11370, 0x11374,),  # Combining Grantha Letter..Combining Grantha Letter
+    (0x113b8, 0x113b8,),  # Tulu-tigalari Vowel Sign Aa
+    (0x113bb, 0x113c0,),  # Tulu-tigalari Vowel Sign..Tulu-tigalari Vowel Sign
+    (0x113c2, 0x113c2,),  # Tulu-tigalari Vowel Sign Ee
+    (0x113c5, 0x113c5,),  # Tulu-tigalari Vowel Sign Ai
+    (0x113c7, 0x113c9,),  # Tulu-tigalari Vowel Sign..Tulu-tigalari Au Length
+    (0x113ce, 0x113cf,),  # Tulu-tigalari Sign Viram..Tulu-tigalari Sign Loope
+    (0x113d2, 0x113d2,),  # Tulu-tigalari Gemination Mark
+    (0x113e1, 0x113e2,),  # Tulu-tigalari Vedic Tone..Tulu-tigalari Vedic Tone
+    (0x11438, 0x1143f,),  # Newa Vowel Sign U       ..Newa Vowel Sign Ai
+    (0x11442, 0x11444,),  # Newa Sign Virama        ..Newa Sign Anusvara
+    (0x11446, 0x11446,),  # Newa Sign Nukta
+    (0x1145e, 0x1145e,),  # Newa Sandhi Mark
+    (0x114b0, 0x114b0,),  # Tirhuta Vowel Sign Aa
+    (0x114b3, 0x114b8,),  # Tirhuta Vowel Sign U    ..Tirhuta Vowel Sign Vocal
+    (0x114ba, 0x114ba,),  # Tirhuta Vowel Sign Short E
+    (0x114bd, 0x114bd,),  # Tirhuta Vowel Sign Short O
+    (0x114bf, 0x114c0,),  # Tirhuta Sign Candrabindu..Tirhuta Sign Anusvara
+    (0x114c2, 0x114c3,),  # Tirhuta Sign Virama     ..Tirhuta Sign Nukta
+    (0x115af, 0x115af,),  # Siddham Vowel Sign Aa
+    (0x115b2, 0x115b5,),  # Siddham Vowel Sign U    ..Siddham Vowel Sign Vocal
+    (0x115bc, 0x115bd,),  # Siddham Sign Candrabindu..Siddham Sign Anusvara
+    (0x115bf, 0x115c0,),  # Siddham Sign Virama     ..Siddham Sign Nukta
+    (0x115dc, 0x115dd,),  # Siddham Vowel Sign Alter..Siddham Vowel Sign Alter
+    (0x11633, 0x1163a,),  # Modi Vowel Sign U       ..Modi Vowel Sign Ai
+    (0x1163d, 0x1163d,),  # Modi Sign Anusvara
+    (0x1163f, 0x11640,),  # Modi Sign Virama        ..Modi Sign Ardhacandra
+    (0x116ab, 0x116ab,),  # Takri Sign Anusvara
+    (0x116ad, 0x116ad,),  # Takri Vowel Sign Aa
+    (0x116b0, 0x116b7,),  # Takri Vowel Sign U      ..Takri Sign Nukta
+    (0x1171d, 0x1171d,),  # Ahom Consonant Sign Medial La
+    (0x1171f, 0x1171f,),  # Ahom Consonant Sign Medial Ligating Ra
+    (0x11722, 0x11725,),  # Ahom Vowel Sign I       ..Ahom Vowel Sign Uu
+    (0x11727, 0x1172b,),  # Ahom Vowel Sign Aw      ..Ahom Sign Killer
+    (0x1182f, 0x11837,),  # Dogra Vowel Sign U      ..Dogra Sign Anusvara
+    (0x11839, 0x1183a,),  # Dogra Sign Virama       ..Dogra Sign Nukta
+    (0x11930, 0x11930,),  # Dives Akuru Vowel Sign Aa
+    (0x1193b, 0x1193d,),  # Dives Akuru Sign Anusvar..Dives Akuru Sign Halanta
+    (0x11943, 0x11943,),  # Dives Akuru Sign Nukta
+    (0x119d4, 0x119d7,),  # Nandinagari Vowel Sign U..Nandinagari Vowel Sign V
+    (0x119da, 0x119db,),  # Nandinagari Vowel Sign E..Nandinagari Vowel Sign A
+    (0x119e0, 0x119e0,),  # Nandinagari Sign Virama
+    (0x11a01, 0x11a0a,),  # Zanabazar Square Vowel S..Zanabazar Square Vowel L
+    (0x11a33, 0x11a38,),  # Zanabazar Square Final C..Zanabazar Square Sign An
+    (0x11a3b, 0x11a3e,),  # Zanabazar Square Cluster..Zanabazar Square Cluster
+    (0x11a51, 0x11a56,),  # Soyombo Vowel Sign I    ..Soyombo Vowel Sign Oe
+    (0x11a59, 0x11a5b,),  # Soyombo Vowel Sign Vocal..Soyombo Vowel Length Mar
+    (0x11a8a, 0x11a96,),  # Soyombo Final Consonant ..Soyombo Sign Anusvara
+    (0x11a98, 0x11a98,),  # Soyombo Gemination Mark
+    (0x11b60, 0x11b60,),  # Sharada Vowel Sign Oe
+    (0x11b62, 0x11b64,),  # Sharada Vowel Sign Ue   ..Sharada Vowel Sign Short
+    (0x11b66, 0x11b66,),  # Sharada Vowel Sign Candra E
+    (0x11c30, 0x11c36,),  # Bhaiksuki Vowel Sign I  ..Bhaiksuki Vowel Sign Voc
+    (0x11c38, 0x11c3d,),  # Bhaiksuki Vowel Sign E  ..Bhaiksuki Sign Anusvara
+    (0x11c3f, 0x11c3f,),  # Bhaiksuki Sign Virama
+    (0x11c92, 0x11ca7,),  # Marchen Subjoined Letter..Marchen Subjoined Letter
+    (0x11caa, 0x11cb0,),  # Marchen Subjoined Letter..Marchen Vowel Sign Aa
+    (0x11cb2, 0x11cb3,),  # Marchen Vowel Sign U    ..Marchen Vowel Sign E
+    (0x11cb5, 0x11cb6,),  # Marchen Sign Anusvara   ..Marchen Sign Candrabindu
+    (0x11d31, 0x11d36,),  # Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign
+    (0x11d3a, 0x11d3a,),  # Masaram Gondi Vowel Sign E
+    (0x11d3c, 0x11d3d,),  # Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign
+    (0x11d3f, 0x11d45,),  # Masaram Gondi Vowel Sign..Masaram Gondi Virama
+    (0x11d47, 0x11d47,),  # Masaram Gondi Ra-kara
+    (0x11d90, 0x11d91,),  # Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign
+    (0x11d95, 0x11d95,),  # Gunjala Gondi Sign Anusvara
+    (0x11d97, 0x11d97,),  # Gunjala Gondi Virama
+    (0x11ef3, 0x11ef4,),  # Makasar Vowel Sign I    ..Makasar Vowel Sign U
+    (0x11f00, 0x11f01,),  # Kawi Sign Candrabindu   ..Kawi Sign Anusvara
+    (0x11f36, 0x11f3a,),  # Kawi Vowel Sign I       ..Kawi Vowel Sign Vocalic
+    (0x11f40, 0x11f41,),  # Kawi Vowel Sign Eu      ..Kawi Sign Killer
+    (0x11f5a, 0x11f5a,),  # Kawi Sign Nukta
+    (0x13440, 0x13440,),  # Egyptian Hieroglyph Mirror Horizontally
+    (0x13447, 0x13455,),  # Egyptian Hieroglyph Modi..Egyptian Hieroglyph Modi
+    (0x1611e, 0x16129,),  # Gurung Khema Vowel Sign ..Gurung Khema Vowel Lengt
+    (0x1612d, 0x1612f,),  # Gurung Khema Sign Anusva..Gurung Khema Sign Tholho
+    (0x16af0, 0x16af4,),  # Bassa Vah Combining High..Bassa Vah Combining High
+    (0x16b30, 0x16b36,),  # Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta
+    (0x16f4f, 0x16f4f,),  # Miao Sign Consonant Modifier Bar
+    (0x16f8f, 0x16f92,),  # Miao Tone Right         ..Miao Tone Below
+    (0x16fe4, 0x16fe4,),  # Khitan Small Script Filler
+    (0x16ff0, 0x16ff1,),  # Vietnamese Alternate Rea..Vietnamese Alternate Rea
+    (0x1bc9d, 0x1bc9e,),  # Duployan Thick Letter Se..Duployan Double Mark
+    (0x1cf00, 0x1cf2d,),  # Znamenny Combining Mark ..Znamenny Combining Mark
+    (0x1cf30, 0x1cf46,),  # Znamenny Combining Tonal..Znamenny Priznak Modifie
+    (0x1d165, 0x1d169,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d16d, 0x1d172,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d17b, 0x1d182,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d185, 0x1d18b,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d1aa, 0x1d1ad,),  # Musical Symbol Combining..Musical Symbol Combining
+    (0x1d242, 0x1d244,),  # Combining Greek Musical ..Combining Greek Musical
+    (0x1da00, 0x1da36,),  # Signwriting Head Rim    ..Signwriting Air Sucking
+    (0x1da3b, 0x1da6c,),  # Signwriting Mouth Closed..Signwriting Excitement
+    (0x1da75, 0x1da75,),  # Signwriting Upper Body Tilting From Hip Joints
+    (0x1da84, 0x1da84,),  # Signwriting Location Head Neck
+    (0x1da9b, 0x1da9f,),  # Signwriting Fill Modifie..Signwriting Fill Modifie
+    (0x1daa1, 0x1daaf,),  # Signwriting Rotation Mod..Signwriting Rotation Mod
+    (0x1e000, 0x1e006,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e008, 0x1e018,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e01b, 0x1e021,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e023, 0x1e024,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e026, 0x1e02a,),  # Combining Glagolitic Let..Combining Glagolitic Let
+    (0x1e08f, 0x1e08f,),  # Combining Cyrillic Small Letter Byelorussian-ukr
+    (0x1e130, 0x1e136,),  # Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T
+    (0x1e2ae, 0x1e2ae,),  # Toto Sign Rising Tone
+    (0x1e2ec, 0x1e2ef,),  # Wancho Tone Tup         ..Wancho Tone Koini
+    (0x1e4ec, 0x1e4ef,),  # Nag Mundari Sign Muhor  ..Nag Mundari Sign Sutuh
+    (0x1e5ee, 0x1e5ef,),  # Ol Onal Sign Mu         ..Ol Onal Sign Ikir
+    (0x1e6e3, 0x1e6e3,),  # Tai Yo Sign Ue
+    (0x1e6e6, 0x1e6e6,),  # Tai Yo Sign Au
+    (0x1e6ee, 0x1e6ef,),  # Tai Yo Sign Ay          ..Tai Yo Sign Ang
+    (0x1e6f5, 0x1e6f5,),  # Tai Yo Sign Om
+    (0x1e8d0, 0x1e8d6,),  # Mende Kikakui Combining ..Mende Kikakui Combining
+    (0x1e944, 0x1e94a,),  # Adlam Alif Lengthener   ..Adlam Nukta
+    (0x1f3fb, 0x1f3ff,),  # Emoji Modifier Fitzpatri..Emoji Modifier Fitzpatri
+    (0xe0020, 0xe007f,),  # Tag Space               ..Cancel Tag
+    (0xe0100, 0xe01ef,),  # Variation Selector-17   ..Variation Selector-256
+)
+
+ISC_CONSONANT = (
+    # Source: IndicSyllabicCategory
+    # Date: see file
+    #
+    (0x00915, 0x00939,),  # Devanagari Letter Ka    ..Devanagari Letter Ha
+    (0x00958, 0x0095f,),  # Devanagari Letter Qa    ..Devanagari Letter Yya
+    (0x00978, 0x0097f,),  # Devanagari Letter Marwar..Devanagari Letter Bba
+    (0x00995, 0x009a8,),  # Bengali Letter Ka       ..Bengali Letter Na
+    (0x009aa, 0x009b0,),  # Bengali Letter Pa       ..Bengali Letter Ra
+    (0x009b2, 0x009b2,),  # Bengali Letter La
+    (0x009b6, 0x009b9,),  # Bengali Letter Sha      ..Bengali Letter Ha
+    (0x009dc, 0x009dd,),  # Bengali Letter Rra      ..Bengali Letter Rha
+    (0x009df, 0x009df,),  # Bengali Letter Yya
+    (0x009f0, 0x009f1,),  # Bengali Letter Ra With M..Bengali Letter Ra With L
+    (0x00a15, 0x00a28,),  # Gurmukhi Letter Ka      ..Gurmukhi Letter Na
+    (0x00a2a, 0x00a30,),  # Gurmukhi Letter Pa      ..Gurmukhi Letter Ra
+    (0x00a32, 0x00a33,),  # Gurmukhi Letter La      ..Gurmukhi Letter Lla
+    (0x00a35, 0x00a36,),  # Gurmukhi Letter Va      ..Gurmukhi Letter Sha
+    (0x00a38, 0x00a39,),  # Gurmukhi Letter Sa      ..Gurmukhi Letter Ha
+    (0x00a59, 0x00a5c,),  # Gurmukhi Letter Khha    ..Gurmukhi Letter Rra
+    (0x00a5e, 0x00a5e,),  # Gurmukhi Letter Fa
+    (0x00a95, 0x00aa8,),  # Gujarati Letter Ka      ..Gujarati Letter Na
+    (0x00aaa, 0x00ab0,),  # Gujarati Letter Pa      ..Gujarati Letter Ra
+    (0x00ab2, 0x00ab3,),  # Gujarati Letter La      ..Gujarati Letter Lla
+    (0x00ab5, 0x00ab9,),  # Gujarati Letter Va      ..Gujarati Letter Ha
+    (0x00af9, 0x00af9,),  # Gujarati Letter Zha
+    (0x00b15, 0x00b28,),  # Oriya Letter Ka         ..Oriya Letter Na
+    (0x00b2a, 0x00b30,),  # Oriya Letter Pa         ..Oriya Letter Ra
+    (0x00b32, 0x00b33,),  # Oriya Letter La         ..Oriya Letter Lla
+    (0x00b35, 0x00b39,),  # Oriya Letter Va         ..Oriya Letter Ha
+    (0x00b5c, 0x00b5d,),  # Oriya Letter Rra        ..Oriya Letter Rha
+    (0x00b5f, 0x00b5f,),  # Oriya Letter Yya
+    (0x00b71, 0x00b71,),  # Oriya Letter Wa
+    (0x00b95, 0x00b95,),  # Tamil Letter Ka
+    (0x00b99, 0x00b9a,),  # Tamil Letter Nga        ..Tamil Letter Ca
+    (0x00b9c, 0x00b9c,),  # Tamil Letter Ja
+    (0x00b9e, 0x00b9f,),  # Tamil Letter Nya        ..Tamil Letter Tta
+    (0x00ba3, 0x00ba4,),  # Tamil Letter Nna        ..Tamil Letter Ta
+    (0x00ba8, 0x00baa,),  # Tamil Letter Na         ..Tamil Letter Pa
+    (0x00bae, 0x00bb9,),  # Tamil Letter Ma         ..Tamil Letter Ha
+    (0x00c15, 0x00c28,),  # Telugu Letter Ka        ..Telugu Letter Na
+    (0x00c2a, 0x00c39,),  # Telugu Letter Pa        ..Telugu Letter Ha
+    (0x00c58, 0x00c5a,),  # Telugu Letter Tsa       ..Telugu Letter Rrra
+    (0x00c95, 0x00ca8,),  # Kannada Letter Ka       ..Kannada Letter Na
+    (0x00caa, 0x00cb3,),  # Kannada Letter Pa       ..Kannada Letter Lla
+    (0x00cb5, 0x00cb9,),  # Kannada Letter Va       ..Kannada Letter Ha
+    (0x00cde, 0x00cde,),  # Kannada Letter Fa
+    (0x00d15, 0x00d3a,),  # Malayalam Letter Ka     ..Malayalam Letter Ttta
+    (0x00d9a, 0x00db1,),  # Sinhala Letter Alpapraan..Sinhala Letter Dantaja N
+    (0x00db3, 0x00dbb,),  # Sinhala Letter Sanyaka D..Sinhala Letter Rayanna
+    (0x00dbd, 0x00dbd,),  # Sinhala Letter Dantaja Layanna
+    (0x00dc0, 0x00dc6,),  # Sinhala Letter Vayanna  ..Sinhala Letter Fayanna
+    (0x00e01, 0x00e2e,),  # Thai Character Ko Kai   ..Thai Character Ho Nokhuk
+    (0x00e81, 0x00e82,),  # Lao Letter Ko           ..Lao Letter Kho Sung
+    (0x00e84, 0x00e84,),  # Lao Letter Kho Tam
+    (0x00e86, 0x00e8a,),  # Lao Letter Pali Gha     ..Lao Letter So Tam
+    (0x00e8c, 0x00ea3,),  # Lao Letter Pali Jha     ..Lao Letter Lo Ling
+    (0x00ea5, 0x00ea5,),  # Lao Letter Lo Loot
+    (0x00ea7, 0x00eae,),  # Lao Letter Wo           ..Lao Letter Ho Tam
+    (0x00edc, 0x00edf,),  # Lao Ho No               ..Lao Letter Khmu Nyo
+    (0x00f40, 0x00f47,),  # Tibetan Letter Ka       ..Tibetan Letter Ja
+    (0x00f49, 0x00f6c,),  # Tibetan Letter Nya      ..Tibetan Letter Rra
+    (0x01000, 0x01020,),  # Myanmar Letter Ka       ..Myanmar Letter Lla
+    (0x0103f, 0x0103f,),  # Myanmar Letter Great Sa
+    (0x01050, 0x01051,),  # Myanmar Letter Sha      ..Myanmar Letter Ssa
+    (0x0105a, 0x0105d,),  # Myanmar Letter Mon Nga  ..Myanmar Letter Mon Bbe
+    (0x01061, 0x01061,),  # Myanmar Letter Sgaw Karen Sha
+    (0x01065, 0x01066,),  # Myanmar Letter Western P..Myanmar Letter Western P
+    (0x0106e, 0x01070,),  # Myanmar Letter Eastern P..Myanmar Letter Eastern P
+    (0x01075, 0x01081,),  # Myanmar Letter Shan Ka  ..Myanmar Letter Shan Ha
+    (0x0108e, 0x0108e,),  # Myanmar Letter Rumai Palaung Fa
+    (0x01703, 0x01711,),  # Tagalog Letter Ka       ..Tagalog Letter Ha
+    (0x0171f, 0x0171f,),  # Tagalog Letter Archaic Ra
+    (0x01723, 0x01731,),  # Hanunoo Letter Ka       ..Hanunoo Letter Ha
+    (0x01743, 0x01751,),  # Buhid Letter Ka         ..Buhid Letter Ha
+    (0x01763, 0x0176c,),  # Tagbanwa Letter Ka      ..Tagbanwa Letter Ya
+    (0x0176e, 0x01770,),  # Tagbanwa Letter La      ..Tagbanwa Letter Sa
+    (0x01780, 0x017a2,),  # Khmer Letter Ka         ..Khmer Letter Qa
+    (0x01900, 0x0191e,),  # Limbu Vowel-carrier Lett..Limbu Letter Tra
+    (0x01950, 0x01962,),  # Tai Le Letter Ka        ..Tai Le Letter Na
+    (0x01980, 0x019ab,),  # New Tai Lue Letter High ..New Tai Lue Letter Low S
+    (0x01a00, 0x01a16,),  # Buginese Letter Ka      ..Buginese Letter Ha
+    (0x01a20, 0x01a4c,),  # Tai Tham Letter High Ka ..Tai Tham Letter Low Ha
+    (0x01a53, 0x01a54,),  # Tai Tham Letter Lae     ..Tai Tham Letter Great Sa
+    (0x01b13, 0x01b33,),  # Balinese Letter Ka      ..Balinese Letter Ha
+    (0x01b45, 0x01b4c,),  # Balinese Letter Kaf Sasa..Balinese Letter Archaic
+    (0x01b8a, 0x01ba0,),  # Sundanese Letter Ka     ..Sundanese Letter Ha
+    (0x01bae, 0x01baf,),  # Sundanese Letter Kha    ..Sundanese Letter Sya
+    (0x01bbb, 0x01bbd,),  # Sundanese Letter Reu    ..Sundanese Letter Bha
+    (0x01bc0, 0x01be3,),  # Batak Letter A          ..Batak Letter Mba
+    (0x01c00, 0x01c23,),  # Lepcha Letter Ka        ..Lepcha Letter A
+    (0x01c4d, 0x01c4f,),  # Lepcha Letter Tta       ..Lepcha Letter Dda
+    (0x0a807, 0x0a80a,),  # Syloti Nagri Letter Ko  ..Syloti Nagri Letter Gho
+    (0x0a80c, 0x0a822,),  # Syloti Nagri Letter Co  ..Syloti Nagri Letter Ho
+    (0x0a840, 0x0a85d,),  # Phags-pa Letter Ka      ..Phags-pa Letter A
+    (0x0a862, 0x0a865,),  # Phags-pa Letter Qa      ..Phags-pa Letter Gga
+    (0x0a869, 0x0a870,),  # Phags-pa Letter Tta     ..Phags-pa Letter Aspirate
+    (0x0a872, 0x0a872,),  # Phags-pa Superfixed Letter Ra
+    (0x0a892, 0x0a8b3,),  # Saurashtra Letter Ka    ..Saurashtra Letter Lla
+    (0x0a90a, 0x0a921,),  # Kayah Li Letter Ka      ..Kayah Li Letter Ca
+    (0x0a930, 0x0a946,),  # Rejang Letter Ka        ..Rejang Letter A
+    (0x0a989, 0x0a98b,),  # Javanese Letter Pa Cerek..Javanese Letter Nga Lele
+    (0x0a98f, 0x0a9b2,),  # Javanese Letter Ka      ..Javanese Letter Ha
+    (0x0a9e0, 0x0a9e4,),  # Myanmar Letter Shan Gha ..Myanmar Letter Shan Bha
+    (0x0a9e7, 0x0a9ef,),  # Myanmar Letter Tai Laing..Myanmar Letter Tai Laing
+    (0x0a9fa, 0x0a9fe,),  # Myanmar Letter Tai Laing..Myanmar Letter Tai Laing
+    (0x0aa06, 0x0aa28,),  # Cham Letter Ka          ..Cham Letter Ha
+    (0x0aa60, 0x0aa6f,),  # Myanmar Letter Khamti Ga..Myanmar Letter Khamti Fa
+    (0x0aa71, 0x0aa73,),  # Myanmar Letter Khamti Xa..Myanmar Letter Khamti Ra
+    (0x0aa7a, 0x0aa7a,),  # Myanmar Letter Aiton Ra
+    (0x0aa7e, 0x0aaaf,),  # Myanmar Letter Shwe Pala..Tai Viet Letter High O
+    (0x0aae2, 0x0aaea,),  # Meetei Mayek Letter Cha ..Meetei Mayek Letter Ssa
+    (0x0abc0, 0x0abcd,),  # Meetei Mayek Letter Kok ..Meetei Mayek Letter Huk
+    (0x0abd0, 0x0abd0,),  # Meetei Mayek Letter Pham
+    (0x0abd2, 0x0abda,),  # Meetei Mayek Letter Gok ..Meetei Mayek Letter Bham
+    (0x10a00, 0x10a00,),  # Kharoshthi Letter A
+    (0x10a10, 0x10a13,),  # Kharoshthi Letter Ka    ..Kharoshthi Letter Gha
+    (0x10a15, 0x10a17,),  # Kharoshthi Letter Ca    ..Kharoshthi Letter Ja
+    (0x10a19, 0x10a35,),  # Kharoshthi Letter Nya   ..Kharoshthi Letter Vha
+    (0x11013, 0x11037,),  # Brahmi Letter Ka        ..Brahmi Letter Old Tamil
+    (0x11075, 0x11075,),  # Brahmi Letter Old Tamil Lla
+    (0x1108d, 0x110af,),  # Kaithi Letter Ka        ..Kaithi Letter Ha
+    (0x11107, 0x11126,),  # Chakma Letter Kaa       ..Chakma Letter Haa
+    (0x11144, 0x11144,),  # Chakma Letter Lhaa
+    (0x11147, 0x11147,),  # Chakma Letter Vaa
+    (0x11155, 0x11172,),  # Mahajani Letter Ka      ..Mahajani Letter Rra
+    (0x11191, 0x111b2,),  # Sharada Letter Ka       ..Sharada Letter Ha
+    (0x11208, 0x11211,),  # Khojki Letter Ka        ..Khojki Letter Jja
+    (0x11213, 0x1122b,),  # Khojki Letter Nya       ..Khojki Letter Lla
+    (0x1123f, 0x1123f,),  # Khojki Letter Qa
+    (0x11284, 0x11286,),  # Multani Letter Ka       ..Multani Letter Ga
+    (0x11288, 0x11288,),  # Multani Letter Gha
+    (0x1128a, 0x1128d,),  # Multani Letter Ca       ..Multani Letter Jja
+    (0x1128f, 0x1129d,),  # Multani Letter Nya      ..Multani Letter Ba
+    (0x1129f, 0x112a8,),  # Multani Letter Bha      ..Multani Letter Rha
+    (0x112ba, 0x112de,),  # Khudawadi Letter Ka     ..Khudawadi Letter Ha
+    (0x11315, 0x11328,),  # Grantha Letter Ka       ..Grantha Letter Na
+    (0x1132a, 0x11330,),  # Grantha Letter Pa       ..Grantha Letter Ra
+    (0x11332, 0x11333,),  # Grantha Letter La       ..Grantha Letter Lla
+    (0x11335, 0x11339,),  # Grantha Letter Va       ..Grantha Letter Ha
+    (0x11392, 0x113b5,),  # Tulu-tigalari Letter Ka ..Tulu-tigalari Letter Lll
+    (0x1140e, 0x11434,),  # Newa Letter Ka          ..Newa Letter Ha
+    (0x1148f, 0x114af,),  # Tirhuta Letter Ka       ..Tirhuta Letter Ha
+    (0x1158e, 0x115ae,),  # Siddham Letter Ka       ..Siddham Letter Ha
+    (0x1160e, 0x1162f,),  # Modi Letter Ka          ..Modi Letter Lla
+    (0x1168a, 0x116aa,),  # Takri Letter Ka         ..Takri Letter Rra
+    (0x116b8, 0x116b8,),  # Takri Letter Archaic Kha
+    (0x11700, 0x1171a,),  # Ahom Letter Ka          ..Ahom Letter Alternate Ba
+    (0x11740, 0x11746,),  # Ahom Letter Ca          ..Ahom Letter Lla
+    (0x1180a, 0x1182b,),  # Dogra Letter Ka         ..Dogra Letter Rra
+    (0x1190c, 0x11913,),  # Dives Akuru Letter Ka   ..Dives Akuru Letter Ja
+    (0x11915, 0x11916,),  # Dives Akuru Letter Nya  ..Dives Akuru Letter Tta
+    (0x11918, 0x1192f,),  # Dives Akuru Letter Dda  ..Dives Akuru Letter Za
+    (0x119ae, 0x119d0,),  # Nandinagari Letter Ka   ..Nandinagari Letter Rra
+    (0x11a00, 0x11a00,),  # Zanabazar Square Letter A
+    (0x11a0b, 0x11a32,),  # Zanabazar Square Letter ..Zanabazar Square Letter
+    (0x11a50, 0x11a50,),  # Soyombo Letter A
+    (0x11a5c, 0x11a83,),  # Soyombo Letter Ka       ..Soyombo Letter Kssa
+    (0x11c0e, 0x11c2e,),  # Bhaiksuki Letter Ka     ..Bhaiksuki Letter Ha
+    (0x11c72, 0x11c8f,),  # Marchen Letter Ka       ..Marchen Letter A
+    (0x11d0c, 0x11d30,),  # Masaram Gondi Letter Ka ..Masaram Gondi Letter Tra
+    (0x11d6c, 0x11d89,),  # Gunjala Gondi Letter Ya ..Gunjala Gondi Letter Sa
+    (0x11ee0, 0x11ef1,),  # Makasar Letter Ka       ..Makasar Letter A
+    (0x11f12, 0x11f33,),  # Kawi Letter Ka          ..Kawi Letter Jnya
+    (0x16101, 0x1611d,),  # Gurung Khema Letter Ka  ..Gurung Khema Letter Sa
+    (0x16d43, 0x16d62,),  # Kirat Rai Letter A      ..Kirat Rai Letter Ha
+)
diff --git a/lib/python3.12/site-packages/wcwidth/table_mc.py b/lib/python3.12/site-packages/wcwidth/table_mc.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c2e6915920591c902f60311c0893bd0f92ea632
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/table_mc.py
@@ -0,0 +1,206 @@
+"""
+Exports CATEGORY_MC table keyed by supporting unicode version level.
+
+This code generated by wcwidth/bin/update-tables.py on 2026-01-29 00:47:54 UTC.
+"""
+# pylint: disable=duplicate-code
+CATEGORY_MC = {
+    '17.0.0': (
+        # Source: DerivedGeneralCategory-17.0.0.txt
+        # Date: 2025-07-24, 00:12:50 GMT
+        #
+        (0x00903, 0x00903,),  # Devanagari Sign Visarga
+        (0x0093b, 0x0093b,),  # Devanagari Vowel Sign Ooe
+        (0x0093e, 0x00940,),  # Devanagari Vowel Sign Aa..Devanagari Vowel Sign Ii
+        (0x00949, 0x0094c,),  # Devanagari Vowel Sign Ca..Devanagari Vowel Sign Au
+        (0x0094e, 0x0094f,),  # Devanagari Vowel Sign Pr..Devanagari Vowel Sign Aw
+        (0x00982, 0x00983,),  # Bengali Sign Anusvara   ..Bengali Sign Visarga
+        (0x009be, 0x009c0,),  # Bengali Vowel Sign Aa   ..Bengali Vowel Sign Ii
+        (0x009c7, 0x009c8,),  # Bengali Vowel Sign E    ..Bengali Vowel Sign Ai
+        (0x009cb, 0x009cc,),  # Bengali Vowel Sign O    ..Bengali Vowel Sign Au
+        (0x009d7, 0x009d7,),  # Bengali Au Length Mark
+        (0x00a03, 0x00a03,),  # Gurmukhi Sign Visarga
+        (0x00a3e, 0x00a40,),  # Gurmukhi Vowel Sign Aa  ..Gurmukhi Vowel Sign Ii
+        (0x00a83, 0x00a83,),  # Gujarati Sign Visarga
+        (0x00abe, 0x00ac0,),  # Gujarati Vowel Sign Aa  ..Gujarati Vowel Sign Ii
+        (0x00ac9, 0x00ac9,),  # Gujarati Vowel Sign Candra O
+        (0x00acb, 0x00acc,),  # Gujarati Vowel Sign O   ..Gujarati Vowel Sign Au
+        (0x00b02, 0x00b03,),  # Oriya Sign Anusvara     ..Oriya Sign Visarga
+        (0x00b3e, 0x00b3e,),  # Oriya Vowel Sign Aa
+        (0x00b40, 0x00b40,),  # Oriya Vowel Sign Ii
+        (0x00b47, 0x00b48,),  # Oriya Vowel Sign E      ..Oriya Vowel Sign Ai
+        (0x00b4b, 0x00b4c,),  # Oriya Vowel Sign O      ..Oriya Vowel Sign Au
+        (0x00b57, 0x00b57,),  # Oriya Au Length Mark
+        (0x00bbe, 0x00bbf,),  # Tamil Vowel Sign Aa     ..Tamil Vowel Sign I
+        (0x00bc1, 0x00bc2,),  # Tamil Vowel Sign U      ..Tamil Vowel Sign Uu
+        (0x00bc6, 0x00bc8,),  # Tamil Vowel Sign E      ..Tamil Vowel Sign Ai
+        (0x00bca, 0x00bcc,),  # Tamil Vowel Sign O      ..Tamil Vowel Sign Au
+        (0x00bd7, 0x00bd7,),  # Tamil Au Length Mark
+        (0x00c01, 0x00c03,),  # Telugu Sign Candrabindu ..Telugu Sign Visarga
+        (0x00c41, 0x00c44,),  # Telugu Vowel Sign U     ..Telugu Vowel Sign Vocali
+        (0x00c82, 0x00c83,),  # Kannada Sign Anusvara   ..Kannada Sign Visarga
+        (0x00cbe, 0x00cbe,),  # Kannada Vowel Sign Aa
+        (0x00cc0, 0x00cc4,),  # Kannada Vowel Sign Ii   ..Kannada Vowel Sign Vocal
+        (0x00cc7, 0x00cc8,),  # Kannada Vowel Sign Ee   ..Kannada Vowel Sign Ai
+        (0x00cca, 0x00ccb,),  # Kannada Vowel Sign O    ..Kannada Vowel Sign Oo
+        (0x00cd5, 0x00cd6,),  # Kannada Length Mark     ..Kannada Ai Length Mark
+        (0x00cf3, 0x00cf3,),  # Kannada Sign Combining Anusvara Above Right
+        (0x00d02, 0x00d03,),  # Malayalam Sign Anusvara ..Malayalam Sign Visarga
+        (0x00d3e, 0x00d40,),  # Malayalam Vowel Sign Aa ..Malayalam Vowel Sign Ii
+        (0x00d46, 0x00d48,),  # Malayalam Vowel Sign E  ..Malayalam Vowel Sign Ai
+        (0x00d4a, 0x00d4c,),  # Malayalam Vowel Sign O  ..Malayalam Vowel Sign Au
+        (0x00d57, 0x00d57,),  # Malayalam Au Length Mark
+        (0x00d82, 0x00d83,),  # Sinhala Sign Anusvaraya ..Sinhala Sign Visargaya
+        (0x00dcf, 0x00dd1,),  # Sinhala Vowel Sign Aela-..Sinhala Vowel Sign Diga
+        (0x00dd8, 0x00ddf,),  # Sinhala Vowel Sign Gaett..Sinhala Vowel Sign Gayan
+        (0x00df2, 0x00df3,),  # Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga
+        (0x00f3e, 0x00f3f,),  # Tibetan Sign Yar Tshes  ..Tibetan Sign Mar Tshes
+        (0x00f7f, 0x00f7f,),  # Tibetan Sign Rnam Bcad
+        (0x0102b, 0x0102c,),  # Myanmar Vowel Sign Tall ..Myanmar Vowel Sign Aa
+        (0x01031, 0x01031,),  # Myanmar Vowel Sign E
+        (0x01038, 0x01038,),  # Myanmar Sign Visarga
+        (0x0103b, 0x0103c,),  # Myanmar Consonant Sign M..Myanmar Consonant Sign M
+        (0x01056, 0x01057,),  # Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal
+        (0x01062, 0x01064,),  # Myanmar Vowel Sign Sgaw ..Myanmar Tone Mark Sgaw K
+        (0x01067, 0x0106d,),  # Myanmar Vowel Sign Weste..Myanmar Sign Western Pwo
+        (0x01083, 0x01084,),  # Myanmar Vowel Sign Shan ..Myanmar Vowel Sign Shan
+        (0x01087, 0x0108c,),  # Myanmar Sign Shan Tone-2..Myanmar Sign Shan Counci
+        (0x0108f, 0x0108f,),  # Myanmar Sign Rumai Palaung Tone-5
+        (0x0109a, 0x0109c,),  # Myanmar Sign Khamti Tone..Myanmar Vowel Sign Aiton
+        (0x01715, 0x01715,),  # Tagalog Sign Pamudpod
+        (0x01734, 0x01734,),  # Hanunoo Sign Pamudpod
+        (0x017b6, 0x017b6,),  # Khmer Vowel Sign Aa
+        (0x017be, 0x017c5,),  # Khmer Vowel Sign Oe     ..Khmer Vowel Sign Au
+        (0x017c7, 0x017c8,),  # Khmer Sign Reahmuk      ..Khmer Sign Yuukaleapintu
+        (0x01923, 0x01926,),  # Limbu Vowel Sign Ee     ..Limbu Vowel Sign Au
+        (0x01929, 0x0192b,),  # Limbu Subjoined Letter Y..Limbu Subjoined Letter W
+        (0x01930, 0x01931,),  # Limbu Small Letter Ka   ..Limbu Small Letter Nga
+        (0x01933, 0x01938,),  # Limbu Small Letter Ta   ..Limbu Small Letter La
+        (0x01a19, 0x01a1a,),  # Buginese Vowel Sign E   ..Buginese Vowel Sign O
+        (0x01a55, 0x01a55,),  # Tai Tham Consonant Sign Medial Ra
+        (0x01a57, 0x01a57,),  # Tai Tham Consonant Sign La Tang Lai
+        (0x01a61, 0x01a61,),  # Tai Tham Vowel Sign A
+        (0x01a63, 0x01a64,),  # Tai Tham Vowel Sign Aa  ..Tai Tham Vowel Sign Tall
+        (0x01a6d, 0x01a72,),  # Tai Tham Vowel Sign Oy  ..Tai Tham Vowel Sign Tham
+        (0x01b04, 0x01b04,),  # Balinese Sign Bisah
+        (0x01b35, 0x01b35,),  # Balinese Vowel Sign Tedung
+        (0x01b3b, 0x01b3b,),  # Balinese Vowel Sign Ra Repa Tedung
+        (0x01b3d, 0x01b41,),  # Balinese Vowel Sign La L..Balinese Vowel Sign Tali
+        (0x01b43, 0x01b44,),  # Balinese Vowel Sign Pepe..Balinese Adeg Adeg
+        (0x01b82, 0x01b82,),  # Sundanese Sign Pangwisad
+        (0x01ba1, 0x01ba1,),  # Sundanese Consonant Sign Pamingkal
+        (0x01ba6, 0x01ba7,),  # Sundanese Vowel Sign Pan..Sundanese Vowel Sign Pan
+        (0x01baa, 0x01baa,),  # Sundanese Sign Pamaaeh
+        (0x01be7, 0x01be7,),  # Batak Vowel Sign E
+        (0x01bea, 0x01bec,),  # Batak Vowel Sign I      ..Batak Vowel Sign O
+        (0x01bee, 0x01bee,),  # Batak Vowel Sign U
+        (0x01bf2, 0x01bf3,),  # Batak Pangolat          ..Batak Panongonan
+        (0x01c24, 0x01c2b,),  # Lepcha Subjoined Letter ..Lepcha Vowel Sign Uu
+        (0x01c34, 0x01c35,),  # Lepcha Consonant Sign Ny..Lepcha Consonant Sign Ka
+        (0x01ce1, 0x01ce1,),  # Vedic Tone Atharvavedic Independent Svarita
+        (0x01cf7, 0x01cf7,),  # Vedic Sign Atikrama
+        (0x0302e, 0x0302f,),  # Hangul Single Dot Tone M..Hangul Double Dot Tone M
+        (0x0a823, 0x0a824,),  # Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign
+        (0x0a827, 0x0a827,),  # Syloti Nagri Vowel Sign Oo
+        (0x0a880, 0x0a881,),  # Saurashtra Sign Anusvara..Saurashtra Sign Visarga
+        (0x0a8b4, 0x0a8c3,),  # Saurashtra Consonant Sig..Saurashtra Vowel Sign Au
+        (0x0a952, 0x0a953,),  # Rejang Consonant Sign H ..Rejang Virama
+        (0x0a983, 0x0a983,),  # Javanese Sign Wignyan
+        (0x0a9b4, 0x0a9b5,),  # Javanese Vowel Sign Taru..Javanese Vowel Sign Tolo
+        (0x0a9ba, 0x0a9bb,),  # Javanese Vowel Sign Tali..Javanese Vowel Sign Dirg
+        (0x0a9be, 0x0a9c0,),  # Javanese Consonant Sign ..Javanese Pangkon
+        (0x0aa2f, 0x0aa30,),  # Cham Vowel Sign O       ..Cham Vowel Sign Ai
+        (0x0aa33, 0x0aa34,),  # Cham Consonant Sign Ya  ..Cham Consonant Sign Ra
+        (0x0aa4d, 0x0aa4d,),  # Cham Consonant Sign Final H
+        (0x0aa7b, 0x0aa7b,),  # Myanmar Sign Pao Karen Tone
+        (0x0aa7d, 0x0aa7d,),  # Myanmar Sign Tai Laing Tone-5
+        (0x0aaeb, 0x0aaeb,),  # Meetei Mayek Vowel Sign Ii
+        (0x0aaee, 0x0aaef,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+        (0x0aaf5, 0x0aaf5,),  # Meetei Mayek Vowel Sign Visarga
+        (0x0abe3, 0x0abe4,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+        (0x0abe6, 0x0abe7,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+        (0x0abe9, 0x0abea,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+        (0x0abec, 0x0abec,),  # Meetei Mayek Lum Iyek
+        (0x11000, 0x11000,),  # Brahmi Sign Candrabindu
+        (0x11002, 0x11002,),  # Brahmi Sign Visarga
+        (0x11082, 0x11082,),  # Kaithi Sign Visarga
+        (0x110b0, 0x110b2,),  # Kaithi Vowel Sign Aa    ..Kaithi Vowel Sign Ii
+        (0x110b7, 0x110b8,),  # Kaithi Vowel Sign O     ..Kaithi Vowel Sign Au
+        (0x1112c, 0x1112c,),  # Chakma Vowel Sign E
+        (0x11145, 0x11146,),  # Chakma Vowel Sign Aa    ..Chakma Vowel Sign Ei
+        (0x11182, 0x11182,),  # Sharada Sign Visarga
+        (0x111b3, 0x111b5,),  # Sharada Vowel Sign Aa   ..Sharada Vowel Sign Ii
+        (0x111bf, 0x111c0,),  # Sharada Vowel Sign Au   ..Sharada Sign Virama
+        (0x111ce, 0x111ce,),  # Sharada Vowel Sign Prishthamatra E
+        (0x1122c, 0x1122e,),  # Khojki Vowel Sign Aa    ..Khojki Vowel Sign Ii
+        (0x11232, 0x11233,),  # Khojki Vowel Sign O     ..Khojki Vowel Sign Au
+        (0x11235, 0x11235,),  # Khojki Sign Virama
+        (0x112e0, 0x112e2,),  # Khudawadi Vowel Sign Aa ..Khudawadi Vowel Sign Ii
+        (0x11302, 0x11303,),  # Grantha Sign Anusvara   ..Grantha Sign Visarga
+        (0x1133e, 0x1133f,),  # Grantha Vowel Sign Aa   ..Grantha Vowel Sign I
+        (0x11341, 0x11344,),  # Grantha Vowel Sign U    ..Grantha Vowel Sign Vocal
+        (0x11347, 0x11348,),  # Grantha Vowel Sign Ee   ..Grantha Vowel Sign Ai
+        (0x1134b, 0x1134d,),  # Grantha Vowel Sign Oo   ..Grantha Sign Virama
+        (0x11357, 0x11357,),  # Grantha Au Length Mark
+        (0x11362, 0x11363,),  # Grantha Vowel Sign Vocal..Grantha Vowel Sign Vocal
+        (0x113b8, 0x113ba,),  # Tulu-tigalari Vowel Sign..Tulu-tigalari Vowel Sign
+        (0x113c2, 0x113c2,),  # Tulu-tigalari Vowel Sign Ee
+        (0x113c5, 0x113c5,),  # Tulu-tigalari Vowel Sign Ai
+        (0x113c7, 0x113ca,),  # Tulu-tigalari Vowel Sign..Tulu-tigalari Sign Candr
+        (0x113cc, 0x113cd,),  # Tulu-tigalari Sign Anusv..Tulu-tigalari Sign Visar
+        (0x113cf, 0x113cf,),  # Tulu-tigalari Sign Looped Virama
+        (0x11435, 0x11437,),  # Newa Vowel Sign Aa      ..Newa Vowel Sign Ii
+        (0x11440, 0x11441,),  # Newa Vowel Sign O       ..Newa Vowel Sign Au
+        (0x11445, 0x11445,),  # Newa Sign Visarga
+        (0x114b0, 0x114b2,),  # Tirhuta Vowel Sign Aa   ..Tirhuta Vowel Sign Ii
+        (0x114b9, 0x114b9,),  # Tirhuta Vowel Sign E
+        (0x114bb, 0x114be,),  # Tirhuta Vowel Sign Ai   ..Tirhuta Vowel Sign Au
+        (0x114c1, 0x114c1,),  # Tirhuta Sign Visarga
+        (0x115af, 0x115b1,),  # Siddham Vowel Sign Aa   ..Siddham Vowel Sign Ii
+        (0x115b8, 0x115bb,),  # Siddham Vowel Sign E    ..Siddham Vowel Sign Au
+        (0x115be, 0x115be,),  # Siddham Sign Visarga
+        (0x11630, 0x11632,),  # Modi Vowel Sign Aa      ..Modi Vowel Sign Ii
+        (0x1163b, 0x1163c,),  # Modi Vowel Sign O       ..Modi Vowel Sign Au
+        (0x1163e, 0x1163e,),  # Modi Sign Visarga
+        (0x116ac, 0x116ac,),  # Takri Sign Visarga
+        (0x116ae, 0x116af,),  # Takri Vowel Sign I      ..Takri Vowel Sign Ii
+        (0x116b6, 0x116b6,),  # Takri Sign Virama
+        (0x1171e, 0x1171e,),  # Ahom Consonant Sign Medial Ra
+        (0x11720, 0x11721,),  # Ahom Vowel Sign A       ..Ahom Vowel Sign Aa
+        (0x11726, 0x11726,),  # Ahom Vowel Sign E
+        (0x1182c, 0x1182e,),  # Dogra Vowel Sign Aa     ..Dogra Vowel Sign Ii
+        (0x11838, 0x11838,),  # Dogra Sign Visarga
+        (0x11930, 0x11935,),  # Dives Akuru Vowel Sign A..Dives Akuru Vowel Sign E
+        (0x11937, 0x11938,),  # Dives Akuru Vowel Sign A..Dives Akuru Vowel Sign O
+        (0x1193d, 0x1193d,),  # Dives Akuru Sign Halanta
+        (0x11940, 0x11940,),  # Dives Akuru Medial Ya
+        (0x11942, 0x11942,),  # Dives Akuru Medial Ra
+        (0x119d1, 0x119d3,),  # Nandinagari Vowel Sign A..Nandinagari Vowel Sign I
+        (0x119dc, 0x119df,),  # Nandinagari Vowel Sign O..Nandinagari Sign Visarga
+        (0x119e4, 0x119e4,),  # Nandinagari Vowel Sign Prishthamatra E
+        (0x11a39, 0x11a39,),  # Zanabazar Square Sign Visarga
+        (0x11a57, 0x11a58,),  # Soyombo Vowel Sign Ai   ..Soyombo Vowel Sign Au
+        (0x11a97, 0x11a97,),  # Soyombo Sign Visarga
+        (0x11b61, 0x11b61,),  # Sharada Vowel Sign Ooe
+        (0x11b65, 0x11b65,),  # Sharada Vowel Sign Short O
+        (0x11b67, 0x11b67,),  # Sharada Vowel Sign Candra O
+        (0x11c2f, 0x11c2f,),  # Bhaiksuki Vowel Sign Aa
+        (0x11c3e, 0x11c3e,),  # Bhaiksuki Sign Visarga
+        (0x11ca9, 0x11ca9,),  # Marchen Subjoined Letter Ya
+        (0x11cb1, 0x11cb1,),  # Marchen Vowel Sign I
+        (0x11cb4, 0x11cb4,),  # Marchen Vowel Sign O
+        (0x11d8a, 0x11d8e,),  # Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign
+        (0x11d93, 0x11d94,),  # Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign
+        (0x11d96, 0x11d96,),  # Gunjala Gondi Sign Visarga
+        (0x11ef5, 0x11ef6,),  # Makasar Vowel Sign E    ..Makasar Vowel Sign O
+        (0x11f03, 0x11f03,),  # Kawi Sign Visarga
+        (0x11f34, 0x11f35,),  # Kawi Vowel Sign Aa      ..Kawi Vowel Sign Alternat
+        (0x11f3e, 0x11f3f,),  # Kawi Vowel Sign E       ..Kawi Vowel Sign Ai
+        (0x11f41, 0x11f41,),  # Kawi Sign Killer
+        (0x1612a, 0x1612c,),  # Gurung Khema Consonant S..Gurung Khema Consonant S
+        (0x16f51, 0x16f87,),  # Miao Sign Aspiration    ..Miao Vowel Sign Ui
+        (0x16ff0, 0x16ff1,),  # Vietnamese Alternate Rea..Vietnamese Alternate Rea
+        (0x1d165, 0x1d166,),  # Musical Symbol Combining..Musical Symbol Combining
+        (0x1d16d, 0x1d172,),  # Musical Symbol Combining..Musical Symbol Combining
+    ),
+}
diff --git a/lib/python3.12/site-packages/wcwidth/table_vs16.py b/lib/python3.12/site-packages/wcwidth/table_vs16.py
new file mode 100644
index 0000000000000000000000000000000000000000..70e4a7373ff6bbc8bdcaa002b3d2f0bf855dd0f6
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/table_vs16.py
@@ -0,0 +1,126 @@
+"""
+Exports VS16_NARROW_TO_WIDE table keyed by supporting unicode version level.
+
+This code generated by wcwidth/bin/update-tables.py on 2025-09-15 16:57:50 UTC.
+"""
+# pylint: disable=duplicate-code
+VS16_NARROW_TO_WIDE = {
+    '9.0.0': (
+        # Source: 9.0.0
+        # Date: 2025-01-30, 21:48:29 GMT
+        #
+        (0x00023, 0x00023,),  # Number Sign
+        (0x0002a, 0x0002a,),  # Asterisk
+        (0x00030, 0x00039,),  # Digit Zero              ..Digit Nine
+        (0x000a9, 0x000a9,),  # Copyright Sign
+        (0x000ae, 0x000ae,),  # Registered Sign
+        (0x0203c, 0x0203c,),  # Double Exclamation Mark
+        (0x02049, 0x02049,),  # Exclamation Question Mark
+        (0x02122, 0x02122,),  # Trade Mark Sign
+        (0x02139, 0x02139,),  # Information Source
+        (0x02194, 0x02199,),  # Left Right Arrow        ..South West Arrow
+        (0x021a9, 0x021aa,),  # Leftwards Arrow With Hoo..Rightwards Arrow With Ho
+        (0x02328, 0x02328,),  # Keyboard
+        (0x023cf, 0x023cf,),  # Eject Symbol
+        (0x023ed, 0x023ef,),  # Black Right-pointing Dou..Black Right-pointing Tri
+        (0x023f1, 0x023f2,),  # Stopwatch               ..Timer Clock
+        (0x023f8, 0x023fa,),  # Double Vertical Bar     ..Black Circle For Record
+        (0x024c2, 0x024c2,),  # Circled Latin Capital Letter M
+        (0x025aa, 0x025ab,),  # Black Small Square      ..White Small Square
+        (0x025b6, 0x025b6,),  # Black Right-pointing Triangle
+        (0x025c0, 0x025c0,),  # Black Left-pointing Triangle
+        (0x025fb, 0x025fc,),  # White Medium Square     ..Black Medium Square
+        (0x02600, 0x02604,),  # Black Sun With Rays     ..Comet
+        (0x0260e, 0x0260e,),  # Black Telephone
+        (0x02611, 0x02611,),  # Ballot Box With Check
+        (0x02618, 0x02618,),  # Shamrock
+        (0x0261d, 0x0261d,),  # White Up Pointing Index
+        (0x02620, 0x02620,),  # Skull And Crossbones
+        (0x02622, 0x02623,),  # Radioactive Sign        ..Biohazard Sign
+        (0x02626, 0x02626,),  # Orthodox Cross
+        (0x0262a, 0x0262a,),  # Star And Crescent
+        (0x0262e, 0x0262f,),  # Peace Symbol            ..Yin Yang
+        (0x02638, 0x0263a,),  # Wheel Of Dharma         ..White Smiling Face
+        (0x02640, 0x02640,),  # Female Sign
+        (0x02642, 0x02642,),  # Male Sign
+        (0x0265f, 0x02660,),  # Black Chess Pawn        ..Black Spade Suit
+        (0x02663, 0x02663,),  # Black Club Suit
+        (0x02665, 0x02666,),  # Black Heart Suit        ..Black Diamond Suit
+        (0x02668, 0x02668,),  # Hot Springs
+        (0x0267b, 0x0267b,),  # Black Universal Recycling Symbol
+        (0x0267e, 0x0267e,),  # Permanent Paper Sign
+        (0x02692, 0x02692,),  # Hammer And Pick
+        (0x02694, 0x02697,),  # Crossed Swords          ..Alembic
+        (0x02699, 0x02699,),  # Gear
+        (0x0269b, 0x0269c,),  # Atom Symbol             ..Fleur-de-lis
+        (0x026a0, 0x026a0,),  # Warning Sign
+        (0x026a7, 0x026a7,),  # Male With Stroke And Male And Female Sign
+        (0x026b0, 0x026b1,),  # Coffin                  ..Funeral Urn
+        (0x026c8, 0x026c8,),  # Thunder Cloud And Rain
+        (0x026cf, 0x026cf,),  # Pick
+        (0x026d1, 0x026d1,),  # Helmet With White Cross
+        (0x026d3, 0x026d3,),  # Chains
+        (0x026e9, 0x026e9,),  # Shinto Shrine
+        (0x026f0, 0x026f1,),  # Mountain                ..Umbrella On Ground
+        (0x026f4, 0x026f4,),  # Ferry
+        (0x026f7, 0x026f9,),  # Skier                   ..Person With Ball
+        (0x02702, 0x02702,),  # Black Scissors
+        (0x02708, 0x02709,),  # Airplane                ..Envelope
+        (0x0270c, 0x0270d,),  # Victory Hand            ..Writing Hand
+        (0x0270f, 0x0270f,),  # Pencil
+        (0x02712, 0x02712,),  # Black Nib
+        (0x02714, 0x02714,),  # Heavy Check Mark
+        (0x02716, 0x02716,),  # Heavy Multiplication X
+        (0x0271d, 0x0271d,),  # Latin Cross
+        (0x02721, 0x02721,),  # Star Of David
+        (0x02733, 0x02734,),  # Eight Spoked Asterisk   ..Eight Pointed Black Star
+        (0x02744, 0x02744,),  # Snowflake
+        (0x02747, 0x02747,),  # Sparkle
+        (0x02763, 0x02764,),  # Heavy Heart Exclamation ..Heavy Black Heart
+        (0x027a1, 0x027a1,),  # Black Rightwards Arrow
+        (0x02934, 0x02935,),  # Arrow Pointing Rightward..Arrow Pointing Rightward
+        (0x02b05, 0x02b07,),  # Leftwards Black Arrow   ..Downwards Black Arrow
+        (0x1f170, 0x1f171,),  # Negative Squared Latin C..Negative Squared Latin C
+        (0x1f17e, 0x1f17f,),  # Negative Squared Latin C..Negative Squared Latin C
+        (0x1f321, 0x1f321,),  # Thermometer
+        (0x1f324, 0x1f32c,),  # White Sun With Small Clo..Wind Blowing Face
+        (0x1f336, 0x1f336,),  # Hot Pepper
+        (0x1f37d, 0x1f37d,),  # Fork And Knife With Plate
+        (0x1f396, 0x1f397,),  # Military Medal          ..Reminder Ribbon
+        (0x1f399, 0x1f39b,),  # Studio Microphone       ..Control Knobs
+        (0x1f39e, 0x1f39f,),  # Film Frames             ..Admission Tickets
+        (0x1f3cb, 0x1f3ce,),  # Weight Lifter           ..Racing Car
+        (0x1f3d4, 0x1f3df,),  # Snow Capped Mountain    ..Stadium
+        (0x1f3f3, 0x1f3f3,),  # Waving White Flag
+        (0x1f3f5, 0x1f3f5,),  # Rosette
+        (0x1f3f7, 0x1f3f7,),  # Label
+        (0x1f43f, 0x1f43f,),  # Chipmunk
+        (0x1f441, 0x1f441,),  # Eye
+        (0x1f4fd, 0x1f4fd,),  # Film Projector
+        (0x1f549, 0x1f54a,),  # Om Symbol               ..Dove Of Peace
+        (0x1f56f, 0x1f570,),  # Candle                  ..Mantelpiece Clock
+        (0x1f573, 0x1f579,),  # Hole                    ..Joystick
+        (0x1f587, 0x1f587,),  # Linked Paperclips
+        (0x1f58a, 0x1f58d,),  # Lower Left Ballpoint Pen..Lower Left Crayon
+        (0x1f590, 0x1f590,),  # Raised Hand With Fingers Splayed
+        (0x1f5a5, 0x1f5a5,),  # Desktop Computer
+        (0x1f5a8, 0x1f5a8,),  # Printer
+        (0x1f5b1, 0x1f5b2,),  # Three Button Mouse      ..Trackball
+        (0x1f5bc, 0x1f5bc,),  # Frame With Picture
+        (0x1f5c2, 0x1f5c4,),  # Card Index Dividers     ..File Cabinet
+        (0x1f5d1, 0x1f5d3,),  # Wastebasket             ..Spiral Calendar Pad
+        (0x1f5dc, 0x1f5de,),  # Compression             ..Rolled-up Newspaper
+        (0x1f5e1, 0x1f5e1,),  # Dagger Knife
+        (0x1f5e3, 0x1f5e3,),  # Speaking Head In Silhouette
+        (0x1f5e8, 0x1f5e8,),  # Left Speech Bubble
+        (0x1f5ef, 0x1f5ef,),  # Right Anger Bubble
+        (0x1f5f3, 0x1f5f3,),  # Ballot Box With Ballot
+        (0x1f5fa, 0x1f5fa,),  # World Map
+        (0x1f6cb, 0x1f6cb,),  # Couch And Lamp
+        (0x1f6cd, 0x1f6cf,),  # Shopping Bags           ..Bed
+        (0x1f6e0, 0x1f6e5,),  # Hammer And Wrench       ..Motor Boat
+        (0x1f6e9, 0x1f6e9,),  # Small Airplane
+        (0x1f6f0, 0x1f6f0,),  # Satellite
+        (0x1f6f3, 0x1f6f3,),  # Passenger Ship
+    ),
+}
diff --git a/lib/python3.12/site-packages/wcwidth/table_wide.py b/lib/python3.12/site-packages/wcwidth/table_wide.py
new file mode 100644
index 0000000000000000000000000000000000000000..ed6f48a73225b3a47ebb822fe02543c63d68b055
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/table_wide.py
@@ -0,0 +1,138 @@
+"""
+Exports WIDE_EASTASIAN table keyed by supporting unicode version level.
+
+This code generated by wcwidth/bin/update-tables.py on 2026-01-30 00:58:17 UTC.
+"""
+# pylint: disable=duplicate-code
+WIDE_EASTASIAN = {
+    '17.0.0': (
+        # Source: EastAsianWidth-17.0.0.txt
+        # Date: 2025-07-24, 00:12:54 GMT
+        #
+        (0x01100, 0x0115f,),  # Hangul Choseong Kiyeok  ..Hangul Choseong Filler
+        (0x0231a, 0x0231b,),  # Watch                   ..Hourglass
+        (0x02329, 0x0232a,),  # Left-pointing Angle Brac..Right-pointing Angle Bra
+        (0x023e9, 0x023ec,),  # Black Right-pointing Dou..Black Down-pointing Doub
+        (0x023f0, 0x023f0,),  # Alarm Clock
+        (0x023f3, 0x023f3,),  # Hourglass With Flowing Sand
+        (0x025fd, 0x025fe,),  # White Medium Small Squar..Black Medium Small Squar
+        (0x02614, 0x02615,),  # Umbrella With Rain Drops..Hot Beverage
+        (0x02630, 0x02637,),  # Trigram For Heaven      ..Trigram For Earth
+        (0x02648, 0x02653,),  # Aries                   ..Pisces
+        (0x0267f, 0x0267f,),  # Wheelchair Symbol
+        (0x0268a, 0x0268f,),  # Monogram For Yang       ..Digram For Greater Yin
+        (0x02693, 0x02693,),  # Anchor
+        (0x026a1, 0x026a1,),  # High Voltage Sign
+        (0x026aa, 0x026ab,),  # Medium White Circle     ..Medium Black Circle
+        (0x026bd, 0x026be,),  # Soccer Ball             ..Baseball
+        (0x026c4, 0x026c5,),  # Snowman Without Snow    ..Sun Behind Cloud
+        (0x026ce, 0x026ce,),  # Ophiuchus
+        (0x026d4, 0x026d4,),  # No Entry
+        (0x026ea, 0x026ea,),  # Church
+        (0x026f2, 0x026f3,),  # Fountain                ..Flag In Hole
+        (0x026f5, 0x026f5,),  # Sailboat
+        (0x026fa, 0x026fa,),  # Tent
+        (0x026fd, 0x026fd,),  # Fuel Pump
+        (0x02705, 0x02705,),  # White Heavy Check Mark
+        (0x0270a, 0x0270b,),  # Raised Fist             ..Raised Hand
+        (0x02728, 0x02728,),  # Sparkles
+        (0x0274c, 0x0274c,),  # Cross Mark
+        (0x0274e, 0x0274e,),  # Negative Squared Cross Mark
+        (0x02753, 0x02755,),  # Black Question Mark Orna..White Exclamation Mark O
+        (0x02757, 0x02757,),  # Heavy Exclamation Mark Symbol
+        (0x02795, 0x02797,),  # Heavy Plus Sign         ..Heavy Division Sign
+        (0x027b0, 0x027b0,),  # Curly Loop
+        (0x027bf, 0x027bf,),  # Double Curly Loop
+        (0x02b1b, 0x02b1c,),  # Black Large Square      ..White Large Square
+        (0x02b50, 0x02b50,),  # White Medium Star
+        (0x02b55, 0x02b55,),  # Heavy Large Circle
+        (0x02e80, 0x02e99,),  # Cjk Radical Repeat      ..Cjk Radical Rap
+        (0x02e9b, 0x02ef3,),  # Cjk Radical Choke       ..Cjk Radical C-simplified
+        (0x02f00, 0x02fd5,),  # Kangxi Radical One      ..Kangxi Radical Flute
+        (0x02ff0, 0x03029,),  # Ideographic Description ..Hangzhou Numeral Nine
+        (0x03030, 0x0303e,),  # Wavy Dash               ..Ideographic Variation In
+        (0x03041, 0x03096,),  # Hiragana Letter Small A ..Hiragana Letter Small Ke
+        (0x0309b, 0x030ff,),  # Katakana-hiragana Voiced..Katakana Digraph Koto
+        (0x03105, 0x0312f,),  # Bopomofo Letter B       ..Bopomofo Letter Nn
+        (0x03131, 0x03163,),  # Hangul Letter Kiyeok    ..Hangul Letter I
+        (0x03165, 0x0318e,),  # Hangul Letter Ssangnieun..Hangul Letter Araeae
+        (0x03190, 0x031e5,),  # Ideographic Annotation L..Cjk Stroke Szp
+        (0x031ef, 0x0321e,),  # Ideographic Description ..Parenthesized Korean Cha
+        (0x03220, 0x03247,),  # Parenthesized Ideograph ..Circled Ideograph Koto
+        (0x03250, 0x0a48c,),  # Partnership Sign        ..Yi Syllable Yyr
+        (0x0a490, 0x0a4c6,),  # Yi Radical Qot          ..Yi Radical Ke
+        (0x0a960, 0x0a97c,),  # Hangul Choseong Tikeut-m..Hangul Choseong Ssangyeo
+        (0x0ac00, 0x0d7a3,),  # Hangul Syllable Ga      ..Hangul Syllable Hih
+        (0x0f900, 0x0faff,),  # Cjk Compatibility Ideogr..(nil)
+        (0x0fe10, 0x0fe19,),  # Presentation Form For Ve..Presentation Form For Ve
+        (0x0fe30, 0x0fe52,),  # Presentation Form For Ve..Small Full Stop
+        (0x0fe54, 0x0fe66,),  # Small Semicolon         ..Small Equals Sign
+        (0x0fe68, 0x0fe6b,),  # Small Reverse Solidus   ..Small Commercial At
+        (0x0ff01, 0x0ff60,),  # Fullwidth Exclamation Ma..Fullwidth Right White Pa
+        (0x0ffe0, 0x0ffe6,),  # Fullwidth Cent Sign     ..Fullwidth Won Sign
+        (0x16fe0, 0x16fe3,),  # Tangut Iteration Mark   ..Old Chinese Iteration Ma
+        (0x16ff2, 0x16ff6,),  # Chinese Small Simplified..Yangqin Sign Slow Two Be
+        (0x17000, 0x18cd5,),  # (nil)                   ..Khitan Small Script Char
+        (0x18cff, 0x18d1e,),  # Khitan Small Script Char..(nil)
+        (0x18d80, 0x18df2,),  # Tangut Component-769    ..Tangut Component-883
+        (0x1aff0, 0x1aff3,),  # Katakana Letter Minnan T..Katakana Letter Minnan T
+        (0x1aff5, 0x1affb,),  # Katakana Letter Minnan T..Katakana Letter Minnan N
+        (0x1affd, 0x1affe,),  # Katakana Letter Minnan N..Katakana Letter Minnan N
+        (0x1b000, 0x1b122,),  # Katakana Letter Archaic ..Katakana Letter Archaic
+        (0x1b132, 0x1b132,),  # Hiragana Letter Small Ko
+        (0x1b150, 0x1b152,),  # Hiragana Letter Small Wi..Hiragana Letter Small Wo
+        (0x1b155, 0x1b155,),  # Katakana Letter Small Ko
+        (0x1b164, 0x1b167,),  # Katakana Letter Small Wi..Katakana Letter Small N
+        (0x1b170, 0x1b2fb,),  # Nushu Character-1b170   ..Nushu Character-1b2fb
+        (0x1d300, 0x1d356,),  # Monogram For Earth      ..Tetragram For Fostering
+        (0x1d360, 0x1d376,),  # Counting Rod Unit Digit ..Ideographic Tally Mark F
+        (0x1f004, 0x1f004,),  # Mahjong Tile Red Dragon
+        (0x1f0cf, 0x1f0cf,),  # Playing Card Black Joker
+        (0x1f18e, 0x1f18e,),  # Negative Squared Ab
+        (0x1f191, 0x1f19a,),  # Squared Cl              ..Squared Vs
+        (0x1f1e6, 0x1f202,),  # Regional Indicator Symbo..Squared Katakana Sa
+        (0x1f210, 0x1f23b,),  # Squared Cjk Unified Ideo..Squared Cjk Unified Ideo
+        (0x1f240, 0x1f248,),  # Tortoise Shell Bracketed..Tortoise Shell Bracketed
+        (0x1f250, 0x1f251,),  # Circled Ideograph Advant..Circled Ideograph Accept
+        (0x1f260, 0x1f265,),  # Rounded Symbol For Fu   ..Rounded Symbol For Cai
+        (0x1f300, 0x1f320,),  # Cyclone                 ..Shooting Star
+        (0x1f32d, 0x1f335,),  # Hot Dog                 ..Cactus
+        (0x1f337, 0x1f37c,),  # Tulip                   ..Baby Bottle
+        (0x1f37e, 0x1f393,),  # Bottle With Popping Cork..Graduation Cap
+        (0x1f3a0, 0x1f3ca,),  # Carousel Horse          ..Swimmer
+        (0x1f3cf, 0x1f3d3,),  # Cricket Bat And Ball    ..Table Tennis Paddle And
+        (0x1f3e0, 0x1f3f0,),  # House Building          ..European Castle
+        (0x1f3f4, 0x1f3f4,),  # Waving Black Flag
+        (0x1f3f8, 0x1f43e,),  # Badminton Racquet And Sh..Paw Prints
+        (0x1f440, 0x1f440,),  # Eyes
+        (0x1f442, 0x1f4fc,),  # Ear                     ..Videocassette
+        (0x1f4ff, 0x1f53d,),  # Prayer Beads            ..Down-pointing Small Red
+        (0x1f54b, 0x1f54e,),  # Kaaba                   ..Menorah With Nine Branch
+        (0x1f550, 0x1f567,),  # Clock Face One Oclock   ..Clock Face Twelve-thirty
+        (0x1f57a, 0x1f57a,),  # Man Dancing
+        (0x1f595, 0x1f596,),  # Reversed Hand With Middl..Raised Hand With Part Be
+        (0x1f5a4, 0x1f5a4,),  # Black Heart
+        (0x1f5fb, 0x1f64f,),  # Mount Fuji              ..Person With Folded Hands
+        (0x1f680, 0x1f6c5,),  # Rocket                  ..Left Luggage
+        (0x1f6cc, 0x1f6cc,),  # Sleeping Accommodation
+        (0x1f6d0, 0x1f6d2,),  # Place Of Worship        ..Shopping Trolley
+        (0x1f6d5, 0x1f6d8,),  # Hindu Temple            ..Landslide
+        (0x1f6dc, 0x1f6df,),  # Wireless                ..Ring Buoy
+        (0x1f6eb, 0x1f6ec,),  # Airplane Departure      ..Airplane Arriving
+        (0x1f6f4, 0x1f6fc,),  # Scooter                 ..Roller Skate
+        (0x1f7e0, 0x1f7eb,),  # Large Orange Circle     ..Large Brown Square
+        (0x1f7f0, 0x1f7f0,),  # Heavy Equals Sign
+        (0x1f90c, 0x1f93a,),  # Pinched Fingers         ..Fencer
+        (0x1f93c, 0x1f945,),  # Wrestlers               ..Goal Net
+        (0x1f947, 0x1f9ff,),  # First Place Medal       ..Nazar Amulet
+        (0x1fa70, 0x1fa7c,),  # Ballet Shoes            ..Crutch
+        (0x1fa80, 0x1fa8a,),  # Yo-yo                   ..Trombone
+        (0x1fa8e, 0x1fac6,),  # Treasure Chest          ..Fingerprint
+        (0x1fac8, 0x1fac8,),  # Hairy Creature
+        (0x1facd, 0x1fadc,),  # Orca                    ..Root Vegetable
+        (0x1fadf, 0x1faea,),  # Splatter                ..Distorted Face
+        (0x1faef, 0x1faf8,),  # Fight Cloud             ..Rightwards Pushing Hand
+        (0x20000, 0x2fffd,),  # Cjk Unified Ideograph-20..(nil)
+        (0x30000, 0x3fffd,),  # Cjk Unified Ideograph-30..(nil)
+    ),
+}
diff --git a/lib/python3.12/site-packages/wcwidth/table_zero.py b/lib/python3.12/site-packages/wcwidth/table_zero.py
new file mode 100644
index 0000000000000000000000000000000000000000..c440bfcf15683eead269743b1bf298e964490fdc
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/table_zero.py
@@ -0,0 +1,350 @@
+"""
+Exports ZERO_WIDTH table keyed by supporting unicode version level.
+
+This code generated by wcwidth/bin/update-tables.py on 2026-01-30 00:48:24 UTC.
+"""
+# pylint: disable=duplicate-code
+ZERO_WIDTH = {
+    '17.0.0': (
+        # Source: DerivedGeneralCategory-17.0.0.txt
+        # Date: 2025-07-24, 00:12:50 GMT
+        #
+        (0x00000, 0x00000,),  # (nil)
+        (0x00300, 0x0036f,),  # Combining Grave Accent  ..Combining Latin Small Le
+        (0x00483, 0x00489,),  # Combining Cyrillic Titlo..Combining Cyrillic Milli
+        (0x00591, 0x005bd,),  # Hebrew Accent Etnahta   ..Hebrew Point Meteg
+        (0x005bf, 0x005bf,),  # Hebrew Point Rafe
+        (0x005c1, 0x005c2,),  # Hebrew Point Shin Dot   ..Hebrew Point Sin Dot
+        (0x005c4, 0x005c5,),  # Hebrew Mark Upper Dot   ..Hebrew Mark Lower Dot
+        (0x005c7, 0x005c7,),  # Hebrew Point Qamats Qatan
+        (0x00610, 0x0061a,),  # Arabic Sign Sallallahou ..Arabic Small Kasra
+        (0x0061c, 0x0061c,),  # Arabic Letter Mark
+        (0x0064b, 0x0065f,),  # Arabic Fathatan         ..Arabic Wavy Hamza Below
+        (0x00670, 0x00670,),  # Arabic Letter Superscript Alef
+        (0x006d6, 0x006dc,),  # Arabic Small High Ligatu..Arabic Small High Seen
+        (0x006df, 0x006e4,),  # Arabic Small High Rounde..Arabic Small High Madda
+        (0x006e7, 0x006e8,),  # Arabic Small High Yeh   ..Arabic Small High Noon
+        (0x006ea, 0x006ed,),  # Arabic Empty Centre Low ..Arabic Small Low Meem
+        (0x00711, 0x00711,),  # Syriac Letter Superscript Alaph
+        (0x00730, 0x0074a,),  # Syriac Pthaha Above     ..Syriac Barrekh
+        (0x007a6, 0x007b0,),  # Thaana Abafili          ..Thaana Sukun
+        (0x007eb, 0x007f3,),  # Nko Combining Short High..Nko Combining Double Dot
+        (0x007fd, 0x007fd,),  # Nko Dantayalan
+        (0x00816, 0x00819,),  # Samaritan Mark In       ..Samaritan Mark Dagesh
+        (0x0081b, 0x00823,),  # Samaritan Mark Epentheti..Samaritan Vowel Sign A
+        (0x00825, 0x00827,),  # Samaritan Vowel Sign Sho..Samaritan Vowel Sign U
+        (0x00829, 0x0082d,),  # Samaritan Vowel Sign Lon..Samaritan Mark Nequdaa
+        (0x00859, 0x0085b,),  # Mandaic Affrication Mark..Mandaic Gemination Mark
+        (0x00897, 0x0089f,),  # Arabic Pepet            ..Arabic Half Madda Over M
+        (0x008ca, 0x008e1,),  # Arabic Small High Farsi ..Arabic Small High Sign S
+        (0x008e3, 0x00903,),  # Arabic Turned Damma Belo..Devanagari Sign Visarga
+        (0x0093a, 0x0093c,),  # Devanagari Vowel Sign Oe..Devanagari Sign Nukta
+        (0x0093e, 0x0094f,),  # Devanagari Vowel Sign Aa..Devanagari Vowel Sign Aw
+        (0x00951, 0x00957,),  # Devanagari Stress Sign U..Devanagari Vowel Sign Uu
+        (0x00962, 0x00963,),  # Devanagari Vowel Sign Vo..Devanagari Vowel Sign Vo
+        (0x00981, 0x00983,),  # Bengali Sign Candrabindu..Bengali Sign Visarga
+        (0x009bc, 0x009bc,),  # Bengali Sign Nukta
+        (0x009be, 0x009c4,),  # Bengali Vowel Sign Aa   ..Bengali Vowel Sign Vocal
+        (0x009c7, 0x009c8,),  # Bengali Vowel Sign E    ..Bengali Vowel Sign Ai
+        (0x009cb, 0x009cd,),  # Bengali Vowel Sign O    ..Bengali Sign Virama
+        (0x009d7, 0x009d7,),  # Bengali Au Length Mark
+        (0x009e2, 0x009e3,),  # Bengali Vowel Sign Vocal..Bengali Vowel Sign Vocal
+        (0x009fe, 0x009fe,),  # Bengali Sandhi Mark
+        (0x00a01, 0x00a03,),  # Gurmukhi Sign Adak Bindi..Gurmukhi Sign Visarga
+        (0x00a3c, 0x00a3c,),  # Gurmukhi Sign Nukta
+        (0x00a3e, 0x00a42,),  # Gurmukhi Vowel Sign Aa  ..Gurmukhi Vowel Sign Uu
+        (0x00a47, 0x00a48,),  # Gurmukhi Vowel Sign Ee  ..Gurmukhi Vowel Sign Ai
+        (0x00a4b, 0x00a4d,),  # Gurmukhi Vowel Sign Oo  ..Gurmukhi Sign Virama
+        (0x00a51, 0x00a51,),  # Gurmukhi Sign Udaat
+        (0x00a70, 0x00a71,),  # Gurmukhi Tippi          ..Gurmukhi Addak
+        (0x00a75, 0x00a75,),  # Gurmukhi Sign Yakash
+        (0x00a81, 0x00a83,),  # Gujarati Sign Candrabind..Gujarati Sign Visarga
+        (0x00abc, 0x00abc,),  # Gujarati Sign Nukta
+        (0x00abe, 0x00ac5,),  # Gujarati Vowel Sign Aa  ..Gujarati Vowel Sign Cand
+        (0x00ac7, 0x00ac9,),  # Gujarati Vowel Sign E   ..Gujarati Vowel Sign Cand
+        (0x00acb, 0x00acd,),  # Gujarati Vowel Sign O   ..Gujarati Sign Virama
+        (0x00ae2, 0x00ae3,),  # Gujarati Vowel Sign Voca..Gujarati Vowel Sign Voca
+        (0x00afa, 0x00aff,),  # Gujarati Sign Sukun     ..Gujarati Sign Two-circle
+        (0x00b01, 0x00b03,),  # Oriya Sign Candrabindu  ..Oriya Sign Visarga
+        (0x00b3c, 0x00b3c,),  # Oriya Sign Nukta
+        (0x00b3e, 0x00b44,),  # Oriya Vowel Sign Aa     ..Oriya Vowel Sign Vocalic
+        (0x00b47, 0x00b48,),  # Oriya Vowel Sign E      ..Oriya Vowel Sign Ai
+        (0x00b4b, 0x00b4d,),  # Oriya Vowel Sign O      ..Oriya Sign Virama
+        (0x00b55, 0x00b57,),  # Oriya Sign Overline     ..Oriya Au Length Mark
+        (0x00b62, 0x00b63,),  # Oriya Vowel Sign Vocalic..Oriya Vowel Sign Vocalic
+        (0x00b82, 0x00b82,),  # Tamil Sign Anusvara
+        (0x00bbe, 0x00bc2,),  # Tamil Vowel Sign Aa     ..Tamil Vowel Sign Uu
+        (0x00bc6, 0x00bc8,),  # Tamil Vowel Sign E      ..Tamil Vowel Sign Ai
+        (0x00bca, 0x00bcd,),  # Tamil Vowel Sign O      ..Tamil Sign Virama
+        (0x00bd7, 0x00bd7,),  # Tamil Au Length Mark
+        (0x00c00, 0x00c04,),  # Telugu Sign Combining Ca..Telugu Sign Combining An
+        (0x00c3c, 0x00c3c,),  # Telugu Sign Nukta
+        (0x00c3e, 0x00c44,),  # Telugu Vowel Sign Aa    ..Telugu Vowel Sign Vocali
+        (0x00c46, 0x00c48,),  # Telugu Vowel Sign E     ..Telugu Vowel Sign Ai
+        (0x00c4a, 0x00c4d,),  # Telugu Vowel Sign O     ..Telugu Sign Virama
+        (0x00c55, 0x00c56,),  # Telugu Length Mark      ..Telugu Ai Length Mark
+        (0x00c62, 0x00c63,),  # Telugu Vowel Sign Vocali..Telugu Vowel Sign Vocali
+        (0x00c81, 0x00c83,),  # Kannada Sign Candrabindu..Kannada Sign Visarga
+        (0x00cbc, 0x00cbc,),  # Kannada Sign Nukta
+        (0x00cbe, 0x00cc4,),  # Kannada Vowel Sign Aa   ..Kannada Vowel Sign Vocal
+        (0x00cc6, 0x00cc8,),  # Kannada Vowel Sign E    ..Kannada Vowel Sign Ai
+        (0x00cca, 0x00ccd,),  # Kannada Vowel Sign O    ..Kannada Sign Virama
+        (0x00cd5, 0x00cd6,),  # Kannada Length Mark     ..Kannada Ai Length Mark
+        (0x00ce2, 0x00ce3,),  # Kannada Vowel Sign Vocal..Kannada Vowel Sign Vocal
+        (0x00cf3, 0x00cf3,),  # Kannada Sign Combining Anusvara Above Right
+        (0x00d00, 0x00d03,),  # Malayalam Sign Combining..Malayalam Sign Visarga
+        (0x00d3b, 0x00d3c,),  # Malayalam Sign Vertical ..Malayalam Sign Circular
+        (0x00d3e, 0x00d44,),  # Malayalam Vowel Sign Aa ..Malayalam Vowel Sign Voc
+        (0x00d46, 0x00d48,),  # Malayalam Vowel Sign E  ..Malayalam Vowel Sign Ai
+        (0x00d4a, 0x00d4d,),  # Malayalam Vowel Sign O  ..Malayalam Sign Virama
+        (0x00d57, 0x00d57,),  # Malayalam Au Length Mark
+        (0x00d62, 0x00d63,),  # Malayalam Vowel Sign Voc..Malayalam Vowel Sign Voc
+        (0x00d81, 0x00d83,),  # Sinhala Sign Candrabindu..Sinhala Sign Visargaya
+        (0x00dca, 0x00dca,),  # Sinhala Sign Al-lakuna
+        (0x00dcf, 0x00dd4,),  # Sinhala Vowel Sign Aela-..Sinhala Vowel Sign Ketti
+        (0x00dd6, 0x00dd6,),  # Sinhala Vowel Sign Diga Paa-pilla
+        (0x00dd8, 0x00ddf,),  # Sinhala Vowel Sign Gaett..Sinhala Vowel Sign Gayan
+        (0x00df2, 0x00df3,),  # Sinhala Vowel Sign Diga ..Sinhala Vowel Sign Diga
+        (0x00e31, 0x00e31,),  # Thai Character Mai Han-akat
+        (0x00e34, 0x00e3a,),  # Thai Character Sara I   ..Thai Character Phinthu
+        (0x00e47, 0x00e4e,),  # Thai Character Maitaikhu..Thai Character Yamakkan
+        (0x00eb1, 0x00eb1,),  # Lao Vowel Sign Mai Kan
+        (0x00eb4, 0x00ebc,),  # Lao Vowel Sign I        ..Lao Semivowel Sign Lo
+        (0x00ec8, 0x00ece,),  # Lao Tone Mai Ek         ..Lao Yamakkan
+        (0x00f18, 0x00f19,),  # Tibetan Astrological Sig..Tibetan Astrological Sig
+        (0x00f35, 0x00f35,),  # Tibetan Mark Ngas Bzung Nyi Zla
+        (0x00f37, 0x00f37,),  # Tibetan Mark Ngas Bzung Sgor Rtags
+        (0x00f39, 0x00f39,),  # Tibetan Mark Tsa -phru
+        (0x00f3e, 0x00f3f,),  # Tibetan Sign Yar Tshes  ..Tibetan Sign Mar Tshes
+        (0x00f71, 0x00f84,),  # Tibetan Vowel Sign Aa   ..Tibetan Mark Halanta
+        (0x00f86, 0x00f87,),  # Tibetan Sign Lci Rtags  ..Tibetan Sign Yang Rtags
+        (0x00f8d, 0x00f97,),  # Tibetan Subjoined Sign L..Tibetan Subjoined Letter
+        (0x00f99, 0x00fbc,),  # Tibetan Subjoined Letter..Tibetan Subjoined Letter
+        (0x00fc6, 0x00fc6,),  # Tibetan Symbol Padma Gdan
+        (0x0102b, 0x0103e,),  # Myanmar Vowel Sign Tall ..Myanmar Consonant Sign M
+        (0x01056, 0x01059,),  # Myanmar Vowel Sign Vocal..Myanmar Vowel Sign Vocal
+        (0x0105e, 0x01060,),  # Myanmar Consonant Sign M..Myanmar Consonant Sign M
+        (0x01062, 0x01064,),  # Myanmar Vowel Sign Sgaw ..Myanmar Tone Mark Sgaw K
+        (0x01067, 0x0106d,),  # Myanmar Vowel Sign Weste..Myanmar Sign Western Pwo
+        (0x01071, 0x01074,),  # Myanmar Vowel Sign Geba ..Myanmar Vowel Sign Kayah
+        (0x01082, 0x0108d,),  # Myanmar Consonant Sign S..Myanmar Sign Shan Counci
+        (0x0108f, 0x0108f,),  # Myanmar Sign Rumai Palaung Tone-5
+        (0x0109a, 0x0109d,),  # Myanmar Sign Khamti Tone..Myanmar Vowel Sign Aiton
+        (0x01160, 0x011ff,),  # Hangul Jungseong Filler ..Hangul Jongseong Ssangni
+        (0x0135d, 0x0135f,),  # Ethiopic Combining Gemin..Ethiopic Combining Gemin
+        (0x01712, 0x01715,),  # Tagalog Vowel Sign I    ..Tagalog Sign Pamudpod
+        (0x01732, 0x01734,),  # Hanunoo Vowel Sign I    ..Hanunoo Sign Pamudpod
+        (0x01752, 0x01753,),  # Buhid Vowel Sign I      ..Buhid Vowel Sign U
+        (0x01772, 0x01773,),  # Tagbanwa Vowel Sign I   ..Tagbanwa Vowel Sign U
+        (0x017b4, 0x017d3,),  # Khmer Vowel Inherent Aq ..Khmer Sign Bathamasat
+        (0x017dd, 0x017dd,),  # Khmer Sign Atthacan
+        (0x0180b, 0x0180f,),  # Mongolian Free Variation..Mongolian Free Variation
+        (0x01885, 0x01886,),  # Mongolian Letter Ali Gal..Mongolian Letter Ali Gal
+        (0x018a9, 0x018a9,),  # Mongolian Letter Ali Gali Dagalga
+        (0x01920, 0x0192b,),  # Limbu Vowel Sign A      ..Limbu Subjoined Letter W
+        (0x01930, 0x0193b,),  # Limbu Small Letter Ka   ..Limbu Sign Sa-i
+        (0x01a17, 0x01a1b,),  # Buginese Vowel Sign I   ..Buginese Vowel Sign Ae
+        (0x01a55, 0x01a5e,),  # Tai Tham Consonant Sign ..Tai Tham Consonant Sign
+        (0x01a60, 0x01a7c,),  # Tai Tham Sign Sakot     ..Tai Tham Sign Khuen-lue
+        (0x01a7f, 0x01a7f,),  # Tai Tham Combining Cryptogrammic Dot
+        (0x01ab0, 0x01add,),  # Combining Doubled Circum..Combining Dot-and-ring B
+        (0x01ae0, 0x01aeb,),  # Combining Left Tack Abov..Combining Double Rightwa
+        (0x01b00, 0x01b04,),  # Balinese Sign Ulu Ricem ..Balinese Sign Bisah
+        (0x01b34, 0x01b44,),  # Balinese Sign Rerekan   ..Balinese Adeg Adeg
+        (0x01b6b, 0x01b73,),  # Balinese Musical Symbol ..Balinese Musical Symbol
+        (0x01b80, 0x01b82,),  # Sundanese Sign Panyecek ..Sundanese Sign Pangwisad
+        (0x01ba1, 0x01bad,),  # Sundanese Consonant Sign..Sundanese Consonant Sign
+        (0x01be6, 0x01bf3,),  # Batak Sign Tompi        ..Batak Panongonan
+        (0x01c24, 0x01c37,),  # Lepcha Subjoined Letter ..Lepcha Sign Nukta
+        (0x01cd0, 0x01cd2,),  # Vedic Tone Karshana     ..Vedic Tone Prenkha
+        (0x01cd4, 0x01ce8,),  # Vedic Sign Yajurvedic Mi..Vedic Sign Visarga Anuda
+        (0x01ced, 0x01ced,),  # Vedic Sign Tiryak
+        (0x01cf4, 0x01cf4,),  # Vedic Tone Candra Above
+        (0x01cf7, 0x01cf9,),  # Vedic Sign Atikrama     ..Vedic Tone Double Ring A
+        (0x01dc0, 0x01dff,),  # Combining Dotted Grave A..Combining Right Arrowhea
+        (0x0200b, 0x0200f,),  # Zero Width Space        ..Right-to-left Mark
+        (0x02028, 0x0202e,),  # Line Separator          ..Right-to-left Override
+        (0x02060, 0x0206f,),  # Word Joiner             ..Nominal Digit Shapes
+        (0x020d0, 0x020f0,),  # Combining Left Harpoon A..Combining Asterisk Above
+        (0x02cef, 0x02cf1,),  # Coptic Combining Ni Abov..Coptic Combining Spiritu
+        (0x02d7f, 0x02d7f,),  # Tifinagh Consonant Joiner
+        (0x02de0, 0x02dff,),  # Combining Cyrillic Lette..Combining Cyrillic Lette
+        (0x0302a, 0x0302f,),  # Ideographic Level Tone M..Hangul Double Dot Tone M
+        (0x03099, 0x0309a,),  # Combining Katakana-hirag..Combining Katakana-hirag
+        (0x03164, 0x03164,),  # Hangul Filler
+        (0x0a66f, 0x0a672,),  # Combining Cyrillic Vzmet..Combining Cyrillic Thous
+        (0x0a674, 0x0a67d,),  # Combining Cyrillic Lette..Combining Cyrillic Payer
+        (0x0a69e, 0x0a69f,),  # Combining Cyrillic Lette..Combining Cyrillic Lette
+        (0x0a6f0, 0x0a6f1,),  # Bamum Combining Mark Koq..Bamum Combining Mark Tuk
+        (0x0a802, 0x0a802,),  # Syloti Nagri Sign Dvisvara
+        (0x0a806, 0x0a806,),  # Syloti Nagri Sign Hasanta
+        (0x0a80b, 0x0a80b,),  # Syloti Nagri Sign Anusvara
+        (0x0a823, 0x0a827,),  # Syloti Nagri Vowel Sign ..Syloti Nagri Vowel Sign
+        (0x0a82c, 0x0a82c,),  # Syloti Nagri Sign Alternate Hasanta
+        (0x0a880, 0x0a881,),  # Saurashtra Sign Anusvara..Saurashtra Sign Visarga
+        (0x0a8b4, 0x0a8c5,),  # Saurashtra Consonant Sig..Saurashtra Sign Candrabi
+        (0x0a8e0, 0x0a8f1,),  # Combining Devanagari Dig..Combining Devanagari Sig
+        (0x0a8ff, 0x0a8ff,),  # Devanagari Vowel Sign Ay
+        (0x0a926, 0x0a92d,),  # Kayah Li Vowel Ue       ..Kayah Li Tone Calya Plop
+        (0x0a947, 0x0a953,),  # Rejang Vowel Sign I     ..Rejang Virama
+        (0x0a980, 0x0a983,),  # Javanese Sign Panyangga ..Javanese Sign Wignyan
+        (0x0a9b3, 0x0a9c0,),  # Javanese Sign Cecak Telu..Javanese Pangkon
+        (0x0a9e5, 0x0a9e5,),  # Myanmar Sign Shan Saw
+        (0x0aa29, 0x0aa36,),  # Cham Vowel Sign Aa      ..Cham Consonant Sign Wa
+        (0x0aa43, 0x0aa43,),  # Cham Consonant Sign Final Ng
+        (0x0aa4c, 0x0aa4d,),  # Cham Consonant Sign Fina..Cham Consonant Sign Fina
+        (0x0aa7b, 0x0aa7d,),  # Myanmar Sign Pao Karen T..Myanmar Sign Tai Laing T
+        (0x0aab0, 0x0aab0,),  # Tai Viet Mai Kang
+        (0x0aab2, 0x0aab4,),  # Tai Viet Vowel I        ..Tai Viet Vowel U
+        (0x0aab7, 0x0aab8,),  # Tai Viet Mai Khit       ..Tai Viet Vowel Ia
+        (0x0aabe, 0x0aabf,),  # Tai Viet Vowel Am       ..Tai Viet Tone Mai Ek
+        (0x0aac1, 0x0aac1,),  # Tai Viet Tone Mai Tho
+        (0x0aaeb, 0x0aaef,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+        (0x0aaf5, 0x0aaf6,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Virama
+        (0x0abe3, 0x0abea,),  # Meetei Mayek Vowel Sign ..Meetei Mayek Vowel Sign
+        (0x0abec, 0x0abed,),  # Meetei Mayek Lum Iyek   ..Meetei Mayek Apun Iyek
+        (0x0d7b0, 0x0d7ff,),  # Hangul Jungseong O-yeo  ..(nil)
+        (0x0fb1e, 0x0fb1e,),  # Hebrew Point Judeo-spanish Varika
+        (0x0fe00, 0x0fe0f,),  # Variation Selector-1    ..Variation Selector-16
+        (0x0fe20, 0x0fe2f,),  # Combining Ligature Left ..Combining Cyrillic Titlo
+        (0x0feff, 0x0feff,),  # Zero Width No-break Space
+        (0x0ffa0, 0x0ffa0,),  # Halfwidth Hangul Filler
+        (0x0fff0, 0x0fffb,),  # (nil)                   ..Interlinear Annotation T
+        (0x101fd, 0x101fd,),  # Phaistos Disc Sign Combining Oblique Stroke
+        (0x102e0, 0x102e0,),  # Coptic Epact Thousands Mark
+        (0x10376, 0x1037a,),  # Combining Old Permic Let..Combining Old Permic Let
+        (0x10a01, 0x10a03,),  # Kharoshthi Vowel Sign I ..Kharoshthi Vowel Sign Vo
+        (0x10a05, 0x10a06,),  # Kharoshthi Vowel Sign E ..Kharoshthi Vowel Sign O
+        (0x10a0c, 0x10a0f,),  # Kharoshthi Vowel Length ..Kharoshthi Sign Visarga
+        (0x10a38, 0x10a3a,),  # Kharoshthi Sign Bar Abov..Kharoshthi Sign Dot Belo
+        (0x10a3f, 0x10a3f,),  # Kharoshthi Virama
+        (0x10ae5, 0x10ae6,),  # Manichaean Abbreviation ..Manichaean Abbreviation
+        (0x10d24, 0x10d27,),  # Hanifi Rohingya Sign Har..Hanifi Rohingya Sign Tas
+        (0x10d69, 0x10d6d,),  # Garay Vowel Sign E      ..Garay Consonant Nasaliza
+        (0x10eab, 0x10eac,),  # Yezidi Combining Hamza M..Yezidi Combining Madda M
+        (0x10efa, 0x10eff,),  # Arabic Double Vertical B..Arabic Small Low Word Ma
+        (0x10f46, 0x10f50,),  # Sogdian Combining Dot Be..Sogdian Combining Stroke
+        (0x10f82, 0x10f85,),  # Old Uyghur Combining Dot..Old Uyghur Combining Two
+        (0x11000, 0x11002,),  # Brahmi Sign Candrabindu ..Brahmi Sign Visarga
+        (0x11038, 0x11046,),  # Brahmi Vowel Sign Aa    ..Brahmi Virama
+        (0x11070, 0x11070,),  # Brahmi Sign Old Tamil Virama
+        (0x11073, 0x11074,),  # Brahmi Vowel Sign Old Ta..Brahmi Vowel Sign Old Ta
+        (0x1107f, 0x11082,),  # Brahmi Number Joiner    ..Kaithi Sign Visarga
+        (0x110b0, 0x110ba,),  # Kaithi Vowel Sign Aa    ..Kaithi Sign Nukta
+        (0x110c2, 0x110c2,),  # Kaithi Vowel Sign Vocalic R
+        (0x11100, 0x11102,),  # Chakma Sign Candrabindu ..Chakma Sign Visarga
+        (0x11127, 0x11134,),  # Chakma Vowel Sign A     ..Chakma Maayyaa
+        (0x11145, 0x11146,),  # Chakma Vowel Sign Aa    ..Chakma Vowel Sign Ei
+        (0x11173, 0x11173,),  # Mahajani Sign Nukta
+        (0x11180, 0x11182,),  # Sharada Sign Candrabindu..Sharada Sign Visarga
+        (0x111b3, 0x111c0,),  # Sharada Vowel Sign Aa   ..Sharada Sign Virama
+        (0x111c9, 0x111cc,),  # Sharada Sandhi Mark     ..Sharada Extra Short Vowe
+        (0x111ce, 0x111cf,),  # Sharada Vowel Sign Prish..Sharada Sign Inverted Ca
+        (0x1122c, 0x11237,),  # Khojki Vowel Sign Aa    ..Khojki Sign Shadda
+        (0x1123e, 0x1123e,),  # Khojki Sign Sukun
+        (0x11241, 0x11241,),  # Khojki Vowel Sign Vocalic R
+        (0x112df, 0x112ea,),  # Khudawadi Sign Anusvara ..Khudawadi Sign Virama
+        (0x11300, 0x11303,),  # Grantha Sign Combining A..Grantha Sign Visarga
+        (0x1133b, 0x1133c,),  # Combining Bindu Below   ..Grantha Sign Nukta
+        (0x1133e, 0x11344,),  # Grantha Vowel Sign Aa   ..Grantha Vowel Sign Vocal
+        (0x11347, 0x11348,),  # Grantha Vowel Sign Ee   ..Grantha Vowel Sign Ai
+        (0x1134b, 0x1134d,),  # Grantha Vowel Sign Oo   ..Grantha Sign Virama
+        (0x11357, 0x11357,),  # Grantha Au Length Mark
+        (0x11362, 0x11363,),  # Grantha Vowel Sign Vocal..Grantha Vowel Sign Vocal
+        (0x11366, 0x1136c,),  # Combining Grantha Digit ..Combining Grantha Digit
+        (0x11370, 0x11374,),  # Combining Grantha Letter..Combining Grantha Letter
+        (0x113b8, 0x113c0,),  # Tulu-tigalari Vowel Sign..Tulu-tigalari Vowel Sign
+        (0x113c2, 0x113c2,),  # Tulu-tigalari Vowel Sign Ee
+        (0x113c5, 0x113c5,),  # Tulu-tigalari Vowel Sign Ai
+        (0x113c7, 0x113ca,),  # Tulu-tigalari Vowel Sign..Tulu-tigalari Sign Candr
+        (0x113cc, 0x113d0,),  # Tulu-tigalari Sign Anusv..Tulu-tigalari Conjoiner
+        (0x113d2, 0x113d2,),  # Tulu-tigalari Gemination Mark
+        (0x113e1, 0x113e2,),  # Tulu-tigalari Vedic Tone..Tulu-tigalari Vedic Tone
+        (0x11435, 0x11446,),  # Newa Vowel Sign Aa      ..Newa Sign Nukta
+        (0x1145e, 0x1145e,),  # Newa Sandhi Mark
+        (0x114b0, 0x114c3,),  # Tirhuta Vowel Sign Aa   ..Tirhuta Sign Nukta
+        (0x115af, 0x115b5,),  # Siddham Vowel Sign Aa   ..Siddham Vowel Sign Vocal
+        (0x115b8, 0x115c0,),  # Siddham Vowel Sign E    ..Siddham Sign Nukta
+        (0x115dc, 0x115dd,),  # Siddham Vowel Sign Alter..Siddham Vowel Sign Alter
+        (0x11630, 0x11640,),  # Modi Vowel Sign Aa      ..Modi Sign Ardhacandra
+        (0x116ab, 0x116b7,),  # Takri Sign Anusvara     ..Takri Sign Nukta
+        (0x1171d, 0x1172b,),  # Ahom Consonant Sign Medi..Ahom Sign Killer
+        (0x1182c, 0x1183a,),  # Dogra Vowel Sign Aa     ..Dogra Sign Nukta
+        (0x11930, 0x11935,),  # Dives Akuru Vowel Sign A..Dives Akuru Vowel Sign E
+        (0x11937, 0x11938,),  # Dives Akuru Vowel Sign A..Dives Akuru Vowel Sign O
+        (0x1193b, 0x1193e,),  # Dives Akuru Sign Anusvar..Dives Akuru Virama
+        (0x11940, 0x11940,),  # Dives Akuru Medial Ya
+        (0x11942, 0x11943,),  # Dives Akuru Medial Ra   ..Dives Akuru Sign Nukta
+        (0x119d1, 0x119d7,),  # Nandinagari Vowel Sign A..Nandinagari Vowel Sign V
+        (0x119da, 0x119e0,),  # Nandinagari Vowel Sign E..Nandinagari Sign Virama
+        (0x119e4, 0x119e4,),  # Nandinagari Vowel Sign Prishthamatra E
+        (0x11a01, 0x11a0a,),  # Zanabazar Square Vowel S..Zanabazar Square Vowel L
+        (0x11a33, 0x11a39,),  # Zanabazar Square Final C..Zanabazar Square Sign Vi
+        (0x11a3b, 0x11a3e,),  # Zanabazar Square Cluster..Zanabazar Square Cluster
+        (0x11a47, 0x11a47,),  # Zanabazar Square Subjoiner
+        (0x11a51, 0x11a5b,),  # Soyombo Vowel Sign I    ..Soyombo Vowel Length Mar
+        (0x11a8a, 0x11a99,),  # Soyombo Final Consonant ..Soyombo Subjoiner
+        (0x11b60, 0x11b67,),  # Sharada Vowel Sign Oe   ..Sharada Vowel Sign Candr
+        (0x11c2f, 0x11c36,),  # Bhaiksuki Vowel Sign Aa ..Bhaiksuki Vowel Sign Voc
+        (0x11c38, 0x11c3f,),  # Bhaiksuki Vowel Sign E  ..Bhaiksuki Sign Virama
+        (0x11c92, 0x11ca7,),  # Marchen Subjoined Letter..Marchen Subjoined Letter
+        (0x11ca9, 0x11cb6,),  # Marchen Subjoined Letter..Marchen Sign Candrabindu
+        (0x11d31, 0x11d36,),  # Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign
+        (0x11d3a, 0x11d3a,),  # Masaram Gondi Vowel Sign E
+        (0x11d3c, 0x11d3d,),  # Masaram Gondi Vowel Sign..Masaram Gondi Vowel Sign
+        (0x11d3f, 0x11d45,),  # Masaram Gondi Vowel Sign..Masaram Gondi Virama
+        (0x11d47, 0x11d47,),  # Masaram Gondi Ra-kara
+        (0x11d8a, 0x11d8e,),  # Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign
+        (0x11d90, 0x11d91,),  # Gunjala Gondi Vowel Sign..Gunjala Gondi Vowel Sign
+        (0x11d93, 0x11d97,),  # Gunjala Gondi Vowel Sign..Gunjala Gondi Virama
+        (0x11ef3, 0x11ef6,),  # Makasar Vowel Sign I    ..Makasar Vowel Sign O
+        (0x11f00, 0x11f01,),  # Kawi Sign Candrabindu   ..Kawi Sign Anusvara
+        (0x11f03, 0x11f03,),  # Kawi Sign Visarga
+        (0x11f34, 0x11f3a,),  # Kawi Vowel Sign Aa      ..Kawi Vowel Sign Vocalic
+        (0x11f3e, 0x11f42,),  # Kawi Vowel Sign E       ..Kawi Conjoiner
+        (0x11f5a, 0x11f5a,),  # Kawi Sign Nukta
+        (0x13430, 0x13440,),  # Egyptian Hieroglyph Vert..Egyptian Hieroglyph Mirr
+        (0x13447, 0x13455,),  # Egyptian Hieroglyph Modi..Egyptian Hieroglyph Modi
+        (0x1611e, 0x1612f,),  # Gurung Khema Vowel Sign ..Gurung Khema Sign Tholho
+        (0x16af0, 0x16af4,),  # Bassa Vah Combining High..Bassa Vah Combining High
+        (0x16b30, 0x16b36,),  # Pahawh Hmong Mark Cim Tu..Pahawh Hmong Mark Cim Ta
+        (0x16f4f, 0x16f4f,),  # Miao Sign Consonant Modifier Bar
+        (0x16f51, 0x16f87,),  # Miao Sign Aspiration    ..Miao Vowel Sign Ui
+        (0x16f8f, 0x16f92,),  # Miao Tone Right         ..Miao Tone Below
+        (0x16fe4, 0x16fe4,),  # Khitan Small Script Filler
+        (0x16ff0, 0x16ff1,),  # Vietnamese Alternate Rea..Vietnamese Alternate Rea
+        (0x1bc9d, 0x1bc9e,),  # Duployan Thick Letter Se..Duployan Double Mark
+        (0x1bca0, 0x1bca3,),  # Shorthand Format Letter ..Shorthand Format Up Step
+        (0x1cf00, 0x1cf2d,),  # Znamenny Combining Mark ..Znamenny Combining Mark
+        (0x1cf30, 0x1cf46,),  # Znamenny Combining Tonal..Znamenny Priznak Modifie
+        (0x1d165, 0x1d169,),  # Musical Symbol Combining..Musical Symbol Combining
+        (0x1d16d, 0x1d182,),  # Musical Symbol Combining..Musical Symbol Combining
+        (0x1d185, 0x1d18b,),  # Musical Symbol Combining..Musical Symbol Combining
+        (0x1d1aa, 0x1d1ad,),  # Musical Symbol Combining..Musical Symbol Combining
+        (0x1d242, 0x1d244,),  # Combining Greek Musical ..Combining Greek Musical
+        (0x1da00, 0x1da36,),  # Signwriting Head Rim    ..Signwriting Air Sucking
+        (0x1da3b, 0x1da6c,),  # Signwriting Mouth Closed..Signwriting Excitement
+        (0x1da75, 0x1da75,),  # Signwriting Upper Body Tilting From Hip Joints
+        (0x1da84, 0x1da84,),  # Signwriting Location Head Neck
+        (0x1da9b, 0x1da9f,),  # Signwriting Fill Modifie..Signwriting Fill Modifie
+        (0x1daa1, 0x1daaf,),  # Signwriting Rotation Mod..Signwriting Rotation Mod
+        (0x1e000, 0x1e006,),  # Combining Glagolitic Let..Combining Glagolitic Let
+        (0x1e008, 0x1e018,),  # Combining Glagolitic Let..Combining Glagolitic Let
+        (0x1e01b, 0x1e021,),  # Combining Glagolitic Let..Combining Glagolitic Let
+        (0x1e023, 0x1e024,),  # Combining Glagolitic Let..Combining Glagolitic Let
+        (0x1e026, 0x1e02a,),  # Combining Glagolitic Let..Combining Glagolitic Let
+        (0x1e08f, 0x1e08f,),  # Combining Cyrillic Small Letter Byelorussian-ukr
+        (0x1e130, 0x1e136,),  # Nyiakeng Puachue Hmong T..Nyiakeng Puachue Hmong T
+        (0x1e2ae, 0x1e2ae,),  # Toto Sign Rising Tone
+        (0x1e2ec, 0x1e2ef,),  # Wancho Tone Tup         ..Wancho Tone Koini
+        (0x1e4ec, 0x1e4ef,),  # Nag Mundari Sign Muhor  ..Nag Mundari Sign Sutuh
+        (0x1e5ee, 0x1e5ef,),  # Ol Onal Sign Mu         ..Ol Onal Sign Ikir
+        (0x1e6e3, 0x1e6e3,),  # Tai Yo Sign Ue
+        (0x1e6e6, 0x1e6e6,),  # Tai Yo Sign Au
+        (0x1e6ee, 0x1e6ef,),  # Tai Yo Sign Ay          ..Tai Yo Sign Ang
+        (0x1e6f5, 0x1e6f5,),  # Tai Yo Sign Om
+        (0x1e8d0, 0x1e8d6,),  # Mende Kikakui Combining ..Mende Kikakui Combining
+        (0x1e944, 0x1e94a,),  # Adlam Alif Lengthener   ..Adlam Nukta
+        (0xe0000, 0xe0fff,),  # (nil)
+    ),
+}
diff --git a/lib/python3.12/site-packages/wcwidth/textwrap.py b/lib/python3.12/site-packages/wcwidth/textwrap.py
new file mode 100644
index 0000000000000000000000000000000000000000..e6cca9161e88568ca262b77a7b069b8fcfc4bb15
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/textwrap.py
@@ -0,0 +1,552 @@
+"""
+Sequence-aware text wrapping functions.
+
+This module provides functions for wrapping text that may contain terminal escape sequences, with
+proper handling of Unicode grapheme clusters and character display widths.
+"""
+from __future__ import annotations
+
+# std imports
+import re
+import secrets
+import textwrap
+
+from typing import TYPE_CHECKING, NamedTuple
+
+# local
+from .wcwidth import width as _width
+from .wcwidth import iter_sequences
+from .grapheme import iter_graphemes
+from .sgr_state import propagate_sgr as _propagate_sgr
+from .escape_sequences import ZERO_WIDTH_PATTERN
+
+if TYPE_CHECKING:  # pragma: no cover
+    from typing import Any, Literal
+
+
+class _HyperlinkState(NamedTuple):
+    """State for tracking an open OSC 8 hyperlink across line breaks."""
+
+    url: str  # hyperlink target URL
+    params: str  # id=xxx and other key=value pairs separated by :
+    terminator: str  # BEL (\x07) or ST (\x1b\\)
+
+
+# Hyperlink parsing: captures (params, url, terminator)
+_HYPERLINK_OPEN_RE = re.compile(r'\x1b]8;([^;]*);([^\x07\x1b]*)(\x07|\x1b\\)')
+
+
+def _parse_hyperlink_open(seq: str) -> _HyperlinkState | None:
+    """Parse OSC 8 open sequence, return state or None."""
+    if (m := _HYPERLINK_OPEN_RE.match(seq)):
+        return _HyperlinkState(url=m.group(2), params=m.group(1), terminator=m.group(3))
+    return None
+
+
+def _make_hyperlink_open(url: str, params: str, terminator: str) -> str:
+    """Generate OSC 8 open sequence."""
+    return f'\x1b]8;{params};{url}{terminator}'
+
+
+def _make_hyperlink_close(terminator: str) -> str:
+    """Generate OSC 8 close sequence."""
+    return f'\x1b]8;;{terminator}'
+
+
+class SequenceTextWrapper(textwrap.TextWrapper):
+    """
+    Sequence-aware text wrapper extending :class:`textwrap.TextWrapper`.
+
+    This wrapper properly handles terminal escape sequences and Unicode grapheme clusters when
+    calculating text width for wrapping.
+
+    This implementation is based on the SequenceTextWrapper from the 'blessed' library, with
+    contributions from Avram Lubkin and grayjk.
+
+    The key difference from the blessed implementation is the addition of grapheme cluster support
+    via :func:`~.iter_graphemes`, providing width calculation for ZWJ emoji sequences, VS-16 emojis
+    and variations, regional indicator flags, and combining characters.
+
+    OSC 8 hyperlinks are handled specially: when a hyperlink must span multiple lines, each line
+    receives complete open/close sequences with a shared ``id`` parameter, ensuring terminals
+    treat the fragments as a single hyperlink for hover underlining. If the original hyperlink
+    already has an ``id`` parameter, it is preserved; otherwise, one is generated.
+    """
+
+    def __init__(self, width: int = 70, *,
+                 control_codes: Literal['parse', 'strict', 'ignore'] = 'parse',
+                 tabsize: int = 8,
+                 ambiguous_width: int = 1,
+                 **kwargs: Any) -> None:
+        """
+        Initialize the wrapper.
+
+        :param width: Maximum line width in display cells.
+        :param control_codes: How to handle control sequences (see :func:`~.width`).
+        :param tabsize: Tab stop width for tab expansion.
+        :param ambiguous_width: Width to use for East Asian Ambiguous (A) characters.
+        :param kwargs: Additional arguments passed to :class:`textwrap.TextWrapper`.
+        """
+        super().__init__(width=width, **kwargs)
+        self.control_codes = control_codes
+        self.tabsize = tabsize
+        self.ambiguous_width = ambiguous_width
+
+    @staticmethod
+    def _next_hyperlink_id() -> str:
+        """Generate unique hyperlink id as 8-character hex string."""
+        return secrets.token_hex(4)
+
+    def _width(self, text: str) -> int:
+        """Measure text width accounting for sequences."""
+        return _width(text, control_codes=self.control_codes, tabsize=self.tabsize,
+                      ambiguous_width=self.ambiguous_width)
+
+    def _strip_sequences(self, text: str) -> str:
+        """Strip all terminal sequences from text."""
+        result = []
+        for segment, is_seq in iter_sequences(text):
+            if not is_seq:
+                result.append(segment)
+        return ''.join(result)
+
+    def _extract_sequences(self, text: str) -> str:
+        """Extract only terminal sequences from text."""
+        result = []
+        for segment, is_seq in iter_sequences(text):
+            if is_seq:
+                result.append(segment)
+        return ''.join(result)
+
+    def _split(self, text: str) -> list[str]:  # pylint: disable=too-many-locals
+        r"""
+        Sequence-aware variant of :meth:`textwrap.TextWrapper._split`.
+
+        This method ensures that terminal escape sequences don't interfere with the text splitting
+        logic, particularly for hyphen-based word breaking. It builds a position mapping from
+        stripped text to original text, calls the parent's _split on stripped text, then maps chunks
+        back.
+
+        OSC hyperlink sequences are treated as word boundaries::
+
+            >>> wrap('foo \x1b]8;;https://example.com\x07link\x1b]8;;\x07 bar', 6)
+            ['foo', '\x1b]8;;https://example.com\x07link\x1b]8;;\x07', 'bar']
+
+        Both BEL (``\x07``) and ST (``\x1b\\``) terminators are supported.
+        """
+        # pylint: disable=too-many-locals,too-many-branches
+        # Build a mapping from stripped text positions to original text positions.
+        #
+        # Track where each character ENDS so that sequences between characters
+        # attach to the following text (not preceding text). This ensures sequences
+        # aren't lost when whitespace is dropped.
+        #
+        # char_end[i] = position in original text right after the i-th stripped char
+        char_end: list[int] = []
+        stripped_text = ''
+        original_pos = 0
+        prev_was_hyperlink_close = False
+
+        for segment, is_seq in iter_sequences(text):
+            if not is_seq:
+                # Conditionally insert space after hyperlink close to force word boundary
+                if prev_was_hyperlink_close and segment and not segment[0].isspace():
+                    stripped_text += ' '
+                    char_end.append(original_pos)
+                for char in segment:
+                    original_pos += 1
+                    char_end.append(original_pos)
+                    stripped_text += char
+                prev_was_hyperlink_close = False
+            else:
+                is_hyperlink_close = segment.startswith(('\x1b]8;;\x1b\\', '\x1b]8;;\x07'))
+
+                # Conditionally insert space before OSC sequences to artificially create word
+                # boundary, but *not* before hyperlink close sequences, to ensure hyperlink is
+                # terminated on the same line.
+                if (segment.startswith('\x1b]') and stripped_text and not
+                        stripped_text[-1].isspace()):
+                    if not is_hyperlink_close:
+                        stripped_text += ' '
+                        char_end.append(original_pos)
+
+                # Escape sequences advance position but don't add to stripped text
+                original_pos += len(segment)
+                prev_was_hyperlink_close = is_hyperlink_close
+
+        # Add sentinel for final position
+        char_end.append(original_pos)
+
+        # Use parent's _split on the stripped text
+        # pylint: disable-next=protected-access
+        stripped_chunks = textwrap.TextWrapper._split(self, stripped_text)
+
+        # Handle text that contains only sequences (no visible characters).
+        # Return the sequences as a single chunk to preserve them.
+        if not stripped_chunks and text:
+            return [text]
+
+        # Map the chunks back to the original text with sequences
+        result: list[str] = []
+        stripped_pos = 0
+        num_chunks = len(stripped_chunks)
+
+        for idx, chunk in enumerate(stripped_chunks):
+            chunk_len = len(chunk)
+
+            # Start is where previous character ended (or 0 for first chunk)
+            start_orig = 0 if stripped_pos == 0 else char_end[stripped_pos - 1]
+
+            # End is where next character starts. For last chunk, use sentinel
+            # to include any trailing sequences.
+            if idx == num_chunks - 1:
+                end_orig = char_end[-1]  # sentinel includes trailing sequences
+            else:
+                end_orig = char_end[stripped_pos + chunk_len - 1]
+
+            # Extract the corresponding portion from the original text
+            # Skip empty chunks (from virtual spaces inserted at OSC boundaries)
+            if start_orig != end_orig:
+                result.append(text[start_orig:end_orig])
+            stripped_pos += chunk_len
+
+        return result
+
+    def _wrap_chunks(self, chunks: list[str]) -> list[str]:  # pylint: disable=too-many-branches
+        """
+        Wrap chunks into lines using sequence-aware width.
+
+        Override TextWrapper._wrap_chunks to use _width instead of len. Follows stdlib's algorithm:
+        greedily fill lines, handle long words.  Also handle OSC hyperlink processing. When
+        hyperlinks span multiple lines, each line gets complete open/close sequences with matching
+        id parameters for hover underlining continuity per OSC 8 spec.
+        """
+        # pylint: disable=too-many-branches,too-many-statements,too-complex,too-many-locals
+        # pylint: disable=too-many-nested-blocks
+        # the hyperlink code in particular really pushes the complexity rating of this method.
+        # preferring to keep it "all in one method" because of so much local state and manipulation.
+        if not chunks:
+            return []
+
+        lines: list[str] = []
+        is_first_line = True
+
+        hyperlink_state: _HyperlinkState | None = None
+        # Track the id we're using for the current hyperlink continuation
+        current_hyperlink_id: str | None = None
+
+        # Arrange in reverse order so items can be efficiently popped
+        chunks = list(reversed(chunks))
+
+        while chunks:
+            current_line: list[str] = []
+            current_width = 0
+
+            # Get the indent and available width for current line
+            indent = self.initial_indent if is_first_line else self.subsequent_indent
+            line_width = self.width - self._width(indent)
+
+            # If continuing a hyperlink from previous line, prepend open sequence
+            if hyperlink_state is not None:
+                open_seq = _make_hyperlink_open(
+                    hyperlink_state.url, hyperlink_state.params, hyperlink_state.terminator)
+                chunks[-1] = open_seq + chunks[-1]
+
+            # Drop leading whitespace (except at very start)
+            # When dropping, transfer any sequences to the next chunk.
+            # Only drop if there's actual whitespace text, not if it's only sequences.
+            stripped = self._strip_sequences(chunks[-1])
+            if self.drop_whitespace and lines and stripped and not stripped.strip():
+                sequences = self._extract_sequences(chunks[-1])
+                del chunks[-1]
+                if sequences and chunks:
+                    chunks[-1] = sequences + chunks[-1]
+
+            # Greedily add chunks that fit
+            while chunks:
+                chunk = chunks[-1]
+                chunk_width = self._width(chunk)
+
+                if current_width + chunk_width <= line_width:
+                    current_line.append(chunks.pop())
+                    current_width += chunk_width
+                else:
+                    break
+
+            # Handle chunk that's too long for any line
+            if chunks and self._width(chunks[-1]) > line_width:
+                self._handle_long_word(
+                    chunks, current_line, current_width, line_width
+                )
+                current_width = self._width(''.join(current_line))
+                # Remove any empty chunks left by _handle_long_word
+                while chunks and not chunks[-1]:
+                    del chunks[-1]
+
+            # Drop trailing whitespace
+            # When dropping, transfer any sequences to the previous chunk.
+            # Only drop if there's actual whitespace text, not if it's only sequences.
+            stripped_last = self._strip_sequences(current_line[-1]) if current_line else ''
+            if (self.drop_whitespace and current_line and
+                    stripped_last and not stripped_last.strip()):
+                sequences = self._extract_sequences(current_line[-1])
+                current_width -= self._width(current_line[-1])
+                del current_line[-1]
+                if sequences and current_line:
+                    current_line[-1] = current_line[-1] + sequences
+
+            if current_line:
+                line_content = ''.join(current_line)
+
+                # Track hyperlink state through this line's content
+                new_state = self._track_hyperlink_state(line_content, hyperlink_state)
+
+                # If we end inside a hyperlink, append close sequence
+                if new_state is not None:
+                    # Ensure we have an id for continuation
+                    if current_hyperlink_id is None:
+                        if 'id=' in new_state.params:
+                            current_hyperlink_id = new_state.params
+                        elif new_state.params:
+                            # Prepend id to existing params (per OSC 8 spec, params can have
+                            # multiple key=value pairs separated by :)
+                            current_hyperlink_id = (
+                                f'id={self._next_hyperlink_id()}:{new_state.params}')
+                        else:
+                            current_hyperlink_id = f'id={self._next_hyperlink_id()}'
+                    line_content = line_content + _make_hyperlink_close(new_state.terminator)
+
+                    # Also need to inject the id into the opening sequence if it didn't have one
+                    if 'id=' not in new_state.params:
+                        # Find and replace the original open sequence with one that has id
+                        old_open = _make_hyperlink_open(
+                            new_state.url, new_state.params, new_state.terminator)
+                        new_open = _make_hyperlink_open(
+                            new_state.url, current_hyperlink_id, new_state.terminator)
+                        line_content = line_content.replace(old_open, new_open, 1)
+
+                    # Update state for next line, using computed id
+                    hyperlink_state = _HyperlinkState(
+                        new_state.url, current_hyperlink_id, new_state.terminator)
+                else:
+                    hyperlink_state = None
+                    current_hyperlink_id = None  # Reset id when hyperlink closes
+
+                # Strip trailing whitespace when drop_whitespace is enabled
+                # (matches CPython #140627 fix behavior)
+                if self.drop_whitespace:
+                    line_content = line_content.rstrip()
+                lines.append(indent + line_content)
+                is_first_line = False
+
+        return lines
+
+    def _track_hyperlink_state(
+            self, text: str,
+            state: _HyperlinkState | None) -> _HyperlinkState | None:
+        """
+        Track hyperlink state through text.
+
+        :param text: Text to scan for hyperlink sequences.
+        :param state: Current state or None if outside hyperlink.
+        :returns: Updated state after processing text.
+        """
+        for segment, is_seq in iter_sequences(text):
+            if is_seq:
+                parsed_link = _parse_hyperlink_open(segment)
+                if parsed_link is not None and parsed_link.url:  # has URL = open
+                    state = parsed_link
+                elif segment.startswith(('\x1b]8;;\x1b\\', '\x1b]8;;\x07')):  # close
+                    state = None
+        return state
+
+    def _handle_long_word(self, reversed_chunks: list[str],
+                          cur_line: list[str], cur_len: int,
+                          width: int) -> None:
+        """
+        Sequence-aware :meth:`textwrap.TextWrapper._handle_long_word`.
+
+        This method ensures that word boundaries are not broken mid-sequence, and respects grapheme
+        cluster boundaries when breaking long words.
+        """
+        if width < 1:
+            space_left = 1
+        else:
+            space_left = width - cur_len
+
+        chunk = reversed_chunks[-1]
+
+        if self.break_long_words:
+            break_at_hyphen = False
+            hyphen_end = 0
+
+            # Handle break_on_hyphens: find last hyphen within space_left
+            if self.break_on_hyphens:
+                # Strip sequences to find hyphen in logical text
+                stripped = self._strip_sequences(chunk)
+                if len(stripped) > space_left:
+                    # Find last hyphen in the portion that fits
+                    hyphen_pos = stripped.rfind('-', 0, space_left)
+                    if hyphen_pos > 0 and any(c != '-' for c in stripped[:hyphen_pos]):
+                        # Map back to original position including sequences
+                        hyphen_end = self._map_stripped_pos_to_original(chunk, hyphen_pos + 1)
+                        break_at_hyphen = True
+
+            # Break at grapheme boundaries to avoid splitting multi-codepoint characters
+            if break_at_hyphen:
+                actual_end = hyphen_end
+            else:
+                actual_end = self._find_break_position(chunk, space_left)
+                # If no progress possible (e.g., wide char exceeds line width),
+                # force at least one grapheme to avoid infinite loop.
+                # Only force when cur_line is empty; if line has content,
+                # appending nothing is safe and the line will be committed.
+                if actual_end == 0 and not cur_line:
+                    actual_end = self._find_first_grapheme_end(chunk)
+            cur_line.append(chunk[:actual_end])
+            reversed_chunks[-1] = chunk[actual_end:]
+
+        elif not cur_line:
+            cur_line.append(reversed_chunks.pop())
+
+    def _map_stripped_pos_to_original(self, text: str, stripped_pos: int) -> int:
+        """Map a position in stripped text back to original text position."""
+        stripped_idx = 0
+        original_idx = 0
+
+        for segment, is_seq in iter_sequences(text):
+            if is_seq:
+                original_idx += len(segment)
+            elif stripped_idx + len(segment) > stripped_pos:
+                # Position is within this segment
+                return original_idx + (stripped_pos - stripped_idx)
+            else:
+                stripped_idx += len(segment)
+                original_idx += len(segment)
+
+        # Caller guarantees stripped_pos < total stripped chars, so we always
+        # return from within the loop. This line satisfies the type checker.
+        return original_idx  # pragma: no cover
+
+    def _find_break_position(self, text: str, max_width: int) -> int:
+        """Find string index in text that fits within max_width cells."""
+        idx = 0
+        width_so_far = 0
+
+        while idx < len(text):
+            char = text[idx]
+
+            # Skip escape sequences (they don't add width)
+            if char == '\x1b':
+                match = ZERO_WIDTH_PATTERN.match(text, idx)
+                if match:
+                    idx = match.end()
+                    continue
+
+            # Get grapheme (use start= to avoid slice allocation)
+            grapheme = next(iter_graphemes(text, start=idx))
+
+            grapheme_width = self._width(grapheme)
+            if width_so_far + grapheme_width > max_width:
+                return idx  # Found break point
+
+            width_so_far += grapheme_width
+            idx += len(grapheme)
+
+        # Caller guarantees chunk_width > max_width, so a grapheme always
+        # exceeds and we return from within the loop. Type checker requires this.
+        return idx  # pragma: no cover
+
+    def _find_first_grapheme_end(self, text: str) -> int:
+        """Find the end position of the first grapheme."""
+        return len(next(iter_graphemes(text)))
+
+
+def wrap(text: str, width: int = 70, *,
+         control_codes: Literal['parse', 'strict', 'ignore'] = 'parse',
+         tabsize: int = 8,
+         ambiguous_width: int = 1,
+         initial_indent: str = '',
+         subsequent_indent: str = '',
+         break_long_words: bool = True,
+         break_on_hyphens: bool = True,
+         propagate_sgr: bool = True) -> list[str]:
+    r"""
+    Wrap text to fit within given width, returning a list of wrapped lines.
+
+    Like :func:`textwrap.wrap`, but measures width in display cells rather than
+    characters, correctly handling wide characters, combining marks, and terminal
+    escape sequences.
+
+    :param text: Text to wrap, may contain terminal sequences.
+    :param width: Maximum line width in display cells.
+    :param control_codes: How to handle terminal sequences (see :func:`~.width`).
+    :param tabsize: Tab stop width for tab expansion.
+    :param ambiguous_width: Width to use for East Asian Ambiguous (A)
+        characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts.
+    :param initial_indent: String prepended to first line.
+    :param subsequent_indent: String prepended to subsequent lines.
+    :param break_long_words: If True, break words longer than width.
+    :param break_on_hyphens: If True, allow breaking at hyphens.
+    :param propagate_sgr: If True (default), SGR (terminal styling) sequences
+        are propagated across wrapped lines. Each line ends with a reset
+        sequence and the next line begins with the active style restored.
+    :returns: List of wrapped lines without trailing newlines.
+
+    SGR (terminal styling) sequences are propagated across wrapped lines
+    by default. Each line ends with a reset sequence and the next line
+    begins with the active style restored::
+
+        >>> wrap('\x1b[1;34mHello world\x1b[0m', width=6)
+        ['\x1b[1;34mHello\x1b[0m', '\x1b[1;34mworld\x1b[0m']
+
+    Set ``propagate_sgr=False`` to disable this behavior.
+
+    Like :func:`textwrap.wrap`, newlines in the input text are treated as
+    whitespace and collapsed. To preserve paragraph breaks, wrap each
+    paragraph separately::
+
+        >>> text = 'First line.\nSecond line.'
+        >>> wrap(text, 40)  # newline collapsed to space
+        ['First line. Second line.']
+        >>> [line for para in text.split('\n')
+        ...  for line in (wrap(para, 40) if para else [''])]
+        ['First line.', 'Second line.']
+
+    .. seealso::
+
+       :func:`textwrap.wrap`, :class:`textwrap.TextWrapper`
+           Standard library text wrapping (character-based).
+
+       :class:`.SequenceTextWrapper`
+           Class interface for advanced wrapping options.
+
+    .. versionadded:: 0.3.0
+
+    .. versionchanged:: 0.5.0
+       Added ``propagate_sgr`` parameter (default True).
+
+    Example::
+
+        >>> from wcwidth import wrap
+        >>> wrap('hello world', 5)
+        ['hello', 'world']
+        >>> wrap('中文字符', 4)  # CJK characters (2 cells each)
+        ['中文', '字符']
+    """
+    wrapper = SequenceTextWrapper(
+        width=width,
+        control_codes=control_codes,
+        tabsize=tabsize,
+        ambiguous_width=ambiguous_width,
+        initial_indent=initial_indent,
+        subsequent_indent=subsequent_indent,
+        break_long_words=break_long_words,
+        break_on_hyphens=break_on_hyphens,
+    )
+    lines = wrapper.wrap(text)
+
+    if propagate_sgr:
+        lines = _propagate_sgr(lines)
+
+    return lines
diff --git a/lib/python3.12/site-packages/wcwidth/unicode_versions.py b/lib/python3.12/site-packages/wcwidth/unicode_versions.py
new file mode 100644
index 0000000000000000000000000000000000000000..e8484116a423eec09b5409a8fc479300ef5403b8
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/unicode_versions.py
@@ -0,0 +1,21 @@
+"""
+Exports function list_versions() for unicode version level support.
+
+This code generated by wcwidth/bin/update-tables.py on 2026-01-27 00:41:01 UTC.
+"""
+
+from __future__ import annotations
+
+
+def list_versions() -> tuple[str, ...]:
+    """
+    Return Unicode version levels supported by this module release.
+
+    .. versionchanged:: 0.5.0
+       Now returns a single-element tuple containing only the latest version.
+
+    :returns: Supported Unicode version numbers in ascending sorted order.
+    """
+    return (
+        "17.0.0",
+    )
diff --git a/lib/python3.12/site-packages/wcwidth/wcwidth.py b/lib/python3.12/site-packages/wcwidth/wcwidth.py
new file mode 100644
index 0000000000000000000000000000000000000000..98e7a635f6951bfc92be67be54b1398eaeb1e83d
--- /dev/null
+++ b/lib/python3.12/site-packages/wcwidth/wcwidth.py
@@ -0,0 +1,1030 @@
+"""
+This is a python implementation of wcwidth() and wcswidth().
+
+https://github.com/jquast/wcwidth
+
+from Markus Kuhn's C code, retrieved from:
+
+    http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+
+This is an implementation of wcwidth() and wcswidth() (defined in
+IEEE Std 1002.1-2001) for Unicode.
+
+http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
+http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
+
+In fixed-width output devices, Latin characters all occupy a single
+"cell" position of equal width, whereas ideographic CJK characters
+occupy two such cells. Interoperability between terminal-line
+applications and (teletype-style) character terminals using the
+UTF-8 encoding requires agreement on which character should advance
+the cursor by how many cell positions. No established formal
+standards exist at present on which Unicode character shall occupy
+how many cell positions on character terminals. These routines are
+a first attempt of defining such behavior based on simple rules
+applied to data provided by the Unicode Consortium.
+
+For some graphical characters, the Unicode standard explicitly
+defines a character-cell width via the definition of the East Asian
+FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
+In all these cases, there is no ambiguity about which width a
+terminal shall use. For characters in the East Asian Ambiguous (A)
+class, the width choice depends purely on a preference of backward
+compatibility with either historic CJK or Western practice.
+Choosing single-width for these characters is easy to justify as
+the appropriate long-term solution, as the CJK practice of
+displaying these characters as double-width comes from historic
+implementation simplicity (8-bit encoded characters were displayed
+single-width and 16-bit ones double-width, even for Greek,
+Cyrillic, etc.) and not any typographic considerations.
+
+Much less clear is the choice of width for the Not East Asian
+(Neutral) class. Existing practice does not dictate a width for any
+of these characters. It would nevertheless make sense
+typographically to allocate two character cells to characters such
+as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
+represented adequately with a single-width glyph. The following
+routines at present merely assign a single-cell width to all
+neutral characters, in the interest of simplicity. This is not
+entirely satisfactory and should be reconsidered before
+establishing a formal standard in this area. At the moment, the
+decision which Not East Asian (Neutral) characters should be
+represented by double-width glyphs cannot yet be answered by
+applying a simple rule from the Unicode database content. Setting
+up a proper standard for the behavior of UTF-8 character terminals
+will require a careful analysis not only of each Unicode character,
+but also of each presentation form, something the author of these
+routines has avoided to do so far.
+
+http://www.unicode.org/unicode/reports/tr11/
+
+Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+"""
+
+from __future__ import annotations
+
+# std imports
+from functools import lru_cache
+
+from typing import TYPE_CHECKING
+
+# local
+from .bisearch import bisearch as _bisearch
+from .grapheme import iter_graphemes
+from .table_mc import CATEGORY_MC
+from .sgr_state import (_SGR_PATTERN,
+                        _SGR_STATE_DEFAULT,
+                        _sgr_state_update,
+                        _sgr_state_is_active,
+                        _sgr_state_to_sequence)
+from .table_vs16 import VS16_NARROW_TO_WIDE
+from .table_wide import WIDE_EASTASIAN
+from .table_zero import ZERO_WIDTH
+from .control_codes import ILLEGAL_CTRL, VERTICAL_CTRL, HORIZONTAL_CTRL, ZERO_WIDTH_CTRL
+from .table_grapheme import ISC_CONSONANT, EXTENDED_PICTOGRAPHIC, GRAPHEME_REGIONAL_INDICATOR
+from .table_ambiguous import AMBIGUOUS_EASTASIAN
+from .escape_sequences import (ZERO_WIDTH_PATTERN,
+                               CURSOR_LEFT_SEQUENCE,
+                               CURSOR_RIGHT_SEQUENCE,
+                               INDETERMINATE_EFFECT_SEQUENCE)
+from .unicode_versions import list_versions
+
+if TYPE_CHECKING:  # pragma: no cover
+    # std imports
+    from collections.abc import Iterator
+
+    from typing import Literal
+
+# Pre-compute table references for the latest (and only) Unicode version.
+_LATEST_VERSION = list_versions()[-1]
+_ZERO_WIDTH_TABLE = ZERO_WIDTH[_LATEST_VERSION]
+_WIDE_EASTASIAN_TABLE = WIDE_EASTASIAN[_LATEST_VERSION]
+_AMBIGUOUS_TABLE = AMBIGUOUS_EASTASIAN[next(iter(AMBIGUOUS_EASTASIAN))]
+_CATEGORY_MC_TABLE = CATEGORY_MC[_LATEST_VERSION]
+_REGIONAL_INDICATOR_SET = frozenset(
+    range(GRAPHEME_REGIONAL_INDICATOR[0][0], GRAPHEME_REGIONAL_INDICATOR[0][1] + 1)
+)
+_EMOJI_ZWJ_SET = frozenset(
+    cp for lo, hi in EXTENDED_PICTOGRAPHIC for cp in range(lo, hi + 1)
+) | _REGIONAL_INDICATOR_SET
+_FITZPATRICK_RANGE = (0x1F3FB, 0x1F3FF)
+# Indic_Syllabic_Category=Virama codepoints, from IndicSyllabicCategory.txt.
+# These are structurally tied to their scripts and not expected to change.
+# https://www.unicode.org/Public/UCD/latest/ucd/IndicSyllabicCategory.txt
+_ISC_VIRAMA_SET = frozenset((
+    0x094D,   # DEVANAGARI SIGN VIRAMA
+    0x09CD,   # BENGALI SIGN VIRAMA
+    0x0A4D,   # GURMUKHI SIGN VIRAMA
+    0x0ACD,   # GUJARATI SIGN VIRAMA
+    0x0B4D,   # ORIYA SIGN VIRAMA
+    0x0BCD,   # TAMIL SIGN VIRAMA
+    0x0C4D,   # TELUGU SIGN VIRAMA
+    0x0CCD,   # KANNADA SIGN VIRAMA
+    0x0D4D,   # MALAYALAM SIGN VIRAMA
+    0x0DCA,   # SINHALA SIGN AL-LAKUNA
+    0x1B44,   # BALINESE ADEG ADEG
+    0xA806,   # SYLOTI NAGRI SIGN HASANTA
+    0xA8C4,   # SAURASHTRA SIGN VIRAMA
+    0xA9C0,   # JAVANESE PANGKON
+    0x11046,  # BRAHMI VIRAMA
+    0x110B9,  # KAITHI SIGN VIRAMA
+    0x111C0,  # SHARADA SIGN VIRAMA
+    0x11235,  # KHOJKI SIGN VIRAMA
+    0x1134D,  # GRANTHA SIGN VIRAMA
+    0x11442,  # NEWA SIGN VIRAMA
+    0x114C2,  # TIRHUTA SIGN VIRAMA
+    0x115BF,  # SIDDHAM SIGN VIRAMA
+    0x1163F,  # MODI SIGN VIRAMA
+    0x116B6,  # TAKRI SIGN VIRAMA
+    0x11839,  # DOGRA SIGN VIRAMA
+    0x119E0,  # NANDINAGARI SIGN VIRAMA
+    0x11C3F,  # BHAIKSUKI SIGN VIRAMA
+))
+_ISC_CONSONANT_TABLE = ISC_CONSONANT
+
+# In 'parse' mode, strings longer than this are checked for cursor-movement
+# controls (BS, TAB, CR, cursor sequences); when absent, mode downgrades to
+# 'ignore' to skip character-by-character parsing. The detection scan cost is
+# negligible for long strings but wasted on short ones like labels or headings.
+_WIDTH_FAST_PATH_MIN_LEN = 20
+
+# Translation table to strip C0/C1 control characters for fast 'ignore' mode.
+_CONTROL_CHAR_TABLE = str.maketrans('', '', (
+    ''.join(chr(c) for c in range(0x00, 0x20)) +   # C0: NUL through US (including tab)
+    '\x7f' +                                       # DEL
+    ''.join(chr(c) for c in range(0x80, 0xa0))     # C1: U+0080-U+009F
+))
+
+# Unlike wcwidth.__all__, wcwidth.wcwidth.__all__ is NOT for the purpose of defining a public API,
+# or what we prefer to be imported with statement, "from wcwidth.wcwidth import *".  Explicitly
+# re-export imports here for no other reason than to satisfy the type checkers (mypy). Yak shavings.
+__all__ = (
+    'ZERO_WIDTH',
+    'WIDE_EASTASIAN',
+    'AMBIGUOUS_EASTASIAN',
+    'VS16_NARROW_TO_WIDE',
+    'list_versions',
+    'wcwidth',
+    'wcswidth',
+    'width',
+    'iter_sequences',
+    'ljust',
+    'rjust',
+    'center',
+    'clip',
+    'strip_sequences',
+    '_wcmatch_version',
+    '_wcversion_value',
+)
+
+
+# maxsize=1024: western scripts need ~64 unique codepoints per session, but
+# CJK sessions may use ~2000 of ~3500 common hanzi/kanji. 1024 accommodates
+# heavy CJK use. Performance floor at 32; bisearch is ~100ns per miss.
+
+@lru_cache(maxsize=1024)
+def wcwidth(wc: str, unicode_version: str = 'auto', ambiguous_width: int = 1) -> int:  # pylint: disable=unused-argument
+    r"""
+    Given one Unicode codepoint, return its printable length on a terminal.
+
+    :param wc: A single Unicode character.
+    :param unicode_version: Ignored. Retained for backwards compatibility.
+
+        .. deprecated:: 0.3.0
+           Only the latest Unicode version is now shipped.
+
+    :param ambiguous_width: Width to use for East Asian Ambiguous (A)
+        characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts
+        where ambiguous characters display as double-width. See
+        :ref:`ambiguous_width` for details.
+    :returns: The width, in cells, necessary to display the character of
+        Unicode string character, ``wc``.  Returns 0 if the ``wc`` argument has
+        no printable effect on a terminal (such as NUL '\0'), -1 if ``wc`` is
+        not printable, or has an indeterminate effect on the terminal, such as
+        a control character.  Otherwise, the number of column positions the
+        character occupies on a graphic terminal (1 or 2) is returned.
+
+    See :ref:`Specification` for details of cell measurement.
+    """
+    ucs = ord(wc) if wc else 0
+
+    # small optimization: early return of 1 for printable ASCII, this provides
+    # approximately 40% performance improvement for mostly-ascii documents, with
+    # less than 1% impact to others.
+    if 32 <= ucs < 0x7f:
+        return 1
+
+    # C0/C1 control characters are -1 for compatibility with POSIX-like calls
+    if ucs and ucs < 32 or 0x07F <= ucs < 0x0A0:
+        return -1
+
+    # Zero width
+    if _bisearch(ucs, _ZERO_WIDTH_TABLE):
+        return 0
+
+    # Wide (F/W categories)
+    if _bisearch(ucs, _WIDE_EASTASIAN_TABLE):
+        return 2
+
+    # Ambiguous width (A category) - only when ambiguous_width=2
+    if ambiguous_width == 2 and _bisearch(ucs, _AMBIGUOUS_TABLE):
+        return 2
+
+    return 1
+
+
+def wcswidth(
+    pwcs: str,
+    n: int | None = None,
+    unicode_version: str = 'auto',
+    ambiguous_width: int = 1,
+) -> int:
+    """
+    Given a unicode string, return its printable length on a terminal.
+
+    :param pwcs: Measure width of given unicode string.
+    :param n: When ``n`` is None (default), return the length of the entire
+        string, otherwise only the first ``n`` characters are measured.
+
+        Better to use string slicing capability, ``wcswidth(pwcs[:n])``, instead,
+        for performance.  This argument is a holdover from the POSIX function for
+        matching signatures. Be careful that ``n`` is at grapheme boundaries.
+
+    :param unicode_version: Ignored. Retained for backwards compatibility.
+
+        .. deprecated:: 0.3.0
+           Only the latest Unicode version is now shipped.
+
+    :param ambiguous_width: Width to use for East Asian Ambiguous (A)
+        characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts.
+    :returns: The width, in cells, needed to display the first ``n`` characters
+        of the unicode string ``pwcs``.  Returns ``-1`` for C0 and C1 control
+        characters!
+
+    See :ref:`Specification` for details of cell measurement.
+    """
+    # pylint: disable=unused-argument,too-many-locals,too-many-statements
+    # pylint: disable=too-complex,too-many-branches
+    # This function intentionally kept long without delegating functions to reduce function calls in
+    # "hot path", the overhead per-character adds up.
+
+    # Fast path: pure ASCII printable strings are always width == length
+    if n is None and pwcs.isascii() and pwcs.isprintable():
+        return len(pwcs)
+
+    # Select wcwidth call pattern for best lru_cache performance:
+    # - ambiguous_width=1 (default): single-arg calls share cache with direct wcwidth() calls
+    # - ambiguous_width=2: full positional args needed (results differ, separate cache is correct)
+    _wcwidth = wcwidth if ambiguous_width == 1 else lambda c: wcwidth(c, 'auto', ambiguous_width)
+
+    end = len(pwcs) if n is None else n
+    total_width = 0
+    idx = 0
+    last_measured_idx = -2  # Track index of last measured char for VS16
+    last_measured_ucs = -1  # Codepoint of last measured char (for deferred emoji check)
+    last_was_virama = False  # Virama conjunct formation state
+    conjunct_pending = False  # Deferred +1 for bare conjuncts (no trailing Mc)
+    while idx < end:
+        char = pwcs[idx]
+        ucs = ord(char)
+        if ucs == 0x200D:
+            if last_was_virama:
+                # ZWJ after virama requests explicit half-form rendering but
+                # does not change cell count — consume ZWJ only, let the next
+                # consonant be handled by the virama conjunct rule.
+                idx += 1
+            elif idx + 1 < end:
+                # Emoji ZWJ: skip next character unconditionally.
+                idx += 2
+                last_was_virama = False
+            else:
+                idx += 1
+                last_was_virama = False
+            continue
+        if ucs == 0xFE0F and last_measured_idx >= 0:
+            # VS16 following a measured character: add 1 if that character is
+            # known to be converted from narrow to wide by VS16.
+            total_width += _bisearch(ord(pwcs[last_measured_idx]),
+                                     VS16_NARROW_TO_WIDE["9.0.0"])
+            last_measured_idx = -2  # Prevent double application
+            # VS16 preserves emoji context: last_measured_ucs stays as the base
+            idx += 1
+            continue
+        # Regional Indicator & Fitzpatrick: both above BMP (U+1F1E6+)
+        if ucs > 0xFFFF:
+            if ucs in _REGIONAL_INDICATOR_SET:
+                # Lazy RI pairing: count preceding consecutive RIs only when the last one is
+                # received, because RI's are received so rarely its better than per-loop tracking of
+                # 'last char was an RI'.
+                ri_before = 0
+                j = idx - 1
+                while j >= 0 and ord(pwcs[j]) in _REGIONAL_INDICATOR_SET:
+                    ri_before += 1
+                    j -= 1
+                if ri_before % 2 == 1:
+                    # Second RI in pair: contributes 0 (pair = one 2-cell flag) using an even-or-odd
+                    # check to determine, 'CAUS' would be two flags, but 'CAU' would be 1 flag
+                    # and wide 'U'.
+                    idx += 1
+                    last_measured_ucs = ucs
+                    continue
+                # First or unpaired RI: measured normally (width 2 from table)
+            # Fitzpatrick modifier: zero-width when following emoji base
+            elif (_FITZPATRICK_RANGE[0] <= ucs <= _FITZPATRICK_RANGE[1]
+                  and last_measured_ucs in _EMOJI_ZWJ_SET):
+                idx += 1
+                continue
+        # Virama conjunct formation: consonant following virama contributes 0 width.
+        # See https://www.unicode.org/reports/tr44/#Indic_Syllabic_Category
+        if last_was_virama and _bisearch(ucs, _ISC_CONSONANT_TABLE):
+            last_measured_idx = idx
+            last_measured_ucs = ucs
+            last_was_virama = False
+            conjunct_pending = True
+            idx += 1
+            continue
+        wcw = _wcwidth(char)
+        if wcw < 0:
+            # early return -1 on C0 and C1 control characters
+            return wcw
+        if wcw > 0:
+            if conjunct_pending:
+                total_width += 1
+                conjunct_pending = False
+            last_measured_idx = idx
+            last_measured_ucs = ucs
+            last_was_virama = False
+        elif last_measured_idx >= 0 and _bisearch(ucs, _CATEGORY_MC_TABLE):
+            # Spacing Combining Mark (Mc) following a base character adds 1
+            wcw = 1
+            last_measured_idx = -2
+            last_was_virama = False
+            conjunct_pending = False
+        else:
+            last_was_virama = ucs in _ISC_VIRAMA_SET
+        total_width += wcw
+        idx += 1
+    if conjunct_pending:
+        total_width += 1
+    return total_width
+
+
+# NOTE: _wcversion_value and _wcmatch_version are no longer used internally
+# by wcwidth since version 0.5.0 (only the latest Unicode version is shipped).
+#
+# They are retained for API compatibility with external tools like ucs-detect
+# that may use these private functions.
+
+
+@lru_cache(maxsize=128)
+def _wcversion_value(ver_string: str) -> tuple[int, ...]:  # pragma: no cover
+    """
+    Integer-mapped value of given dotted version string.
+
+    .. deprecated:: 0.3.0
+
+        This function is no longer used internally by wcwidth but is retained
+        for API compatibility with external tools.
+
+    :param ver_string: Unicode version string, of form ``n.n.n``.
+    :returns: tuple of digit tuples, ``tuple(int, [...])``.
+    """
+    retval = tuple(map(int, (ver_string.split('.'))))
+    return retval
+
+
+@lru_cache(maxsize=8)
+def _wcmatch_version(given_version: str) -> str:  # pylint: disable=unused-argument
+    """
+    Return the supported Unicode version level.
+
+    .. deprecated:: 0.3.0
+        This function now always returns the latest version.
+
+        This function is no longer used internally by wcwidth but is retained
+        for API compatibility with external tools.
+
+    :param given_version: Ignored. Any value is accepted for compatibility.
+    :returns: The latest unicode version string.
+    """
+    return _LATEST_VERSION
+
+
+def iter_sequences(text: str) -> Iterator[tuple[str, bool]]:
+    r"""
+    Iterate through text, yielding segments with sequence identification.
+
+    This generator yields tuples of ``(segment, is_sequence)`` for each part
+    of the input text, where ``is_sequence`` is ``True`` if the segment is
+    a recognized terminal escape sequence.
+
+    :param text: String to iterate through.
+    :returns: Iterator of (segment, is_sequence) tuples.
+
+    .. versionadded:: 0.3.0
+
+    Example::
+
+        >>> list(iter_sequences('hello'))
+        [('hello', False)]
+        >>> list(iter_sequences('\x1b[31mred'))
+        [('\x1b[31m', True), ('red', False)]
+        >>> list(iter_sequences('\x1b[1m\x1b[31m'))
+        [('\x1b[1m', True), ('\x1b[31m', True)]
+    """
+    idx = 0
+    text_len = len(text)
+    segment_start = 0
+
+    while idx < text_len:
+        char = text[idx]
+
+        if char == '\x1b':
+            # Yield any accumulated non-sequence text
+            if idx > segment_start:
+                yield (text[segment_start:idx], False)
+
+            # Try to match an escape sequence
+            match = ZERO_WIDTH_PATTERN.match(text, idx)
+            if match:
+                yield (match.group(), True)
+                idx = match.end()
+            else:
+                # Lone ESC or unrecognized - yield as sequence anyway
+                yield (char, True)
+                idx += 1
+            segment_start = idx
+        else:
+            idx += 1
+
+    # Yield any remaining text
+    if segment_start < text_len:
+        yield (text[segment_start:], False)
+
+
+def _width_ignored_codes(text: str, ambiguous_width: int = 1) -> int:
+    """
+    Fast path for width() with control_codes='ignore'.
+
+    Strips escape sequences and control characters, then measures remaining text.
+    """
+    return wcswidth(
+        strip_sequences(text).translate(_CONTROL_CHAR_TABLE),
+        ambiguous_width=ambiguous_width
+    )
+
+
+def width(
+    text: str,
+    *,
+    control_codes: Literal['parse', 'strict', 'ignore'] = 'parse',
+    tabsize: int = 8,
+    ambiguous_width: int = 1,
+) -> int:
+    r"""
+    Return printable width of text containing many kinds of control codes and sequences.
+
+    Unlike :func:`wcswidth`, this function handles most control characters and many popular terminal
+    output sequences.  Never returns -1.
+
+    :param text: String to measure.
+    :param control_codes: How to handle control characters and sequences:
+
+        - ``'parse'`` (default): Track horizontal cursor movement from BS ``\b``, CR ``\r``, TAB
+          ``\t``, and cursor left and right movement sequences.  Vertical movement (LF, VT, FF) and
+          indeterminate sequences are zero-width. Never raises.
+        - ``'strict'``: Like parse, but raises :exc:`ValueError` on control characters with
+          indeterminate results of the screen or cursor, like clear or vertical movement. Generally,
+          these should be handled with a virtual terminal emulator (like 'pyte').
+        - ``'ignore'``: All C0 and C1 control characters and escape sequences are measured as
+          width 0. This is the fastest measurement for text already filtered or known not to contain
+          any kinds of control codes or sequences. TAB ``\t`` is zero-width; for tab expansion,
+          pre-process: ``text.replace('\t', ' ' * 8)``.
+
+    :param tabsize: Tab stop width for ``'parse'`` and ``'strict'`` modes. Default is 8.
+        Must be positive. Has no effect when ``control_codes='ignore'``.
+    :param ambiguous_width: Width to use for East Asian Ambiguous (A)
+        characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts.
+    :returns: Maximum cursor position reached, "extent", accounting for cursor movement sequences
+        present in ``text`` according to given parameters.  This represents the rightmost column the
+        cursor reaches.  Always a non-negative integer.
+
+    :raises ValueError: If ``control_codes='strict'`` and control characters with indeterminate
+        effects, such as vertical movement or clear sequences are encountered, or on unexpected
+        C0 or C1 control code. Also raised when ``control_codes`` is not one of the valid values.
+
+    .. versionadded:: 0.3.0
+
+    Examples::
+
+        >>> width('hello')
+        5
+        >>> width('コンニチハ')
+        10
+        >>> width('\x1b[31mred\x1b[0m')
+        3
+        >>> width('\x1b[31mred\x1b[0m', control_codes='ignore')  # same result (ignored)
+        3
+        >>> width('123\b4')     # backspace overwrites previous cell (outputs '124')
+        3
+        >>> width('abc\t')      # tab caused cursor to move to column 8
+        8
+        >>> width('1\x1b[10C')  # '1' + cursor right 10, cursor ends on column 11
+        11
+        >>> width('1\x1b[10C', control_codes='ignore')   # faster but wrong in this case
+        1
+    """
+    # pylint: disable=too-complex,too-many-branches,too-many-statements,too-many-locals
+    # This could be broken into sub-functions (#1, #3, and 6 especially), but for reduced overhead
+    # considering this function is a likely "hot path", they are inlined, breaking many of our
+    # complexity rules.
+
+    # Fast path for ASCII printable (no tabs, escapes, or control chars)
+    if text.isascii() and text.isprintable():
+        return len(text)
+
+    # Fast parse: if no horizontal cursor movements are possible, switch to 'ignore' mode.
+    # Only check for longer strings - the detection overhead hurts short string performance.
+    if control_codes == 'parse' and len(text) > _WIDTH_FAST_PATH_MIN_LEN:
+        # Check for cursor-affecting control characters
+        if '\b' not in text and '\t' not in text and '\r' not in text:
+            # Check for escape sequences - if none, or only non-cursor-movement sequences
+            if '\x1b' not in text or (
+                not CURSOR_RIGHT_SEQUENCE.search(text) and
+                not CURSOR_LEFT_SEQUENCE.search(text)
+            ):
+                control_codes = 'ignore'
+
+    # Fast path for ignore mode -- this is useful if you know the text is already "clean"
+    if control_codes == 'ignore':
+        return _width_ignored_codes(text, ambiguous_width)
+
+    strict = control_codes == 'strict'
+    # Track absolute positions: tab stops need modulo on absolute column, CR resets to 0.
+    # Initialize max_extent to 0 so backward movement (CR, BS) won't yield negative width.
+    current_col = 0
+    max_extent = 0
+    idx = 0
+    last_measured_idx = -2  # Track index of last measured char for VS16; -2 can never match idx-1
+    last_measured_ucs = -1  # Codepoint of last measured char (for deferred emoji check)
+    last_was_virama = False  # Virama conjunct formation state
+    conjunct_pending = False  # Deferred +1 for bare conjuncts (no trailing Mc)
+    text_len = len(text)
+
+    # Select wcwidth call pattern for best lru_cache performance:
+    # - ambiguous_width=1 (default): single-arg calls share cache with direct wcwidth() calls
+    # - ambiguous_width=2: full positional args needed (results differ, separate cache is correct)
+    _wcwidth = wcwidth if ambiguous_width == 1 else lambda c: wcwidth(c, 'auto', ambiguous_width)
+
+    while idx < text_len:
+        char = text[idx]
+
+        # 1. Handle ESC sequences
+        if char == '\x1b':
+            match = ZERO_WIDTH_PATTERN.match(text, idx)
+            if match:
+                seq = match.group()
+                if strict and INDETERMINATE_EFFECT_SEQUENCE.match(seq):
+                    raise ValueError(f"Indeterminate cursor sequence at position {idx}")
+                # Apply cursor movement
+                right = CURSOR_RIGHT_SEQUENCE.match(seq)
+                if right:
+                    current_col += int(right.group(1) or 1)
+                else:
+                    left = CURSOR_LEFT_SEQUENCE.match(seq)
+                    if left:
+                        current_col = max(0, current_col - int(left.group(1) or 1))
+                idx = match.end()
+            else:
+                idx += 1
+            max_extent = max(max_extent, current_col)
+            continue
+
+        # 2. Handle illegal and vertical control characters (zero width, error in strict)
+        if char in ILLEGAL_CTRL:
+            if strict:
+                raise ValueError(f"Illegal control character {ord(char):#x} at position {idx}")
+            idx += 1
+            continue
+
+        if char in VERTICAL_CTRL:
+            if strict:
+                raise ValueError(f"Vertical movement character {ord(char):#x} at position {idx}")
+            idx += 1
+            continue
+
+        # 3. Handle horizontal movement characters
+        if char in HORIZONTAL_CTRL:
+            if char == '\x09' and tabsize > 0:  # Tab
+                current_col += tabsize - (current_col % tabsize)
+            elif char == '\x08':  # Backspace
+                if current_col > 0:
+                    current_col -= 1
+            elif char == '\x0d':  # Carriage return
+                current_col = 0
+            max_extent = max(max_extent, current_col)
+            idx += 1
+            continue
+
+        # 4. Handle ZWJ
+        if char == '\u200D':
+            if last_was_virama:
+                # ZWJ after virama requests explicit half-form rendering but
+                # does not change cell count — consume ZWJ only, let the next
+                # consonant be handled by the virama conjunct rule.
+                idx += 1
+            elif idx + 1 < text_len:
+                # Emoji ZWJ: skip next character unconditionally.
+                idx += 2
+                last_was_virama = False
+            else:
+                idx += 1
+                last_was_virama = False
+            continue
+
+        # 5. Handle other zero-width characters (control chars)
+        if char in ZERO_WIDTH_CTRL:
+            idx += 1
+            continue
+
+        ucs = ord(char)
+
+        # 6. Handle VS16: converts preceding narrow character to wide
+        if ucs == 0xFE0F:
+            if last_measured_idx == idx - 1:
+                if _bisearch(ord(text[last_measured_idx]), VS16_NARROW_TO_WIDE["9.0.0"]):
+                    current_col += 1
+                    max_extent = max(max_extent, current_col)
+            # VS16 preserves emoji context: last_measured_ucs stays as the base
+            idx += 1
+            continue
+
+        # 6b. Regional Indicator & Fitzpatrick: both above BMP (U+1F1E6+)
+        if ucs > 0xFFFF:
+            if ucs in _REGIONAL_INDICATOR_SET:
+                # Lazy RI pairing: count preceding consecutive RIs
+                ri_before = 0
+                j = idx - 1
+                while j >= 0 and ord(text[j]) in _REGIONAL_INDICATOR_SET:
+                    ri_before += 1
+                    j -= 1
+                if ri_before % 2 == 1:
+                    last_measured_ucs = ucs
+                    idx += 1
+                    continue
+            # 6c. Fitzpatrick modifier: zero-width when following emoji base
+            elif (_FITZPATRICK_RANGE[0] <= ucs <= _FITZPATRICK_RANGE[1]
+                  and last_measured_ucs in _EMOJI_ZWJ_SET):
+                idx += 1
+                continue
+
+        # 7. Virama conjunct formation: consonant following virama contributes 0 width.
+        # See https://www.unicode.org/reports/tr44/#Indic_Syllabic_Category
+        if last_was_virama and _bisearch(ucs, _ISC_CONSONANT_TABLE):
+            last_measured_idx = idx
+            last_measured_ucs = ucs
+            last_was_virama = False
+            conjunct_pending = True
+            idx += 1
+            continue
+
+        # 8. Normal characters: measure with wcwidth
+        w = _wcwidth(char)
+        if w > 0:
+            if conjunct_pending:
+                current_col += 1
+                conjunct_pending = False
+            current_col += w
+            max_extent = max(max_extent, current_col)
+            last_measured_idx = idx
+            last_measured_ucs = ucs
+            last_was_virama = False
+        elif last_measured_idx >= 0 and _bisearch(ucs, _CATEGORY_MC_TABLE):
+            # Spacing Combining Mark (Mc) following a base character adds 1
+            current_col += 1
+            max_extent = max(max_extent, current_col)
+            last_measured_idx = -2
+            last_was_virama = False
+            conjunct_pending = False
+        else:
+            last_was_virama = ucs in _ISC_VIRAMA_SET
+        idx += 1
+
+    if conjunct_pending:
+        current_col += 1
+        max_extent = max(max_extent, current_col)
+    return max_extent
+
+
+def ljust(
+    text: str,
+    dest_width: int,
+    fillchar: str = ' ',
+    *,
+    control_codes: Literal['parse', 'strict', 'ignore'] = 'parse',
+    ambiguous_width: int = 1,
+) -> str:
+    r"""
+    Return text left-justified in a string of given display width.
+
+    :param text: String to justify, may contain terminal sequences.
+    :param dest_width: Total display width of result in terminal cells.
+    :param fillchar: Single character for padding (default space). Must have
+        display width of 1 (not wide, not zero-width, not combining). Unicode
+        characters like ``'·'`` are acceptable. The width is not validated.
+    :param control_codes: How to handle control sequences when measuring.
+        Passed to :func:`width` for measurement.
+    :param ambiguous_width: Width to use for East Asian Ambiguous (A)
+        characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts.
+    :returns: Text padded on the right to reach ``dest_width``.
+
+    .. versionadded:: 0.3.0
+
+    Example::
+
+        >>> wcwidth.ljust('hi', 5)
+        'hi   '
+        >>> wcwidth.ljust('\x1b[31mhi\x1b[0m', 5)
+        '\x1b[31mhi\x1b[0m   '
+        >>> wcwidth.ljust('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6)
+        '👨‍👩‍👧    '
+    """
+    if text.isascii() and text.isprintable():
+        text_width = len(text)
+    else:
+        text_width = width(text, control_codes=control_codes, ambiguous_width=ambiguous_width)
+    padding_cells = max(0, dest_width - text_width)
+    return text + fillchar * padding_cells
+
+
+def rjust(
+    text: str,
+    dest_width: int,
+    fillchar: str = ' ',
+    *,
+    control_codes: Literal['parse', 'strict', 'ignore'] = 'parse',
+    ambiguous_width: int = 1,
+) -> str:
+    r"""
+    Return text right-justified in a string of given display width.
+
+    :param text: String to justify, may contain terminal sequences.
+    :param dest_width: Total display width of result in terminal cells.
+    :param fillchar: Single character for padding (default space). Must have
+        display width of 1 (not wide, not zero-width, not combining). Unicode
+        characters like ``'·'`` are acceptable. The width is not validated.
+    :param control_codes: How to handle control sequences when measuring.
+        Passed to :func:`width` for measurement.
+    :param ambiguous_width: Width to use for East Asian Ambiguous (A)
+        characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts.
+    :returns: Text padded on the left to reach ``dest_width``.
+
+    .. versionadded:: 0.3.0
+
+    Example::
+
+        >>> wcwidth.rjust('hi', 5)
+        '   hi'
+        >>> wcwidth.rjust('\x1b[31mhi\x1b[0m', 5)
+        '   \x1b[31mhi\x1b[0m'
+        >>> wcwidth.rjust('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6)
+        '    👨‍👩‍👧'
+    """
+    if text.isascii() and text.isprintable():
+        text_width = len(text)
+    else:
+        text_width = width(text, control_codes=control_codes, ambiguous_width=ambiguous_width)
+    padding_cells = max(0, dest_width - text_width)
+    return fillchar * padding_cells + text
+
+
+def center(
+    text: str,
+    dest_width: int,
+    fillchar: str = ' ',
+    *,
+    control_codes: Literal['parse', 'strict', 'ignore'] = 'parse',
+    ambiguous_width: int = 1,
+) -> str:
+    r"""
+    Return text centered in a string of given display width.
+
+    :param text: String to center, may contain terminal sequences.
+    :param dest_width: Total display width of result in terminal cells.
+    :param fillchar: Single character for padding (default space). Must have
+        display width of 1 (not wide, not zero-width, not combining). Unicode
+        characters like ``'·'`` are acceptable. The width is not validated.
+    :param control_codes: How to handle control sequences when measuring.
+        Passed to :func:`width` for measurement.
+    :param ambiguous_width: Width to use for East Asian Ambiguous (A)
+        characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts.
+    :returns: Text padded on both sides to reach ``dest_width``.
+
+    For odd-width padding, the extra cell goes on the right (matching
+    Python's :meth:`str.center` behavior).
+
+    .. versionadded:: 0.3.0
+
+    Example::
+
+        >>> wcwidth.center('hi', 6)
+        '  hi  '
+        >>> wcwidth.center('\x1b[31mhi\x1b[0m', 6)
+        '  \x1b[31mhi\x1b[0m  '
+        >>> wcwidth.center('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6)
+        '  👨‍👩‍👧  '
+    """
+    if text.isascii() and text.isprintable():
+        text_width = len(text)
+    else:
+        text_width = width(text, control_codes=control_codes, ambiguous_width=ambiguous_width)
+    total_padding = max(0, dest_width - text_width)
+    # matching https://jazcap53.github.io/pythons-eccentric-strcenter.html
+    left_pad = total_padding // 2 + (total_padding & dest_width & 1)
+    right_pad = total_padding - left_pad
+    return fillchar * left_pad + text + fillchar * right_pad
+
+
+def strip_sequences(text: str) -> str:
+    r"""
+    Return text with all terminal escape sequences removed.
+
+    Unknown or incomplete ESC sequences are preserved.
+
+    :param text: String that may contain terminal escape sequences.
+    :returns: The input text with all escape sequences stripped.
+
+    .. versionadded:: 0.3.0
+
+    Example::
+
+        >>> strip_sequences('\x1b[31mred\x1b[0m')
+        'red'
+        >>> strip_sequences('hello')
+        'hello'
+        >>> strip_sequences('\x1b[1m\x1b[31mbold red\x1b[0m text')
+        'bold red text'
+    """
+    return ZERO_WIDTH_PATTERN.sub('', text)
+
+
+def clip(
+    text: str,
+    start: int,
+    end: int,
+    *,
+    fillchar: str = ' ',
+    tabsize: int = 8,
+    ambiguous_width: int = 1,
+    propagate_sgr: bool = True,
+) -> str:
+    r"""
+    Clip text to display columns ``(start, end)`` while preserving all terminal sequences.
+
+    This function extracts a substring based on visible column positions rather than
+    character indices. Terminal escape sequences are preserved in the output since
+    they have zero display width. If a wide character (width 2) would be split at
+    either boundary, it is replaced with ``fillchar``.
+
+    TAB characters (``\t``) are expanded to spaces up to the next tab stop,
+    controlled by the ``tabsize`` parameter.
+
+    Other cursor movement characters (backspace, carriage return) and cursor
+    movement sequences are passed through unchanged as zero-width.
+
+    :param text: String to clip, may contain terminal escape sequences.
+    :param start: Absolute starting column (inclusive, 0-indexed).
+    :param end: Absolute ending column (exclusive).
+    :param fillchar: Character to use when a wide character must be split at
+        a boundary (default space). Must have display width of 1.
+    :param tabsize: Tab stop width (default 8). Set to 0 to pass tabs through
+        as zero-width (preserved in output but don't advance column position).
+    :param ambiguous_width: Width to use for East Asian Ambiguous (A)
+        characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts.
+    :param propagate_sgr: If True (default), SGR (terminal styling) sequences
+        are propagated. The result begins with any active style at the start
+        position and ends with a reset sequence if styles are active.
+    :returns: Substring of ``text`` spanning display columns ``(start, end)``,
+        with all terminal sequences preserved and wide characters at boundaries
+        replaced with ``fillchar``.
+
+    SGR (terminal styling) sequences are propagated by default. The result
+    begins with any active style and ends with a reset::
+
+        >>> clip('\x1b[1;34mHello world\x1b[0m', 6, 11)
+        '\x1b[1;34mworld\x1b[0m'
+
+    Set ``propagate_sgr=False`` to disable this behavior.
+
+    .. versionadded:: 0.3.0
+
+    .. versionchanged:: 0.5.0
+       Added ``propagate_sgr`` parameter (default True).
+
+    Example::
+
+        >>> clip('hello world', 0, 5)
+        'hello'
+        >>> clip('中文字', 0, 3)  # Wide char split at column 3
+        '中 '
+        >>> clip('a\tb', 0, 10)  # Tab expanded to spaces
+        'a       b'
+    """
+    # pylint: disable=too-complex,too-many-locals,too-many-branches,too-many-statements,too-many-nested-blocks
+    # Again, for 'hot path', we avoid additional delegate functions and accept the cost
+    # of complexity for improved python performance.
+    start = max(start, 0)
+    if end <= start:
+        return ''
+
+    # Fast path: printable ASCII only (no tabs, escape sequences, or wide or zero-width chars)
+    if text.isascii() and text.isprintable():
+        return text[start:end]
+
+    # Fast path: no escape sequences means no SGR tracking needed
+    if propagate_sgr and '\x1b' not in text:
+        propagate_sgr = False
+
+    # SGR tracking state (only when propagate_sgr=True)
+    sgr_at_clip_start = None  # state when first visible char emitted (None = not yet)
+    if propagate_sgr:
+        sgr = _SGR_STATE_DEFAULT  # current SGR state, updated by all sequences
+
+    output: list[str] = []
+    col = 0
+    idx = 0
+
+    while idx < len(text):
+        char = text[idx]
+
+        # Early exit: past visible region, SGR captured, no escape ahead
+        if col >= end and sgr_at_clip_start is not None and char != '\x1b':
+            break
+
+        # Handle escape sequences
+        if char == '\x1b' and (match := ZERO_WIDTH_PATTERN.match(text, idx)):
+            seq = match.group()
+            if propagate_sgr and _SGR_PATTERN.match(seq):
+                # Update SGR state; will be applied as prefix when visible content starts
+                sgr = _sgr_state_update(sgr, seq)
+            else:
+                # Non-SGR sequences always preserved
+                output.append(seq)
+            idx = match.end()
+            continue
+
+        # Handle bare ESC (not a valid sequence)
+        if char == '\x1b':
+            output.append(char)
+            idx += 1
+            continue
+
+        # TAB expansion
+        if char == '\t':
+            if tabsize > 0:
+                next_tab = col + (tabsize - (col % tabsize))
+                while col < next_tab:
+                    if start <= col < end:
+                        output.append(' ')
+                        if propagate_sgr and sgr_at_clip_start is None:
+                            sgr_at_clip_start = sgr
+                    col += 1
+            else:
+                output.append(char)
+            idx += 1
+            continue
+
+        # Grapheme clustering for everything else
+        grapheme = next(iter_graphemes(text, start=idx))
+        w = width(grapheme, ambiguous_width=ambiguous_width)
+
+        if w == 0:
+            if start <= col < end:
+                output.append(grapheme)
+        elif col >= start and col + w <= end:
+            # Fully visible
+            output.append(grapheme)
+            if propagate_sgr and sgr_at_clip_start is None:
+                sgr_at_clip_start = sgr
+            col += w
+        elif col < end and col + w > start:
+            # Partially visible (wide char at boundary)
+            output.append(fillchar * (min(end, col + w) - max(start, col)))
+            if propagate_sgr and sgr_at_clip_start is None:
+                sgr_at_clip_start = sgr
+            col += w
+        else:
+            col += w
+
+        idx += len(grapheme)
+
+    result = ''.join(output)
+
+    # Apply SGR prefix/suffix
+    if sgr_at_clip_start is not None:
+        if prefix := _sgr_state_to_sequence(sgr_at_clip_start):
+            result = prefix + result
+        if _sgr_state_is_active(sgr_at_clip_start):
+            result += '\x1b[0m'
+
+    return result