using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Codecrete")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) Manuel Bleichenbacher and Project Nayuki (MIT License)")] [assembly: AssemblyDescription("QR Code Generator for .NET – simple, compact and with many examples.\r\n\r\nCore features:\r\n- Supports encoding all 40 versions (sizes) and all 4 error correction levels, as per the QR Code Model 2 standard\r\n- Output formats: Raw modules/pixels of the QR symbol, SVG, XAML path, PNG and BMP files. For other raster bitmap formats, see project home page.\r\n- Encodes numeric and special-alphanumeric text in less space than general text\r\n- Open source code under the permissive MIT License\r\n- Built for .NET Standard 2.0 and therefore runs on most modern .NET platforms (.NET Core, .NET Framework, Mono etc.).\r\n- Example code for WinForms, WPF, ASP.NET, ImageSharp, SkiaSharp and many more\r\n\r\nManual parameters:\r\n- You can specify the minimum and maximum version number allowed, and the library will automatically choose the smallest version in the range that fits the data.\r\n- You can specify the mask pattern manually, otherwise library will automatically evaluate all 8 masks and select the optimal one.\r\n- You can specify an error correction level, or optionally allow the library to boost it if it doesn't increase the version number.\r\n- You can create a list of data segments manually and add ECI segments.\r\n\r\nOptional advanced features:\r\n- Long text can be split into multiple linked QR codes (aka Structured Append)\r\n- Encodes Japanese Unicode text in Kanji mode to save a lot of space compared to UTF-8 bytes\r\n- Computes optimal segment mode switching for text with mixed numeric/alphanumeric/general/kanji parts\r\n")] [assembly: AssemblyFileVersion("2.0.1.0")] [assembly: AssemblyInformationalVersion("2.1.0+d75ad20b2f2c04a41120c3e7c7326842fc837fcc")] [assembly: AssemblyProduct("QR Code Generator for .NET")] [assembly: AssemblyTitle("QrCodeGenerator")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/manuelbl/QrCodeGenerator")] [assembly: AssemblyVersion("1.6.0.0")] namespace Net.Codecrete.QrCodeGenerator; public static class BitArrayExtensions { public static void AppendBits(this BitArray bitArray, uint val, int len) { if (len < 0 || len > 31) { throw new ArgumentOutOfRangeException("len", "'len' out of range"); } if (val >> len != 0) { throw new ArgumentOutOfRangeException("val", "'val' out of range"); } int length = bitArray.Length; bitArray.Length = length + len; uint num = (uint)(1 << len - 1); for (int i = length; i < length + len; i++) { if ((val & num) != 0) { bitArray.Set(i, value: true); } num >>= 1; } } public static void AppendData(this BitArray bitArray, BitArray otherArray) { Objects.RequireNonNull(otherArray); int num = bitArray.Length; bitArray.Length = num + otherArray.Length; int num2 = 0; while (num2 < otherArray.Length) { if (otherArray[num2]) { bitArray.Set(num, value: true); } num2++; num++; } } public static uint ExtractBits(this BitArray bitArray, int index, int len) { if (len < 0 || len > 31) { throw new ArgumentOutOfRangeException("len", "'len' out of range"); } if (index < 0 || index + len > bitArray.Length) { throw new ArgumentOutOfRangeException("index", "'index' out of range"); } uint num = 0u; for (int i = 0; i < len; i++) { num <<= 1; if (bitArray.Get(index + i)) { num |= 1u; } } return num; } } public class DataTooLongException : ArgumentException { public DataTooLongException(string message) : base(message) { } } internal class Graphics { private readonly int _size; private readonly bool[,] _modules; internal Graphics(int size, bool[,] modules) { _size = size; _modules = modules; } internal string ToSvgString(int border, string foreground, string background) { if (border < 0) { throw new ArgumentOutOfRangeException("border", "Border must be non-negative"); } int num = _size + border * 2; StringBuilder stringBuilder = new StringBuilder().Append("\n").Append("\n").Append($"\n") .Append("\t\n") .Append("\t\n").Append("\n").ToString(); } internal string ToGraphicsPath(int border) { if (border < 0) { throw new ArgumentOutOfRangeException("border", "Border must be non-negative"); } bool[,] modules = CopyModules(); StringBuilder stringBuilder = new StringBuilder(); CreatePath(stringBuilder, modules, border); return stringBuilder.ToString(); } internal byte[] ToBmpBitmap(int border, int scale, int foreground, int background) { if (scale < 1) { throw new ArgumentOutOfRangeException("scale", scale, "Scale must be greater than 0."); } if (border < 0) { throw new ArgumentOutOfRangeException("border", border, "Border must be non-negative."); } int num = (_size + 2 * border) * scale; if (num > 32767) { throw new ArgumentOutOfRangeException("scale", "Scale or border too large."); } int num2 = (num - 1 >> 3) + 1; int num3 = (num2 + 3) & -4; int num4 = 62 + num * num3; byte[] array = new byte[num4]; array[0] = 66; array[1] = 77; array[2] = (byte)num4; array[3] = (byte)(num4 >> 8); array[4] = (byte)(num4 >> 16); array[5] = (byte)(num4 >> 24); array[10] = 62; array[14] = 40; array[18] = (byte)num; array[19] = (byte)(num >> 8); array[20] = (byte)(num >> 16); array[21] = (byte)(num >> 24); array[22] = array[18]; array[23] = array[19]; array[24] = array[20]; array[25] = array[21]; array[26] = 1; array[28] = 1; array[38] = 196; array[39] = 14; array[42] = array[38]; array[43] = array[39]; array[54] = (byte)foreground; array[55] = (byte)(foreground >> 8); array[56] = (byte)(foreground >> 16); array[58] = (byte)background; array[59] = (byte)(background >> 8); array[60] = (byte)(background >> 16); int num5 = border * scale; if (border > 0) { int num6 = _size * scale; for (int i = 0; i < num3; i++) { byte b = byte.MaxValue; if (i == num2 - 1) { b = (byte)(255 << (num2 << 3) - num); } else if (i >= num2) { b = 0; } for (int j = 0; j < num5; j++) { array[62 + i + j * num3] = b; array[62 + i + (j + num6 + num5) * num3] = b; } } } for (int j = 0; j < _size; j++) { int num7 = j * scale + num5; for (int i = 0; i < num3; i++) { byte b = 0; for (int k = 0; k < 8; k++) { int num8 = ((i << 3) + k) / scale; if (num8 < num) { b = ((num8 >= border && num8 < _size + border) ? ((byte)(b | (byte)((!_modules[_size - j - 1, num8 - border]) ? ((uint)(1 << 7 - k)) : 0u))) : ((byte)(b | (byte)(1 << 7 - k)))); } } array[62 + i + num7 * num3] = b; } for (int i = 1; i <= scale - 1; i++) { for (int k = 0; k < num3; k++) { array[62 + k + (num7 + i) * num3] = array[62 + k + num7 * num3]; } } } return array; } private static void CreatePath(StringBuilder path, bool[,] modules, int border) { int length = modules.GetLength(0); for (int i = 0; i < length; i++) { for (int j = 0; j < length; j++) { if (modules[i, j]) { DrawLargestRectangle(path, modules, j, i, border); } } } } private static void DrawLargestRectangle(StringBuilder path, bool[,] modules, int x, int y, int border) { int length = modules.GetLength(0); int num = 1; int num2 = 1; int num3 = 1; int num4 = length; for (int i = y; i < length && modules[i, x]; i++) { int j; for (j = 0; x + j < num4 && modules[i, x + j]; j++) { } int num5 = j * (i - y + 1); if (num5 > num3) { num3 = num5; num = j; num2 = i - y + 1; } num4 = x + j; } if (x != 0 || y != 0) { path.Append(' '); } FormattableString formattableString = $"M{x + border},{y + border}h{num}v{num2}h{-num}z"; path.Append(formattableString.ToString(CultureInfo.InvariantCulture)); ClearRectangle(modules, x, y, num, num2); } private static void ClearRectangle(bool[,] modules, int x, int y, int width, int height) { for (int i = y; i < y + height; i++) { for (int j = x; j < x + width; j++) { modules[i, j] = false; } } } private bool[,] CopyModules() { bool[,] array = new bool[_size, _size]; for (int i = 0; i < _size; i++) { for (int j = 0; j < _size; j++) { array[i, j] = _modules[i, j]; } } return array; } } internal static class Objects { internal static T RequireNonNull(T arg) { if (arg == null) { throw new ArgumentNullException(); } return arg; } } internal sealed class PngBuilder { private static readonly byte[] Signature = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 }; private static readonly uint[] CrcTable = new uint[256] { 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u }; private static readonly byte[] IHDR = new byte[4] { 73, 72, 68, 82 }; private static readonly byte[] PLTE = new byte[4] { 80, 76, 84, 69 }; private static readonly byte[] IDAT = new byte[4] { 73, 68, 65, 84 }; private static readonly byte[] IEND = new byte[4] { 73, 69, 78, 68 }; private readonly MemoryStream stream = new MemoryStream(); internal static byte[] ToImage(QrCode qrCode, int scale, int border, int foreground, int background) { int num = (qrCode.Size + border * 2) * scale; PngBuilder pngBuilder = new PngBuilder(); pngBuilder.WriteHeader(num, num, 1, 3); pngBuilder.WritePalette(new int[2] { background, foreground }); pngBuilder.WriteData(CreateBitmap(qrCode, border, scale)); pngBuilder.WriteEnd(); return pngBuilder.GetBytes(); } private static byte[] CreateBitmap(QrCode qrCode, int border, int scale) { int size = qrCode.Size; int num = (size + border * 2) * scale; int num2 = (num + 7) / 8 + 1; byte[] array = new byte[num2 * num]; for (int i = 0; i < size; i++) { int num3 = (border + i) * scale * num2; for (int j = 0; j < size; j++) { if (qrCode.GetModule(j, i)) { int k = (border + j) * scale; for (int num4 = k + scale; k < num4; k++) { int num5 = num3 + k / 8 + 1; array[num5] |= (byte)(128 >>> k % 8); } } } for (int l = 1; l < scale; l++) { Array.Copy(array, num3, array, num3 + l * num2, num2); } } return array; } private byte[] GetBytes() { byte[] array = stream.ToArray(); SetCRC(array); return array; } private void WriteHeader(int width, int height, byte bitDepth, byte colorType) { stream.Write(Signature, 0, Signature.Length); WriteChunkStart(IHDR, 13); WriteIntBigEndian((uint)width); WriteIntBigEndian((uint)height); stream.WriteByte(bitDepth); stream.WriteByte(colorType); stream.WriteByte(0); stream.WriteByte(0); stream.WriteByte(0); WriteChunkEnd(); } private void WritePalette(int[] palette) { WriteChunkStart(PLTE, palette.Length * 3); foreach (int num in palette) { stream.WriteByte((byte)((uint)(num >> 16) & 0xFFu)); stream.WriteByte((byte)((uint)(num >> 8) & 0xFFu)); stream.WriteByte((byte)((uint)num & 0xFFu)); } WriteChunkEnd(); } private void WriteData(byte[] data) { byte[] array = Deflate(data); WriteChunkStart(IDAT, array.Length + 6); stream.WriteByte(120); stream.WriteByte(156); stream.Write(array, 0, array.Length); uint value = CalcAdler32(data, 0, data.Length); WriteIntBigEndian(value); WriteChunkEnd(); } private void WriteEnd() { WriteChunkStart(IEND, 0); WriteChunkEnd(); } private static void SetCRC(byte[] bytes) { int num = Signature.Length; while (num < bytes.Length) { int num2 = (bytes[num] << 24) | (bytes[num + 1] << 16) | (bytes[num + 2] << 8) | bytes[num + 3]; uint num3 = CalcCrc32(bytes, num + 4, num2 + 4); int num4 = num + 8 + num2; bytes[num4] = (byte)(num3 >> 24); bytes[num4 + 1] = (byte)(num3 >> 16); bytes[num4 + 2] = (byte)(num3 >> 8); bytes[num4 + 3] = (byte)num3; num = num4 + 4; } } private void WriteChunkStart(byte[] type, int length) { WriteIntBigEndian((uint)length); stream.Write(type, 0, 4); } private void WriteChunkEnd() { stream.SetLength(stream.Length + 4); stream.Position += 4L; } private void WriteIntBigEndian(uint value) { stream.WriteByte((byte)(value >> 24)); stream.WriteByte((byte)(value >> 16)); stream.WriteByte((byte)(value >> 8)); stream.WriteByte((byte)value); } private static byte[] Deflate(byte[] data) { MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionLevel.Optimal)) { deflateStream.Write(data, 0, data.Length); } return memoryStream.ToArray(); } private static uint CalcAdler32(byte[] data, int index, int length) { uint num = 1u; uint num2 = 0u; int num3 = index + length; for (int i = index; i < num3; i++) { num = (num + data[i]) % 65521; num2 = (num2 + num) % 65521; } return (num2 << 16) + num; } private static uint CalcCrc32(byte[] data, int index, int length) { uint num = uint.MaxValue; int num2 = index + length; for (int i = index; i < num2; i++) { num = CrcTable[(num ^ data[i]) & 0xFF] ^ (num >> 8); } return num ^ 0xFFFFFFFFu; } } public class QrCode { private struct FinderPenalty { private readonly short[] _runHistory; private readonly int _size; public FinderPenalty(int size) { _size = size; _runHistory = new short[7]; } internal int CountPatterns() { int num = _runHistory[1]; bool flag = num > 0 && _runHistory[2] == num && _runHistory[3] == num * 3 && _runHistory[4] == num && _runHistory[5] == num; return ((flag && _runHistory[0] >= num * 4 && _runHistory[6] >= num) ? 1 : 0) + ((flag && _runHistory[6] >= num * 4 && _runHistory[0] >= num) ? 1 : 0); } internal int TerminateAndCount(bool currentRunColor, int currentRunLength) { if (currentRunColor) { AddHistory(currentRunLength); currentRunLength = 0; } currentRunLength += _size; AddHistory(currentRunLength); return CountPatterns(); } internal void AddHistory(int currentRunLength) { if (_runHistory[0] == 0) { currentRunLength += _size; } Array.Copy(_runHistory, 0, _runHistory, 1, 6); _runHistory[0] = (short)currentRunLength; } } public sealed class Ecc { public static readonly Ecc Low = new Ecc(0, 1u); public static readonly Ecc Medium = new Ecc(1, 0u); public static readonly Ecc Quartile = new Ecc(2, 3u); public static readonly Ecc High = new Ecc(3, 2u); internal static readonly Ecc[] AllValues = new Ecc[4] { Low, Medium, Quartile, High }; public int Ordinal { get; } internal uint FormatBits { get; } private Ecc(int ordinal, uint fb) { Ordinal = ordinal; FormatBits = fb; } } private readonly bool[,] _modules; private readonly bool[,] _isFunction; public const int MinVersion = 1; public const int MaxVersion = 40; private const int PenaltyN1 = 3; private const int PenaltyN2 = 3; private const int PenaltyN3 = 40; private const int PenaltyN4 = 10; private static readonly byte[,] EccCodewordsPerBlock = new byte[4, 41] { { 255, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }, { 255, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28 }, { 255, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 }, { 255, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30 } }; private static readonly byte[,] NumErrorCorrectionBlocks = new byte[4, 41] { { 255, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25 }, { 255, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49 }, { 255, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68 }, { 255, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81 } }; public int Version { get; } public int Size { get; } public Ecc ErrorCorrectionLevel { get; } public int Mask { get; } public static QrCode EncodeText(string text, Ecc ecl) { Objects.RequireNonNull(text); Objects.RequireNonNull(ecl); return EncodeSegments(QrSegment.MakeSegments(text), ecl); } public static List EncodeTextInMultipleCodes(string text, Ecc ecl, int version = 29, bool boostEcl = true) { Objects.RequireNonNull(text); Objects.RequireNonNull(ecl); try { QrCode item = EncodeSegments(QrSegmentAdvanced.MakeSegmentsOptimally(text, ecl, version, version), ecl, version, version, -1, boostEcl); return new List { item }; } catch (DataTooLongException) { } return (from segmentList in QrSegmentAdvanced.MakeSegmentsForMultipleCodes(text, ecl, version) select EncodeSegments(segmentList, ecl, version, version, -1, boostEcl)).ToList(); } public static QrCode EncodeBinary(byte[] data, Ecc ecl) { Objects.RequireNonNull(data); Objects.RequireNonNull(ecl); QrSegment item = QrSegment.MakeBytes(data); return EncodeSegments(new List { item }, ecl); } public static QrCode EncodeSegments(List segments, Ecc ecl, int minVersion = 1, int maxVersion = 40, int mask = -1, bool boostEcl = true) { Objects.RequireNonNull(segments); Objects.RequireNonNull(ecl); if (minVersion < 1 || minVersion > maxVersion) { throw new ArgumentOutOfRangeException("minVersion", "Invalid value"); } if (maxVersion > 40) { throw new ArgumentOutOfRangeException("maxVersion", "Invalid value"); } if (mask < -1 || mask > 7) { throw new ArgumentOutOfRangeException("mask", "Invalid value"); } int num = minVersion; int totalBits; while (true) { int num2 = GetNumDataCodewords(num, ecl) * 8; totalBits = QrSegment.GetTotalBits(segments, num); if (totalBits != -1 && totalBits <= num2) { break; } if (num >= maxVersion) { string message = "Segment too long"; if (totalBits != -1) { message = $"Data length = {totalBits} bits, Max capacity = {num2} bits"; } throw new DataTooLongException(message); } num++; } Ecc[] allValues = Ecc.AllValues; foreach (Ecc ecc in allValues) { if (boostEcl && totalBits <= GetNumDataCodewords(num, ecc) * 8) { ecl = ecc; } } BitArray bitArray = new BitArray(0); foreach (QrSegment segment in segments) { bitArray.AppendBits(segment.EncodingMode.ModeBits, 4); bitArray.AppendBits((uint)segment.NumChars, segment.EncodingMode.NumCharCountBits(num)); bitArray.AppendData(segment.GetData()); } int num3 = GetNumDataCodewords(num, ecl) * 8; bitArray.AppendBits(0u, Math.Min(4, num3 - bitArray.Length)); bitArray.AppendBits(0u, (8 - bitArray.Length % 8) % 8); uint num4 = 236u; while (bitArray.Length < num3) { bitArray.AppendBits(num4, 8); num4 ^= 0xFDu; } byte[] array = new byte[bitArray.Length / 8]; for (int j = 0; j < bitArray.Length; j++) { if (bitArray.Get(j)) { array[j >> 3] |= (byte)(1 << 7 - (j & 7)); } } return new QrCode(num, ecl, array, mask); } public QrCode(int version, Ecc ecl, byte[] dataCodewords, int mask = -1) { if (version < 1 || version > 40) { throw new ArgumentOutOfRangeException("version", "Version value out of range"); } if (mask < -1 || mask > 7) { throw new ArgumentOutOfRangeException("mask", "Mask value out of range"); } Version = version; Size = version * 4 + 17; Objects.RequireNonNull(ecl); ErrorCorrectionLevel = ecl; Objects.RequireNonNull(dataCodewords); _modules = new bool[Size, Size]; _isFunction = new bool[Size, Size]; DrawFunctionPatterns(); byte[] data = AddEccAndInterleave(dataCodewords); DrawCodewords(data); if (mask == -1) { int num = int.MaxValue; for (uint num2 = 0u; num2 < 8; num2++) { ApplyMask(num2); DrawFormatBits(num2); int penaltyScore = GetPenaltyScore(); if (penaltyScore < num) { mask = (int)num2; num = penaltyScore; } ApplyMask(num2); } } Mask = mask; ApplyMask((uint)mask); DrawFormatBits((uint)mask); _isFunction = null; } public bool GetModule(int x, int y) { if (0 <= x && x < Size && 0 <= y && y < Size) { return _modules[y, x]; } return false; } public string ToSvgString(int border) { return ToSvgString(border, "#000000", "#ffffff"); } public string ToSvgString(int border, string foreground, string background) { return AsGraphics().ToSvgString(border, foreground, background); } public string ToGraphicsPath(int border = 0) { return AsGraphics().ToGraphicsPath(border); } public byte[] ToBmpBitmap(int border, int scale, int foreground, int background) { return AsGraphics().ToBmpBitmap(border, scale, foreground, background); } public byte[] ToBmpBitmap(int border = 0, int scale = 1) { return ToBmpBitmap(border, scale, 0, 16777215); } public byte[] ToPngBitmap(int border, int scale, int foreground, int background) { return PngBuilder.ToImage(this, scale, border, foreground, background); } public byte[] ToPngBitmap(int border = 0, int scale = 1) { return PngBuilder.ToImage(this, scale, border, 0, 16777215); } public int RgbColor(byte red, byte green, byte blue) { return (red << 16) | (green << 8) | blue; } private void DrawFunctionPatterns() { for (int i = 0; i < Size; i++) { SetFunctionModule(6, i, i % 2 == 0); SetFunctionModule(i, 6, i % 2 == 0); } DrawFinderPattern(3, 3); DrawFinderPattern(Size - 4, 3); DrawFinderPattern(3, Size - 4); int[] alignmentPatternPositions = GetAlignmentPatternPositions(); int num = alignmentPatternPositions.Length; for (int j = 0; j < num; j++) { for (int k = 0; k < num; k++) { if ((j != 0 || k != 0) && (j != 0 || k != num - 1) && (j != num - 1 || k != 0)) { DrawAlignmentPattern(alignmentPatternPositions[j], alignmentPatternPositions[k]); } } } DrawFormatBits(0u); DrawVersion(); } private void DrawFormatBits(uint mask) { uint num = (ErrorCorrectionLevel.FormatBits << 3) | mask; uint num2 = num; for (int i = 0; i < 10; i++) { num2 = (num2 << 1) ^ ((num2 >> 9) * 1335); } uint x = ((num << 10) | num2) ^ 0x5412u; for (int j = 0; j <= 5; j++) { SetFunctionModule(8, j, GetBit(x, j)); } SetFunctionModule(8, 7, GetBit(x, 6)); SetFunctionModule(8, 8, GetBit(x, 7)); SetFunctionModule(7, 8, GetBit(x, 8)); for (int k = 9; k < 15; k++) { SetFunctionModule(14 - k, 8, GetBit(x, k)); } for (int l = 0; l < 8; l++) { SetFunctionModule(Size - 1 - l, 8, GetBit(x, l)); } for (int m = 8; m < 15; m++) { SetFunctionModule(8, Size - 15 + m, GetBit(x, m)); } SetFunctionModule(8, Size - 8, isDark: true); } private void DrawVersion() { if (Version >= 7) { uint num = (uint)Version; for (int i = 0; i < 12; i++) { num = (num << 1) ^ ((num >> 11) * 7973); } uint x = (uint)(Version << 12) | num; for (int j = 0; j < 18; j++) { bool bit = GetBit(x, j); int num2 = Size - 11 + j % 3; int num3 = j / 3; SetFunctionModule(num2, num3, bit); SetFunctionModule(num3, num2, bit); } } } private void DrawFinderPattern(int x, int y) { for (int i = -4; i <= 4; i++) { for (int j = -4; j <= 4; j++) { int num = Math.Max(Math.Abs(j), Math.Abs(i)); int num2 = x + j; int num3 = y + i; if (0 <= num2 && num2 < Size && 0 <= num3 && num3 < Size) { SetFunctionModule(num2, num3, num != 2 && num != 4); } } } } private void DrawAlignmentPattern(int x, int y) { for (int i = -2; i <= 2; i++) { for (int j = -2; j <= 2; j++) { SetFunctionModule(x + j, y + i, Math.Max(Math.Abs(j), Math.Abs(i)) != 1); } } } private void SetFunctionModule(int x, int y, bool isDark) { _modules[y, x] = isDark; _isFunction[y, x] = true; } private Graphics AsGraphics() { return new Graphics(Size, _modules); } private byte[] AddEccAndInterleave(byte[] data) { Objects.RequireNonNull(data); if (data.Length != GetNumDataCodewords(Version, ErrorCorrectionLevel)) { throw new ArgumentOutOfRangeException("data", "Length of data does not match version and ecl"); } int num = NumErrorCorrectionBlocks[ErrorCorrectionLevel.Ordinal, Version]; int num2 = EccCodewordsPerBlock[ErrorCorrectionLevel.Ordinal, Version]; int num3 = GetNumRawDataModules(Version) / 8; int num4 = num - num3 % num; int num5 = num3 / num; byte[][] array = new byte[num][]; ReedSolomonGenerator reedSolomonGenerator = new ReedSolomonGenerator(num2); int i = 0; int num6 = 0; for (; i < num; i++) { byte[] array2 = CopyOfRange(data, num6, num6 + num5 - num2 + ((i >= num4) ? 1 : 0)); num6 += array2.Length; byte[] array3 = CopyOf(array2, num5 + 1); byte[] remainder = reedSolomonGenerator.GetRemainder(array2); Array.Copy(remainder, 0, array3, array3.Length - num2, remainder.Length); array[i] = array3; } byte[] array4 = new byte[num3]; int j = 0; int num7 = 0; for (; j < array[0].Length; j++) { for (int k = 0; k < array.Length; k++) { if (j != num5 - num2 || k >= num4) { array4[num7] = array[k][j]; num7++; } } } return array4; } private void DrawCodewords(byte[] data) { Objects.RequireNonNull(data); if (data.Length != GetNumRawDataModules(Version) / 8) { throw new ArgumentOutOfRangeException("data", "data length does not match version"); } int num = 0; for (int num2 = Size - 1; num2 >= 1; num2 -= 2) { if (num2 == 6) { num2 = 5; } for (int i = 0; i < Size; i++) { for (int j = 0; j < 2; j++) { int num3 = num2 - j; int num4 = ((((num2 + 1) & 2) == 0) ? (Size - 1 - i) : i); if (!_isFunction[num4, num3] && num < data.Length * 8) { _modules[num4, num3] = GetBit(data[num >>> 3], 7 - (num & 7)); num++; } } } } } private void ApplyMask(uint mask) { if (mask < 0 || mask > 7) { throw new ArgumentOutOfRangeException("mask", "Mask value out of range"); } for (int i = 0; i < Size; i++) { for (int j = 0; j < Size; j++) { bool flag = false; switch (mask) { case 0u: flag = (j + i) % 2 == 0; break; case 1u: flag = i % 2 == 0; break; case 2u: flag = j % 3 == 0; break; case 3u: flag = (j + i) % 3 == 0; break; case 4u: flag = (j / 3 + i / 2) % 2 == 0; break; case 5u: flag = j * i % 2 + j * i % 3 == 0; break; case 6u: flag = (j * i % 2 + j * i % 3) % 2 == 0; break; case 7u: flag = ((j + i) % 2 + j * i % 3) % 2 == 0; break; } _modules[i, j] ^= flag && !_isFunction[i, j]; } } } private int GetPenaltyScore() { int num = 0; for (int i = 0; i < Size; i++) { bool flag = false; int num2 = 0; FinderPenalty finderPenalty = new FinderPenalty(Size); for (int j = 0; j < Size; j++) { if (_modules[i, j] == flag) { num2++; if (num2 == 5) { num += 3; } else if (num2 > 5) { num++; } } else { finderPenalty.AddHistory(num2); if (!flag) { num += finderPenalty.CountPatterns() * 40; } flag = _modules[i, j]; num2 = 1; } } num += finderPenalty.TerminateAndCount(flag, num2) * 40; } for (int k = 0; k < Size; k++) { bool flag2 = false; int num3 = 0; FinderPenalty finderPenalty2 = new FinderPenalty(Size); for (int l = 0; l < Size; l++) { if (_modules[l, k] == flag2) { num3++; if (num3 == 5) { num += 3; } else if (num3 > 5) { num++; } } else { finderPenalty2.AddHistory(num3); if (!flag2) { num += finderPenalty2.CountPatterns() * 40; } flag2 = _modules[l, k]; num3 = 1; } } num += finderPenalty2.TerminateAndCount(flag2, num3) * 40; } for (int m = 0; m < Size - 1; m++) { for (int n = 0; n < Size - 1; n++) { bool flag3 = _modules[m, n]; if (flag3 == _modules[m, n + 1] && flag3 == _modules[m + 1, n] && flag3 == _modules[m + 1, n + 1]) { num += 3; } } } int num4 = 0; for (int num5 = 0; num5 < Size; num5++) { for (int num6 = 0; num6 < Size; num6++) { if (_modules[num5, num6]) { num4++; } } } int num7 = Size * Size; int num8 = (Math.Abs(num4 * 20 - num7 * 10) + num7 - 1) / num7 - 1; return num + num8 * 10; } private int[] GetAlignmentPatternPositions() { if (Version == 1) { return Array.Empty(); } int num = Version / 7 + 2; int num2 = (Version * 8 + num * 3 + 5) / (num * 4 - 4) * 2; int[] array = new int[num]; array[0] = 6; int num3 = array.Length - 1; int num4 = Size - 7; while (num3 >= 1) { array[num3] = num4; num3--; num4 -= num2; } return array; } private static int GetNumRawDataModules(int ver) { if (ver < 1 || ver > 40) { throw new ArgumentOutOfRangeException("ver", "Version number out of range"); } int num = ver * 4 + 17; int num2 = num * num; num2 -= 192; num2 -= 31; num2 -= (num - 16) * 2; if (ver >= 2) { int num3 = ver / 7 + 2; num2 -= (num3 - 1) * (num3 - 1) * 25; num2 -= (num3 - 2) * 2 * 20; if (ver >= 7) { num2 -= 36; } } return num2; } public static int GetNumDataCodewords(int ver, Ecc ecl) { return GetNumRawDataModules(ver) / 8 - EccCodewordsPerBlock[ecl.Ordinal, ver] * NumErrorCorrectionBlocks[ecl.Ordinal, ver]; } private static byte[] CopyOfRange(byte[] original, int from, int to) { byte[] array = new byte[to - from]; Array.Copy(original, from, array, 0, to - from); return array; } private static byte[] CopyOf(byte[] original, int newLength) { byte[] array = new byte[newLength]; Array.Copy(original, array, Math.Min(original.Length, newLength)); return array; } private static bool GetBit(uint x, int i) { return ((x >> i) & 1) != 0; } } public class QrSegment { public sealed class Mode { public static readonly Mode Numeric = new Mode(1u, 10, 12, 14); public static readonly Mode Alphanumeric = new Mode(2u, 9, 11, 13); public static readonly Mode Byte = new Mode(4u, 8, 16, 16); public static readonly Mode Kanji = new Mode(8u, 8, 10, 12); public static readonly Mode Eci = new Mode(7u, default(int), default(int), default(int)); public static readonly Mode StructuredAppend = new Mode(3u, default(int), default(int), default(int)); internal uint ModeBits { get; } private int[] NumBitsCharCount { get; } internal int NumCharCountBits(int ver) { return NumBitsCharCount[(ver + 7) / 17]; } private Mode(uint modeBits, params int[] numBitsCharCount) { ModeBits = modeBits; NumBitsCharCount = numBitsCharCount; } } private readonly BitArray _data; private static readonly Regex NumericRegex = new Regex("^[0-9]*$", RegexOptions.Compiled); private static readonly Regex AlphanumericRegex = new Regex("^[A-Z0-9 $%*+./:-]*$", RegexOptions.Compiled); internal const string AlphanumericCharset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; public Mode EncodingMode { get; } public int NumChars { get; } public static QrSegment MakeBytes(byte[] data) { Objects.RequireNonNull(data); BitArray bitArray = new BitArray(0); foreach (byte val in data) { bitArray.AppendBits(val, 8); } return new QrSegment(Mode.Byte, data.Length, bitArray); } public static QrSegment MakeBytes(ArraySegment data) { Objects.RequireNonNull(data); BitArray bitArray = new BitArray(0); foreach (byte item in (IEnumerable)data) { bitArray.AppendBits(item, 8); } return new QrSegment(Mode.Byte, data.Count, bitArray); } public static QrSegment MakeNumeric(string digits) { Objects.RequireNonNull(digits); if (!IsNumeric(digits)) { throw new ArgumentOutOfRangeException("digits", "String contains non-numeric characters"); } BitArray bitArray = new BitArray(0); int num; for (int i = 0; i < digits.Length; i += num) { num = Math.Min(digits.Length - i, 3); bitArray.AppendBits(uint.Parse(digits.Substring(i, num)), num * 3 + 1); } return new QrSegment(Mode.Numeric, digits.Length, bitArray); } public static QrSegment MakeAlphanumeric(string text) { Objects.RequireNonNull(text); if (!IsAlphanumeric(text)) { throw new ArgumentOutOfRangeException("text", "String contains unencodable characters in alphanumeric mode"); } BitArray bitArray = new BitArray(0); int i; for (i = 0; i <= text.Length - 2; i += 2) { uint num = (uint)("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".IndexOf(text[i]) * 45); num += (uint)"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".IndexOf(text[i + 1]); bitArray.AppendBits(num, 11); } if (i < text.Length) { bitArray.AppendBits((uint)"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:".IndexOf(text[i]), 6); } return new QrSegment(Mode.Alphanumeric, text.Length, bitArray); } internal static QrSegment MakeStructuredAppend(byte parity, int position, int total) { BitArray bitArray = new BitArray(0); bitArray.AppendBits((uint)(position - 1), 4); bitArray.AppendBits((uint)(total - 1), 4); bitArray.AppendBits(parity, 8); return new QrSegment(Mode.StructuredAppend, 0, bitArray); } public static List MakeSegments(string text) { Objects.RequireNonNull(text); List list = new List(); if (!(text == "")) { if (IsNumeric(text)) { list.Add(MakeNumeric(text)); } else if (IsAlphanumeric(text)) { list.Add(MakeAlphanumeric(text)); } else { list.Add(MakeBytes(Encoding.UTF8.GetBytes(text))); } } return list; } public static QrSegment MakeEci(int assignVal) { BitArray bitArray = new BitArray(0); if (assignVal < 0) { throw new ArgumentOutOfRangeException("assignVal", "ECI assignment value out of range"); } if (assignVal < 128) { bitArray.AppendBits((uint)assignVal, 8); } else if (assignVal < 16384) { bitArray.AppendBits(2u, 2); bitArray.AppendBits((uint)assignVal, 14); } else { if (assignVal >= 1000000) { throw new ArgumentOutOfRangeException("assignVal", "ECI assignment value out of range"); } bitArray.AppendBits(6u, 3); bitArray.AppendBits((uint)assignVal, 21); } return new QrSegment(Mode.Eci, 0, bitArray); } public static bool IsNumeric(string text) { return NumericRegex.IsMatch(text); } public static bool IsAlphanumeric(string text) { return AlphanumericRegex.IsMatch(text); } public QrSegment(Mode mode, int numChars, BitArray data) { EncodingMode = Objects.RequireNonNull(mode); Objects.RequireNonNull(data); if (numChars < 0) { throw new ArgumentOutOfRangeException("numChars", "Invalid value"); } NumChars = numChars; _data = (BitArray)data.Clone(); } public BitArray GetData() { return (BitArray)_data.Clone(); } public string GetText() { StringBuilder stringBuilder = new StringBuilder(); AppendText(stringBuilder); return stringBuilder.ToString(); } public static string GetJoinedText(List segments) { StringBuilder stringBuilder = new StringBuilder(); foreach (QrSegment segment in segments) { segment.AppendText(stringBuilder); } return stringBuilder.ToString(); } public static string GetJoinedText(List> segments) { StringBuilder stringBuilder = new StringBuilder(); foreach (List segment in segments) { foreach (QrSegment item in segment) { item.AppendText(stringBuilder); } } return stringBuilder.ToString(); } private void AppendText(StringBuilder builder) { if (EncodingMode == Mode.Numeric) { for (int i = 0; i < NumChars; i += 3) { int num = Math.Min(NumChars - i, 3); int index = i / 3 * 10; switch (num) { case 3: { uint num4 = _data.ExtractBits(index, 10); builder.Append((char)(48 + num4 / 100)); builder.Append((char)(48 + num4 / 10 % 10)); builder.Append((char)(48 + num4 % 10)); break; } case 2: { uint num3 = _data.ExtractBits(index, 7); builder.Append((char)(48 + num3 / 10)); builder.Append((char)(48 + num3 % 10)); break; } case 1: { uint num2 = _data.ExtractBits(index, 4); builder.Append((char)(48 + num2)); break; } } } } else if (EncodingMode == Mode.Alphanumeric) { for (int j = 0; j < NumChars; j += 2) { int num5 = Math.Min(NumChars - j, 2); int index2 = j / 2 * 11; if (num5 == 2) { int num6 = (int)_data.ExtractBits(index2, 11); builder.Append("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"[num6 / 45]); builder.Append("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"[num6 % 45]); } else { int index3 = (int)_data.ExtractBits(index2, 6); builder.Append("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"[index3]); } } } else if (EncodingMode == Mode.Byte) { byte[] array = new byte[NumChars]; for (int k = 0; k < NumChars; k++) { array[k] = (byte)_data.ExtractBits(k * 8, 8); } builder.Append(Encoding.UTF8.GetString(array)); } } internal static int GetTotalBits(List segments, int version) { Objects.RequireNonNull(segments); long num = 0L; foreach (QrSegment segment in segments) { Objects.RequireNonNull(segment); int num2 = segment.EncodingMode.NumCharCountBits(version); if (segment.NumChars >= 1 << num2) { return -1; } num += 4L + (long)num2 + segment._data.Length; if (num > int.MaxValue) { return -1; } } return (int)num; } internal static int GetTotalBits(int numChars, Mode mode, int version) { int num = mode.NumCharCountBits(version); if (numChars >= 1 << num) { return -1; } int num2 = 0; if (mode == Mode.Numeric) { num2 = numChars / 3 * 10 + ((numChars % 3 != 0) ? (numChars % 3 * 3 + 1) : 0); } else if (mode == Mode.Alphanumeric) { num2 = numChars / 2 * 11 + ((numChars % 2 != 0) ? 6 : 0); } else if (mode == Mode.Byte) { num2 = numChars * 8; } else { if (mode != Mode.Kanji) { throw new ArgumentOutOfRangeException("mode", "Unsupported mode for this calculation"); } num2 = numChars * 13; } return 4 + num + num2; } } public static class QrSegmentAdvanced { private const string PackedQrKanjiToUnicode = "MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZAALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA/////////////////////////////8iICKlIxIiAiIHImEiUiJqImsiGiI9Ih0iNSIrIiz//////////////////yErIDAmbyZtJmogICAhALb//////////yXv/////////////////////////////////////////////////xD/Ef8S/xP/FP8V/xb/F/8Y/xn///////////////////8h/yL/I/8k/yX/Jv8n/yj/Kf8q/yv/LP8t/y7/L/8w/zH/Mv8z/zT/Nf82/zf/OP85/zr///////////////////9B/0L/Q/9E/0X/Rv9H/0j/Sf9K/0v/TP9N/07/T/9Q/1H/Uv9T/1T/Vf9W/1f/WP9Z/1r//////////zBBMEIwQzBEMEUwRjBHMEgwSTBKMEswTDBNME4wTzBQMFEwUjBTMFQwVTBWMFcwWDBZMFowWzBcMF0wXjBfMGAwYTBiMGMwZDBlMGYwZzBoMGkwajBrMGwwbTBuMG8wcDBxMHIwczB0MHUwdjB3MHgweTB6MHswfDB9MH4wfzCAMIEwgjCDMIQwhTCGMIcwiDCJMIowizCMMI0wjjCPMJAwkTCSMJP/////////////////////////////////////MKEwojCjMKQwpTCmMKcwqDCpMKowqzCsMK0wrjCvMLAwsTCyMLMwtDC1MLYwtzC4MLkwujC7MLwwvTC+ML8wwDDBMMIwwzDEMMUwxjDHMMgwyTDKMMswzDDNMM4wzzDQMNEw0jDTMNQw1TDWMNcw2DDZMNow2zDcMN0w3jDf//8w4DDhMOIw4zDkMOUw5jDnMOgw6TDqMOsw7DDtMO4w7zDwMPEw8jDzMPQw9TD2/////////////////////wORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDowOkA6UDpgOnA6gDqf////////////////////8DsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+A78DwAPBA8MDxAPFA8YDxwPIA8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////BBAEEQQSBBMEFAQVBAEEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQmBCcEKAQpBCoEKwQsBC0ELgQv////////////////////////////////////////BDAEMQQyBDMENAQ1BFEENgQ3BDgEOQQ6BDsEPAQ9//8EPgQ/BEAEQQRCBEMERARFBEYERwRIBEkESgRLBEwETQROBE///////////////////////////////////yUAJQIlDCUQJRglFCUcJSwlJCU0JTwlASUDJQ8lEyUbJRclIyUzJSslOyVLJSAlLyUoJTclPyUdJTAlJSU4JUL//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////06cVRZaA5Y/VMBhG2MoWfaQIoR1gxx6UGCqY+FuJWXthGaCppv1aJNXJ2WhYnFbm1nQhnuY9H1ifb6bjmIWfJ+It1uJXrVjCWaXaEiVx5eNZ09O5U8KT01PnVBJVvJZN1nUWgFcCWDfYQ9hcGYTaQVwunVPdXB5+32tfe+Aw4QOiGOLApBVkHpTO06VTqVX34CykMF4704AWPFuopA4ejKDKIKLnC9RQVNwVL1U4VbgWftfFZjybeuA5IUt////////lmKWcJagl/tUC1PzW4dwz3+9j8KW6FNvnVx6uk4ReJOB/G4mVhhVBGsdhRqcO1nlU6ltZnTclY9WQk6RkEuW8oNPmQxT4VW2WzBfcWYgZvNoBGw4bPNtKXRbdsh6Tpg0gvGIW4pgku1tsnWrdsqZxWCmiwGNipWyaY5TrVGG//9XElgwWURbtF72YChjqWP0bL9vFHCOcRRxWXHVcz9+AYJ2gtGFl5BgkludG1hpZbxsWnUlUflZLlllX4Bf3GK8ZfpqKmsna7Rzi3/BiVadLJ0OnsRcoWyWg3tRBFxLYbaBxmh2cmFOWU/6U3hgaW4pek+X804LUxZO7k9VTz1PoU9zUqBT71YJWQ9awVu2W+F50WaHZ5xntmtMbLNwa3PCeY15vno8e4eCsYLbgwSDd4Pvg9OHZoqyVimMqI/mkE6XHoaKT8Rc6GIRcll1O4Hlgr2G/ozAlsWZE5nVTstPGonjVt5YSljKXvtf62AqYJRgYmHQYhJi0GU5////////m0FmZmiwbXdwcHVMdoZ9dYKlh/mVi5aOjJ1R8VK+WRZUs1uzXRZhaGmCba94jYTLiFeKcpOnmrhtbJmohtlXo2f/hs6SDlKDVodUBF7TYuFkuWg8aDhru3NyeLp6a4maidKNa48DkO2Vo5aUl2lbZlyzaX2YTZhOY5t7IGor//9qf2i2nA1vX1JyVZ1gcGLsbTtuB27RhFuJEI9EThScOVP2aRtqOpeEaCpRXHrDhLKR3JOMVludKGgigwWEMXylUgiCxXTmTn5Pg1GgW9JSClLYUudd+1WaWCpZ5luMW5hb215yXnlgo2EfYWNhvmPbZWJn0WhTaPprPmtTbFdvIm+Xb0V0sHUYduN3C3r/e6F8IX3pfzZ/8ICdgmaDnomzisyMq5CElFGVk5WRlaKWZZfTmSiCGE44VCtcuF3Mc6l2THc8XKl/640LlsGYEZhUmFhPAU8OU3FVnFZoV/pZR1sJW8RckF4MXn5fzGPuZzpl12XiZx9oy2jE////////al9eMGvFbBdsfXV/eUhbY3oAfQBfvYmPihiMtI13jsyPHZjimg6bPE6AUH1RAFmTW5xiL2KAZOxrOnKgdZF5R3+ph/uKvItwY6yDypegVAlUA1WraFRqWIpweCdndZ7NU3RbooEahlCQBk4YTkVOx08RU8pUOFuuXxNgJWVR//9nPWxCbHJs43B4dAN6dnquewh9Gnz+fWZl53JbU7tcRV3oYtJi4GMZbiCGWooxjd2S+G8BeaabWk6oTqtOrE+bT6BQ0VFHevZRcVH2U1RTIVN/U+tVrFiDXOFfN19KYC9gUGBtYx9lWWpLbMFywnLtd++A+IEFggiFTpD3k+GX/5lXmlpO8FHdXC1mgWltXEBm8ml1c4loUHyBUMVS5FdHXf6TJmWkayNrPXQ0eYF5vXtLfcqCuYPMiH+JX4s5j9GR0VQfkoBOXVA2U+VTOnLXc5Z36YLmjq+ZxpnImdJRd2Eahl5VsHp6UHZb05BHloVOMmrbkedcUVxI////////Y5h6n2yTl3SPYXqqcYqWiHyCaBd+cGhRk2xS8lQbhauKE3+kjs2Q4VNmiIh5QU/CUL5SEVFEVVNXLXPqV4tZUV9iX4RgdWF2YWdhqWOyZDplbGZvaEJuE3Vmej18+31MfZl+S39rgw6DSobNigiKY4tmjv2YGp2PgriPzpvo//9Sh2IfZINvwJaZaEFQkWsgbHpvVHp0fVCIQIojZwhO9lA5UCZQZVF8UjhSY1WnVw9YBVrMXvphsmH4YvNjcmkcailyfXKscy54FHhvfXl3DICpiYuLGYzijtKQY5N1lnqYVZoTnnhRQ1OfU7Nee18mbhtukHOEc/59Q4I3igCK+pZQTk5QC1PkVHxW+lnRW2Rd8V6rXydiOGVFZ69uVnLQfMqItIChgOGD8IZOioeN6JI3lseYZ58TTpROkk8NU0hUSVQ+Wi9fjF+hYJ9op2qOdFp4gYqeiqSLd5GQTl6byU6kT3xPr1AZUBZRSVFsUp9SuVL+U5pT41QR////////VA5ViVdRV6JZfVtUW11bj13lXedd9154XoNeml63XxhgUmFMYpdi2GOnZTtmAmZDZvRnbWghaJdpy2xfbSptaW4vbp11MnaHeGx6P3zgfQV9GH1efbGAFYADgK+AsYFUgY+CKoNSiEyIYYsbjKKM/JDKkXWScXg/kvyVpJZN//+YBZmZmtidO1JbUqtT91QIWNVi92/gjGqPX565UUtSO1RKVv16QJF3nWCe0nNEbwmBcHURX/1g2pqoctuPvGtkmANOylbwV2RYvlpaYGhhx2YPZgZoOWixbfd11X06gm6bQk6bT1BTyVUGXW9d5l3uZ/tsmXRzeAKKUJOWiN9XUF6nYytQtVCsUY1nAFTJWF5Zu1uwX2liTWOhaD1rc24IcH2Rx3KAeBV4JnltZY59MIPciMGPCZabUmRXKGdQf2qMoVG0V0KWKlg6aYqAtFSyXQ5X/HiVnfpPXFJKVItkPmYoZxRn9XqEe1Z9IpMvaFybrXs5UxlRilI3////////W99i9mSuZOZnLWu6hamW0XaQm9ZjTJMGm6t2v2ZSTglQmFPCXHFg6GSSZWNoX3Hmc8p1I3uXfoKGlYuDjNuReJkQZaxmq2uLTtVO1E86T39SOlP4U/JV41bbWOtZy1nJWf9bUFxNXgJeK1/XYB1jB2UvW1xlr2W9ZehnnWti//9re2wPc0V5SXnBfPh9GX0rgKKBAoHziZaKXoppimaKjIrujMeM3JbMmPxrb06LTzxPjVFQW1db+mFIYwFmQmshbstsu3I+dL111HjBeTqADIAzgeqElI+ebFCef18Pi1idK3r6jvhbjZbrTgNT8Vf3WTFayVukYIluf28Gdb6M6lufhQB74FByZ/SCnVxhhUp+HoIOUZlcBGNojWZlnHFueT59F4AFix2OypBuhseQqlAfUvpcOmdTcHxyNZFMkciTK4LlW8JfMWD5TjtT1luIYktnMWuKculz4HougWuNo5FSmZZRElPXVGpb/2OIajl9rJcAVtpTzlRo////////W5dcMV3eT+5hAWL+bTJ5wHnLfUJ+TX/Sge2CH4SQiEaJcouQjnSPL5AxkUuRbJbGkZxOwE9PUUVTQV+TYg5n1GxBbgtzY34mkc2Sg1PUWRlbv23ReV1+LnybWH5xn1H6iFOP8E/KXPtmJXeseuOCHJn/UcZfqmXsaW9riW3z//9ulm9kdv59FF3hkHWRh5gGUeZSHWJAZpFm2W4aXrZ90n9yZviFr4X3ivhSqVPZWXNej1+QYFWS5JZkULdRH1LdUyBTR1PsVOhVRlUxVhdZaFm+WjxbtVwGXA9cEVwaXoReil7gX3Bif2KEYttjjGN3ZgdmDGYtZnZnfmiiah9qNWy8bYhuCW5YcTxxJnFndcd3AXhdeQF5ZXnweuB7EXynfTmAloPWhIuFSYhdiPOKH4o8ilSKc4xhjN6RpJJmk36UGJacl5hOCk4ITh5OV1GXUnBXzlg0WMxbIl44YMVk/mdhZ1ZtRHK2dXN6Y4S4i3KRuJMgVjFX9Jj+////////Yu1pDWuWce1+VIB3gnKJ5pjfh1WPsVw7TzhP4U+1VQdaIFvdW+lfw2FOYy9lsGZLaO5pm214bfF1M3W5dx95XnnmfTOB44KvhaqJqoo6jquPm5Aykd2XB066TsFSA1h1WOxcC3UaXD2BTooKj8WWY5dteyWKz5gIkWJW81Oo//+QF1Q5V4JeJWOobDRwindhfIt/4IhwkEKRVJMQkxiWj3RemsRdB11pZXBnoo2olttjbmdJaRmDxZgXlsCI/m+EZHpb+E4WcCx1XWYvUcRSNlLiWdNfgWAnYhBlP2V0Zh9mdGjyaBZrY24FcnJ1H3bbfL6AVljwiP2Jf4qgipOKy5AdkZKXUpdZZYl6DoEGlrteLWDcYhplpWYUZ5B383pNfE1+PoEKjKyNZI3hjl94qVIHYtljpWRCYpiKLXqDe8CKrJbqfXaCDIdJTtlRSFNDU2Bbo1wCXBZd3WImYkdksGgTaDRsyW1FbRdn029ccU5xfWXLen97rX3a////////fkp/qIF6ghuCOYWmim6Mzo31kHiQd5KtkpGVg5uuUk1VhG84cTZRaHmFflWBs3zOVkxYUVyoY6pm/mb9aVpy2XWPdY55DnlWed98l30gfUSGB4o0ljuQYZ8gUOdSdVPMU+JQCVWqWO5ZT3I9W4tcZFMdYONg82NcY4NjP2O7//9kzWXpZvld42nNaf1vFXHlTol16Xb4epN8333PfZyAYYNJg1iEbIS8hfuIxY1wkAGQbZOXlxyaElDPWJdhjoHThTWNCJAgT8NQdFJHU3Ngb2NJZ19uLI2zkB9P11xejMplz32aU1KIllF2Y8NbWFtrXApkDWdRkFxO1lkaWSpscIpRVT5YFVmlYPBiU2fBgjVpVZZAmcSaKE9TWAZb/oAQXLFeL1+FYCBhS2I0Zv9s8G7egM6Bf4LUiIuMuJAAkC6Wip7bm9tO41PwWSd7LJGNmEyd+W7dcCdTU1VEW4ViWGKeYtNsom/vdCKKF5Q4b8GK/oM4UeeG+FPq////////U+lPRpBUj7BZaoExXf166o+/aNqMN3L4nEhqPYqwTjlTWFYGV2ZixWOiZeZrTm3hbltwrXfteu97qn27gD2AxobLipWTW1bjWMdfPmWtZpZqgGu1dTeKx1Akd+VXMF8bYGVmemxgdfR6Gn9ugfSHGJBFmbN7yXVcevl7UYTE//+QEHnpepKDNlrhd0BOLU7yW5lf4GK9Zjxn8WzohmuId4o7kU6S85nQahdwJnMqgueEV4yvTgFRRlHLVYtb9V4WXjNegV8UXzVfa1+0YfJjEWaiZx1vbnJSdTp3OoB0gTmBeId2ir+K3I2FjfOSmpV3mAKc5VLFY1d29GcVbIhzzYzDk66Wc20lWJxpDmnMj/2TmnXbkBpYWmgCY7Rp+09Dbyxn2I+7hSZ9tJNUaT9vcFdqWPdbLH0scipUCpHjnbROrU9OUFxQdVJDjJ5USFgkW5peHV6VXq1e918fYIxitWM6Y9Bor2xAeId5jnoLfeCCR4oCiuaORJAT////////kLiRLZHYnw5s5WRYZOJldW70doR7G5Bpk9FuulTyX7lkpI9Nj+2SRFF4WGtZKVxVXpdt+36PdRyMvI7imFtwuU8da79vsXUwlvtRTlQQWDVYV1msXGBfkmWXZ1xuIXZ7g9+M7ZAUkP2TTXgleDpSql6mVx9ZdGASUBJRWlGs//9RzVIAVRBYVFhYWVdblVz2XYtgvGKVZC1ncWhDaLxo33bXbdhub22bcG9xyF9Tddh5d3tJe1R7UnzWfXFSMIRjhWmF5IoOiwSMRo4PkAOQD5QZlnaYLZowldhQzVLVVAxYAlwOYadknm0ed7N65YD0hASQU5KFXOCdB1M/X5dfs22ccnl3Y3m/e+Rr0nLsiq1oA2phUfh6gWk0XEqc9oLrW8WRSXAeVnhcb2DHZWZsjIxakEGYE1RRZseSDVlIkKNRhU5NUeqFmYsOcFhjepNLaWKZtH4EdXdTV2lgjt+W42xdToxcPF8Qj+lTAozRgImGeV7/ZeVOc1Fl////////WYJcP5fuTvtZil/Nio1v4XmweWJb54RxcytxsV50X/Vje2SaccN8mE5DXvxOS1fcVqJgqW/DfQ2A/YEzgb+PsomXhqRd9GKKZK2Jh2d3bOJtPnQ2eDRaRn91gq2ZrE/zXsNi3WOSZVdnb3bDckyAzIC6jymRTVANV/lakmiF//9pc3Fkcv2Mt1jyjOCWapAZh3955HfnhClPL1JlU1pizWfPbMp2fXuUfJWCNoWEj+tm3W8gcgZ+G4OrmcGeplH9e7F4cnu4gId7SGroXmGAjHVRdWBRa5Jibox2epGXmupPEH9wYpx7T5WlnOlWelhZhuSWvE80UiRTSlPNU9teBmQsZZFnf2w+bE5ySHKvc+11VH5BgiyF6Yype8SRxnFpmBKY72M9Zml1anbkeNCFQ4buUypTUVQmWYNeh198YLJiSWJ5YqtlkGvUbMx1snaueJF52H3Lf3eApYirirmMu5B/l16Y22oLfDhQmVw+X65nh2vYdDV3CX+O////////nztnynoXUzl1i5rtX2aBnYPxgJhfPF/FdWJ7RpA8aGdZ61qbfRB2fossT/VfamoZbDdvAnTieWiIaIpVjHle32PPdcV50oLXkyiS8oSchu2cLVTBX2xljG1ccBWMp4zTmDtlT3T2Tg1O2FfgWStaZlvMUaheA16cYBZidmV3//9lp2ZubW5yNnsmgVCBmoKZi1yMoIzmjXSWHJZET65kq2tmgh6EYYVqkOhcAWlTmKiEeoVXTw9Sb1+pXkVnDXmPgXmJB4mGbfVfF2JVbLhOz3Jpm5JSBlQ7VnRYs2GkYm5xGllufIl83n0blvBlh4BeThlPdVF1WEBeY15zXwpnxE4mhT2ViZZbfHOYAVD7WMF2VninUiV3pYURe4ZQT1kJckd7x33oj7qP1JBNT79SyVopXwGXrU/dgheS6lcDY1VraXUriNyPFHpCUt9Yk2FVYgpmrmvNfD+D6VAjT/hTBVRGWDFZSVudXPBc710pXpZisWNnZT5luWcL////////bNVs4XD5eDJ+K4DegrOEDITshwKJEooqjEqQppLSmP2c851sTk9OoVCNUlZXSlmoXj1f2F/ZYj9mtGcbZ9Bo0lGSfSGAqoGoiwCMjIy/kn6WMlQgmCxTF1DVU1xYqGSyZzRyZ3dmekaR5lLDbKFrhlgAXkxZVGcsf/tR4XbG//9kaXjom1Seu1fLWblmJ2eaa85U6WnZXlWBnGeVm6pn/pxSaF1Opk/jU8hiuWcrbKuPxE+tfm2ev04HYWJugG8rhRNUc2cqm0Vd83uVXKxbxoccbkqE0XoUgQhZmXyNbBF3IFLZWSJxIXJfd9uXJ51haQtaf1oYUaVUDVR9Zg5234/3kpic9Fnqcl1uxVFNaMl9v33sl2KeumR4aiGDAlmEW19r23MbdvJ9soAXhJlRMmcontl27mdiUv+ZBVwkYjt8foywVU9gtn0LlYBTAU5fUbZZHHI6gDaRzl8ld+JThF95fQSFrIozjo2XVmfzha6UU2EJYQhsuXZS////////iu2POFUvT1FRKlLHU8tbpV59YKBhgmPWZwln2m5nbYxzNnM3dTF5UIjVipiQSpCRkPWWxIeNWRVOiE9ZTg6KiY8/mBBQrV58WZZbuV64Y9pj+mTBZtxpSmnYbQtutnGUdSh6r3+KgACESYTJiYGLIY4KkGWWfZkKYX5ikWsy//9sg210f8x//G3Af4WHuoj4Z2WDsZg8lvdtG31hhD2Rak5xU3VdUGsEb+uFzYYtiadSKVQPXGVnTmiodAZ0g3XiiM+I4ZHMluKWeF+Lc4d6y4ROY6B1ZVKJbUFunHQJdVl4a3ySloZ63J+NT7ZhbmXFhlxOhk6uUNpOIVHMW+5lmWiBbbxzH3ZCd616HHzngm+K0pB8kc+WdZgYUpt90VArU5hnl23LcdB0M4HojyqWo5xXnp90YFhBbZl9L5heTuRPNk+LUbdSsV26YBxzsnk8gtOSNJa3lvaXCp6Xn2Jmpmt0UhdSo3DIiMJeyWBLYZBvI3FJfD599IBv////////hO6QI5MsVEKbb2rTcImMwo3vlzJStFpBXspfBGcXaXxplG1qbw9yYnL8e+2AAYB+h0uQzlFtnpN5hICLkzKK1lAtVIyKcWtqjMSBB2DRZ6Cd8k6ZTpicEIprhcGFaGkAbn54l4FV/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////18MThBOFU4qTjFONk48Tj9OQk5WTlhOgk6FjGtOioISXw1Ojk6eTp9OoE6iTrBOs062Ts5OzU7ETsZOwk7XTt5O7U7fTvdPCU9aTzBPW09dT1dPR092T4hPj0+YT3tPaU9wT5FPb0+GT5ZRGE/UT99Pzk/YT9tP0U/aT9BP5E/lUBpQKFAUUCpQJVAFTxxP9lAhUClQLE/+T+9QEVAGUENQR2cDUFVQUFBIUFpQVlBsUHhQgFCaUIVQtFCy////////UMlQylCzUMJQ1lDeUOVQ7VDjUO5Q+VD1UQlRAVECURZRFVEUURpRIVE6UTdRPFE7UT9RQFFSUUxRVFFievhRaVFqUW5RgFGCVthRjFGJUY9RkVGTUZVRllGkUaZRolGpUapRq1GzUbFRslGwUbVRvVHFUclR21HghlVR6VHt//9R8FH1Uf5SBFILUhRSDlInUipSLlIzUjlST1JEUktSTFJeUlRSalJ0UmlSc1J/Un1SjVKUUpJScVKIUpGPqI+nUqxSrVK8UrVSwVLNUtdS3lLjUuaY7VLgUvNS9VL4UvlTBlMIdThTDVMQUw9TFVMaUyNTL1MxUzNTOFNAU0ZTRU4XU0lTTVHWU15TaVNuWRhTe1N3U4JTllOgU6ZTpVOuU7BTtlPDfBKW2VPfZvxx7lPuU+hT7VP6VAFUPVRAVCxULVQ8VC5UNlQpVB1UTlSPVHVUjlRfVHFUd1RwVJJUe1SAVHZUhFSQVIZUx1SiVLhUpVSsVMRUyFSo////////VKtUwlSkVL5UvFTYVOVU5lUPVRRU/VTuVO1U+lTiVTlVQFVjVUxVLlVcVUVVVlVXVThVM1VdVZlVgFSvVYpVn1V7VX5VmFWeVa5VfFWDValVh1WoVdpVxVXfVcRV3FXkVdRWFFX3VhZV/lX9VhtV+VZOVlBx31Y0VjZWMlY4//9Wa1ZkVi9WbFZqVoZWgFaKVqBWlFaPVqVWrla2VrRWwla8VsFWw1bAVshWzlbRVtNW11buVvlXAFb/VwRXCVcIVwtXDVcTVxhXFlXHVxxXJlc3VzhXTlc7V0BXT1dpV8BXiFdhV39XiVeTV6BXs1ekV6pXsFfDV8ZX1FfSV9NYClfWV+NYC1gZWB1YclghWGJYS1hwa8BYUlg9WHlYhVi5WJ9Yq1i6WN5Yu1i4WK5YxVjTWNFY11jZWNhY5VjcWORY31jvWPpY+Vj7WPxY/VkCWQpZEFkbaKZZJVksWS1ZMlk4WT560llVWVBZTllaWVhZYllgWWdZbFlp////////WXhZgVmdT15Pq1mjWbJZxlnoWdxZjVnZWdpaJVofWhFaHFoJWhpaQFpsWklaNVo2WmJaalqaWrxavlrLWsJavVrjWtda5lrpWtZa+lr7WwxbC1sWWzJa0FsqWzZbPltDW0VbQFtRW1VbWltbW2VbaVtwW3NbdVt4ZYhbeluA//9bg1umW7hbw1vHW8lb1FvQW+Rb5lviW95b5VvrW/Bb9lvzXAVcB1wIXA1cE1wgXCJcKFw4XDlcQVxGXE5cU1xQXE9bcVxsXG5OYlx2XHlcjFyRXJRZm1yrXLtctly8XLdcxVy+XMdc2VzpXP1c+lztXYxc6l0LXRVdF11cXR9dG10RXRRdIl0aXRldGF1MXVJdTl1LXWxdc112XYddhF2CXaJdnV2sXa5dvV2QXbddvF3JXc1d013SXdZd213rXfJd9V4LXhpeGV4RXhteNl43XkReQ15AXk5eV15UXl9eYl5kXkdedV52XnqevF5/XqBewV7CXshe0F7P////////XtZe417dXtpe217iXuFe6F7pXuxe8V7zXvBe9F74Xv5fA18JX11fXF8LXxFfFl8pXy1fOF9BX0hfTF9OXy9fUV9WX1dfWV9hX21fc193X4Nfgl9/X4pfiF+RX4dfnl+ZX5hfoF+oX61fvF/WX/tf5F/4X/Ff3WCzX/9gIWBg//9gGWAQYClgDmAxYBtgFWArYCZgD2A6YFpgQWBqYHdgX2BKYEZgTWBjYENgZGBCYGxga2BZYIFgjWDnYINgmmCEYJtglmCXYJJgp2CLYOFguGDgYNNgtF/wYL1gxmC1YNhhTWEVYQZg9mD3YQBg9GD6YQNhIWD7YPFhDWEOYUdhPmEoYSdhSmE/YTxhLGE0YT1hQmFEYXNhd2FYYVlhWmFrYXRhb2FlYXFhX2FdYVNhdWGZYZZhh2GsYZRhmmGKYZFhq2GuYcxhymHJYfdhyGHDYcZhumHLf3lhzWHmYeNh9mH6YfRh/2H9Yfxh/mIAYghiCWINYgxiFGIb////////Yh5iIWIqYi5iMGIyYjNiQWJOYl5iY2JbYmBiaGJ8YoJiiWJ+YpJik2KWYtRig2KUYtdi0WK7Ys9i/2LGZNRiyGLcYsxiymLCYsdim2LJYwxi7mLxYydjAmMIYu9i9WNQYz5jTWQcY09jlmOOY4Bjq2N2Y6Njj2OJY59jtWNr//9jaWO+Y+ljwGPGY+NjyWPSY/ZjxGQWZDRkBmQTZCZkNmUdZBdkKGQPZGdkb2R2ZE5lKmSVZJNkpWSpZIhkvGTaZNJkxWTHZLtk2GTCZPFk54IJZOBk4WKsZONk72UsZPZk9GTyZPplAGT9ZRhlHGUFZSRlI2UrZTRlNWU3ZTZlOHVLZUhlVmVVZU1lWGVeZV1lcmV4ZYJlg4uKZZtln2WrZbdlw2XGZcFlxGXMZdJl22XZZeBl4WXxZ3JmCmYDZftnc2Y1ZjZmNGYcZk9mRGZJZkFmXmZdZmRmZ2ZoZl9mYmZwZoNmiGaOZolmhGaYZp1mwWa5Zslmvma8////////ZsRmuGbWZtpm4GY/ZuZm6WbwZvVm92cPZxZnHmcmZyeXOGcuZz9nNmdBZzhnN2dGZ15nYGdZZ2NnZGeJZ3BnqWd8Z2pnjGeLZ6ZnoWeFZ7dn72e0Z+xns2fpZ7hn5GfeZ91n4mfuZ7lnzmfGZ+dqnGgeaEZoKWhAaE1oMmhO//9os2graFloY2h3aH9on2iPaK1olGidaJtog2quaLlodGi1aKBoumkPaI1ofmkBaMppCGjYaSJpJmjhaQxozWjUaOdo1Wk2aRJpBGjXaONpJWj5aOBo72koaSppGmkjaSFoxml5aXdpXGl4aWtpVGl+aW5pOWl0aT1pWWkwaWFpXmldaYFpammyaa5p0Gm/acFp02m+ac5b6GnKad1pu2nDaadqLmmRaaBpnGmVabRp3mnoagJqG2n/awpp+WnyaedqBWmxah5p7WoUaetqCmoSasFqI2oTakRqDGpyajZqeGpHamJqWWpmakhqOGoiapBqjWqgaoRqomqj////////apeGF2q7asNqwmq4arNqrGreatFq32qqatpq6mr7awWGFmr6axJrFpsxax9rOGs3dtxrOZjua0drQ2tJa1BrWWtUa1trX2tha3hreWt/a4BrhGuDa41rmGuVa55rpGuqa6trr2uya7Frs2u3a7xrxmvLa9Nr32vsa+tr82vv//+evmwIbBNsFGwbbCRsI2xebFVsYmxqbIJsjWyabIFsm2x+bGhsc2ySbJBsxGzxbNNsvWzXbMVs3WyubLFsvmy6bNts72zZbOptH4hNbTZtK209bThtGW01bTNtEm0MbWNtk21kbVpteW1ZbY5tlW/kbYVt+W4VbgpttW3HbeZtuG3Gbext3m3Mbeht0m3Fbfpt2W3kbdVt6m3ubi1ubm4ubhlucm5fbj5uI25rbitudm5Nbh9uQ246bk5uJG7/bh1uOG6CbqpumG7Jbrdu0269bq9uxG6ybtRu1W6PbqVuwm6fb0FvEXBMbuxu+G7+bz9u8m8xbu9vMm7M////////bz5vE273b4Zvem94b4FvgG9vb1tv829tb4JvfG9Yb45vkW/Cb2Zvs2+jb6FvpG+5b8Zvqm/fb9Vv7G/Ub9hv8W/ub9twCXALb/pwEXABcA9v/nAbcBpvdHAdcBhwH3AwcD5wMnBRcGNwmXCScK9w8XCscLhws3CucN9wy3Dd//9w2XEJcP1xHHEZcWVxVXGIcWZxYnFMcVZxbHGPcftxhHGVcahxrHHXcblxvnHScclx1HHOceBx7HHncfVx/HH5cf9yDXIQchtyKHItcixyMHIycjtyPHI/ckByRnJLclhydHJ+coJygXKHcpJylnKicqdyuXKycsNyxnLEcs5y0nLicuBy4XL5cvdQD3MXcwpzHHMWcx1zNHMvcylzJXM+c05zT57Yc1dzanNoc3BzeHN1c3tzenPIc7NzznO7c8Bz5XPuc950onQFdG90JXP4dDJ0OnRVdD90X3RZdEF0XHRpdHB0Y3RqdHZ0fnSLdJ50p3TKdM901HPx////////dOB043TndOl07nTydPB08XT4dPd1BHUDdQV1DHUOdQ11FXUTdR51JnUsdTx1RHVNdUp1SXVbdUZ1WnVpdWR1Z3VrdW11eHV2dYZ1h3V0dYp1iXWCdZR1mnWddaV1o3XCdbN1w3W1db11uHW8dbF1zXXKddJ12XXjdd51/nX///91/HYBdfB1+nXydfN2C3YNdgl2H3YndiB2IXYidiR2NHYwdjt2R3ZIdkZ2XHZYdmF2YnZodml2anZndmx2cHZydnZ2eHZ8doB2g3aIdot2jnaWdpN2mXaadrB2tHa4drl2unbCds121nbSdt524Xbldud26oYvdvt3CHcHdwR3KXckdx53JXcmdxt3N3c4d0d3Wndod2t3W3dld393fnd5d453i3eRd6B3nnewd7Z3uXe/d7x3vXe7d8d3zXfXd9p33Hfjd+53/HgMeBJ5JnggeSp4RXiOeHR4hnh8eJp4jHijeLV4qniveNF4xnjLeNR4vni8eMV4ynjs////////eOd42nj9ePR5B3kSeRF5GXkseSt5QHlgeVd5X3laeVV5U3l6eX95inmdeaefS3mqea55s3m5ebp5yXnVeed57HnheeN6CHoNehh6GXogeh95gHoxejt6Pno3ekN6V3pJemF6Ynppn516cHp5en16iHqXepV6mHqWeql6yHqw//96tnrFesR6v5CDesd6ynrNes961XrTetl62nrdeuF64nrmeu168HsCew97CnsGezN7GHsZex57NXsoezZ7UHt6ewR7TXsLe0x7RXt1e2V7dHtne3B7cXtse257nXuYe597jXuce5p7i3uSe497XXuZe8t7wXvMe897tHvGe9176XwRfBR75nvlfGB8AHwHfBN783v3fBd8DXv2fCN8J3wqfB98N3wrfD18THxDfFR8T3xAfFB8WHxffGR8VnxlfGx8dXyDfJB8pHytfKJ8q3yhfKh8s3yyfLF8rny5fL18wHzFfMJ82HzSfNx84ps7fO988nz0fPZ8+n0G////////fQJ9HH0VfQp9RX1LfS59Mn0/fTV9Rn1zfVZ9Tn1yfWh9bn1PfWN9k32JfVt9j319fZt9un2ufaN9tX3Hfb19q349faJ9r33cfbh9n32wfdh93X3kfd59+33yfeF+BX4KfiN+IX4SfjF+H34Jfgt+In5GfmZ+O341fjl+Q343//9+Mn46fmd+XX5Wfl5+WX5afnl+an5pfnx+e36DfdV+fY+ufn9+iH6Jfox+kn6QfpN+lH6Wfo5+m36cfzh/On9Ff0x/TX9Of1B/UX9Vf1R/WH9ff2B/aH9pf2d/eH+Cf4Z/g3+If4d/jH+Uf55/nX+af6N/r3+yf7l/rn+2f7iLcX/Ff8Z/yn/Vf9R/4X/mf+l/83/5mNyABoAEgAuAEoAYgBmAHIAhgCiAP4A7gEqARoBSgFiAWoBfgGKAaIBzgHKAcIB2gHmAfYB/gISAhoCFgJuAk4CagK1RkICsgNuA5YDZgN2AxIDagNaBCYDvgPGBG4EpgSOBL4FL////////louBRoE+gVOBUYD8gXGBboFlgWaBdIGDgYiBioGAgYKBoIGVgaSBo4FfgZOBqYGwgbWBvoG4gb2BwIHCgbqByYHNgdGB2YHYgciB2oHfgeCB54H6gfuB/oIBggKCBYIHggqCDYIQghaCKYIrgjiCM4JAglmCWIJdglqCX4Jk//+CYoJogmqCa4IugnGCd4J4gn6CjYKSgquCn4K7gqyC4YLjgt+C0oL0gvOC+oOTgwOC+4L5gt6DBoLcgwmC2YM1gzSDFoMygzGDQIM5g1CDRYMvgyuDF4MYg4WDmoOqg5+DooOWgyODjoOHg4qDfIO1g3ODdYOgg4mDqIP0hBOD64POg/2EA4PYhAuDwYP3hAeD4IPyhA2EIoQgg72EOIUGg/uEbYQqhDyFWoSEhHeEa4SthG6EgoRphEaELIRvhHmENYTKhGKEuYS/hJ+E2YTNhLuE2oTQhMGExoTWhKGFIYT/hPSFF4UYhSyFH4UVhRSE/IVAhWOFWIVI////////hUGGAoVLhVWFgIWkhYiFkYWKhaiFbYWUhZuF6oWHhZyFd4V+hZCFyYW6hc+FuYXQhdWF3YXlhdyF+YYKhhOGC4X+hfqGBoYihhqGMIY/hk1OVYZUhl+GZ4ZxhpOGo4aphqqGi4aMhraGr4bEhsaGsIbJiCOGq4bUht6G6Ybs//+G34bbhu+HEocGhwiHAIcDhvuHEYcJhw2G+YcKhzSHP4c3hzuHJYcphxqHYIdfh3iHTIdOh3SHV4doh26HWYdTh2OHaogFh6KHn4eCh6+Hy4e9h8CH0JbWh6uHxIezh8eHxoe7h++H8ofgiA+IDYf+h/aH94gOh9KIEYgWiBWIIoghiDGINog5iCeIO4hEiEKIUohZiF6IYohriIGIfoieiHWIfYi1iHKIgoiXiJKIroiZiKKIjYikiLCIv4ixiMOIxIjUiNiI2YjdiPmJAoj8iPSI6IjyiQSJDIkKiROJQ4keiSWJKokriUGJRIk7iTaJOIlMiR2JYIle////////iWaJZIltiWqJb4l0iXeJfomDiYiJiomTiZiJoYmpiaaJrImvibKJuom9ib+JwInaidyJ3YnnifSJ+IoDihaKEIoMihuKHYolijaKQYpbilKKRopIinyKbYpsimKKhYqCioSKqIqhipGKpYqmipqKo4rEis2KworaiuuK84rn//+K5IrxixSK4IriiveK3orbiwyLB4saiuGLFosQixeLIIszl6uLJosriz6LKItBi0yLT4tOi0mLVotbi1qLa4tfi2yLb4t0i32LgIuMi46LkouTi5aLmYuajDqMQYw/jEiMTIxOjFCMVYxijGyMeIx6jIKMiYyFjIqMjYyOjJSMfIyYYh2MrYyqjL2MsoyzjK6MtozIjMGM5IzjjNqM/Yz6jPuNBI0FjQqNB40PjQ2NEJ9OjROMzY0UjRaNZ41tjXGNc42BjZmNwo2+jbqNz43ajdaNzI3bjcuN6o3rjd+N4438jgiOCY3/jh2OHo4Qjh+OQo41jjCONI5K////////jkeOSY5MjlCOSI5ZjmSOYI4qjmOOVY52jnKOfI6BjoeOhY6EjouOio6TjpGOlI6ZjqqOoY6sjrCOxo6xjr6OxY7IjsuO247jjvyO+47rjv6PCo8FjxWPEo8ZjxOPHI8fjxuPDI8mjzOPO485j0WPQo8+j0yPSY9Gj06PV49c//+PYo9jj2SPnI+fj6OPrY+vj7eP2o/lj+KP6o/vkIeP9JAFj/mP+pARkBWQIZANkB6QFpALkCeQNpA1kDmP+JBPkFCQUZBSkA6QSZA+kFaQWJBekGiQb5B2lqiQcpCCkH2QgZCAkIqQiZCPkKiQr5CxkLWQ4pDkYkiQ25ECkRKRGZEykTCRSpFWkViRY5FlkWmRc5FykYuRiZGCkaKRq5GvkaqRtZG0kbqRwJHBkcmRy5HQkdaR35HhkduR/JH1kfaSHpH/khSSLJIVkhGSXpJXkkWSSZJkkkiSlZI/kkuSUJKckpaSk5KbklqSz5K5kreS6ZMPkvqTRJMu////////kxmTIpMakyOTOpM1kzuTXJNgk3yTbpNWk7CTrJOtk5STuZPWk9eT6JPlk9iTw5Pdk9CTyJPklBqUFJQTlAOUB5QQlDaUK5Q1lCGUOpRBlFKURJRblGCUYpRelGqSKZRwlHWUd5R9lFqUfJR+lIGUf5WClYeVipWUlZaVmJWZ//+VoJWolaeVrZW8lbuVuZW+lcpv9pXDlc2VzJXVldSV1pXcleGV5ZXiliGWKJYuli+WQpZMlk+WS5Z3llyWXpZdll+WZpZylmyWjZaYlpWWl5aqlqeWsZaylrCWtJa2lriWuZbOlsuWyZbNiU2W3JcNltWW+ZcElwaXCJcTlw6XEZcPlxaXGZcklyqXMJc5lz2XPpdEl0aXSJdCl0mXXJdgl2SXZpdoUtKXa5dxl3mXhZd8l4GXepeGl4uXj5eQl5yXqJeml6OXs5e0l8OXxpfIl8uX3Jftn0+X8nrfl/aX9ZgPmAyYOJgkmCGYN5g9mEaYT5hLmGuYb5hw////////mHGYdJhzmKqYr5ixmLaYxJjDmMaY6ZjrmQOZCZkSmRSZGJkhmR2ZHpkkmSCZLJkumT2ZPplCmUmZRZlQmUuZUZlSmUyZVZmXmZiZpZmtma6ZvJnfmduZ3ZnYmdGZ7ZnumfGZ8pn7mfiaAZoPmgWZ4poZmiuaN5pFmkKaQJpD//+aPppVmk2aW5pXml+aYpplmmSaaZprmmqarZqwmryawJrPmtGa05rUmt6a35rimuOa5prvmuua7pr0mvGa95r7mwabGJsamx+bIpsjmyWbJ5somymbKpsumy+bMptEm0ObT5tNm06bUZtYm3Sbk5uDm5GblpuXm5+boJuom7SbwJvKm7mbxpvPm9Gb0pvjm+Kb5JvUm+GcOpvym/Gb8JwVnBScCZwTnAycBpwInBKcCpwEnC6cG5wlnCScIZwwnEecMpxGnD6cWpxgnGecdpx4nOec7JzwnQmdCJzrnQOdBp0qnSadr50jnR+dRJ0VnRKdQZ0/nT6dRp1I////////nV2dXp1knVGdUJ1ZnXKdiZ2Hnaudb516nZqdpJ2pnbKdxJ3BnbuduJ26ncadz53Cndmd0534nead7Z3vnf2eGp4bnh6edZ55nn2egZ6InouejJ6SnpWekZ6dnqWeqZ64nqqerZdhnsyezp7PntCe1J7cnt6e3Z7gnuWe6J7v//+e9J72nvee+Z77nvye/Z8Hnwh2t58VnyGfLJ8+n0qfUp9Un2OfX59gn2GfZp9nn2yfap93n3Kfdp+Vn5yfoFgvaceQWXRkUdxxmf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w=="; private static readonly ushort[] UnicodeToQrKanji; public static List MakeSegmentsOptimally(string text, QrCode.Ecc ecl, int minVersion = 1, int maxVersion = 40) { Objects.RequireNonNull(text); Objects.RequireNonNull(ecl); if (minVersion < 1 || minVersion > maxVersion) { throw new ArgumentOutOfRangeException("minVersion", "Invalid value"); } if (maxVersion > 40) { throw new ArgumentOutOfRangeException("maxVersion", "Invalid value"); } List list = null; int[] codePoints = ToCodePoints(text); int num = 0; int num2 = 0; for (int i = minVersion; i <= maxVersion; i++) { if (i == minVersion || i == 10 || i == 27) { list = MakeSegmentsOptimally(codePoints, i); } num = QrCode.GetNumDataCodewords(i, ecl) * 8; num2 = QrSegment.GetTotalBits(list, i); if (num2 != -1 && num2 <= num) { return list; } } string message = "Segment too long"; if (num2 != -1) { message = $"Data length = {num2} bits, Max capacity = {num} bits"; } throw new DataTooLongException(message); } private static List MakeSegmentsOptimally(IReadOnlyList codePoints, int version) { if (codePoints.Count == 0) { return new List(); } QrSegment.Mode[] charModes = ComputeCharacterModes(codePoints, version); return SplitIntoSegments(codePoints, charModes); } private static int MeasureSegmentsOptimally(IReadOnlyList codePoints, int version) { if (codePoints.Count == 0) { return 0; } QrSegment.Mode[] charModes = ComputeCharacterModes(codePoints, version); return MeasureSegments(codePoints, charModes, version); } private static QrSegment.Mode[] ComputeCharacterModes(IReadOnlyList codePoints, int version) { if (codePoints.Count == 0) { throw new ArgumentOutOfRangeException("codePoints"); } QrSegment.Mode[] array = new QrSegment.Mode[4] { QrSegment.Mode.Byte, QrSegment.Mode.Alphanumeric, QrSegment.Mode.Numeric, QrSegment.Mode.Kanji }; int num = array.Length; int[] array2 = new int[num]; for (int i = 0; i < num; i++) { array2[i] = (4 + array[i].NumCharCountBits(version)) * 6; } QrSegment.Mode[,] array3 = new QrSegment.Mode[codePoints.Count, num]; int[] array4 = (int[])array2.Clone(); for (int j = 0; j < codePoints.Count; j++) { int num2 = codePoints[j]; int[] array5 = new int[num]; array5[0] = array4[0] + CountUtf8Bytes(num2) * 8 * 6; array3[j, 0] = array[0]; if (Enumerable.Contains("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:", (char)num2)) { array5[1] = array4[1] + 33; array3[j, 1] = array[1]; } if (48 <= num2 && num2 <= 57) { array5[2] = array4[2] + 20; array3[j, 2] = array[2]; } if (IsKanji(num2)) { array5[3] = array4[3] + 78; array3[j, 3] = array[3]; } for (int k = 0; k < num; k++) { for (int l = 0; l < num; l++) { int num3 = (array5[l] + 5) / 6 * 6 + array2[k]; if (array3[j, l] != null && (array3[j, k] == null || num3 < array5[k])) { array5[k] = num3; array3[j, k] = array[l]; } } } array4 = array5; } QrSegment.Mode mode = null; int m = 0; int num4 = 0; for (; m < num; m++) { if (mode == null || array4[m] < num4) { num4 = array4[m]; mode = array[m]; } } QrSegment.Mode[] array6 = new QrSegment.Mode[codePoints.Count]; for (int num5 = array6.Length - 1; num5 >= 0; num5--) { for (int n = 0; n < num; n++) { if (array[n] == mode) { mode = (array6[num5] = array3[num5, n]); break; } } } return array6; } private static List SplitIntoSegments(IReadOnlyList codePoints, IReadOnlyList charModes) { if (codePoints.Count == 0) { throw new ArgumentOutOfRangeException("codePoints"); } List result = new List(); GroupConsecutiveModes(charModes, delegate(int startIndex, int endIndex, QrSegment.Mode mode) { string text = FromCodePoints(codePoints, startIndex, endIndex - startIndex); if (mode == QrSegment.Mode.Byte) { result.Add(QrSegment.MakeBytes(Encoding.UTF8.GetBytes(text))); } else if (mode == QrSegment.Mode.Numeric) { result.Add(QrSegment.MakeNumeric(text)); } else if (mode == QrSegment.Mode.Alphanumeric) { result.Add(QrSegment.MakeAlphanumeric(text)); } else if (mode == QrSegment.Mode.Kanji) { result.Add(MakeKanji(text)); } }); return result; } private static int MeasureSegments(IReadOnlyList codePoints, IReadOnlyList charModes, int version) { if (codePoints.Count == 0) { throw new ArgumentOutOfRangeException("codePoints"); } int result = 0; GroupConsecutiveModes(charModes, delegate(int startIndex, int endIndex, QrSegment.Mode mode) { int num; if (mode == QrSegment.Mode.Byte) { num = 0; for (int i = startIndex; i < endIndex; i++) { num += CountUtf8Bytes(codePoints[i]); } } else { num = endIndex - startIndex; } result += QrSegment.GetTotalBits(num, mode, version); }); return result; } private static string FromCodePoints(IReadOnlyList codepoints, int startIndex, int count) { Encoding encoding = new UTF32Encoding(!BitConverter.IsLittleEndian, byteOrderMark: false, throwOnInvalidCharacters: true); byte[] array = new byte[count * 4]; int num = startIndex; int num2 = 0; while (num < startIndex + count) { byte[] bytes = BitConverter.GetBytes(codepoints[num]); array[num2] = bytes[0]; array[num2 + 1] = bytes[1]; array[num2 + 2] = bytes[2]; array[num2 + 3] = bytes[3]; num++; num2 += 4; } return encoding.GetString(array); } private static int[] ToCodePoints(string s) { byte[] bytes = new UTF32Encoding(!BitConverter.IsLittleEndian, byteOrderMark: false, throwOnInvalidCharacters: true).GetBytes(s); int[] array = new int[bytes.Length / 4]; int num = 0; int num2 = 0; while (num < bytes.Length) { array[num2] = BitConverter.ToInt32(bytes, num); num += 4; num2++; } return array; } private static int CountUtf8Bytes(int cp) { if (cp < 0) { throw new ArgumentOutOfRangeException("cp", "Invalid code point"); } if (cp < 128) { return 1; } if (cp < 2048) { return 2; } if (cp < 65536) { return 3; } if (cp < 1114112) { return 4; } throw new ArgumentOutOfRangeException("cp", "Invalid code point"); } public static QrSegment MakeKanji(string text) { Objects.RequireNonNull(text); BitArray bitArray = new BitArray(0); foreach (ushort item in text.Select((char t) => UnicodeToQrKanji[(uint)t])) { if (item == ushort.MaxValue) { throw new ArgumentOutOfRangeException("text", "String contains non-kanji-mode characters"); } bitArray.AppendBits(item, 13); } return new QrSegment(QrSegment.Mode.Kanji, text.Length, bitArray); } public static bool IsEncodableAsKanji(string text) { Objects.RequireNonNull(text); return text.All((char t) => IsKanji(t)); } private static bool IsKanji(int c) { if (c < UnicodeToQrKanji.Length) { return UnicodeToQrKanji[c] != ushort.MaxValue; } return false; } static QrSegmentAdvanced() { UnicodeToQrKanji = new ushort[65536]; for (int i = 0; i < UnicodeToQrKanji.Length; i++) { UnicodeToQrKanji[i] = ushort.MaxValue; } byte[] array = Convert.FromBase64String("MAAwATAC/wz/DjD7/xr/G/8f/wEwmzCcALT/QACo/z7/4/8/MP0w/jCdMJ4wA07dMAUwBjAHMPwgFSAQ/w8AXDAcIBb/XCAmICUgGCAZIBwgHf8I/wkwFDAV/zv/Pf9b/10wCDAJMAowCzAMMA0wDjAPMBAwEf8LIhIAsQDX//8A9/8dImD/HP8eImYiZyIeIjQmQiZAALAgMiAzIQP/5f8EAKIAo/8F/wP/Bv8K/yAApyYGJgUlyyXPJc4lxyXGJaEloCWzJbIlvSW8IDswEiGSIZAhkSGTMBP/////////////////////////////IggiCyKGIocigiKDIioiKf////////////////////8iJyIoAKwh0iHUIgAiA/////////////////////////////8iICKlIxIiAiIHImEiUiJqImsiGiI9Ih0iNSIrIiz//////////////////yErIDAmbyZtJmogICAhALb//////////yXv/////////////////////////////////////////////////xD/Ef8S/xP/FP8V/xb/F/8Y/xn///////////////////8h/yL/I/8k/yX/Jv8n/yj/Kf8q/yv/LP8t/y7/L/8w/zH/Mv8z/zT/Nf82/zf/OP85/zr///////////////////9B/0L/Q/9E/0X/Rv9H/0j/Sf9K/0v/TP9N/07/T/9Q/1H/Uv9T/1T/Vf9W/1f/WP9Z/1r//////////zBBMEIwQzBEMEUwRjBHMEgwSTBKMEswTDBNME4wTzBQMFEwUjBTMFQwVTBWMFcwWDBZMFowWzBcMF0wXjBfMGAwYTBiMGMwZDBlMGYwZzBoMGkwajBrMGwwbTBuMG8wcDBxMHIwczB0MHUwdjB3MHgweTB6MHswfDB9MH4wfzCAMIEwgjCDMIQwhTCGMIcwiDCJMIowizCMMI0wjjCPMJAwkTCSMJP/////////////////////////////////////MKEwojCjMKQwpTCmMKcwqDCpMKowqzCsMK0wrjCvMLAwsTCyMLMwtDC1MLYwtzC4MLkwujC7MLwwvTC+ML8wwDDBMMIwwzDEMMUwxjDHMMgwyTDKMMswzDDNMM4wzzDQMNEw0jDTMNQw1TDWMNcw2DDZMNow2zDcMN0w3jDf//8w4DDhMOIw4zDkMOUw5jDnMOgw6TDqMOsw7DDtMO4w7zDwMPEw8jDzMPQw9TD2/////////////////////wORA5IDkwOUA5UDlgOXA5gDmQOaA5sDnAOdA54DnwOgA6EDowOkA6UDpgOnA6gDqf////////////////////8DsQOyA7MDtAO1A7YDtwO4A7kDugO7A7wDvQO+A78DwAPBA8MDxAPFA8YDxwPIA8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////BBAEEQQSBBMEFAQVBAEEFgQXBBgEGQQaBBsEHAQdBB4EHwQgBCEEIgQjBCQEJQQmBCcEKAQpBCoEKwQsBC0ELgQv////////////////////////////////////////BDAEMQQyBDMENAQ1BFEENgQ3BDgEOQQ6BDsEPAQ9//8EPgQ/BEAEQQRCBEMERARFBEYERwRIBEkESgRLBEwETQROBE///////////////////////////////////yUAJQIlDCUQJRglFCUcJSwlJCU0JTwlASUDJQ8lEyUbJRclIyUzJSslOyVLJSAlLyUoJTclPyUdJTAlJSU4JUL//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////06cVRZaA5Y/VMBhG2MoWfaQIoR1gxx6UGCqY+FuJWXthGaCppv1aJNXJ2WhYnFbm1nQhnuY9H1ifb6bjmIWfJ+It1uJXrVjCWaXaEiVx5eNZ09O5U8KT01PnVBJVvJZN1nUWgFcCWDfYQ9hcGYTaQVwunVPdXB5+32tfe+Aw4QOiGOLApBVkHpTO06VTqVX34CykMF4704AWPFuopA4ejKDKIKLnC9RQVNwVL1U4VbgWftfFZjybeuA5IUt////////lmKWcJagl/tUC1PzW4dwz3+9j8KW6FNvnVx6uk4ReJOB/G4mVhhVBGsdhRqcO1nlU6ltZnTclY9WQk6RkEuW8oNPmQxT4VW2WzBfcWYgZvNoBGw4bPNtKXRbdsh6Tpg0gvGIW4pgku1tsnWrdsqZxWCmiwGNipWyaY5TrVGG//9XElgwWURbtF72YChjqWP0bL9vFHCOcRRxWXHVcz9+AYJ2gtGFl5BgkludG1hpZbxsWnUlUflZLlllX4Bf3GK8ZfpqKmsna7Rzi3/BiVadLJ0OnsRcoWyWg3tRBFxLYbaBxmh2cmFOWU/6U3hgaW4pek+X804LUxZO7k9VTz1PoU9zUqBT71YJWQ9awVu2W+F50WaHZ5xntmtMbLNwa3PCeY15vno8e4eCsYLbgwSDd4Pvg9OHZoqyVimMqI/mkE6XHoaKT8Rc6GIRcll1O4Hlgr2G/ozAlsWZE5nVTstPGonjVt5YSljKXvtf62AqYJRgYmHQYhJi0GU5////////m0FmZmiwbXdwcHVMdoZ9dYKlh/mVi5aOjJ1R8VK+WRZUs1uzXRZhaGmCba94jYTLiFeKcpOnmrhtbJmohtlXo2f/hs6SDlKDVodUBF7TYuFkuWg8aDhru3NyeLp6a4maidKNa48DkO2Vo5aUl2lbZlyzaX2YTZhOY5t7IGor//9qf2i2nA1vX1JyVZ1gcGLsbTtuB27RhFuJEI9EThScOVP2aRtqOpeEaCpRXHrDhLKR3JOMVludKGgigwWEMXylUgiCxXTmTn5Pg1GgW9JSClLYUudd+1WaWCpZ5luMW5hb215yXnlgo2EfYWNhvmPbZWJn0WhTaPprPmtTbFdvIm+Xb0V0sHUYduN3C3r/e6F8IX3pfzZ/8ICdgmaDnomzisyMq5CElFGVk5WRlaKWZZfTmSiCGE44VCtcuF3Mc6l2THc8XKl/640LlsGYEZhUmFhPAU8OU3FVnFZoV/pZR1sJW8RckF4MXn5fzGPuZzpl12XiZx9oy2jE////////al9eMGvFbBdsfXV/eUhbY3oAfQBfvYmPihiMtI13jsyPHZjimg6bPE6AUH1RAFmTW5xiL2KAZOxrOnKgdZF5R3+ph/uKvItwY6yDypegVAlUA1WraFRqWIpweCdndZ7NU3RbooEahlCQBk4YTkVOx08RU8pUOFuuXxNgJWVR//9nPWxCbHJs43B4dAN6dnquewh9Gnz+fWZl53JbU7tcRV3oYtJi4GMZbiCGWooxjd2S+G8BeaabWk6oTqtOrE+bT6BQ0VFHevZRcVH2U1RTIVN/U+tVrFiDXOFfN19KYC9gUGBtYx9lWWpLbMFywnLtd++A+IEFggiFTpD3k+GX/5lXmlpO8FHdXC1mgWltXEBm8ml1c4loUHyBUMVS5FdHXf6TJmWkayNrPXQ0eYF5vXtLfcqCuYPMiH+JX4s5j9GR0VQfkoBOXVA2U+VTOnLXc5Z36YLmjq+ZxpnImdJRd2Eahl5VsHp6UHZb05BHloVOMmrbkedcUVxI////////Y5h6n2yTl3SPYXqqcYqWiHyCaBd+cGhRk2xS8lQbhauKE3+kjs2Q4VNmiIh5QU/CUL5SEVFEVVNXLXPqV4tZUV9iX4RgdWF2YWdhqWOyZDplbGZvaEJuE3Vmej18+31MfZl+S39rgw6DSobNigiKY4tmjv2YGp2PgriPzpvo//9Sh2IfZINvwJaZaEFQkWsgbHpvVHp0fVCIQIojZwhO9lA5UCZQZVF8UjhSY1WnVw9YBVrMXvphsmH4YvNjcmkcailyfXKscy54FHhvfXl3DICpiYuLGYzijtKQY5N1lnqYVZoTnnhRQ1OfU7Nee18mbhtukHOEc/59Q4I3igCK+pZQTk5QC1PkVHxW+lnRW2Rd8V6rXydiOGVFZ69uVnLQfMqItIChgOGD8IZOioeN6JI3lseYZ58TTpROkk8NU0hUSVQ+Wi9fjF+hYJ9op2qOdFp4gYqeiqSLd5GQTl6byU6kT3xPr1AZUBZRSVFsUp9SuVL+U5pT41QR////////VA5ViVdRV6JZfVtUW11bj13lXedd9154XoNeml63XxhgUmFMYpdi2GOnZTtmAmZDZvRnbWghaJdpy2xfbSptaW4vbp11MnaHeGx6P3zgfQV9GH1efbGAFYADgK+AsYFUgY+CKoNSiEyIYYsbjKKM/JDKkXWScXg/kvyVpJZN//+YBZmZmtidO1JbUqtT91QIWNVi92/gjGqPX565UUtSO1RKVv16QJF3nWCe0nNEbwmBcHURX/1g2pqoctuPvGtkmANOylbwV2RYvlpaYGhhx2YPZgZoOWixbfd11X06gm6bQk6bT1BTyVUGXW9d5l3uZ/tsmXRzeAKKUJOWiN9XUF6nYytQtVCsUY1nAFTJWF5Zu1uwX2liTWOhaD1rc24IcH2Rx3KAeBV4JnltZY59MIPciMGPCZabUmRXKGdQf2qMoVG0V0KWKlg6aYqAtFSyXQ5X/HiVnfpPXFJKVItkPmYoZxRn9XqEe1Z9IpMvaFybrXs5UxlRilI3////////W99i9mSuZOZnLWu6hamW0XaQm9ZjTJMGm6t2v2ZSTglQmFPCXHFg6GSSZWNoX3Hmc8p1I3uXfoKGlYuDjNuReJkQZaxmq2uLTtVO1E86T39SOlP4U/JV41bbWOtZy1nJWf9bUFxNXgJeK1/XYB1jB2UvW1xlr2W9ZehnnWti//9re2wPc0V5SXnBfPh9GX0rgKKBAoHziZaKXoppimaKjIrujMeM3JbMmPxrb06LTzxPjVFQW1db+mFIYwFmQmshbstsu3I+dL111HjBeTqADIAzgeqElI+ebFCef18Pi1idK3r6jvhbjZbrTgNT8Vf3WTFayVukYIluf28Gdb6M6lufhQB74FByZ/SCnVxhhUp+HoIOUZlcBGNojWZlnHFueT59F4AFix2OypBuhseQqlAfUvpcOmdTcHxyNZFMkciTK4LlW8JfMWD5TjtT1luIYktnMWuKculz4HougWuNo5FSmZZRElPXVGpb/2OIajl9rJcAVtpTzlRo////////W5dcMV3eT+5hAWL+bTJ5wHnLfUJ+TX/Sge2CH4SQiEaJcouQjnSPL5AxkUuRbJbGkZxOwE9PUUVTQV+TYg5n1GxBbgtzY34mkc2Sg1PUWRlbv23ReV1+LnybWH5xn1H6iFOP8E/KXPtmJXeseuOCHJn/UcZfqmXsaW9riW3z//9ulm9kdv59FF3hkHWRh5gGUeZSHWJAZpFm2W4aXrZ90n9yZviFr4X3ivhSqVPZWXNej1+QYFWS5JZkULdRH1LdUyBTR1PsVOhVRlUxVhdZaFm+WjxbtVwGXA9cEVwaXoReil7gX3Bif2KEYttjjGN3ZgdmDGYtZnZnfmiiah9qNWy8bYhuCW5YcTxxJnFndcd3AXhdeQF5ZXnweuB7EXynfTmAloPWhIuFSYhdiPOKH4o8ilSKc4xhjN6RpJJmk36UGJacl5hOCk4ITh5OV1GXUnBXzlg0WMxbIl44YMVk/mdhZ1ZtRHK2dXN6Y4S4i3KRuJMgVjFX9Jj+////////Yu1pDWuWce1+VIB3gnKJ5pjfh1WPsVw7TzhP4U+1VQdaIFvdW+lfw2FOYy9lsGZLaO5pm214bfF1M3W5dx95XnnmfTOB44KvhaqJqoo6jquPm5Aykd2XB066TsFSA1h1WOxcC3UaXD2BTooKj8WWY5dteyWKz5gIkWJW81Oo//+QF1Q5V4JeJWOobDRwindhfIt/4IhwkEKRVJMQkxiWj3RemsRdB11pZXBnoo2olttjbmdJaRmDxZgXlsCI/m+EZHpb+E4WcCx1XWYvUcRSNlLiWdNfgWAnYhBlP2V0Zh9mdGjyaBZrY24FcnJ1H3bbfL6AVljwiP2Jf4qgipOKy5AdkZKXUpdZZYl6DoEGlrteLWDcYhplpWYUZ5B383pNfE1+PoEKjKyNZI3hjl94qVIHYtljpWRCYpiKLXqDe8CKrJbqfXaCDIdJTtlRSFNDU2Bbo1wCXBZd3WImYkdksGgTaDRsyW1FbRdn029ccU5xfWXLen97rX3a////////fkp/qIF6ghuCOYWmim6Mzo31kHiQd5KtkpGVg5uuUk1VhG84cTZRaHmFflWBs3zOVkxYUVyoY6pm/mb9aVpy2XWPdY55DnlWed98l30gfUSGB4o0ljuQYZ8gUOdSdVPMU+JQCVWqWO5ZT3I9W4tcZFMdYONg82NcY4NjP2O7//9kzWXpZvld42nNaf1vFXHlTol16Xb4epN8333PfZyAYYNJg1iEbIS8hfuIxY1wkAGQbZOXlxyaElDPWJdhjoHThTWNCJAgT8NQdFJHU3Ngb2NJZ19uLI2zkB9P11xejMplz32aU1KIllF2Y8NbWFtrXApkDWdRkFxO1lkaWSpscIpRVT5YFVmlYPBiU2fBgjVpVZZAmcSaKE9TWAZb/oAQXLFeL1+FYCBhS2I0Zv9s8G7egM6Bf4LUiIuMuJAAkC6Wip7bm9tO41PwWSd7LJGNmEyd+W7dcCdTU1VEW4ViWGKeYtNsom/vdCKKF5Q4b8GK/oM4UeeG+FPq////////U+lPRpBUj7BZaoExXf166o+/aNqMN3L4nEhqPYqwTjlTWFYGV2ZixWOiZeZrTm3hbltwrXfteu97qn27gD2AxobLipWTW1bjWMdfPmWtZpZqgGu1dTeKx1Akd+VXMF8bYGVmemxgdfR6Gn9ugfSHGJBFmbN7yXVcevl7UYTE//+QEHnpepKDNlrhd0BOLU7yW5lf4GK9Zjxn8WzohmuId4o7kU6S85nQahdwJnMqgueEV4yvTgFRRlHLVYtb9V4WXjNegV8UXzVfa1+0YfJjEWaiZx1vbnJSdTp3OoB0gTmBeId2ir+K3I2FjfOSmpV3mAKc5VLFY1d29GcVbIhzzYzDk66Wc20lWJxpDmnMj/2TmnXbkBpYWmgCY7Rp+09Dbyxn2I+7hSZ9tJNUaT9vcFdqWPdbLH0scipUCpHjnbROrU9OUFxQdVJDjJ5USFgkW5peHV6VXq1e918fYIxitWM6Y9Bor2xAeId5jnoLfeCCR4oCiuaORJAT////////kLiRLZHYnw5s5WRYZOJldW70doR7G5Bpk9FuulTyX7lkpI9Nj+2SRFF4WGtZKVxVXpdt+36PdRyMvI7imFtwuU8da79vsXUwlvtRTlQQWDVYV1msXGBfkmWXZ1xuIXZ7g9+M7ZAUkP2TTXgleDpSql6mVx9ZdGASUBJRWlGs//9RzVIAVRBYVFhYWVdblVz2XYtgvGKVZC1ncWhDaLxo33bXbdhub22bcG9xyF9Tddh5d3tJe1R7UnzWfXFSMIRjhWmF5IoOiwSMRo4PkAOQD5QZlnaYLZowldhQzVLVVAxYAlwOYadknm0ed7N65YD0hASQU5KFXOCdB1M/X5dfs22ccnl3Y3m/e+Rr0nLsiq1oA2phUfh6gWk0XEqc9oLrW8WRSXAeVnhcb2DHZWZsjIxakEGYE1RRZseSDVlIkKNRhU5NUeqFmYsOcFhjepNLaWKZtH4EdXdTV2lgjt+W42xdToxcPF8Qj+lTAozRgImGeV7/ZeVOc1Fl////////WYJcP5fuTvtZil/Nio1v4XmweWJb54RxcytxsV50X/Vje2SaccN8mE5DXvxOS1fcVqJgqW/DfQ2A/YEzgb+PsomXhqRd9GKKZK2Jh2d3bOJtPnQ2eDRaRn91gq2ZrE/zXsNi3WOSZVdnb3bDckyAzIC6jymRTVANV/lakmiF//9pc3Fkcv2Mt1jyjOCWapAZh3955HfnhClPL1JlU1pizWfPbMp2fXuUfJWCNoWEj+tm3W8gcgZ+G4OrmcGeplH9e7F4cnu4gId7SGroXmGAjHVRdWBRa5Jibox2epGXmupPEH9wYpx7T5WlnOlWelhZhuSWvE80UiRTSlPNU9teBmQsZZFnf2w+bE5ySHKvc+11VH5BgiyF6Yype8SRxnFpmBKY72M9Zml1anbkeNCFQ4buUypTUVQmWYNeh198YLJiSWJ5YqtlkGvUbMx1snaueJF52H3Lf3eApYirirmMu5B/l16Y22oLfDhQmVw+X65nh2vYdDV3CX+O////////nztnynoXUzl1i5rtX2aBnYPxgJhfPF/FdWJ7RpA8aGdZ61qbfRB2fossT/VfamoZbDdvAnTieWiIaIpVjHle32PPdcV50oLXkyiS8oSchu2cLVTBX2xljG1ccBWMp4zTmDtlT3T2Tg1O2FfgWStaZlvMUaheA16cYBZidmV3//9lp2ZubW5yNnsmgVCBmoKZi1yMoIzmjXSWHJZET65kq2tmgh6EYYVqkOhcAWlTmKiEeoVXTw9Sb1+pXkVnDXmPgXmJB4mGbfVfF2JVbLhOz3Jpm5JSBlQ7VnRYs2GkYm5xGllufIl83n0blvBlh4BeThlPdVF1WEBeY15zXwpnxE4mhT2ViZZbfHOYAVD7WMF2VninUiV3pYURe4ZQT1kJckd7x33oj7qP1JBNT79SyVopXwGXrU/dgheS6lcDY1VraXUriNyPFHpCUt9Yk2FVYgpmrmvNfD+D6VAjT/hTBVRGWDFZSVudXPBc710pXpZisWNnZT5luWcL////////bNVs4XD5eDJ+K4DegrOEDITshwKJEooqjEqQppLSmP2c851sTk9OoVCNUlZXSlmoXj1f2F/ZYj9mtGcbZ9Bo0lGSfSGAqoGoiwCMjIy/kn6WMlQgmCxTF1DVU1xYqGSyZzRyZ3dmekaR5lLDbKFrhlgAXkxZVGcsf/tR4XbG//9kaXjom1Seu1fLWblmJ2eaa85U6WnZXlWBnGeVm6pn/pxSaF1Opk/jU8hiuWcrbKuPxE+tfm2ev04HYWJugG8rhRNUc2cqm0Vd83uVXKxbxoccbkqE0XoUgQhZmXyNbBF3IFLZWSJxIXJfd9uXJ51haQtaf1oYUaVUDVR9Zg5234/3kpic9Fnqcl1uxVFNaMl9v33sl2KeumR4aiGDAlmEW19r23MbdvJ9soAXhJlRMmcontl27mdiUv+ZBVwkYjt8foywVU9gtn0LlYBTAU5fUbZZHHI6gDaRzl8ld+JThF95fQSFrIozjo2XVmfzha6UU2EJYQhsuXZS////////iu2POFUvT1FRKlLHU8tbpV59YKBhgmPWZwln2m5nbYxzNnM3dTF5UIjVipiQSpCRkPWWxIeNWRVOiE9ZTg6KiY8/mBBQrV58WZZbuV64Y9pj+mTBZtxpSmnYbQtutnGUdSh6r3+KgACESYTJiYGLIY4KkGWWfZkKYX5ikWsy//9sg210f8x//G3Af4WHuoj4Z2WDsZg8lvdtG31hhD2Rak5xU3VdUGsEb+uFzYYtiadSKVQPXGVnTmiodAZ0g3XiiM+I4ZHMluKWeF+Lc4d6y4ROY6B1ZVKJbUFunHQJdVl4a3ySloZ63J+NT7ZhbmXFhlxOhk6uUNpOIVHMW+5lmWiBbbxzH3ZCd616HHzngm+K0pB8kc+WdZgYUpt90VArU5hnl23LcdB0M4HojyqWo5xXnp90YFhBbZl9L5heTuRPNk+LUbdSsV26YBxzsnk8gtOSNJa3lvaXCp6Xn2Jmpmt0UhdSo3DIiMJeyWBLYZBvI3FJfD599IBv////////hO6QI5MsVEKbb2rTcImMwo3vlzJStFpBXspfBGcXaXxplG1qbw9yYnL8e+2AAYB+h0uQzlFtnpN5hICLkzKK1lAtVIyKcWtqjMSBB2DRZ6Cd8k6ZTpicEIprhcGFaGkAbn54l4FV/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////18MThBOFU4qTjFONk48Tj9OQk5WTlhOgk6FjGtOioISXw1Ojk6eTp9OoE6iTrBOs062Ts5OzU7ETsZOwk7XTt5O7U7fTvdPCU9aTzBPW09dT1dPR092T4hPj0+YT3tPaU9wT5FPb0+GT5ZRGE/UT99Pzk/YT9tP0U/aT9BP5E/lUBpQKFAUUCpQJVAFTxxP9lAhUClQLE/+T+9QEVAGUENQR2cDUFVQUFBIUFpQVlBsUHhQgFCaUIVQtFCy////////UMlQylCzUMJQ1lDeUOVQ7VDjUO5Q+VD1UQlRAVECURZRFVEUURpRIVE6UTdRPFE7UT9RQFFSUUxRVFFievhRaVFqUW5RgFGCVthRjFGJUY9RkVGTUZVRllGkUaZRolGpUapRq1GzUbFRslGwUbVRvVHFUclR21HghlVR6VHt//9R8FH1Uf5SBFILUhRSDlInUipSLlIzUjlST1JEUktSTFJeUlRSalJ0UmlSc1J/Un1SjVKUUpJScVKIUpGPqI+nUqxSrVK8UrVSwVLNUtdS3lLjUuaY7VLgUvNS9VL4UvlTBlMIdThTDVMQUw9TFVMaUyNTL1MxUzNTOFNAU0ZTRU4XU0lTTVHWU15TaVNuWRhTe1N3U4JTllOgU6ZTpVOuU7BTtlPDfBKW2VPfZvxx7lPuU+hT7VP6VAFUPVRAVCxULVQ8VC5UNlQpVB1UTlSPVHVUjlRfVHFUd1RwVJJUe1SAVHZUhFSQVIZUx1SiVLhUpVSsVMRUyFSo////////VKtUwlSkVL5UvFTYVOVU5lUPVRRU/VTuVO1U+lTiVTlVQFVjVUxVLlVcVUVVVlVXVThVM1VdVZlVgFSvVYpVn1V7VX5VmFWeVa5VfFWDValVh1WoVdpVxVXfVcRV3FXkVdRWFFX3VhZV/lX9VhtV+VZOVlBx31Y0VjZWMlY4//9Wa1ZkVi9WbFZqVoZWgFaKVqBWlFaPVqVWrla2VrRWwla8VsFWw1bAVshWzlbRVtNW11buVvlXAFb/VwRXCVcIVwtXDVcTVxhXFlXHVxxXJlc3VzhXTlc7V0BXT1dpV8BXiFdhV39XiVeTV6BXs1ekV6pXsFfDV8ZX1FfSV9NYClfWV+NYC1gZWB1YclghWGJYS1hwa8BYUlg9WHlYhVi5WJ9Yq1i6WN5Yu1i4WK5YxVjTWNFY11jZWNhY5VjcWORY31jvWPpY+Vj7WPxY/VkCWQpZEFkbaKZZJVksWS1ZMlk4WT560llVWVBZTllaWVhZYllgWWdZbFlp////////WXhZgVmdT15Pq1mjWbJZxlnoWdxZjVnZWdpaJVofWhFaHFoJWhpaQFpsWklaNVo2WmJaalqaWrxavlrLWsJavVrjWtda5lrpWtZa+lr7WwxbC1sWWzJa0FsqWzZbPltDW0VbQFtRW1VbWltbW2VbaVtwW3NbdVt4ZYhbeluA//9bg1umW7hbw1vHW8lb1FvQW+Rb5lviW95b5VvrW/Bb9lvzXAVcB1wIXA1cE1wgXCJcKFw4XDlcQVxGXE5cU1xQXE9bcVxsXG5OYlx2XHlcjFyRXJRZm1yrXLtctly8XLdcxVy+XMdc2VzpXP1c+lztXYxc6l0LXRVdF11cXR9dG10RXRRdIl0aXRldGF1MXVJdTl1LXWxdc112XYddhF2CXaJdnV2sXa5dvV2QXbddvF3JXc1d013SXdZd213rXfJd9V4LXhpeGV4RXhteNl43XkReQ15AXk5eV15UXl9eYl5kXkdedV52XnqevF5/XqBewV7CXshe0F7P////////XtZe417dXtpe217iXuFe6F7pXuxe8V7zXvBe9F74Xv5fA18JX11fXF8LXxFfFl8pXy1fOF9BX0hfTF9OXy9fUV9WX1dfWV9hX21fc193X4Nfgl9/X4pfiF+RX4dfnl+ZX5hfoF+oX61fvF/WX/tf5F/4X/Ff3WCzX/9gIWBg//9gGWAQYClgDmAxYBtgFWArYCZgD2A6YFpgQWBqYHdgX2BKYEZgTWBjYENgZGBCYGxga2BZYIFgjWDnYINgmmCEYJtglmCXYJJgp2CLYOFguGDgYNNgtF/wYL1gxmC1YNhhTWEVYQZg9mD3YQBg9GD6YQNhIWD7YPFhDWEOYUdhPmEoYSdhSmE/YTxhLGE0YT1hQmFEYXNhd2FYYVlhWmFrYXRhb2FlYXFhX2FdYVNhdWGZYZZhh2GsYZRhmmGKYZFhq2GuYcxhymHJYfdhyGHDYcZhumHLf3lhzWHmYeNh9mH6YfRh/2H9Yfxh/mIAYghiCWINYgxiFGIb////////Yh5iIWIqYi5iMGIyYjNiQWJOYl5iY2JbYmBiaGJ8YoJiiWJ+YpJik2KWYtRig2KUYtdi0WK7Ys9i/2LGZNRiyGLcYsxiymLCYsdim2LJYwxi7mLxYydjAmMIYu9i9WNQYz5jTWQcY09jlmOOY4Bjq2N2Y6Njj2OJY59jtWNr//9jaWO+Y+ljwGPGY+NjyWPSY/ZjxGQWZDRkBmQTZCZkNmUdZBdkKGQPZGdkb2R2ZE5lKmSVZJNkpWSpZIhkvGTaZNJkxWTHZLtk2GTCZPFk54IJZOBk4WKsZONk72UsZPZk9GTyZPplAGT9ZRhlHGUFZSRlI2UrZTRlNWU3ZTZlOHVLZUhlVmVVZU1lWGVeZV1lcmV4ZYJlg4uKZZtln2WrZbdlw2XGZcFlxGXMZdJl22XZZeBl4WXxZ3JmCmYDZftnc2Y1ZjZmNGYcZk9mRGZJZkFmXmZdZmRmZ2ZoZl9mYmZwZoNmiGaOZolmhGaYZp1mwWa5Zslmvma8////////ZsRmuGbWZtpm4GY/ZuZm6WbwZvVm92cPZxZnHmcmZyeXOGcuZz9nNmdBZzhnN2dGZ15nYGdZZ2NnZGeJZ3BnqWd8Z2pnjGeLZ6ZnoWeFZ7dn72e0Z+xns2fpZ7hn5GfeZ91n4mfuZ7lnzmfGZ+dqnGgeaEZoKWhAaE1oMmhO//9os2graFloY2h3aH9on2iPaK1olGidaJtog2quaLlodGi1aKBoumkPaI1ofmkBaMppCGjYaSJpJmjhaQxozWjUaOdo1Wk2aRJpBGjXaONpJWj5aOBo72koaSppGmkjaSFoxml5aXdpXGl4aWtpVGl+aW5pOWl0aT1pWWkwaWFpXmldaYFpammyaa5p0Gm/acFp02m+ac5b6GnKad1pu2nDaadqLmmRaaBpnGmVabRp3mnoagJqG2n/awpp+WnyaedqBWmxah5p7WoUaetqCmoSasFqI2oTakRqDGpyajZqeGpHamJqWWpmakhqOGoiapBqjWqgaoRqomqj////////apeGF2q7asNqwmq4arNqrGreatFq32qqatpq6mr7awWGFmr6axJrFpsxax9rOGs3dtxrOZjua0drQ2tJa1BrWWtUa1trX2tha3hreWt/a4BrhGuDa41rmGuVa55rpGuqa6trr2uya7Frs2u3a7xrxmvLa9Nr32vsa+tr82vv//+evmwIbBNsFGwbbCRsI2xebFVsYmxqbIJsjWyabIFsm2x+bGhsc2ySbJBsxGzxbNNsvWzXbMVs3WyubLFsvmy6bNts72zZbOptH4hNbTZtK209bThtGW01bTNtEm0MbWNtk21kbVpteW1ZbY5tlW/kbYVt+W4VbgpttW3HbeZtuG3Gbext3m3Mbeht0m3Fbfpt2W3kbdVt6m3ubi1ubm4ubhlucm5fbj5uI25rbitudm5Nbh9uQ246bk5uJG7/bh1uOG6CbqpumG7Jbrdu0269bq9uxG6ybtRu1W6PbqVuwm6fb0FvEXBMbuxu+G7+bz9u8m8xbu9vMm7M////////bz5vE273b4Zvem94b4FvgG9vb1tv829tb4JvfG9Yb45vkW/Cb2Zvs2+jb6FvpG+5b8Zvqm/fb9Vv7G/Ub9hv8W/ub9twCXALb/pwEXABcA9v/nAbcBpvdHAdcBhwH3AwcD5wMnBRcGNwmXCScK9w8XCscLhws3CucN9wy3Dd//9w2XEJcP1xHHEZcWVxVXGIcWZxYnFMcVZxbHGPcftxhHGVcahxrHHXcblxvnHScclx1HHOceBx7HHncfVx/HH5cf9yDXIQchtyKHItcixyMHIycjtyPHI/ckByRnJLclhydHJ+coJygXKHcpJylnKicqdyuXKycsNyxnLEcs5y0nLicuBy4XL5cvdQD3MXcwpzHHMWcx1zNHMvcylzJXM+c05zT57Yc1dzanNoc3BzeHN1c3tzenPIc7NzznO7c8Bz5XPuc950onQFdG90JXP4dDJ0OnRVdD90X3RZdEF0XHRpdHB0Y3RqdHZ0fnSLdJ50p3TKdM901HPx////////dOB043TndOl07nTydPB08XT4dPd1BHUDdQV1DHUOdQ11FXUTdR51JnUsdTx1RHVNdUp1SXVbdUZ1WnVpdWR1Z3VrdW11eHV2dYZ1h3V0dYp1iXWCdZR1mnWddaV1o3XCdbN1w3W1db11uHW8dbF1zXXKddJ12XXjdd51/nX///91/HYBdfB1+nXydfN2C3YNdgl2H3YndiB2IXYidiR2NHYwdjt2R3ZIdkZ2XHZYdmF2YnZodml2anZndmx2cHZydnZ2eHZ8doB2g3aIdot2jnaWdpN2mXaadrB2tHa4drl2unbCds121nbSdt524Xbldud26oYvdvt3CHcHdwR3KXckdx53JXcmdxt3N3c4d0d3Wndod2t3W3dld393fnd5d453i3eRd6B3nnewd7Z3uXe/d7x3vXe7d8d3zXfXd9p33Hfjd+53/HgMeBJ5JnggeSp4RXiOeHR4hnh8eJp4jHijeLV4qniveNF4xnjLeNR4vni8eMV4ynjs////////eOd42nj9ePR5B3kSeRF5GXkseSt5QHlgeVd5X3laeVV5U3l6eX95inmdeaefS3mqea55s3m5ebp5yXnVeed57HnheeN6CHoNehh6GXogeh95gHoxejt6Pno3ekN6V3pJemF6Ynppn516cHp5en16iHqXepV6mHqWeql6yHqw//96tnrFesR6v5CDesd6ynrNes961XrTetl62nrdeuF64nrmeu168HsCew97CnsGezN7GHsZex57NXsoezZ7UHt6ewR7TXsLe0x7RXt1e2V7dHtne3B7cXtse257nXuYe597jXuce5p7i3uSe497XXuZe8t7wXvMe897tHvGe9176XwRfBR75nvlfGB8AHwHfBN783v3fBd8DXv2fCN8J3wqfB98N3wrfD18THxDfFR8T3xAfFB8WHxffGR8VnxlfGx8dXyDfJB8pHytfKJ8q3yhfKh8s3yyfLF8rny5fL18wHzFfMJ82HzSfNx84ps7fO988nz0fPZ8+n0G////////fQJ9HH0VfQp9RX1LfS59Mn0/fTV9Rn1zfVZ9Tn1yfWh9bn1PfWN9k32JfVt9j319fZt9un2ufaN9tX3Hfb19q349faJ9r33cfbh9n32wfdh93X3kfd59+33yfeF+BX4KfiN+IX4SfjF+H34Jfgt+In5GfmZ+O341fjl+Q343//9+Mn46fmd+XX5Wfl5+WX5afnl+an5pfnx+e36DfdV+fY+ufn9+iH6Jfox+kn6QfpN+lH6Wfo5+m36cfzh/On9Ff0x/TX9Of1B/UX9Vf1R/WH9ff2B/aH9pf2d/eH+Cf4Z/g3+If4d/jH+Uf55/nX+af6N/r3+yf7l/rn+2f7iLcX/Ff8Z/yn/Vf9R/4X/mf+l/83/5mNyABoAEgAuAEoAYgBmAHIAhgCiAP4A7gEqARoBSgFiAWoBfgGKAaIBzgHKAcIB2gHmAfYB/gISAhoCFgJuAk4CagK1RkICsgNuA5YDZgN2AxIDagNaBCYDvgPGBG4EpgSOBL4FL////////louBRoE+gVOBUYD8gXGBboFlgWaBdIGDgYiBioGAgYKBoIGVgaSBo4FfgZOBqYGwgbWBvoG4gb2BwIHCgbqByYHNgdGB2YHYgciB2oHfgeCB54H6gfuB/oIBggKCBYIHggqCDYIQghaCKYIrgjiCM4JAglmCWIJdglqCX4Jk//+CYoJogmqCa4IugnGCd4J4gn6CjYKSgquCn4K7gqyC4YLjgt+C0oL0gvOC+oOTgwOC+4L5gt6DBoLcgwmC2YM1gzSDFoMygzGDQIM5g1CDRYMvgyuDF4MYg4WDmoOqg5+DooOWgyODjoOHg4qDfIO1g3ODdYOgg4mDqIP0hBOD64POg/2EA4PYhAuDwYP3hAeD4IPyhA2EIoQgg72EOIUGg/uEbYQqhDyFWoSEhHeEa4SthG6EgoRphEaELIRvhHmENYTKhGKEuYS/hJ+E2YTNhLuE2oTQhMGExoTWhKGFIYT/hPSFF4UYhSyFH4UVhRSE/IVAhWOFWIVI////////hUGGAoVLhVWFgIWkhYiFkYWKhaiFbYWUhZuF6oWHhZyFd4V+hZCFyYW6hc+FuYXQhdWF3YXlhdyF+YYKhhOGC4X+hfqGBoYihhqGMIY/hk1OVYZUhl+GZ4ZxhpOGo4aphqqGi4aMhraGr4bEhsaGsIbJiCOGq4bUht6G6Ybs//+G34bbhu+HEocGhwiHAIcDhvuHEYcJhw2G+YcKhzSHP4c3hzuHJYcphxqHYIdfh3iHTIdOh3SHV4doh26HWYdTh2OHaogFh6KHn4eCh6+Hy4e9h8CH0JbWh6uHxIezh8eHxoe7h++H8ofgiA+IDYf+h/aH94gOh9KIEYgWiBWIIoghiDGINog5iCeIO4hEiEKIUohZiF6IYohriIGIfoieiHWIfYi1iHKIgoiXiJKIroiZiKKIjYikiLCIv4ixiMOIxIjUiNiI2YjdiPmJAoj8iPSI6IjyiQSJDIkKiROJQ4keiSWJKokriUGJRIk7iTaJOIlMiR2JYIle////////iWaJZIltiWqJb4l0iXeJfomDiYiJiomTiZiJoYmpiaaJrImvibKJuom9ib+JwInaidyJ3YnnifSJ+IoDihaKEIoMihuKHYolijaKQYpbilKKRopIinyKbYpsimKKhYqCioSKqIqhipGKpYqmipqKo4rEis2KworaiuuK84rn//+K5IrxixSK4IriiveK3orbiwyLB4saiuGLFosQixeLIIszl6uLJosriz6LKItBi0yLT4tOi0mLVotbi1qLa4tfi2yLb4t0i32LgIuMi46LkouTi5aLmYuajDqMQYw/jEiMTIxOjFCMVYxijGyMeIx6jIKMiYyFjIqMjYyOjJSMfIyYYh2MrYyqjL2MsoyzjK6MtozIjMGM5IzjjNqM/Yz6jPuNBI0FjQqNB40PjQ2NEJ9OjROMzY0UjRaNZ41tjXGNc42BjZmNwo2+jbqNz43ajdaNzI3bjcuN6o3rjd+N4438jgiOCY3/jh2OHo4Qjh+OQo41jjCONI5K////////jkeOSY5MjlCOSI5ZjmSOYI4qjmOOVY52jnKOfI6BjoeOhY6EjouOio6TjpGOlI6ZjqqOoY6sjrCOxo6xjr6OxY7IjsuO247jjvyO+47rjv6PCo8FjxWPEo8ZjxOPHI8fjxuPDI8mjzOPO485j0WPQo8+j0yPSY9Gj06PV49c//+PYo9jj2SPnI+fj6OPrY+vj7eP2o/lj+KP6o/vkIeP9JAFj/mP+pARkBWQIZANkB6QFpALkCeQNpA1kDmP+JBPkFCQUZBSkA6QSZA+kFaQWJBekGiQb5B2lqiQcpCCkH2QgZCAkIqQiZCPkKiQr5CxkLWQ4pDkYkiQ25ECkRKRGZEykTCRSpFWkViRY5FlkWmRc5FykYuRiZGCkaKRq5GvkaqRtZG0kbqRwJHBkcmRy5HQkdaR35HhkduR/JH1kfaSHpH/khSSLJIVkhGSXpJXkkWSSZJkkkiSlZI/kkuSUJKckpaSk5KbklqSz5K5kreS6ZMPkvqTRJMu////////kxmTIpMakyOTOpM1kzuTXJNgk3yTbpNWk7CTrJOtk5STuZPWk9eT6JPlk9iTw5Pdk9CTyJPklBqUFJQTlAOUB5QQlDaUK5Q1lCGUOpRBlFKURJRblGCUYpRelGqSKZRwlHWUd5R9lFqUfJR+lIGUf5WClYeVipWUlZaVmJWZ//+VoJWolaeVrZW8lbuVuZW+lcpv9pXDlc2VzJXVldSV1pXcleGV5ZXiliGWKJYuli+WQpZMlk+WS5Z3llyWXpZdll+WZpZylmyWjZaYlpWWl5aqlqeWsZaylrCWtJa2lriWuZbOlsuWyZbNiU2W3JcNltWW+ZcElwaXCJcTlw6XEZcPlxaXGZcklyqXMJc5lz2XPpdEl0aXSJdCl0mXXJdgl2SXZpdoUtKXa5dxl3mXhZd8l4GXepeGl4uXj5eQl5yXqJeml6OXs5e0l8OXxpfIl8uX3Jftn0+X8nrfl/aX9ZgPmAyYOJgkmCGYN5g9mEaYT5hLmGuYb5hw////////mHGYdJhzmKqYr5ixmLaYxJjDmMaY6ZjrmQOZCZkSmRSZGJkhmR2ZHpkkmSCZLJkumT2ZPplCmUmZRZlQmUuZUZlSmUyZVZmXmZiZpZmtma6ZvJnfmduZ3ZnYmdGZ7ZnumfGZ8pn7mfiaAZoPmgWZ4poZmiuaN5pFmkKaQJpD//+aPppVmk2aW5pXml+aYpplmmSaaZprmmqarZqwmryawJrPmtGa05rUmt6a35rimuOa5prvmuua7pr0mvGa95r7mwabGJsamx+bIpsjmyWbJ5somymbKpsumy+bMptEm0ObT5tNm06bUZtYm3Sbk5uDm5GblpuXm5+boJuom7SbwJvKm7mbxpvPm9Gb0pvjm+Kb5JvUm+GcOpvym/Gb8JwVnBScCZwTnAycBpwInBKcCpwEnC6cG5wlnCScIZwwnEecMpxGnD6cWpxgnGecdpx4nOec7JzwnQmdCJzrnQOdBp0qnSadr50jnR+dRJ0VnRKdQZ0/nT6dRp1I////////nV2dXp1knVGdUJ1ZnXKdiZ2Hnaudb516nZqdpJ2pnbKdxJ3BnbuduJ26ncadz53Cndmd0534nead7Z3vnf2eGp4bnh6edZ55nn2egZ6InouejJ6SnpWekZ6dnqWeqZ64nqqerZdhnsyezp7PntCe1J7cnt6e3Z7gnuWe6J7v//+e9J72nvee+Z77nvye/Z8Hnwh2t58VnyGfLJ8+n0qfUp9Un2OfX59gn2GfZp9nn2yfap93n3Kfdp+Vn5yfoFgvaceQWXRkUdxxmf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////w=="); for (int j = 0; j < array.Length; j += 2) { int num = (array[j] << 8) | array[j + 1]; if (num != 65535) { UnicodeToQrKanji[num] = (ushort)(j / 2); } } } public static List> MakeSegmentsForMultipleCodes(string text, QrCode.Ecc ecl, int version = 29) { Objects.RequireNonNull(text); Objects.RequireNonNull(ecl); if (version < 1 || version > 40) { throw new ArgumentOutOfRangeException("version", "Invalid value"); } List> list = SplitTextIntoMultipleCodes(text, ecl, version); byte parity = CalculateParity(text); for (int i = 0; i < list.Count; i++) { list[i].Insert(0, QrSegment.MakeStructuredAppend(parity, i + 1, list.Count)); } return list; } private static List> SplitTextIntoMultipleCodes(string text, QrCode.Ecc ecl, int version) { int[] array = ToCodePoints(text); int num = QrCode.GetNumDataCodewords(version, ecl) * 8 - 20; List> list = new List>(); int num2 = 0; while (num2 < array.Length) { if (list.Count >= 16) { throw new DataTooLongException("The text is too long to fit into 16 QR codes"); } int num3 = num2; int num4 = array.Length; while (num3 < num4) { int num5 = (num3 + num4 + 1) / 2; if (MeasureSegmentsOptimally(new ArraySegment(array, num2, num5 - num2), version) <= num) { num3 = num5; } else { num4 = num5 - 1; } } if (num4 == num2) { throw new InvalidOperationException("QR code splitting: should not reach"); } list.Add(MakeSegmentsOptimally(new ArraySegment(array, num2, num4 - num2), version)); num2 = num4; } return list; } private static byte CalculateParity(string text) { byte[] bytes = Encoding.UTF8.GetBytes(text); byte b = 0; byte[] array = bytes; foreach (byte b2 in array) { b ^= (byte)(b2 >> 8); } return b; } private static void GroupConsecutiveModes(IReadOnlyList elements, Action action) { int arg = 0; QrSegment.Mode mode = elements[0]; int num = 0; while (true) { if (num == elements.Count || elements[num] != mode) { action(arg, num, mode); if (num == elements.Count) { break; } arg = num; mode = elements[num]; } num++; } } } internal class ReedSolomonGenerator { private readonly byte[] _coefficients; internal ReedSolomonGenerator(int degree) { if (degree < 1 || degree > 255) { throw new ArgumentOutOfRangeException("degree", "Degree out of range"); } _coefficients = new byte[degree]; _coefficients[degree - 1] = 1; uint num = 1u; for (int i = 0; i < degree; i++) { for (int j = 0; j < _coefficients.Length; j++) { _coefficients[j] = Multiply(_coefficients[j], num); if (j + 1 < _coefficients.Length) { _coefficients[j] ^= _coefficients[j + 1]; } } num = Multiply(num, 2u); } } internal byte[] GetRemainder(byte[] data) { Objects.RequireNonNull(data); byte[] array = new byte[_coefficients.Length]; for (int i = 0; i < data.Length; i++) { uint y = (uint)(data[i] ^ array[0]); Array.Copy(array, 1, array, 0, array.Length - 1); array[^1] = 0; for (int j = 0; j < array.Length; j++) { array[j] ^= Multiply(_coefficients[j], y); } } return array; } private static byte Multiply(uint x, uint y) { uint num = 0u; for (int num2 = 7; num2 >= 0; num2--) { num = (num << 1) ^ ((num >> 7) * 285); num ^= ((y >> num2) & 1) * x; } return (byte)num; } }