File: Contracts\StackWalk\Context\X86\GCInfoDecoding\InfoHdr.cs
Web Access
Project: src\src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.


using System;
using System.Collections.Immutable;
using System.Diagnostics;

namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers.X86;

/// <summary>
/// based on <a href="https://github.com/dotnet/runtime/blob/main/src/coreclr/inc/gcinfotypes.h">src\inc\gcinfotypes.h</a> InfoHdrSmall
/// </summary>
public struct InfoHdr
{
    /* Fields set by the initial table encoding */
    public byte PrologSize { get; private set; }
    public byte EpilogSize { get; private set; }

    public byte EpilogCount { get; private set; }
    public bool EpilogAtEnd { get; private set; }
    public bool EdiSaved { get; private set; }
    public bool EsiSaved { get; private set; }
    public bool EbxSaved { get; private set; }
    public bool EbpSaved { get; private set; }

    public bool EbpFrame { get; private set; }
    public bool Interruptible { get; private set; }
    public bool DoubleAlign { get; private set; }
    public bool Security { get; private set; }
    public bool Handlers { get; private set; }
    public bool LocalAlloc { get; private set; }
    public bool EditAndContinue { get; private set; }
    public bool VarArgs { get; private set; }

    public bool ProfCallbacks { get; private set; }
    public bool GenericsContext { get; private set; }
    public bool GenericsContextIsMethodDesc { get; private set; }
    public ReturnKinds ReturnKind { get; private set; }

    public ushort ArgCount { get; private set; }
    public uint FrameSize { get; private set; }
    public uint UntrackedCount { get; private set; }
    public uint VarPtrTableSize { get; private set; }

    /* Fields not set by the initial table encoding */
    public uint GsCookieOffset { get; private set; } = 0;
    public uint SyncStartOffset { get; private set; } = 0;
    public uint SyndEndOffset { get; private set; } = 0;
    public uint RevPInvokeOffset { get; private set; } = INVALID_REV_PINVOKE_OFFSET;
    public uint NoGCRegionCount { get; private set; } = 0;

    public bool HasArgTabOffset { get; private set; }
    public uint ArgTabOffset { get; private set; }
    public ImmutableArray<int> Epilogs { get; private set; }

    #region Adjustments

    private const byte SET_FRAMESIZE_MAX = 7;
    private const byte SET_ARGCOUNT_MAX = 8;
    private const byte SET_PROLOGSIZE_MAX = 16;
    private const byte SET_EPILOGSIZE_MAX = 10;
    private const byte SET_EPILOGCNT_MAX = 4;
    private const byte SET_UNTRACKED_MAX = 3;
    private const byte SET_RET_KIND_MAX = 3;        // 2 bits for ReturnKind
    private const byte SET_NOGCREGIONS_MAX = 4;
    private const byte ADJ_ENCODING_MAX = 0x7f;     // Maximum valid encoding in a byte
                                                    // Also used to mask off next bit from each encoding byte.
    private const byte MORE_BYTES_TO_FOLLOW = 0x80; // If the High-bit of a header or adjustment byte
                                                    // is set, then there are more adjustments to follow.

    /// <summary>
    // Enum to define codes that are used to incrementally adjust the InfoHdr structure.
    // First set of opcodes
    /// </summary>
    private enum InfoHdrAdjust : byte
    {

        SET_FRAMESIZE = 0, // 0x00
        SET_ARGCOUNT = SET_FRAMESIZE + SET_FRAMESIZE_MAX + 1, // 0x08
        SET_PROLOGSIZE = SET_ARGCOUNT + SET_ARGCOUNT_MAX + 1, // 0x11
        SET_EPILOGSIZE = SET_PROLOGSIZE + SET_PROLOGSIZE_MAX + 1, // 0x22
        SET_EPILOGCNT = SET_EPILOGSIZE + SET_EPILOGSIZE_MAX + 1, // 0x2d
        SET_UNTRACKED = SET_EPILOGCNT + (SET_EPILOGCNT_MAX + 1) * 2, // 0x37

        FIRST_FLIP = SET_UNTRACKED + SET_UNTRACKED_MAX + 1,

        FLIP_EDI_SAVED = FIRST_FLIP, // 0x3b
        FLIP_ESI_SAVED,           // 0x3c
        FLIP_EBX_SAVED,           // 0x3d
        FLIP_EBP_SAVED,           // 0x3e
        FLIP_EBP_FRAME,           // 0x3f
        FLIP_INTERRUPTIBLE,       // 0x40
        FLIP_DOUBLE_ALIGN,        // 0x41
        FLIP_SECURITY,            // 0x42
        FLIP_HANDLERS,            // 0x43
        FLIP_LOCALLOC,            // 0x44
        FLIP_EDITnCONTINUE,       // 0x45
        FLIP_VAR_PTR_TABLE_SZ,    // 0x46 Flip whether a table-size exits after the header encoding
        FFFF_UNTRACKED_CNT,       // 0x47 There is a count (>SET_UNTRACKED_MAX) after the header encoding
        FLIP_VARARGS,             // 0x48
        FLIP_PROF_CALLBACKS,      // 0x49
        FLIP_HAS_GS_COOKIE,       // 0x4A - The offset of the GuardStack cookie follows after the header encoding
        FLIP_SYNC,                // 0x4B
        FLIP_HAS_GENERICS_CONTEXT, // 0x4C
        FLIP_GENERICS_CONTEXT_IS_METHODDESC, // 0x4D
        FLIP_REV_PINVOKE_FRAME,   // 0x4E
        NEXT_OPCODE,              // 0x4F -- see next Adjustment enumeration
        NEXT_FOUR_START = 0x50,
        NEXT_FOUR_FRAMESIZE = 0x50,
        NEXT_FOUR_ARGCOUNT = 0x60,
        NEXT_THREE_PROLOGSIZE = 0x70,
        NEXT_THREE_EPILOGSIZE = 0x78
    };

    /// <summary>
    // Enum to define codes that are used to incrementally adjust the InfoHdr structure.
    // Second set of opcodes, when first code is 0x4F
    /// </summary>
    private enum InfoHdrAdjust2 : uint
    {
        SET_RETURNKIND = 0,  // 0x00-SET_RET_KIND_MAX Set ReturnKind to value
        SET_NOGCREGIONS_CNT = SET_RETURNKIND + SET_RET_KIND_MAX + 1,        // 0x04
        FFFF_NOGCREGION_CNT = SET_NOGCREGIONS_CNT + SET_NOGCREGIONS_MAX + 1 // 0x09 There is a count (>SET_NOGCREGIONS_MAX) after the header encoding
    };

    public enum ReturnKinds
    {
        RT_Scalar = 0,
        RT_Object = 1,
        RT_ByRef = 2,
        RT_Unset = 3, // Encoding 3 means RT_Float on X86
        RT_Scalar_Obj = RT_Object << 2 | RT_Scalar,
        RT_Scalar_ByRef = RT_ByRef << 2 | RT_Scalar,

        RT_Obj_Obj = RT_Object << 2 | RT_Object,
        RT_Obj_ByRef = RT_ByRef << 2 | RT_Object,

        RT_ByRef_Obj = RT_Object << 2 | RT_ByRef,
        RT_ByRef_ByRef = RT_ByRef << 2 | RT_ByRef,

        RT_Illegal = 0xFF
    };

    public static InfoHdr DecodeHeader(Target target, ref TargetPointer offset, uint codeLength)
    {
        byte nextByte = target.Read<byte>(offset++);
        byte encoding = (byte)(nextByte & 0x7Fu);

        if (encoding < 0 || encoding >= INFO_HDR_TABLE.Length)
        {
            throw new InvalidOperationException("Table encoding is invalid.");
        }

        InfoHdr infoHdr = INFO_HDR_TABLE[encoding];

        while ((nextByte & MORE_BYTES_TO_FOLLOW) != 0)
        {
            nextByte = target.Read<byte>(offset++);
            encoding = (byte)(nextByte & ADJ_ENCODING_MAX);

            if (encoding < (uint)InfoHdrAdjust.NEXT_FOUR_START)
            {
                if (encoding < (uint)InfoHdrAdjust.SET_ARGCOUNT)
                {
                    infoHdr.FrameSize = (byte)(encoding - (uint)InfoHdrAdjust.SET_FRAMESIZE);
                }
                else if (encoding < (uint)InfoHdrAdjust.SET_PROLOGSIZE)
                {
                    infoHdr.ArgCount = (byte)(encoding - (uint)InfoHdrAdjust.SET_ARGCOUNT);
                }
                else if (encoding < (uint)InfoHdrAdjust.SET_EPILOGSIZE)
                {
                    infoHdr.PrologSize = (byte)(encoding - (uint)InfoHdrAdjust.SET_PROLOGSIZE);
                }
                else if (encoding < (uint)InfoHdrAdjust.SET_EPILOGCNT)
                {
                    infoHdr.EpilogSize = (byte)(encoding - (uint)InfoHdrAdjust.SET_EPILOGSIZE);
                }
                else if (encoding < (uint)InfoHdrAdjust.SET_UNTRACKED)
                {
                    infoHdr.EpilogCount = (byte)((encoding - (uint)InfoHdrAdjust.SET_EPILOGCNT) / 2);
                    infoHdr.EpilogAtEnd = ((encoding - (uint)InfoHdrAdjust.SET_EPILOGCNT) & 1) == 1 ? true : false;
                    Debug.Assert(!infoHdr.EpilogAtEnd || infoHdr.EpilogCount == 1);
                }
                else if (encoding < (uint)InfoHdrAdjust.FIRST_FLIP)
                {
                    infoHdr.UntrackedCount = (byte)(encoding - (uint)InfoHdrAdjust.SET_UNTRACKED);
                }
                else
                {
                    switch (encoding)
                    {
                        case (byte)InfoHdrAdjust.FLIP_EDI_SAVED:
                            infoHdr.EdiSaved = !infoHdr.EdiSaved;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_ESI_SAVED:
                            infoHdr.EsiSaved = !infoHdr.EsiSaved;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_EBX_SAVED:
                            infoHdr.EbxSaved = !infoHdr.EbxSaved;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_EBP_SAVED:
                            infoHdr.EbpSaved = !infoHdr.EbpSaved;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_EBP_FRAME:
                            infoHdr.EbpFrame = !infoHdr.EbpFrame;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_INTERRUPTIBLE:
                            infoHdr.Interruptible = !infoHdr.Interruptible;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_DOUBLE_ALIGN:
                            infoHdr.DoubleAlign = !infoHdr.DoubleAlign;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_SECURITY:
                            infoHdr.Security = !infoHdr.Security;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_HANDLERS:
                            infoHdr.Handlers = !infoHdr.Handlers;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_LOCALLOC:
                            infoHdr.LocalAlloc = !infoHdr.LocalAlloc;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_EDITnCONTINUE:
                            infoHdr.EditAndContinue = !infoHdr.EditAndContinue;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_VAR_PTR_TABLE_SZ:
                            infoHdr.VarPtrTableSize ^= HAS_VARPTR;
                            break;
                        case (byte)InfoHdrAdjust.FFFF_UNTRACKED_CNT:
                            infoHdr.UntrackedCount = HAS_UNTRACKED;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_VARARGS:
                            infoHdr.VarArgs = !infoHdr.VarArgs;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_PROF_CALLBACKS:
                            infoHdr.ProfCallbacks = !infoHdr.ProfCallbacks;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_HAS_GENERICS_CONTEXT:
                            infoHdr.GenericsContext = !infoHdr.GenericsContext;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_GENERICS_CONTEXT_IS_METHODDESC:
                            infoHdr.GenericsContextIsMethodDesc = !infoHdr.GenericsContextIsMethodDesc;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_HAS_GS_COOKIE:
                            infoHdr.GsCookieOffset ^= HAS_GS_COOKIE_OFFSET;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_SYNC:
                            infoHdr.SyncStartOffset ^= HAS_SYNC_OFFSET;
                            break;
                        case (byte)InfoHdrAdjust.FLIP_REV_PINVOKE_FRAME:
                            infoHdr.RevPInvokeOffset ^= INVALID_REV_PINVOKE_OFFSET ^ HAS_REV_PINVOKE_FRAME_OFFSET;
                            break;

                        case (byte)InfoHdrAdjust.NEXT_OPCODE:
                            nextByte = target.Read<byte>(offset++);
                            encoding = (byte)(nextByte & ADJ_ENCODING_MAX);

                            // encoding here always corresponds to codes in InfoHdrAdjust2 set
                            if (encoding <= SET_RET_KIND_MAX)
                            {
                                infoHdr.ReturnKind = (ReturnKinds)encoding;
                            }
                            else if (encoding < (int)InfoHdrAdjust2.FFFF_NOGCREGION_CNT)
                            {
                                infoHdr.NoGCRegionCount = (uint)encoding - (uint)InfoHdrAdjust2.SET_NOGCREGIONS_CNT;
                            }
                            else if (encoding == (int)InfoHdrAdjust2.FFFF_NOGCREGION_CNT)
                            {
                                infoHdr.NoGCRegionCount = HAS_NOGCREGIONS;
                            }
                            else
                            {
                                throw new BadImageFormatException("Unexpected gcinfo header encoding");
                            }
                            break;
                        default:
                            throw new BadImageFormatException("Unexpected gcinfo header encoding");
                    }
                }
            }
            else
            {
                byte lowBits;
                switch (encoding >> 4)
                {
                    case 5:
                        lowBits = (byte)(encoding & 0xf);
                        infoHdr.FrameSize <<= 4;
                        infoHdr.FrameSize += lowBits;
                        break;
                    case 6:
                        lowBits = (byte)(encoding & 0xf);
                        infoHdr.ArgCount <<= 4;
                        infoHdr.ArgCount += lowBits;
                        break;
                    case 7:
                        if ((encoding & 0x8) == 0)
                        {
                            lowBits = (byte)(encoding & 0x7);
                            infoHdr.PrologSize <<= 3;
                            infoHdr.PrologSize += lowBits;
                        }
                        else
                        {
                            lowBits = (byte)(encoding & 0x7);
                            infoHdr.EpilogSize <<= 3;
                            infoHdr.EpilogSize += lowBits;
                        }
                        break;
                    default:
                        throw new BadImageFormatException("Unexpected gcinfo header encoding");
                }
            }
        }

        if (infoHdr.UntrackedCount == HAS_UNTRACKED)
        {
            infoHdr.HasArgTabOffset = true;
            infoHdr.UntrackedCount = target.GCDecodeUnsigned(ref offset);
        }
        if (infoHdr.VarPtrTableSize == HAS_VARPTR)
        {
            infoHdr.HasArgTabOffset = true;
            infoHdr.VarPtrTableSize = target.GCDecodeUnsigned(ref offset);
        }
        if (infoHdr.GsCookieOffset == HAS_GS_COOKIE_OFFSET)
        {
            infoHdr.GsCookieOffset = target.GCDecodeUnsigned(ref offset);
        }
        if (infoHdr.SyncStartOffset == HAS_SYNC_OFFSET)
        {
            infoHdr.SyncStartOffset = target.GCDecodeUnsigned(ref offset);
            infoHdr.SyndEndOffset = target.GCDecodeUnsigned(ref offset);
        }
        if (infoHdr.RevPInvokeOffset == HAS_REV_PINVOKE_FRAME_OFFSET)
        {
            infoHdr.RevPInvokeOffset = target.GCDecodeUnsigned(ref offset);
        }
        if (infoHdr.NoGCRegionCount == HAS_NOGCREGIONS)
        {
            infoHdr.HasArgTabOffset = true;
            infoHdr.NoGCRegionCount = target.GCDecodeUnsigned(ref offset);
        }
        else if (infoHdr.NoGCRegionCount > 0)
        {
            infoHdr.HasArgTabOffset = true;
        }

        ImmutableArray<int>.Builder epilogsBuilder = ImmutableArray.CreateBuilder<int>();
        if (infoHdr.EpilogCount > 1 || (infoHdr.EpilogCount != 0 && !infoHdr.EpilogAtEnd))
        {
            uint offs = 0;

            for (int i = 0; i < infoHdr.EpilogCount; i++)
            {
                offs = target.GCDecodeUDelta(ref offset, offs);
                epilogsBuilder.Add((int)offs);
            }
        }
        else
        {
            if (infoHdr.EpilogCount != 0)
                epilogsBuilder.Add((int)(codeLength - infoHdr.EpilogSize));
        }
        infoHdr.Epilogs = epilogsBuilder.ToImmutable();

        if (infoHdr.HasArgTabOffset)
        {
            infoHdr.ArgTabOffset = target.GCDecodeUnsigned(ref offset);
        }

        /* Sanity Checks */
        Debug.Assert(infoHdr.PrologSize + (infoHdr.EpilogCount * infoHdr.EpilogSize) <= codeLength);
        Debug.Assert(infoHdr.EpilogCount == 1 || !infoHdr.EpilogAtEnd);

        Debug.Assert(infoHdr.UntrackedCount <= infoHdr.ArgCount + infoHdr.FrameSize);

        Debug.Assert(infoHdr.EbpSaved || !(infoHdr.EbpFrame || infoHdr.DoubleAlign));
        Debug.Assert(!infoHdr.EbpFrame || !infoHdr.DoubleAlign);
        Debug.Assert(infoHdr.EbpFrame || !infoHdr.Security);
        Debug.Assert(infoHdr.EbpFrame || !infoHdr.Handlers);
        Debug.Assert(infoHdr.EbpFrame || !infoHdr.LocalAlloc);
        Debug.Assert(infoHdr.EbpFrame || !infoHdr.EditAndContinue);

        return infoHdr;
    }

    #endregion
    #region EncodingTable

    public const uint HAS_VARPTR = 0xFFFFFFFF;
    public const uint HAS_UNTRACKED = 0xFFFFFFFF;
    public const uint HAS_GS_COOKIE_OFFSET = 0xFFFFFFFF;
    public const uint HAS_SYNC_OFFSET = 0xFFFFFFFF;
    public const uint INVALID_REV_PINVOKE_OFFSET = unchecked((uint)-1);
    public const uint HAS_REV_PINVOKE_FRAME_OFFSET = unchecked((uint)-2);
    public const uint HAS_NOGCREGIONS = 0xFFFFFFFF;
    private const uint YES = HAS_VARPTR;

    private InfoHdr(
        byte prologSize,
        byte epilogSize,
        byte epilogCount,
        byte epilogAtEnd,
        byte ediSaved,
        byte esiSaved,
        byte ebxSaved,
        byte ebpSaved,
        byte ebpFrame,
        byte interruptible,
        byte doubleAlign,
        byte security,
        byte handlers,
        byte localAlloc,
        byte editAndContinue,
        byte varArgs,
        byte profCallbacks,
        byte genericsContext,
        byte genericsContextIsMethodDesc,
        byte returnKind,
        ushort argCount,
        uint frameSize,
        uint untrackedCount,
        uint varPtrTableSize)
    {
        PrologSize = prologSize;
        EpilogSize = epilogSize;
        EpilogCount = epilogCount;
        EpilogAtEnd = epilogAtEnd == 1;
        EdiSaved = ediSaved == 1;
        EsiSaved = esiSaved == 1;
        EbxSaved = ebxSaved == 1;
        EbpSaved = ebpSaved == 1;

        EbpFrame = ebpFrame == 1;
        Interruptible = interruptible == 1;
        DoubleAlign = doubleAlign == 1;
        Security = security == 1;
        Handlers = handlers == 1;
        LocalAlloc = localAlloc == 1;
        EditAndContinue = editAndContinue == 1;
        VarArgs = varArgs == 1;

        ProfCallbacks = profCallbacks == 1;
        GenericsContext = genericsContext == 1;
        GenericsContextIsMethodDesc = genericsContextIsMethodDesc == 1;
        ReturnKind = (ReturnKinds)returnKind;

        ArgCount = argCount;
        FrameSize = frameSize;
        UntrackedCount = untrackedCount;
        VarPtrTableSize = varPtrTableSize;

        HasArgTabOffset = false;
        ArgTabOffset = 0;
        Epilogs = [];
    }

    private static InfoHdr[] INFO_HDR_TABLE =
    {
    //        Prolog size
    //        |
    //        |   Epilog size
    //        |   |
    //        |   |  Epilog count
    //        |   |  |
    //        |   |  |  Epilog at end
    //        |   |  |  |
    //        |   |  |  |  EDI saved
    //        |   |  |  |  |
    //        |   |  |  |  |  ESI saved
    //        |   |  |  |  |  |
    //        |   |  |  |  |  |  EBX saved
    //        |   |  |  |  |  |  |
    //        |   |  |  |  |  |  |  EBP saved
    //        |   |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  EBP-frame
    //        |   |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  Interruptible method
    //        |   |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  doubleAlign
    //        |   |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  security flag
    //        |   |  |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  |  handlers
    //        |   |  |  |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  localloc
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  edit and continue
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  varargs
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  ProfCallbacks
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  genericsContext
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  genericsContextIsMethodDesc
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  returnKind
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  Arg count
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |                                 Counted occurrences
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   Frame size                    |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |                             |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   untrackedCnt              |   Header encoding
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |                         |   |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |  varPtrTable            |   |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |                     |   |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |  gsCookieOffs       |   |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |                 |   |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   | syncOffs        |   |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |  |  |           |   |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |  |  |           |   |
    //        |   |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   |   |   |   |  |  |           |   |
    //        v   v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v  v   v   v   v   v  v  v           v   v
        new(  0,  1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    1139  00
        new(  0,  1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //  128738  01
        new(  0,  1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    3696  02
        new(  0,  1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     402  03
        new(  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //    4259  04
        new(  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          ),  //    3379  05
        new(  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          ),  //    2058  06
        new(  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  1,  0          ),  //     728  07
        new(  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  2,  0          ),  //     984  08
        new(  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,  0,  0,  0          ),  //     606  09
        new(  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,  0,  0,  0          ),  //    1110  0a
        new(  0,  3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,  0,  1,  0          ),  //     414  0b
        new(  1,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //    1553  0c
        new(  1,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  1,  0, YES         ),  //     584  0d
        new(  1,  2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //    2182  0e
        new(  1,  2, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    3445  0f
        new(  1,  2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //    1369  10
        new(  1,  2, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     515  11
        new(  1,  2, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //   21127  12
        new(  1,  2, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    3517  13
        new(  1,  2, 3, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     750  14
        new(  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //    1876  15
        new(  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          ),  //    1665  16
        new(  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          ),  //     729  17
        new(  1,  4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  2,  0          ),  //     484  18
        new(  1,  4, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //     331  19
        new(  2,  3, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //     361  1a
        new(  2,  3, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     964  1b
        new(  2,  3, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    3713  1c
        new(  2,  3, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     466  1d
        new(  2,  3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //    1325  1e
        new(  2,  3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //     712  1f
        new(  2,  3, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     588  20
        new(  2,  3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //   20542  21
        new(  2,  3, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    3802  22
        new(  2,  3, 3, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     798  23
        new(  2,  5, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //    1900  24
        new(  2,  5, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          ),  //     385  25
        new(  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //    1617  26
        new(  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          ),  //    1743  27
        new(  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          ),  //     909  28
        new(  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  1,  0          ),  //     602  29
        new(  2,  5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  2,  0          ),  //     352  2a
        new(  2,  6, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //     657  2b
        new(  2,  7, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, YES         ),  //    1283  2c
        new(  2,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //    1286  2d
        new(  3,  4, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //    1495  2e
        new(  3,  4, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    1989  2f
        new(  3,  4, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //    1154  30
        new(  3,  4, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    9300  31
        new(  3,  4, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //     392  32
        new(  3,  4, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    1720  33
        new(  3,  6, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //    1246  34
        new(  3,  6, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          ),  //     800  35
        new(  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //    1179  36
        new(  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          ),  //    1368  37
        new(  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          ),  //     349  38
        new(  3,  6, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  2,  0          ),  //     505  39
        new(  3,  6, 2, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //     629  3a
        new(  3,  8, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  9,  2, YES         ),  //     365  3b
        new(  4,  5, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //     487  3c
        new(  4,  5, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    1752  3d
        new(  4,  5, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //    1959  3e
        new(  4,  5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    2436  3f
        new(  4,  5, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     861  40
        new(  4,  7, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //    1459  41
        new(  4,  7, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          ),  //     950  42
        new(  4,  7, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //    1491  43
        new(  4,  7, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  1,  0          ),  //     879  44
        new(  4,  7, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  0,  0,  0          ),  //     408  45
        new(  5,  4, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //    4870  46
        new(  5,  6, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //     359  47
        new(  5,  6, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          ),  //     915  48
        new(  5,  6, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0,  0          ),  //     412  49
        new(  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //    1288  4a
        new(  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //    1591  4b
        new(  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  1,  0, YES         ),  //     361  4c
        new(  5,  6, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  1,  0,  0          ),  //     623  4d
        new(  5,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  1,  0,  0          ),  //    1239  4e
        new(  6,  0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     457  4f
        new(  6,  0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     606  50
        new(  6,  4, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0, YES         ),  //    1073  51
        new(  6,  4, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0, YES         ),  //     508  52
        new(  6,  6, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //     330  53
        new(  6,  6, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //    1709  54
        new(  6,  7, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          ),  //    1164  55
        new(  7,  4, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0          ),  //     556  56
        new(  7,  5, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  3,  0, YES         ),  //     529  57
        new(  7,  5, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  5,  0, YES         ),  //    1423  58
        new(  7,  8, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  3,  0, YES         ),  //    2455  59
        new(  7,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          ),  //     956  5a
        new(  7,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0, YES         ),  //    1399  5b
        new(  7,  8, 2, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  3,  0, YES         ),  //     587  5c
        new(  7, 10, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  6,  1, YES         ),  //     743  5d
        new(  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  2,  0,  0          ),  //    1004  5e
        new(  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  2,  1, YES         ),  //     487  5f
        new(  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  2,  0,  0          ),  //     337  60
        new(  7, 10, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  3,  0, YES         ),  //     361  61
        new(  8,  3, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  1,  0          ),  //     560  62
        new(  8,  6, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          ),  //    1377  63
        new(  9,  4, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  1,  0          ),  //     877  64
        new(  9,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  0,  0          ),  //    3041  65
        new(  9,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, YES         ),  //     349  66
        new( 10,  5, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  4,  1,  0          ),  //    2061  67
        new( 10,  5, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  1,  0          ),  //     577  68
        new( 11,  6, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  4,  1,  0          ),  //    1195  69
        new( 12,  5, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0,  0          ),  //     491  6a
        new( 13,  8, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  9,  0, YES         ),  //     627  6b
        new( 13,  8, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  2,  1,  0          ),  //    1099  6c
        new( 13, 10, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,  6,  1, YES         ),  //     488  6d
        new( 14,  7, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //     574  6e
        new( 16,  7, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0, YES         ),  //    1281  6f
        new( 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, YES         ),  //    1881  70
        new( 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //     339  71
        new( 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  3,  0,  0          ),  //    2594  72
        new( 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0,  0          ),  //     339  73
        new( 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0, YES         ),  //    2107  74
        new( 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  5,  0, YES         ),  //    2372  75
        new( 16,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  6,  0, YES         ),  //    1078  76
        new( 16,  7, 2, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  4,  0, YES         ),  //     384  77
        new( 16,  9, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,  4,  1, YES         ),  //    1541  78
        new( 16,  9, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2,  4,  1, YES         ),  //     975  79
        new( 19,  7, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  5,  0, YES         ),  //     546  7a
        new( 24,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,  5,  0, YES         ),  //     675  7b
        new( 45,  9, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  0,  0,  0          ),  //     902  7c
        new( 51,  7, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13,  0, YES         ),  //     432  7d
        new( 51,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  1,  0, YES         ),  //     361  7e
        new( 51,  7, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11,  0,  0          ),  //     703  7f
    };

    #endregion
};