1
0
mirror of https://github.com/XLabsProject/img-format-helper.git synced 2023-08-02 15:02:11 +02:00

Initial project commit

This commit is contained in:
rackover 2021-04-29 21:55:59 +02:00
parent 1fc2f09392
commit a178219779
35 changed files with 3366 additions and 0 deletions

31
ImgFormatHelper.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31129.286
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImgFormatHelper", "ImgFormatHelper\ImgFormatHelper.csproj", "{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}.Debug|x86.ActiveCfg = Debug|x86
{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}.Debug|x86.Build.0 = Debug|x86
{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}.Release|Any CPU.Build.0 = Release|Any CPU
{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}.Release|x86.ActiveCfg = Release|x86
{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D7107476-F580-470C-9D9A-B9F14DD1E31F}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
class EasyFilters
{
struct Filter
{
public string extension;
public string description;
}
List<Filter> filters = new List<Filter>();
public EasyFilters(params (string description, string ext)[] textFilters)
{
Add(textFilters);
}
public void Add(params (string description, string ext)[] textFilters)
{
for (int i = 0; i < textFilters.Length; i++)
{
filters.Add(new Filter() { extension = textFilters[i].ext, description = textFilters[i].description });
}
}
public string GetFilterExtensionByOneBasedIndex(int index)
{
return filters[index-1].extension;
}
public string GetFilterDescriptionByOneBasedIndex(int index)
{
return filters[index - 1].description;
}
public override string ToString()
{
return string.Join("|", filters.Select(o => $"{o.description} (*.{o.extension})|*.{o.extension}"));
}
}
}

View File

@ -0,0 +1,164 @@
using System.IO;
using System.Text;
using System.Linq;
namespace IWImgViewer
{
public class FFImgHeader : IImageFileHeader
{
public MapType mapType;
public byte semantic;
public ImageCategory category;
public byte gfxImageFlags;
public int cardMemory;
public int dataLen1;
public int dataLen2;
public int height;
public int width;
public int depth;
public string cName;
public byte mipLevels;
public byte flags;
public int wrongHeight;
public int wrongWidth;
public int wrongDepth;
public _D3DFORMAT format;
public int resourceSize;
public System.Collections.Generic.IReadOnlyList<IImageFileHeader> CompatibleDestinations => new System.Collections.Generic.List<IImageFileHeader>()
{
new IW4XImageHeader(),
new CoD4_GfxImageFileHeader(),
new CoD6_GfxImageFileHeader()
}.AsReadOnly();
public string FormatDescription => $"Zonetool-compatible (29/04/2021) ({FormatExtension})";
public string FormatExtension => "ffImg";
public byte IwiVersion => 8;
public int Flags => flags;
public byte MipLevels => mipLevels;
public byte Semantic => semantic;
public int Width => width;
public int Height => height;
public int Depth => depth;
public int DataLength => resourceSize;
public string Name => cName;
public MapType MapType => mapType;
public _D3DFORMAT D3dFormat => format;
public GfxImageFileFormat GfxFormat
{
get
{
switch (format)
{
default:
return GfxImageFileFormat.IMG_FORMAT_BITMAP_RGBA;
case _D3DFORMAT.D3DFMT_A8R8G8B8:
return GfxImageFileFormat.IMG_FORMAT_BITMAP_RGBA; // Channels will be swapped
case _D3DFORMAT.D3DFMT_L8:
return GfxImageFileFormat.IMG_FORMAT_BITMAP_ALPHA;
}
}
}
public ImageCategory Category => category;
public void Deserialize(BinaryReader br)
{
mapType = (MapType)br.ReadByte();
semantic = br.ReadByte();
category = (ImageCategory)br.ReadByte();
flags = br.ReadByte(); // Flags (gfximage)
cardMemory = br.ReadInt32(); // CardMemory
dataLen1 = br.ReadInt32(); // dataLen1
dataLen2 = br.ReadInt32(); // dataLen2
height = br.ReadInt32(); // height
width = br.ReadInt32(); // width
depth = br.ReadInt32(); // depth
// Read string
StringBuilder sb = new StringBuilder();
byte b;
while ((b = br.ReadByte()) != 0)
{
sb.Append((char)b);
// Skip!
}
cName = sb.ToString();
mipLevels = br.ReadByte();
flags = br.ReadByte(); // Flags again (loaddef)
// We read wrong dimensions here
wrongWidth = br.ReadInt32();
wrongHeight = br.ReadInt32();
wrongDepth = br.ReadInt32();
format = (_D3DFORMAT)br.ReadInt32();
resourceSize = br.ReadInt32();
}
public void Serialize(BinaryWriter bw)
{
bw.Write((byte)mapType);
bw.Write(semantic);
bw.Write((byte)category);
bw.Write(flags);
bw.Write(cardMemory);
bw.Write(dataLen1);
bw.Write(dataLen2);
bw.Write(height);
bw.Write(width);
bw.Write(depth);
// Null-terminated string
bw.Write(cName.ToCharArray().Append('\0').ToArray());
bw.Write(mipLevels);
bw.Write(flags);
bw.Write(wrongWidth);
bw.Write(wrongHeight);
bw.Write(wrongDepth);
bw.Write((int)format);
bw.Write(resourceSize);
}
public void From(IImageFileHeader header)
{
mapType = header.MapType;
semantic = header.Semantic;
category = header.Category;
gfxImageFlags = (byte)header.Flags;
height = header.Height;
width = header.Width;
depth = header.Depth;
cName = header.Name;
mipLevels = header.MipLevels;
flags = (byte)header.Flags;
wrongDepth = 1;
wrongHeight = 1;
wrongWidth = 1;
format = header.D3dFormat;
resourceSize = header.DataLength;
}
}
}

View File

@ -0,0 +1,12 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura>
<Unmanaged32Assemblies>
NativeSquish_x86
OpenJpegDotNetNative
</Unmanaged32Assemblies>
<Unmanaged64Assemblies>
NativeSquish_x64
OpenJpegDotNetNative
</Unmanaged64Assemblies>
</Costura>
</Weavers>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 32 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged 64 bit assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -0,0 +1,31 @@
using System.Collections.Generic;
namespace IWImgViewer
{
public static class FormatHelper
{
public static Dictionary<GfxImageFileFormat, byte> ChannelCount = new Dictionary<GfxImageFileFormat, byte>()
{
{GfxImageFileFormat.IMG_FORMAT_BITMAP_ALPHA, 1 },
{GfxImageFileFormat.IMG_FORMAT_BITMAP_LUMINANCE, 1 },
{GfxImageFileFormat.IMG_FORMAT_BITMAP_RGB, 3 },
{GfxImageFileFormat.IMG_FORMAT_BITMAP_RGBA, 4 },
{GfxImageFileFormat.IMG_FORMAT_DXT1, 4 },
{GfxImageFileFormat.IMG_FORMAT_DXT3, 4 },
{GfxImageFileFormat.IMG_FORMAT_DXT5, 4 }
};
public static Dictionary<GfxImageFileFormat, ManagedSquish.SquishFlags> GfxFormatToSquishFormat = new Dictionary<GfxImageFileFormat, ManagedSquish.SquishFlags>()
{
{ GfxImageFileFormat.IMG_FORMAT_DXT1, ManagedSquish.SquishFlags.Dxt1 },
{ GfxImageFileFormat.IMG_FORMAT_DXT3, ManagedSquish.SquishFlags.Dxt3 },
{ GfxImageFileFormat.IMG_FORMAT_DXT5, ManagedSquish.SquishFlags.Dxt5 },
};
public static byte GetBlockSize(GfxImageFileFormat format)
{
return (byte)(format.ToString().Contains("DXT") ? 4 : 1);
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
public enum GfxImageFileFormat : byte
{
IMG_FORMAT_INVALID = 0x0,
IMG_FORMAT_BITMAP_RGBA = 0x1,
IMG_FORMAT_BITMAP_RGB = 0x2,
IMG_FORMAT_BITMAP_LUMINANCE_ALPHA = 0x3,
IMG_FORMAT_BITMAP_LUMINANCE = 0x4,
IMG_FORMAT_BITMAP_ALPHA = 0x5,
IMG_FORMAT_WAVELET_RGBA = 0x6,
IMG_FORMAT_WAVELET_RGB = 0x7,
IMG_FORMAT_WAVELET_LUMINANCE_ALPHA = 0x8,
IMG_FORMAT_WAVELET_LUMINANCE = 0x9,
IMG_FORMAT_WAVELET_ALPHA = 0xA,
IMG_FORMAT_DXT1 = 0xB,
IMG_FORMAT_DXT3 = 0xC,
IMG_FORMAT_DXT5 = 0xD,
IMG_FORMAT_DXN = 0xE,
IMG_FORMAT_DXT3A_AS_LUMINANCE = 0xF,
IMG_FORMAT_DXT5A_AS_LUMINANCE = 0x10,
IMG_FORMAT_DXT3A_AS_ALPHA = 0x11,
IMG_FORMAT_DXT5A_AS_ALPHA = 0x12,
IMG_FORMAT_DXT1_AS_LUMINANCE_ALPHA = 0x13,
IMG_FORMAT_DXN_AS_LUMINANCE_ALPHA = 0x14,
IMG_FORMAT_DXT1_AS_LUMINANCE = 0x15,
IMG_FORMAT_DXT1_AS_ALPHA = 0x16,
IMG_FORMAT_COUNT = 0x17,
};
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
public enum ImageCategory : byte
{
IMG_CATEGORY_UNKNOWN = 0x0,
IMG_CATEGORY_AUTO_GENERATED = 0x1,
IMG_CATEGORY_LIGHTMAP = 0x2,
IMG_CATEGORY_LOAD_FROM_FILE = 0x3,
IMG_CATEGORY_RAW = 0x4,
IMG_CATEGORY_FIRST_UNMANAGED = 0x5,
IMG_CATEGORY_WATER = 0x5,
IMG_CATEGORY_RENDERTARGET = 0x6,
IMG_CATEGORY_TEMP = 0x7,
};
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
enum IwiFlags : int
{
IMG_FLAG_NOPICMIP = 1 << 0,
IMG_FLAG_NOMIPMAPS = 1 << 1,
IMG_FLAG_CUBEMAP = 1 << 2,
IMG_FLAG_VOLMAP = 1 << 3,
IMG_FLAG_STREAMING = 1 << 4,
IMG_FLAG_LEGACY_NORMALS = 1 << 5,
IMG_FLAG_CLAMP_U = 1 << 6,
IMG_FLAG_CLAMP_V = 1 << 7,
IMG_FLAG_DYNAMIC = 1 << 16,
IMG_FLAG_RENDER_TARGET = 1 << 17,
IMG_FLAG_SYSTEMMEM = 1 << 18
};
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
public enum _D3DFORMAT : int
{
D3DFMT_UNKNOWN = 0,
D3DFMT_R8G8B8 = 20,
D3DFMT_A8R8G8B8 = 21,
D3DFMT_X8R8G8B8 = 22,
D3DFMT_R5G6B5 = 23,
D3DFMT_X1R5G5B5 = 24,
D3DFMT_A1R5G5B5 = 25,
D3DFMT_A4R4G4B4 = 26,
D3DFMT_R3G3B2 = 27,
D3DFMT_A8 = 28,
D3DFMT_A8R3G3B2 = 29,
D3DFMT_X4R4G4B4 = 30,
D3DFMT_A2B10G10R10 = 31,
D3DFMT_A8B8G8R8 = 32,
D3DFMT_X8B8G8R8 = 33,
D3DFMT_G16R16 = 34,
D3DFMT_A2R10G10B10 = 35,
D3DFMT_A16B16G16R16 = 36,
D3DFMT_A8P8 = 40,
D3DFMT_P8 = 41,
D3DFMT_L8 = 50,
D3DFMT_A8L8 = 51,
D3DFMT_A4L4 = 52,
D3DFMT_V8U8 = 60,
D3DFMT_L6V5U5 = 61,
D3DFMT_X8L8V8U8 = 62,
D3DFMT_Q8W8V8U8 = 63,
D3DFMT_V16U16 = 64,
D3DFMT_A2W10V10U10 = 67,
}
}

View File

@ -0,0 +1,167 @@
using System;
using System.IO;
using System.Linq;
namespace IWImgViewer
{
public class CoD4_GfxImageFileHeader : IImageFileHeader
{
public char[] tag = new char[] { 'I', 'W', 'i' }; // 3 bytes
public byte version = 8;
public GfxImageFileFormat format = GfxImageFileFormat.IMG_FORMAT_BITMAP_RGBA;
public byte flags;
public short[] dimensions; // 3 shorts
public int[] fileSizeForPicmip = new int[4]; // 4 ints
[NonSerialized] string name = "iwi6";
[NonSerialized] int dataLength = 0;
public System.Collections.Generic.IReadOnlyList<IImageFileHeader> CompatibleDestinations => new System.Collections.Generic.List<IImageFileHeader>()
{
new CoD4_GfxImageFileHeader(),
new CoD6_GfxImageFileHeader()
}.AsReadOnly();
public string FormatDescription => "Call Of Duty 4 IWI (version 6)";
public string FormatExtension => "iwi";
public byte IwiVersion => version;
public int Flags => flags;
public byte MipLevels => (byte)((flags & (byte)IwiFlags.IMG_FLAG_NOMIPMAPS) == 0 ? 0 : 1 + Math.Floor(Math.Log(Math.Max(dimensions[0], Math.Max(dimensions[1], dimensions[2])), 2)));
public byte Semantic => 0;
public int Width => dimensions[0];
public int Height => dimensions[1];
public int Depth => dimensions[2];
public int DataLength => dataLength; // :shrug:
public string Name => name;
public MapType MapType => (flags & (int) IwiFlags.IMG_FLAG_CUBEMAP) == 0 ? MapType.MAPTYPE_2D : MapType.MAPTYPE_CUBE;
public _D3DFORMAT D3dFormat => _D3DFORMAT.D3DFMT_A8B8G8R8;
public GfxImageFileFormat GfxFormat => format;
public ImageCategory Category => ImageCategory.IMG_CATEGORY_LOAD_FROM_FILE;
public void Deserialize(BinaryReader br)
{
tag = br.ReadChars(3);
if (new string(tag) != "IWi")
{
throw new FormatException();
}
version = br.ReadByte();
if (version > 6)
{
throw new FormatException();
}
else if (version != 6)
{
System.Windows.Forms.MessageBox.Show($"Invalid IWI version {version} (expected 6), I will try to deserialize regardless.");
}
format = (GfxImageFileFormat)br.ReadByte();
flags = br.ReadByte();
dimensions = new short[]
{
br.ReadInt16(),
br.ReadInt16(),
br.ReadInt16()
};
fileSizeForPicmip = new int[]
{
br.ReadInt32(),
br.ReadInt32(),
br.ReadInt32(),
br.ReadInt32()
};
}
public void Serialize(BinaryWriter bw)
{
bw.Write(tag[0]);
bw.Write(tag[1]);
bw.Write(tag[2]);
bw.Write(version);
bw.Write((byte)format);
bw.Write(flags);
bw.Write(dimensions[0]);
bw.Write(dimensions[1]);
bw.Write(dimensions[2]);
for (int i = 0; i < 4; i++)
{
bw.Write(fileSizeForPicmip[i]);
}
}
public CoD4_GfxImageFileHeader()
{
}
public CoD4_GfxImageFileHeader(string name)
{
this.name = name;
}
public void From(CoD6_GfxImageFileHeader header)
{
flags = (byte) header.flags;
format = header.format;
dimensions = header.dimensions;
fileSizeForPicmip = header.fileSizeForPicmip;
}
public void From(IImageFileHeader header)
{
if (header is CoD6_GfxImageFileHeader)
{
From(header as CoD6_GfxImageFileHeader);
return;
}
format = header.GfxFormat;
flags = (byte)header.Flags;
dimensions = new short[]{
(short)header.Width,
(short)header.Height,
(short)header.Depth
};
// Compute mips filesizes
var currentFileSize = 28; // IWI Header Size
var textureMipCount = (flags & (uint)IwiFlags.IMG_FLAG_NOMIPMAPS) == 0 ? 1 : header.MipLevels;
for (var currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{
var blockSize = FormatHelper.GetBlockSize(format);
var mipLevelSize =
Math.Max(blockSize, Width / Math.Pow(2, currentMipLevel)) * Math.Max(blockSize, Height / Math.Pow(2, currentMipLevel))
* FormatHelper.ChannelCount[format]
* (header.MapType == MapType.MAPTYPE_CUBE ? 6 : 1);
currentFileSize += (int)mipLevelSize;
if (currentMipLevel < fileSizeForPicmip.Length)
{
fileSizeForPicmip[currentMipLevel] = currentFileSize;
}
}
name = header.Name;
}
}
}

View File

@ -0,0 +1,169 @@
using System;
using System.IO;
namespace IWImgViewer
{
public class CoD6_GfxImageFileHeader : IImageFileHeader
{
public char[] tag = new char[] { 'I', 'W', 'i' }; // 3 bytes
public byte version = 8;
public uint flags;
public GfxImageFileFormat format = GfxImageFileFormat.IMG_FORMAT_BITMAP_RGBA;
public byte unused;
public short[] dimensions; // 3 shorts
public int[] fileSizeForPicmip = new int[4]; // 4 ints
[NonSerialized] string name = "iwi8";
[NonSerialized] int dataLength = 0;
public System.Collections.Generic.IReadOnlyList<IImageFileHeader> CompatibleDestinations => new System.Collections.Generic.List<IImageFileHeader>()
{
new CoD4_GfxImageFileHeader(),
new CoD6_GfxImageFileHeader()
}.AsReadOnly();
public string FormatDescription => "Modern Warfare 2 IWI (version 8)";
public string FormatExtension => "iwi";
public byte IwiVersion => version;
public int Flags => (int)flags;
public byte MipLevels => (byte)((flags & (byte)IwiFlags.IMG_FLAG_NOMIPMAPS) == 0 ? 0 : 1 + Math.Floor(Math.Log(Math.Max(dimensions[0], Math.Max(dimensions[1], dimensions[2])), 2)));
public byte Semantic => 0;
public int Width => dimensions[0];
public int Height => dimensions[1];
public int Depth => dimensions[2];
public int DataLength => dataLength; // :shrug:
public string Name => name;
public MapType MapType => (flags & (int)IwiFlags.IMG_FLAG_CUBEMAP) == 0 ? MapType.MAPTYPE_2D : MapType.MAPTYPE_CUBE;
public _D3DFORMAT D3dFormat => _D3DFORMAT.D3DFMT_A8B8G8R8;
public GfxImageFileFormat GfxFormat => format;
public ImageCategory Category => ImageCategory.IMG_CATEGORY_LOAD_FROM_FILE;
public void Deserialize(BinaryReader br)
{
tag = br.ReadChars(3);
if (new string(tag) != "IWi")
{
throw new FormatException();
}
version = br.ReadByte();
if (version < 8)
{
throw new FormatException();
}
else if (version != 8)
{
System.Windows.Forms.MessageBox.Show($"Invalid IWI version {version} (expected 8), I will try to deserialize regardless.");
}
flags = br.ReadUInt32();
format = (GfxImageFileFormat)br.ReadByte();
unused = br.ReadByte();
dimensions = new short[]
{
br.ReadInt16(),
br.ReadInt16(),
br.ReadInt16()
};
fileSizeForPicmip = new int[]
{
br.ReadInt32(),
br.ReadInt32(),
br.ReadInt32(),
br.ReadInt32()
};
dataLength = (int)br.BaseStream.Length;
}
public void Serialize(BinaryWriter bw)
{
bw.Write(tag[0]);
bw.Write(tag[1]);
bw.Write(tag[2]);
bw.Write(version);
bw.Write(flags);
bw.Write((byte)format);
bw.Write(unused);
bw.Write(dimensions[0]);
bw.Write(dimensions[1]);
bw.Write(dimensions[2]);
for (int i = 0; i < 4; i++)
{
bw.Write(fileSizeForPicmip[i]);
}
}
public void From(CoD4_GfxImageFileHeader header)
{
flags = header.flags;
format = header.format;
dimensions = header.dimensions;
fileSizeForPicmip = header.fileSizeForPicmip;
}
public void From(IImageFileHeader header)
{
if (header is CoD4_GfxImageFileHeader)
{
From(header as CoD4_GfxImageFileHeader);
return;
}
format = header.GfxFormat;
flags = (byte)header.Flags;
dimensions = new short[]{
(short)header.Width,
(short)header.Height,
(short)header.Depth
};
name = header.Name;
// Compute mips filesizes
var currentFileSize = 32; // IWI Header Size
var textureMipCount = (flags & (uint)IwiFlags.IMG_FLAG_NOMIPMAPS) == 0 ? 1 : header.MipLevels;
for (var currentMipLevel = textureMipCount - 1; currentMipLevel >= 0; currentMipLevel--)
{
var blockSize = FormatHelper.GetBlockSize(format);
var mipLevelSize =
Math.Max(blockSize, Width / Math.Pow(2, currentMipLevel)) * Math.Max(blockSize, Height / Math.Pow(2, currentMipLevel))
* FormatHelper.ChannelCount[format]
* (header.MapType == MapType.MAPTYPE_CUBE ? 6 : 1);
currentFileSize += (int)mipLevelSize;
if (currentMipLevel < fileSizeForPicmip.Length)
{
fileSizeForPicmip[currentMipLevel] = currentFileSize;
}
}
}
public CoD6_GfxImageFileHeader()
{
}
public CoD6_GfxImageFileHeader(string name)
{
this.name = name;
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
struct GfxImageLoadDef
{
public byte levelCount;
public byte flags;
public short[] dimensions;
public _D3DFORMAT format;
public int resourceSize;
public byte[] data;
};
}

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
public interface IImageFileHeader
{
string FormatDescription { get; }
string FormatExtension { get; }
IReadOnlyList<IImageFileHeader> CompatibleDestinations { get; }
byte IwiVersion { get; }
int Flags { get; }
byte MipLevels { get; }
byte Semantic { get; }
int Width { get; }
int Height { get; }
int Depth { get; }
int DataLength { get; }
string Name { get; }
MapType MapType { get; }
_D3DFORMAT D3dFormat { get; }
GfxImageFileFormat GfxFormat { get; }
ImageCategory Category { get; }
void Deserialize(BinaryReader reader);
void Serialize(BinaryWriter writer);
void From(IImageFileHeader header);
}
}

View File

@ -0,0 +1,121 @@
using System.Collections.Generic;
using System.IO;
namespace IWImgViewer
{
public class IW4XImageHeader : IImageFileHeader
{
public MapType mapType;
public byte semantic;
public ImageCategory category;
public int size;
public byte levelCount;
public byte flags;
public short[] dimensions; // 3
public _D3DFORMAT format;
public int resourceSize;
public IReadOnlyList<IImageFileHeader> CompatibleDestinations => new List<IImageFileHeader>()
{
new FFImgHeader(),
new CoD4_GfxImageFileHeader(),
new CoD6_GfxImageFileHeader()
}.AsReadOnly();
public string FormatDescription => $"Zonebuilder-compatible ({FormatExtension})";
public string FormatExtension => "iw4xImage";
public byte IwiVersion => 8;
public int Flags => flags;
public byte MipLevels => levelCount;
public byte Semantic => semantic;
public int Width => dimensions[0];
public int Height => dimensions[1];
public int Depth => dimensions[2];
public int DataLength => resourceSize;
public string Name => "iw4ximage";
public MapType MapType => mapType;
public _D3DFORMAT D3dFormat => format;
public GfxImageFileFormat GfxFormat
{
get
{
switch (format)
{
default:
return GfxImageFileFormat.IMG_FORMAT_BITMAP_RGBA;
case _D3DFORMAT.D3DFMT_A8R8G8B8:
return GfxImageFileFormat.IMG_FORMAT_BITMAP_RGBA; // Channels will be swapped
case _D3DFORMAT.D3DFMT_L8:
return GfxImageFileFormat.IMG_FORMAT_BITMAP_ALPHA;
}
}
}
public ImageCategory Category => category;
public void Deserialize(BinaryReader br)
{
mapType = (MapType)br.ReadByte();
semantic = br.ReadByte();
category = (ImageCategory)br.ReadByte();
size = br.ReadInt32();
levelCount = br.ReadByte();
flags = br.ReadByte();
dimensions = new short[]
{
br.ReadInt16(),
br.ReadInt16(),
br.ReadInt16()
};
format = (_D3DFORMAT)br.ReadInt32();
resourceSize = br.ReadInt32();
}
public void Serialize(BinaryWriter bw)
{
bw.Write((byte)mapType);
bw.Write(semantic);
bw.Write((byte)category);
bw.Write(size);
bw.Write(levelCount);
bw.Write(flags);
bw.Write(dimensions[0]);
bw.Write(dimensions[1]);
bw.Write(dimensions[2]);
bw.Write((int)format);
bw.Write(resourceSize);
}
public void From(IImageFileHeader header)
{
mapType = header.MapType;
semantic = header.Semantic;
category = header.Category;
size = header.DataLength;
levelCount = header.MipLevels;
flags = (byte)header.Flags;
dimensions = new short[]{
(short)header.Width,
(short)header.Height,
(short)header.Depth
};
format = header.D3dFormat;
resourceSize = header.DataLength; // Yes, we have the same info twice
}
}
}

View File

@ -0,0 +1,298 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Costura.Fody.5.3.0\build\Costura.Fody.props" Condition="Exists('..\packages\Costura.Fody.5.3.0\build\Costura.Fody.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{02B056CA-BC9B-4BE3-8730-F7506DABD8BB}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>IWImgViewer</RootNamespace>
<AssemblyName>iw4 image helper</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>cardicon_juggernaut_1_MGP_icon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Costura, Version=5.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Costura.Fody.5.3.0\lib\netstandard1.0\Costura.dll</HintPath>
</Reference>
<Reference Include="ManagedSquish, Version=2.0.0.0, Culture=neutral, PublicKeyToken=fac8b2bfeda84eab, processorArchitecture=MSIL">
<HintPath>..\packages\ManagedSquish.2.0.0.0\lib\net40\ManagedSquish.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="NativeSquish_x64, Version=2.0.0.0, Culture=neutral, PublicKeyToken=fac8b2bfeda84eab, processorArchitecture=AMD64">
<HintPath>..\packages\ManagedSquish.2.0.0.0\lib\net40\NativeSquish_x64.dll</HintPath>
</Reference>
<Reference Include="NativeSquish_x86, Version=2.0.0.0, Culture=neutral, PublicKeyToken=fac8b2bfeda84eab, processorArchitecture=x86">
<HintPath>..\packages\ManagedSquish.2.0.0.0\lib\net40\NativeSquish_x86.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.AppContext, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Core" />
<Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.Tracing, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Drawing.Common, Version=4.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Drawing.Common.5.0.2\lib\net461\System.Drawing.Common.dll</HintPath>
</Reference>
<Reference Include="System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.4.3.0\lib\net462\System.IO.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Linq, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Linq.Expressions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Reflection, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.InteropServices, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Text.RegularExpressions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="FormatHelper.cs" />
<Compile Include="IImageFileHeader.cs" />
<Compile Include="EasyFilters.cs" />
<Compile Include="Game\Enums\GfxImageFileFormat.cs" />
<Compile Include="Game\Structs\CoD4_GfxImageFileHeader.cs" />
<Compile Include="Game\Structs\CoD6_GfxImageFileHeader.cs" />
<Compile Include="FFImgHeader.cs" />
<Compile Include="Game\Structs\GfxImageLoadDef.cs" />
<Compile Include="Game\Enums\ImageCategory.cs" />
<Compile Include="Game\Enums\IwiFlags.cs" />
<Compile Include="IW4XImageHeader.cs" />
<Compile Include="MainWindow.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainWindow.Designer.cs">
<DependentUpon>MainWindow.cs</DependentUpon>
</Compile>
<Compile Include="MapType.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Reader.cs" />
<Compile Include="Viewport.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Viewport.Designer.cs">
<DependentUpon>Viewport.cs</DependentUpon>
</Compile>
<Compile Include="Writer.cs" />
<Compile Include="Game\Enums\_D3DFORMAT.cs" />
<EmbeddedResource Include="MainWindow.resx">
<DependentUpon>MainWindow.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<EmbeddedResource Include="Viewport.resx">
<DependentUpon>Viewport.cs</DependentUpon>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="cardicon_juggernaut_1_MGP_icon.ico" />
<Content Include="FodyWeavers.xml" />
<None Include="Resources\cardicon_juggernaut_1.png" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Fody.6.5.1\build\Fody.targets" Condition="Exists('..\packages\Fody.6.5.1\build\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Fody.6.5.1\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.6.5.1\build\Fody.targets'))" />
<Error Condition="!Exists('..\packages\Costura.Fody.5.3.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.5.3.0\build\Costura.Fody.props'))" />
<Error Condition="!Exists('..\packages\Costura.Fody.5.3.0\build\Costura.Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.5.3.0\build\Costura.Fody.targets'))" />
</Target>
<Import Project="..\packages\Costura.Fody.5.3.0\build\Costura.Fody.targets" Condition="Exists('..\packages\Costura.Fody.5.3.0\build\Costura.Fody.targets')" />
</Project>

102
ImgFormatHelper/MainWindow.Designer.cs generated Normal file
View File

@ -0,0 +1,102 @@

namespace IWImgViewer
{
partial class MainWindow
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow));
this.MetaDataLabel = new System.Windows.Forms.Label();
this.closeAllButton = new System.Windows.Forms.Button();
this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
this.SplashPictureBox = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.SplashPictureBox)).BeginInit();
this.SuspendLayout();
//
// MetaDataLabel
//
this.MetaDataLabel.Dock = System.Windows.Forms.DockStyle.Fill;
this.MetaDataLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.MetaDataLabel.Location = new System.Drawing.Point(0, 0);
this.MetaDataLabel.Name = "MetaDataLabel";
this.MetaDataLabel.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.MetaDataLabel.Size = new System.Drawing.Size(284, 261);
this.MetaDataLabel.TabIndex = 1;
this.MetaDataLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// closeAllButton
//
this.closeAllButton.Dock = System.Windows.Forms.DockStyle.Bottom;
this.closeAllButton.Location = new System.Drawing.Point(0, 238);
this.closeAllButton.Name = "closeAllButton";
this.closeAllButton.Size = new System.Drawing.Size(284, 23);
this.closeAllButton.TabIndex = 4;
this.closeAllButton.Text = "Close all viewports";
this.closeAllButton.UseVisualStyleBackColor = true;
this.closeAllButton.Click += new System.EventHandler(this.closeAllButton_Click);
//
// saveFileDialog1
//
this.saveFileDialog1.FileOk += new System.ComponentModel.CancelEventHandler(this.saveFileDialog1_FileOk);
//
// SplashPictureBox
//
this.SplashPictureBox.Anchor = System.Windows.Forms.AnchorStyles.None;
this.SplashPictureBox.Image = global::IWImgViewer.Properties.Resources.cardicon_juggernaut_1;
this.SplashPictureBox.InitialImage = global::IWImgViewer.Properties.Resources.cardicon_juggernaut_1;
this.SplashPictureBox.Location = new System.Drawing.Point(108, 12);
this.SplashPictureBox.Name = "SplashPictureBox";
this.SplashPictureBox.Size = new System.Drawing.Size(64, 64);
this.SplashPictureBox.TabIndex = 5;
this.SplashPictureBox.TabStop = false;
this.SplashPictureBox.WaitOnLoad = true;
//
// MainWindow
//
this.AllowDrop = true;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.SplashPictureBox);
this.Controls.Add(this.closeAllButton);
this.Controls.Add(this.MetaDataLabel);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "MainWindow";
this.Text = "IW4 Image Format Helper";
((System.ComponentModel.ISupportInitialize)(this.SplashPictureBox)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Label MetaDataLabel;
private System.Windows.Forms.Button closeAllButton;
private System.Windows.Forms.SaveFileDialog saveFileDialog1;
private System.Windows.Forms.PictureBox SplashPictureBox;
}
}

View File

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace IWImgViewer
{
public partial class MainWindow : Form
{
public string ImageName { get; private set; }
Reader reader;
Queue<Viewport> viewports = new Queue<Viewport>();
EasyFilters convertFilters = new EasyFilters();
public MainWindow()
{
InitializeComponent();
this.DragEnter += new DragEventHandler(Form1_DragEnter);
this.DragDrop += new DragEventHandler(Form1_DragDrop);
Reader.OnBitmapRead += Viewer_OnBitmapRead;
MetaDataLabel.Text = "Ready!\nDrag and drop an image\nover here to start!";
}
private void Viewer_OnBitmapRead(Bitmap arg1)
{
var viewport = new Viewport(this);
viewport.Show();
viewport.ShowImage(arg1);
viewports.Enqueue(viewport);
}
void Form1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
}
void Form1_DragDrop(object sender, DragEventArgs e)
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
string file = files[0];
ShowImage(file);
}
void ShowImage(string path)
{
try
{
var v = new Reader(path);
reader = v;
ImageName = System.IO.Path.GetFileNameWithoutExtension(path);
MetaDataLabel.Text = $"{ImageName}\n{reader.ImageFormat}";
}
catch (FormatException e)
{
MessageBox.Show($"Format not supported:{e.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
private void closeAllButton_Click(object sender, EventArgs e)
{
while(viewports.Count > 0)
{
viewports.Dequeue().Close();
}
}
private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
{
int index = saveFileDialog1.FilterIndex - 1;
if (index < 0 || index > reader.CurrentHeader.CompatibleDestinations.Count)
{
return;
}
var format = reader.CurrentHeader.CompatibleDestinations[index];
format.From(reader.CurrentHeader);
using(FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create))
{
using(BinaryWriter bw = new BinaryWriter(fs))
{
format.Serialize(bw);
bw.Write(reader.Data);
}
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.C)
{
convertFilters = new EasyFilters();
IEnumerable<IImageFileHeader> compatibleDestinationFormats = reader.CurrentHeader.CompatibleDestinations;
foreach (var format in compatibleDestinationFormats)
{
convertFilters.Add((format.FormatDescription, format.FormatExtension));
}
saveFileDialog1.DefaultExt = convertFilters.GetFilterExtensionByOneBasedIndex(1);
saveFileDialog1.FileName = System.IO.Path.GetFileNameWithoutExtension(ImageName);
saveFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
saveFileDialog1.Filter = convertFilters.ToString();
saveFileDialog1.ShowDialog(this);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
}

View File

@ -0,0 +1,703 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="saveFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAUAEBAAAAEAIABoBAAAVgAAABgYAAABACAAiAkAAL4EAAAgIAAAAQAgAKgQAABGDgAAMDAAAAEA
IACoJQAA7h4AAEBAAAABACAAKEIAAJZEAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAADDDgAAww4AAAAA
AAAAAAAAbn18/3R/f/9ER0j/GRMZ/xAJEP8QCA//EQkO/xEKEf8QCxD/EQoQ/yIgJP9ZXmH/eIKE/3B2
e/93gIL/dH1+/3iJiP9gZmb/GhUa/wwEC/8MBgv/EAgM/xAHDP8PBgv/DwUL/w0FCP8RChD/KSIp/2ls
bv9+hon/hI2O/4OOjv9sdXf/MC0y/xMJDv8pICD/NS8u/zMrKv8pHh7/IhYY/x0TGP8TCQ//DAQG/yAY
HP8vKy7/ZWlr/36Ghv9zf4D/UVhZ/yYdIP8jFRT/FQwR/wwEC/8NAQn/DAAJ/w0ACv8OAQz/DQIK/wUA
Av8hGhz/KiMo/zk0Nv9+h4f/c31//0lKS/8VDBL/CgII/w4IDf8bEhj/Ixgc/yASF/8YDBP/FgcT/xgK
E/8NAgj/FxAW/ywjKf8pIiX/cnl4/4GOjf85Nzv/EQkP/zAlJf8sJCf/Miks/1ZQTf9TTEr/TkdH/05F
Rf87MTD/FwwP/xIID/8xIyj/LyYp/1lbW/9xenj/Ojc6/y8nJ/9BOTf/MCgs/09ISf9pZmT/Yl9f/2Bd
XP9jXVz/V1NT/0lDRf8pHiH/PzQ3/15ja/9HSEz/YGJh/0dJSv84MTT/MSos/0pHSf9XUVP/Rj4//1dS
U/9eWFj/SEJD/0E8QP9TT0//Rj4//01GRv9SUVT/TUxN/01PT/9DREPyUE9P/yQeI/9QTVH/Y2Bi/2xp
av+CgoH/f4J//2tsbP9ZWFv/XFZY/1hVVf9bVVT/VVRU/11eXf9IR0f/KykqoUJBQv8mISX/i46L/7zD
v//G0s7/xNLO/7zIwv+turf/oKup/5eem/+PlpX/i5CP/1ZWVf9DQUL/V1dX/yUiJHg/PDv7MSsq/4SF
gf+2v7j/t8O+/7vIwv+3wbr/r7q0/6CppP+co5//o66y/7nO1f9eY2T/IBod/zYzNv8hHh4VLSgnjTQw
Lu9iY2H/ucO9/7fGv/+6ycL/t8G6/7G7tP+iq6X/oail/7jL0f+rwMT/PDo7/y8rLP8yMTH/FhEUABkT
FQcTERJDREJFrbW6uf3C08z/zd7V/7/Kwv+uubT/pK2n/6Krp//K2dr/s8TE/0I/Pf86OTj1Ly8t0AAA
AAAAAAAAGxcWABQQDy2UmZbj0+Lb/8LSyv+3w77/q7Sw/6Otqf+rtLL/y9fU/3t/fc8jICB5GRcYSBYV
FRkAAAAAAAAAABgVEQAAAAACQ0RCaZ2lou65w77/sLax/7C2s/+8xsH/wMjF/4SIhtoqKig9RUtIAEpG
SAAAAAAAAAAAAAAAAAAAAAAABwUFAAAAAAY5OTpXZWdlzYODgv+IiIf/goWD+mhmZbYqKyk9AAAAABUW
EwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA
AADgAAAA4AcAAPAPAAAoAAAAGAAAADAAAAABACAAAAAAAAAJAADDDgAAww4AAAAAAAAAAAAAW2dl/3yL
i/9ocHH/W2Ji/y8uMP8VDxX/DgUO/xAIEP8SChL/FAsQ/xMLEf8TCxP/EQ0S/w4IDf8QCQ//JCMm/0VJ
S/9ob3L/c3x+/211ef9nbXL/anJ0/3mDhP9gZ2f/bH18/5Chof9udnX/OTk7/xkTGf8SCxL/EgwS/w4J
Dv8MBAv/DQQK/w4FC/8PBg3/DggN/xILD/8TCw//Eg0S/xsWHP9cXmP/hY6P/3yEh/99hIr/gouN/5Cc
nf9/iYr/bn9+/4ORkP9GR0X/FQ8U/wsDC/8HAAb/BQAE/wcBBf8NBAn/DAQK/wwDCf8MAgf/DQAI/wwB
Bv8JAQP/DwgO/xcOF/8ZDxj/VFNU/4OLjP97goX/gIiI/4+amv97hYX/bHV3/2x0d/8ZFBr/CQEI/xEJ
Df8oIB7/Pjk3/0U/PP9EOzf/OS0q/zImJP8qHx7/Jh0f/yAVG/8SBw//DQIF/xMLDv8pICT/Ih0h/1RX
Wf93f4H/dnt8/4OPkP9rd3n/Ymts/05QU/8SCRD/JRUW/zMkIv80Kyv/Ih0e/xsVFv8XDhD/EggM/xIG
DP8RBQv/EAYO/xEID/8MBAn/BwED/wsFB/8sIyb/KCMn/yMcH/9cXF3/gImJ/36Ji/9ncXT/XGZn/y8u
Mv8nGx3/KRkW/w8FCP8HAAf/BwAH/woACP8NAAn/DAAL/wwACv8OAAv/DwAN/w8BC/8PAgr/BwIE/wUA
Af8vJin/My4y/x0UGf86NDb/f4eH/4KNjv9sdXj/X2Rj/yomKv8UChD/CQEI/wUABf8HAAf/CwMK/xAH
Dv8VCxD/EwML/w8CCf8KAAn/DgAO/xEDEP8TBxH/EAML/wYABf8fFh7/LiYu/ysiJf8jHSD/cXd1/46b
mv93hIL/U1ZX/xsVG/8GAAf/DgYM/xgQFf8qIyT/OC4v/0Q6Of9GPDn/QjY0/0A1NP81Ky3/Khwj/y0f
Iv8iFhj/FAcM/wcABf8aERj/LiIo/ywgI/8kHCD/WFlY/5Genf94hIL/SUpN/xcSGP8RCQ//PTAt/0M4
Nf8lHiT/HBMZ/0hBQP9fW1j/W1VS/1NMTP9XUlH/XlZV/1JKSP8+NTL/HBES/woBBv8SCA//MyUq/zcr
Lv8sIyb/PTs7/4KLiv9VW1j/Q0BD/yEcH/81LCv/RDw5/zgwMf8cEhr/PzY5/2VgXv9wbmv/ZmRj/05H
Sf9hXl7/bWdl/19ZWP9ZVVT/T0hK/y8lKP8dEhb/Lx8i/1dTWP9gZ3H/Ly0z/2lsbP9bXVv/RkdI/z04
Of80Kiv/MCoq/0xJSP9AOz3/Y15f/2djYf9YU1L/Yl9g/29ubf9mY2L/VU9P/1NOUP9PS03/XVpb/0ZA
Qf84LjD/Sj8//1ZUWP9yf4j/QUFG/1RVVf9aXVz/Sk5O/0FAQv82LzL/KCAj/zgyNf9QTVD/WlVX/0M6
Pf9FPD3/SkJE/2ZhYf9WTU3/S0ZH/zozOP9DPkP/TUhJ/1dUU/9COTr/Vk9O/0I7PP9KRUf/T0tL/0tL
S/9GSkr/RUdG/1ZYVv9WVVX/HRYc/zErMf9RT1T/TUdK/zszNv9HQEL/YFpZ/29sav9gXlz/UU1O/z03
PP9BPkL/TUNG/1JMTf9MSUr/WlJR/1NOT/9ZWlr/X2Fe/1ZXVv88Ojn/Ih0esEdHRvpOTU7/GBIZ/z47
PP90dXX/naCg/73Ewv/Ay8f/wcvI/7zIxP+4xsD/qbaz/6i1s/+MlJP/g4SE/3Fycv94fHn/ZmBe/2xs
av9KSEj/Xl5d/2FhYf9IRkb/Ew4SVD08PPc+Oz3/IBgf/0hHRv+5wbv/v8W//7zFwP/I1dH/xtfS/7zI
w/+6xr//q7e0/6Ktq/+gqqj/nqej/56ppv+VnZz/lZ2d/4+Wlf87ODf/JyEm/2JiYv9VVVX/FhIWTTk3
NvNGREH/KSIi/z86Of+ztrH/srqz/7G6tf+4xMD/vMrF/7jEvf+4wbn/s8C6/6i0rv+epqH/mJ2Y/6Gs
rP+dpqr/uc3V/7vQ0/89PT7/GxQX/ykkKP9BPkL/GBUZFSQhIag9ODb7RUA9/y0nJf+EhoP/usS9/7bB
u/+4xcD/ucjB/7bCu/+2v7j/sLqy/6mzrv+fp6H/m5+a/6eztP+ptrz/vNff/52srv8rKCr/KiMl/ysm
KP8sKiz/b2BfAD43NxciGhuOLisq6zk2NP90d3X/v8rD/7XAuf+4yMH/u8vD/7nFvv+2v7n/tr+3/6u0
rv+gqKP/nKGc/7LBw/++0tn/vdje/2ZpaP8kHh//Lyss/zQyM/81NjT/AAAAAC0oKQAqJCUIDw4PQRYS
FZ9KSEzlwcbF/7nCv//C1s7/0+fe/8bSyf+/yMD/s7+5/6eyrf+kq6b/naWg/7O/vf/L2tz/1/L1/2tt
bf8/Ojf/RURD/0ZFRP8qKijyAAAAAAAAAAAAAAAAW1ZbAIaEigMVEBNrnJ+e/Nbj3v/C1Mz/y93U/8nY
zv+5xL3/q7Ww/6exrP+jraj/naWi/7K7uf/b6+n/zNnZ/05OTPsyLy7vIyIizxkYGJ4XFxVLAAAAAAAA
AAAAAAAAAAAAABQRDgALBwUqXV9c3Nvm4v/R4Nn/vc3F/7/Ox/+wurj/rrax/6myrv+irKj/oqmo/8PP
zP/T4Nz/bW1q4SAcG2wNCw06Hh0eGSMkIwUAAAAAAAAAAAAAAAAAAAAAAAAAACsnIwAtIBUBGhgXXnB1
c+zO2tb/x9PN/7O9uP+utrL/paqn/7C6t/+2wbv/xdHM/9HX1f95fXrzHh8dbTAbGwFKSUYAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8OzoARUJABB0dHWBgZGPYoaek/qOlov+6u7b/t7q3/8jR
zf+/xsH/trq4/29xb+chJCBzQkRCCDo9OgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAABAMDAAAAAAEbGBsyJiYml1VWVfBnaGf/ZF9h/19dXf9YWFf3NjAwph0XF0MHDQoEDQ4NAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAwAAAAPAAAAD4AAEA+AAPAPwAHwD+AD8AKAAAACAA
AABAAAAAAQAgAAAAAAAAEAAAww4AAMMOAAAAAAAAAAAAAENLSP9ufXz/anN0/1dbXP9eZmb/Ozw8/ykl
KP8QChD/CQEJ/wsDC/8NBQ3/EAgQ/xIKDv8RCAz/EgkR/w8HD/8OCg7/CwgL/wgBCP8RChD/JyYp/zs9
P/9TV1v/WF1g/2Ztb/9lbW//X2Ro/1tgZP9bYWP/Z29w/3B5ev9FSUj/YW9t/5eurv+Wpaf/d4GC/1xk
ZP81NTb/FxEX/xUOFf8YEBj/GRIa/xMME/8TCxL/FAsR/xIKD/8VDRX/FQ0V/xMPFP8bFRr/Fg0S/xML
Ef8TDxP/HBoe/0hKTv+Mlpn/jpud/4aSlf+AiI//gIiP/4SPkf+Ll5f/nqyv/3F7e/9fbmz/hpua/4eS
kP9SVVL/JSEl/xAJEP8TChP/DAUM/wgECP8HAwf/BwEF/wkABv8IAAf/CAAH/woBB/8LAQf/CAAF/wkD
Bv8MBAX/EgkN/xUOFP8RChH/EAYR/z87Qf98gYH/en+A/3h+gv97gob/foaI/4WPjv+YpKT/b3h4/2Ny
cP+Im5v/dn99/zU0Mv8WEBX/DQYN/wgAB/8HAAb/BAAE/wQAA/8IAQX/CwMI/woDCP8KAgj/CgEG/woB
Bv8MAAf/DwAK/woBA/8HAAH/CgMJ/xkSGP8ZDxn/EgcR/z05Ov+CiIj/hY2R/3mAg/9+hYb/ipSS/5aj
o/9td3f/XmVl/4eUl/9NTlL/EAkQ/wkBCf8HAAf/DQUG/xwUE/80Li3/QTw5/0Y+O/9JQT3/QDMw/z4w
Lf8zJyT/MCUj/yohIv8jGh7/GA0V/w8FDP8OAwX/CgID/yEYHf8oHyT/Hxkd/zo4O/9/iYv/dXx+/29y
c/+DjY7/g5KT/2BrbP9WXFz/hZCT/zYzOP8KAwr/DwUL/yMWGP9BNjL/UUhE/0ZBPv9APDn/Ni4s/ywj
Iv8iFxb/IRYV/xwPEv8aDhH/GBAU/x4WGv8ZDxb/EQcO/xEFCP8HAAH/GREV/zIpLP8oIyf/GBQX/0NA
Qf9xd3n/eX+A/4OMjf9+jI7/Xmlq/1VeX/9bY2T/Hxgc/xULEP83Ix//Mh8b/yEVF/8SChD/BgIF/wQA
A/8IAAT/CgAG/wkACP8JAAj/DAAJ/w0ACf8LAAr/CwAK/woBB/8IAQX/AgAB/wEAAP8TCwz/Migr/y0o
LP8lICT/HhQY/1xbW/+Aioj/gouL/3uHiv9dZWb/XGZn/0tSVP8WDhT/Nygo/ygZFv8PBgb/BgAG/wgA
CP8JAAn/CwAK/w8ACv8PAAr/DgAM/w0ADP8NAAv/DwAL/xABDf8QAQ3/EAIL/xEDC/8LAwf/AQAA/wsD
BP88Mjb/OTQ4/yIcIf8ZDhL/Pjk7/4CIh/+Bi4v/hpOW/2Jpa/9gZWT/TE9P/xYNE/8aDxX/CAEH/wcA
Bv8FAQX/CAEI/wcAB/8HAAf/CQEJ/wwCCv8PAAj/DgAI/wgACP8JAAn/DwAP/xAAD/8QAw//EgUQ/xID
DP8GAQT/CAEH/yUcJP8yKTL/KR8l/yghI/8gGh3/cXZ1/4uWlP+RoaD/anVz/15iYv89Oz3/CAAH/wcA
B/8HAAj/BgAH/wgCCf8RCw//JRsf/zIoKv87MC//OS0r/y0eHv8pGRr/JBcZ/xYLEf8SAhD/GQgU/yAT
Gf8dEBf/FQUO/wkBBv8IAQj/IRgg/zAmLv8kGR7/Ni8v/xkRFv9XWVf/i5aU/5Kjof9teHb/TlBT/zMx
Nv8GAAb/CAAI/xkQE/8mHB3/ODEx/0I6Ov87MTL/PzU1/01FQv9QSEb/VExI/1RNSf9UTk3/TUZG/0c8
Pf9CNTb/Nysp/yQWFv8XCQz/CQED/wcAB/8bERf/NSgt/ysbH/8sIib/JBwg/z89Pf+JkpD/k6Kg/2Rs
av9KS0//MjA1/wYABv8XDhP/QTQw/1JDO/80LC//FA4X/w4FDf8yKiz/XllW/2NeW/9eWFb/U01L/1FL
S/9XU1L/YVtZ/1lRT/9TTkr/Qjo4/yEUFv8NBAX/CAAH/xIID/8zJSr/Oiww/zYsL/8sIiX/KyYn/3F4
dv96hIL/PkA9/0JAQ/8xLjH/EQwP/zcvLf9IQT7/Qzs5/yUdIv8WDBb/NCkt/1dQT/9kYF7/cG5r/2hn
Zv9GPUH/Rz9B/2NiYP9vamj/ZF1c/1dTUv9VUVD/TkZI/zowM/8eFBf/FgoO/ykYHP9DNjn/YmJp/1pd
Zf8jHiT/UlVW/3+Cgf9OT03/QD5B/z48Pv85MC7/SD05/yoiIf9LRkT/OzQ0/zEoLP9XUFD/cm9r/29t
av9mYmH/b3Bu/25vbv9qamn/amtp/2ZgX/9cVVX/WFRU/1pWVv9lYmT/VE5Q/y4lJ/84Ly//Oywu/1BG
Sf9zfYf/gpqr/zU3Pv9CQkT/b3Jx/1FTUv9AQkP/UFNT/ywjKP8lGiD/JR0f/01NS/9MSkv/SUVI/2ll
Z/9dV1n/WlRS/0xFRf9NRkj/aWdo/3Brav9dVlb/R0BB/1FNTv9LR0v/R0JG/01JSv9gX17/OC4w/z41
Nv9WT07/RDw8/01JTP9jaGv/TUtM/zs2OP9kaWj/S1BP/0FERP9SVlX/OTM2/z85Ov8pISP/HxUa/0M/
Q/9QTVD/WFFU/1BITP8uIib/T0hI/0U9P/9eWVv/Z2Fg/1BISP9NSEj/SENF/yUcJP9OSk7/SEJD/1tY
V/9NR0f/Qzs8/11XVf9EPDz/RT9C/0ZAQv9ST0//SEVF/09SUv86Pj3/RkhH/1dcWv9YWFf/VVVV/yUf
Jf8SChH/UE1S/1RSVv9QSk3/Pzc6/x0RFf80Ki3/QDY2/2BaWf9aVVL/UEpI/z83Ov88NTj/IRkg/0hF
Sf9EOj3/Y1xc/0I9QP9PTU3/WlFQ/1dQUP9PTU7/YGFg/1teW/9dX13/UFBQ/zIwL/8mISHmOjk4+mNk
Y/9PT0//GhMa/xUPFf9ZVln/R0RK/2BeYP96enr/naGg/6yysP+zuLb/tby5/6i0rv+lsaz/kpqY/5Ob
mv+Bh4b/YGFj/15XWf9cVFb/S0lM/2tua/9bUlH/Y19e/1VUVf9TUlL/Z2ln/11fXP9WVVX/Ojc3/zMt
Lk4ZFhjfYGJg/zw5PP8eGB//GhYZ/3R2cv+jqab/0NbV/9vk4f/T39v/wtDL/8PRzv+/zMn/vszF/77L
xf+uu7j/ssG//7C+vP+lsK//o62p/5qin/+RmZf/h4qH/21pZv97e3r/dHVx/zItLf9IRkf/b3Bv/2Vm
Zf9DQkP/LCgsJBoYGt9XV1b/Mi4x/yUdJP8dGBz/goWB/8LKxf+ytq//tLmz/7TAu//T4Nz/zN7Y/73L
x/+9ycL/u8a//626t/+hq6r/nKak/5ympP+aoZ3/nKWh/5ynp/+Vnp7/naen/6Gtrf99gH3/KiUl/xUN
FP9FQ0X/dHV0/0lISf84NDYmGRYY3VdVUv87OTf/KiMj/x8YGP96eXb/wMS//7C4sv+0vLb/rbe0/7nF
wf+8ycT/ucfB/7jBuf+4wLn/tcO9/6+8t/+iq6b/nqag/5idmP+coqD/qLW5/5qjp/+3ytL/wdnh/6Gv
r/8iHyL/Hhca/xcRFf88OTz/REFE/zMvMgsXExaiQT48/0pIRf86NDL/KCEg/0I8O/+vs67/tsC5/7fB
uv+zvrr/usjD/7zKxf+2xL3/uMG5/7e/uP+wu7T/rbmy/6Swqv+epqD/mp+a/5qgnP+jr7P/mqGl/7zU
3v/I4+v/m6en/xwYHP8lHiD/KiIk/ywnK/8vKy//DQoKABAODi4iGxurLign+U9MSP9FQj7/Jx8f/4mP
jP+8x8D/tsC5/7bDvf+2xb//uMfA/7bEvv+2wLn/tb+4/7O8tP+utq//pK+q/56loP+doZ3/nqSi/73U
2v+wvcT/u9jg/67Bw/9ERET/IRwe/y4oK/8tKCr/Kysq/yorKv////8AAAAAAFdQTxocFRWOHBga5Dk3
Nf4+Ozr/i5KP/8TQyf+zurX/tsS+/7nJwv+7y8T/usnC/7fBu/+1v7n/t8C4/7K7tP+kr6r/oKeh/56j
n/+gpqT/wdje/7rM1P/C4+v/naim/ywoKP8qJSX/Lyor/y4rLf89Pjz/MzQz/wAAAAAAAAAAPzs8AD44
OAkXFhc/CwkLnRgSGOBYVlr80dfW/7q/vf+3xsD/xdrS/9Po3//M2tL/v8i//7/JwP+2w73/qrex/6Wu
qf+kqqX/nqei/6Krp//I19j/yNbX/9z6/v+jsrL/NS4t/zw3Nf9CQUH/Tk5O/05NSv8lJCP+AAAAAAAA
AAAAAAAA////ACAeIAAZGBkKMi0yMhsTGqygoKH/0djW/7vKxP/D18//1enh/9Dh1//H0sj/vce//625
s/+msq3/pbCr/6SsqP+epqL/oaqn/7W6u//b7u7/5v///5+rqv9LR0P/T01I/zk4OP8qKSr6HBsa1RIS
EYsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKBwYAAAAAYm5wbvrs9vP/2Ofh/8DSyf/C0sr/xdbN/8HP
yP+wurf/rLWw/6u0r/+kr6r/oq2o/52jov+rtLP/z93Z/+T08f/JzMv/SUhF9RcTFdsUEBPGExITkgYG
BmMlJCQqjoyEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0ZFgAhHBomMC8s07W9uf/s+fX/ytrT/7zL
xP+9zMX/ucbB/6y1s/+utrH/rLSw/6WxrP+iq6f/nKKh/7bCwP/I09D/1+Th/2ZmY/MgHRl4REJCKA4M
DhJLS0wFNDM0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOTUxAP///AERDw1TPT4947nD
wP/c6uX/yNTO/7rFwP++y8b/tb+6/6uyr/+ut7X/q7Wy/7S/uf+5xcD/ztjV/9jb2f90d3X9FhYVnygm
JQ4fHh0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUE9OAK2r
qQMYGBhfPUA/5qWuq//S3dj/qa2q/6Kjnv+goZz/l5WS/7S8uf/I1M3/y9bP/+Dp5v/V29r/cnVz/Rsf
G6s2ODYdKi0qAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAVlVVAKCgoAQSERJHKikrtGdqaPaBg4D/qqyp/8/Sz//Jz8z/xczJ/7q/u/+bnZr/hYKC/UtG
RuMYGReJJCYlGgAAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAgHt/AAAAAAA7ODoYDAwMYzQ0NMRLTEv/Pj0+/zsyNf87MzX/PDw8/0pK
SfMjHR2RHBQUQmxqaQdRTEsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAgAAAAMAAAADgAAAA+AAAAP4AAAD+AAAH/gAAP/8AAH//gAD//+AB/ygA
AAAwAAAAYAAAAAEAIAAAAAAAACQAAMMOAADDDgAAAAAAAAAAAAAYFxT/QEdF/0JIRv9ERUb/Ozs7/zIw
Mf8/QUH/Nzg3/x8bHP8iHSH/GhQa/woCCv8IAAj/CAAI/wgACP8JAQn/CQEJ/wwEC/8NBQf/CwME/wwE
Bv8LAwr/CwIL/wgBCP8FAwX/BQQF/wQCBP8HAAf/CAAI/xEJD/8eHB//JSQn/yssLv84OT3/Li8y/zIy
Nv8+QEH/P0BB/z5AQP86PDz/Ojs8/zg5Ov8yMzb/P0FE/z9CRP9ER0b/Q0ZF/xkXFP9AR0X/tNLS/6fB
wf+zyMv/kZ+i/4WRk/+Up6b/cX18/0lNTf8yMDP/Ix8j/wsEC/8NBA3/EAgQ/xQLFP8XDhf/Fg4W/xsT
G/8dFBz/GhIZ/xgQFv8dFB3/HhUe/xoSGv8dFh3/Hhge/xUQFf8MBAv/CwIK/xcPFP8pKSv/NDY3/01S
Uv91fX//ipWY/52qrP+fsLL/nq+x/52tsP+SnaX/kZuk/4+Zov+JlZb/nqys/5+urv+qur3/vM/S/0NG
Rf80OTb/j6Wl/4SZmP+OnJ7/go6Q/2Nqa/9NUVH/Pj9A/yAdHv8IAAj/EQoR/xoVGv8gFyD/IRkh/x0V
Hf8TCxP/DwcP/w8HDv8PBwr/DwcK/w4FCP8RCRD/EQkR/xEJEf8LCQv/FBAU/yEaIf8eFRj/Fg0S/xEJ
EP8JBAj/BgEF/wwIDP8fHSL/YGVp/5aipP+Ej5H/fYiK/32Hif91fIL/dn2D/3d+hP9+iIr/foiK/4CL
jP+Ik5X/rLy//0RIRv87Qz//la6u/3yPjv+SnZv/eoKA/0hKR/8zMTP/EwwT/w0GDf8aERr/FAwU/woD
Cv8HAwf/BQMF/wQCBP8DAAL/BgAE/wgABf8HAAb/CAAH/wgAB/8IAAX/CgEG/wkBBv8EAAL/BQED/wUD
BP8KAwL/EgkN/xkRF/8XERf/FQ8V/woDCv8OAw7/HxYg/1taXf+KkpH/en5//3J2d/92fH//f4aL/3yD
h/99hIb/gIiJ/4iRkP+Ml5f/sb/A/0FGRv88RkH/l7Cx/3yPjv+OmZf/YGVi/zw9Of8cFhv/EQoR/xEK
Ef8MBAz/CAAI/wcAB/8DAAP/BgAG/wgAB/8LAAf/DgAJ/w0ACP8KAAr/CgAK/woACv8NAgj/EAIK/xAC
Cv8QAAr/EAAK/w0ACP8IAAH/CAAA/wgAAP8MBQz/Hhge/xsUG/8RBRH/EAMQ/x4UHv9XVlf/iI6O/4aM
jP94foD/e4KF/3l/gv9+hof/ho+O/4qTkv+Ml5f/scDA/0FGRv8+RkL/mbGy/32Pjv+Fj43/UlVS/yYk
Iv8WEBb/FA0U/wkBCf8IAAf/CAAH/wgAB/8GAAb/BAAD/wIAAf8EAAL/BwIE/wcCBP8GAQX/BgEG/wcB
Bv8IAAX/BAAC/wgABP8JAAX/CwAH/xQADf8MAwb/CAAA/wgAAf8HAAb/CgMK/xwWG/8iGCH/EgcS/w8E
D/8hGRr/VlZW/5Obm/+LlZn/foWJ/3h+gf97goT/ho+O/4yXlf+Klpb/r729/0BGRv8/QUD/lqWp/3+K
jf9gZWj/KCUq/wgBCP8KAgr/CQEJ/wgAB/8HAAH/BgAA/w4GBv8aExP/IRoa/yYgH/8tJiT/QDc0/0A3
NP86LSr/OSwp/zgrKP8qHh7/KB0c/ygdHP8hGBv/HBMY/xcOFP8QBw7/DQQM/wkBCP8LAQP/CAAA/woC
A/8gGBz/LyUp/xkRF/8fGx//Gxcb/1RTVv+Nm57/h5OV/2hsbv9ucHL/fYSF/4mUlP94hYf/lKWo/ztB
Qv8xMS//kZ6i/4eTlv9GR0v/GBIZ/wcAB/8IAAj/CAAI/wkBCP8bExL/MSgm/0lAPP9lYVz/cW9p/3p3
cf9pYFv/aF5Z/1lPSv9LPDj/Sjs2/0k6Nv89MCz/PC8r/zsuK/82LSz/Ny8u/zgwL/8qHCT/HxIb/xQJ
Ef8eChD/DQID/wcAAP8PBw3/Myot/zoxM/8rJyr/GBQY/xYSFv9WVlf/gYyO/3N5e/9lZWb/e4GB/4KL
jP91goT/kaOl/zpBQv8wMC7/nauw/3N8f/9BP0P/FxEY/wcAB/8LAgn/HA8U/zUjI/9JPTn/YlhS/1RL
R/86NTL/JyEf/yUfHv8cFBP/GxMS/xMLC/8PBgf/DwYH/w8GBv8OAgb/DQEG/w0BBv8IAgj/DgYN/xQM
Ev8SCRD/DgYN/w0EC/8QBAf/CgEC/wcAAP8QCA7/LiUo/ysiJf8oJCj/JSEl/xMOEv8zKiz/VFNU/3qC
g/94fX7/jZmZ/4CIiP90gIL/kKKl/zpBQf80NjX/e4uP/09VVv8vJij/CQEJ/xAHDf81IR3/QSok/zci
Hv8sHBz/GxAU/w0FDP8EAQP/AQAA/wEAAP8FAAL/CQAE/wkABf8JAAj/CAAI/wkACP8NAAr/DQAK/w0A
Cv8KAAn/CgAJ/wkACP8IAAX/BAAD/wQAA/8AAAD/AAAA/wEAAP8MBAX/LSMl/y0jJv8lICT/MS0x/yId
Iv8ZDxL/OzU2/3Bycf98hoT/hpCQ/4SNjf9zfX//jJqe/z1AP/9BRkb/eIiM/z5CQv8WDxT/DwcN/zAj
JP9DLCb/LxwY/xgLCv8IAAj/CAAI/wgACP8IAAj/CgAK/woACv8PAAr/EAAK/xAACv8MAAv/CwAL/wsA
C/8NAAr/DQAK/w0ACv8QAQ3/EAEN/xABDf8QAgr/EAIK/w8CCv8HAgT/AAAA/wEAAP8GAAD/Ixob/0k+
Qf83Mzb/KSUp/yIcIf8QBQn/IRgb/15dXP+Bion/gYuK/32Hhv9yfH//i5me/z1AP/9CRkb/eIiL/zxA
Qf8LBQz/LiIk/0U2NP8kFRP/EAYG/wkBAv8HAAf/CAAI/wgACP8KAAr/CgAK/woACv8PAAr/DwAK/w8A
Cv8OAA3/DwAO/w0ADP8NAAr/EAAM/xAADP8QAQ3/EAEN/xABDf8QAgv/EAIK/xEDC/8SBQz/AwEC/wEA
AP8HAAD/GQ8R/0xBRf9GQkX/Ihwh/yIdIv8iGRz/FAkN/0hERf+BiYn/hI2N/4SNjf9+io3/nq60/z0/
Pv9GRUb/e4aD/0FAQf8QCRD/KRog/xoPFf8GAAX/CAAH/wYABf8CAAL/BgEG/woCCv8IAAj/CAAI/wgA
CP8IAAj/CAAI/wgACP8PAAj/EAAJ/w8ACf8JAAj/CQAI/woACf8PAA//EAAQ/xAAEP8QBBD/EAQP/xAE
D/8VBA7/CgEG/wQAA/8HAAf/DwcO/y0kLP80KzT/LCIr/yYcIf8yKyv/DQUM/ychJP9vdHL/i5WU/4uV
lP+FlJL/prq5/0FGQ/9HRUb/e4aD/zEsLv8LAwv/CAAI/wgACP8IAAj/CQAJ/wkACf8JAgn/CgIK/wYB
Bv8HAAf/CAAI/wgACP8NBAv/GRAU/xgOE/8RAQn/EAAI/w8ACP8JAAj/CAAI/wgACf8PAA//EAAQ/xAA
EP8QBBD/EwcS/xYKE/8TAw3/EgMM/wQAAv8HAAf/DwcP/yohKv8yKTL/KiEp/yQZH/8+NzX/IBkc/xcQ
FP9WVlT/jJaU/4uWlP+FlJL/pbq4/0JGQ/9FQ0X/eYSB/yAXGv8IAAf/CAAI/wgACP8JAAn/BQAF/wYA
B/8GAQf/BwQH/xEKEP8pHyP/OS4w/0c8O/9QRD//VEhB/0U5Nf8/LSn/NSQi/zQjIf8yIB//KBka/xII
Dv8RAhD/FAMR/yAPGf8qHSD/IhYb/x4SGP8UBQ3/FAMN/wUAA/8HAAf/DgYO/ykgKf8zKTL/Jhsi/yAU
Gf8/ODb/KCEj/w4GDf9EQkD/gIiG/42Xlf+GlZP/p7u6/0NIRf8zMDX/bHJz/xkTGf8HAAf/CAAI/wcA
CP8MBAv/FQsQ/xYNEv8lHyP/Pjc3/1NJRv9TSkb/TkVC/1VLSP9GPjz/Qjo5/0I5OP9NRkL/UElF/1BI
Rf9SS0r/UUpJ/0k/P/9AMjT/NyYp/zUkJ/80JyX/KBoa/ycaGf8cDhH/EgYJ/wcAAP8IAAf/CQEJ/yIX
Hf84LDH/LR0i/yUTF/8nHiL/Ny4w/xoTGP82MzP/am9t/5agnv+Qnp3/qLq6/0lNSv8xLzT/a3By/xgS
Gf8HAAf/CAAI/woCCf8vIyL/QjQu/1FCOv9VTEf/RT08/ykiJ/8VDRP/CAAI/yIaHv9OSEb/aGRg/2Bc
WP9hW1j/XlhV/11YVf9bWVr/V1RV/1lWV/9iXVr/Y11a/1xVUv9QSkX/Ny0q/x4QD/8SBgj/DQME/wgA
AP8IAAf/CAAI/x4TGf84KzD/MyQp/zYoLf8tIyf/KiAk/yEYHf8nIyP/XWBe/5CamP+Kl5b/cn17/zMz
L/8wLjP/am9x/xgSGf8GAAb/CQIJ/yUZHf87Liz/V0c+/1NEO/8sJSn/EAsV/wYCDv8KAgr/GBAW/01F
Q/9mYl7/Yl1a/19aV/9iXFn/UktJ/1JLSv9RS0v/TEJA/1lVVf9gWlj/Vk1M/1NKSf9UT0v/XVpV/05I
RP8vHiL/EggJ/woCA/8IAAf/CAAI/xAGDf8yJCn/OCov/zsuMv89MzT/Migr/ywjJf8dFhf/QD8+/36G
hP+Djoz/VltZ/yopJf8pJCn/YWJi/xoUGv8IAwj/HBYY/zUsK/9NRkT/TkdE/zoyMP8rIib/FgsV/xQJ
E/8sICX/RTs9/1pTUf9QSEf/XVhX/2lmZf9tbWz/TERH/zMlK/84LDD/TEVH/2dnZv9xbGr/aWJh/1hP
UP9JRUb/RkJE/0xISf9ORUj/QTY6/zQoK/8YDRH/EQUK/xAECP8rGx7/NCQn/0g7Pv9dWV3/XVld/1VR
Vf8cFhz/Liwx/19lZf+JjIv/foB+/y8vLv8oIyj/YGFg/xsVG/8bFRb/NCwq/1dLRf89NjT/OTIx/0tF
Qv80LC3/HBIa/yQaIP86LzL/XFVU/2VgXf+AgX3/hoeD/319ev90dnT/bW1s/1xZWv9aV1f/Zmdm/2xt
a/9ybWv/c21r/3Nta/9wbmn/aWZi/2JfXP9eWVv/VlBT/0tDRv8sIyX/MSgp/yAVF/8fDRH/MyMm/0s/
Qv9weoX/eoua/3eLnP8YEhv/LSsw/1NXWP91d3b/goOC/y8wL/8oJCj/YWJi/zEtMP9BNzT/VElD/0U6
Nv8WDQ3/OjQy/1JMSf9BOzn/OTMz/zUtL/9RSkr/eHZx/3h2cf9raGb/VU9P/19aWf9vcG7/cnRy/3N1
c/9tb23/bG1r/2pqaf9kXl3/WlJT/01DRf9LR0j/SkZI/1tXVv9pZ2j/aGZo/1FKTf8oHiD/MCco/0Y/
Pf9DNjj/Rzo8/1tSVf9xe4X/eYiV/5G1zP9HTFL/Ih0j/0pNT/9jZWT/gYOC/y8wL/8lJCf/aXBu/0VH
R/8yKS3/LyUq/xwRGf8aEBP/REJB/1teW/9QT0//RkJF/0M/Q/9zcHL/amVn/1ZPUv9bVlT/T0dG/z40
Nv9GPUH/YF1f/21rbP9ybWv/bGZl/11WVv9IQkP/QTo8/1NQUP9WU1b/SUVJ/z03PP9FQEH/ZWZl/15d
XP89MzX/JRcd/0lBQf9WT07/UElH/0Q8Pf9TUVT/ZGhq/3+Njf9bW1v/KCAj/0VBQv9gZmX/fISC/y4w
MP8lJCb/anJw/0RGR/8cEhv/Jhwj/ykfJf8jGRz/Lico/zo2N/9LSUr/RkJG/1JQUv9raGr/UEdL/11X
Wv9TTEz/WlVS/19aV/9ANjn/UkxP/2pnaf9ybGr/Y1tb/1FISf89Njj/WFZW/1dVVf81LjX/PDY8/11b
Xf9BOzz/RkBB/2lqaP9PSUj/LCAk/0hAQP9cVlT/T0hH/y8nKP87Mjb/MSQp/z83Ov9RTk//SkVG/zcw
Mv9NUVH/bnZ1/yUnJ/8mJSf/aXFv/0ZJSf9FQED/SkRD/0lDQ/80Li//FgoP/xYKD/89OD3/R0NH/1RS
VP9XUFP/U0tP/0xDR/8ZChH/Jxsf/2BbWP9FPD//S0NG/2ViZP9pY2L/XFRU/05FRv9GQEH/X19e/zQr
Lv8lHCT/HxUf/2JhYv9VUVH/ODAy/2hoZv9dWlb/Myks/0tERP9jXVr/V1BO/0A4OP9PTU//TEhL/0xI
Sv9ST0//VFFR/0pHR/8/QkL/YGZl/x0fHv8wLi3/b3h2/0NEQ/9WVlX/WFhY/1VVVP8yLTL/DgYO/w8H
Dv9VUVb/T0xR/1tZXf9VUFL/Uk1P/z42Of8VCAz/FQkN/zcuMP8hExP/Qzk5/1xWVf9TTkv/UkxK/0xF
Q/8xJyr/VFFT/y8lKf8YEBf/IBkh/2ZoaP9KQET/QjY6/3Vwbv9RT1D/Miwx/1xdW/9cVFP/WVBP/1dP
T/9LSEr/X2Bf/2JkY/9ZW1j/XF5c/2JkYf9LSkr/T05P/yAdG/8kIB//X2Zk/1JVVP9iZGL/Y2Rj/05O
Tv8nISf/CAAI/xEJEf9gXWD/T0xS/05MUv9YVVf/NCou/0A4O/86MjX/TEZI/11ZWv9mYWD/gH18/358
ev9ra2j/aWlm/2ZlYv9COz3/TklM/0dCRf81MTb/RURH/z06Pv8xJCr/WlBS/2dfX/8xKjD/Ozc7/2Nl
Yv9VSkn/VUlJ/2BdXP9HREf/TkxO/2NkY/9jZmP/XF9c/11gXf9UU1P/U1FS/x4bGP8XEBDaHxkZ8yom
JvtnaWb/YWJh/0lISf8aFBr/DgcO/xQNE/9iX2H/Uk9U/zAtNv9gXmD/dXZ2/5mgnf/Dy8j/zdbT/9Pe
2v/S29j/0tvY/9Da1//E1s//xNfR/8PVz/+1xMH/tMLA/7bFwv+lsa3/ho2L/11eYP9nYWH/a2Rl/0xC
Rf9FQUT/cHZy/3F1cP9aUVD/XldW/2hoZv9fYF//SUZI/1VVVf9qbGr/aWxp/1dZV/9NS0z/ZGJk/yQg
Hv9+eXc8GBMWoBIOEflwdHD/VFVU/zk2Of8eGB7/GxUb/xAND/9ubWn/jZCM/5Walv/S2dj/6vLy/+bu
7f/l8u3/z9zX/7PAvP+5xcL/vcnG/7rGxP+5xr7/xdLM/7/Mxf+turj/sb+9/73Py/++zcv/sr++/666
uf+ptbL/prGu/5eem/+IjIn/obCx/4CBff9pY2H/bWhm/3x8ev97fXn/XFtY/x8ZGf9MSkv/d3h3/2do
Z/9ZWln/Zmdm/yooKv8AAAAADwsPdhMQE/5scG3/S0pL/ykkKf8fGB//JR0l/xEPEP9vb2r/srq1/9Le
2f/N1ND/yc/L/8TKxv+yvrn/t8S//9Dd2f/S5uD/wdDN/7zKx/+5xb7/ucS9/7O+tv+ksK7/n6qp/5ym
pf+cpqX/nKal/5ympf+aop7/pbCs/6axrv+PlZL/l6Cg/4CBfP94dnT/g4WE/46Uk/9+gHz/Xl1a/xYP
D/8WDxb/TkxO/3h6eP92eHb/cXJx/yooKv8AAAAAFxMWhhMQE/9naWb/Q0FC/ysmKv8lHSX/KSAo/xIP
Ef90dnD/vMS//7jAu/+prKT/o6ad/7K3sP+0wLv/xNHM/+Tx7f/P4tz/v87K/73Kx/+/y8T/wMvE/7/L
xP+zwr7/qba0/6Crqf+cpqX/nKal/5ympP+aop3/lZuW/5eemf+mtrf/kZiW/6W0tv+qurr/q7m4/6y8
vP+Dh4P/XV1a/xYPEP8PBw7/GBEY/z47Pv9zdHP/e317/yooKv////8CHhodhxEOEf9gXlr/S0pG/zAu
LP8qIyP/KyQj/xUODv9STkz/3uTf/6+wrf+vs63/tsK6/7O5s/+ttrT/rri2/7vHw/+5x8H/u8jD/7nG
wf+3wLj/t764/7fAuP+1w73/tMK9/667tf+iq6b/n6ii/52kn/+aoJv/lZmV/5yjoP+91Nr/kpaY/56o
rf++1t//sbzE/8Xi6/+xwL//WFtc/w4KDf8hGh3/GhMX/w8KDv8yLjL/a2tr/y4pLv8AAAAAEAwQahIO
EfZlY17/VlVR/zw7OP8sJST/KyQj/ycfH/87NTT/vcC7/7K1sf+1wrr/t8O7/7W9t/+strP/r7q3/7nG
wv+/zMf/ucfB/7fEvv+4wbj/t7+3/7e/uP+0wrv/ssC5/7G+uP+kr6r/oKmk/56loP+YnZj/l5yX/5id
mv+ntbn/kZWY/5mgpP+3ytP/vNLc/8rm8P/V6ef/WFxd/w4JDf8jHB7/Jx8h/x4XGv8aExr/RkJG/ykj
Kf9PTE0AT0tMIRANEMMrKij/TUxI/01LSP9CPDr/Ligm/ykiIf8ZERH/fnx6/7a6tv+1wLn/tsC5/7fC
u/+1wbz/uMXA/77Mxv+/zcf/t8a//7XDvf+5w7r/t7+3/7e/uP+vu7T/qLKq/625sv+msq3/oKmk/52k
nv+boJv/mZ6Z/5mfm/+ntbn/naWp/5qgpP++1+D/xeTv/8Xe5v++zsz/OTo9/xEMEP8lHiD/LSUm/y4m
KP8sJyv/PTo9/yAbIP////8AAAAAAAcFBloeFxe9HBQU+D85OP9dWlT/VVNN/zMwLv8eFRX/PDc3/7XC
v/+8x7//t8C4/7jCu/+1w73/tcO9/7fFv/+4yMH/uMfA/7XDvf+3wLr/tsC5/7bAuf+0vbX/r7Wv/62z
rv+lsaz/oKmk/52jnf+fo5//nJ+c/5yioP/E3uX/t8fP/6iutP+82+P/vd3l/7TLz/9gXlv/EAwQ/yci
I/8sJyr/Miwt/ywoKv8kJCT/Njg2/xwcHP8AAAAAqKOgAP///wFqZGIzIxsbphgREfYsKSj/VFJM/1hV
UP86NDP/IRgY/6m1sv+/y8T/sLaw/7bAuf+1w73/tcO9/7bFv/+2xb//uMjB/7bFv/+1wLr/s764/7O+
t/+3wLf/t8C3/7G4sf+lsaz/oKmk/56ln/+eop7/mp2a/5qgnv/F4ej/wNbe/7PByP+93+j/sMPE/5+n
o/8vLCz/HBcZ/zItLP8uKSv/Likr/ywoKv8iIyL/PkA+/yIjIv8AAAAAAAAAAO3q5QD///8CXldWIBsT
FJIMCAvSFxMV/TIwL/9TUlH/SUZG/7jGwv/M3dP/sbex/7W9t/+2xL7/t8fA/7vMxP+8zcX/vMzE/7rK
wv+6wrz/tr+5/7a/uf+3wLj/t8C3/7G6s/+lsaz/oaqk/5+nof+gpaD/n6Of/52jof/I4+n/ucnQ/7rN
1P/H8fv/utXZ/5yinv8tKSn/HRgZ/zEsK/8wLCz/Likr/y4qLf89Pjz/U1VS/yAhIP8AAAAAAAAAAAAA
AAAAAAAA4+rpAE5IRwk5OTg7BAQFlAUEBdsVDhX5GBAY/4yOjv/o7+7/wMTD/7a6uf+2xL7/vc/I/8bb
0//Q4tn/0ODY/8jUy/+9xb3/vsa+/77Hv/+4xL//sr65/6i0r/+lr6r/paum/6Sqpf+gqaT/mqKc/52l
oP/Z7u3/vcXG/8jW2P/d+v//0Ort/5ehoP8kGx3/MCko/zIrKv8xLzD/QUFB/01NTP9YVlP/VFNP/xcW
Ff8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACanJoAmZyZCBAPEEUiHCKCGBEYxB0WHfe8v8D/2N3d/7W5
uf+3xsD/u8zF/8zk2//d9u7/2vDo/8/e1f/EzsT/wcvB/8TQxf+3xL//q7iz/6azrv+lr6r/pa2o/6Wr
pv+gqqX/maGc/6ezr//F0NH/vcXF/9vv7//g/f//3vv//5Ocmv80LCv/VVFM/1VSTP9YWVf/W11b/1JT
Uv8+PTr/ISEf+wYGBuoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCoqagIRUFFKhMM
Erxva2z/7vX1/8fMzP+8zcb/vM7H/8LVzf/S5Nz/0+Xd/87c0//L2Mz/wcvC/7nBuv+qtrH/pbKt/6ay
rf+lsaz/pa6p/6StqP+gqqX/maCb/6ezsf+koqP/yNTU/+b+/v/i/f//4fv9/4aLiP9RTUj/XFlT/01K
Rf8vLi//Gxkb/hYUFvwMDAzgFxYVmSAfHkYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA+5U8AAAAAJpCQj7/5/Lu/+v38//W5d7/xtfP/7zOxf/C0sr/xdbN/8bXzv/G1s3/u8jC/664
tv+stbH/rLSv/6y0r/+lsKv/oqyn/6KsqP+gp6b/lpmZ/6iwsP/L19T/1+fk/+j69//y9vX/rq+u/zMw
Lf4OCg39EAwP9A4KDe8NDA3JBAQEnwQEBIk+PDtBPT09Cf///wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAABwZGVwnJSLwtb25//P/+//u+vb/1uXe/77Qx/+/z8f/vczF/8LS
yv/A0Mj/r7m3/622tf+ttbD/rbSv/6y0r/+lsav/o6+q/6Otqf+fpaX/n6Wl/8fY1f/Z6ub/0N7a/+X1
8f/Jysj/JSIe8iIeG8QmIiSQEAwQZgsHC1pQUFAura6tCKmpqQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEdCQBoNCgbFSElF/87X0//x/fr/3uzn/8PU
zP+7ysP/ucjB/7vKw/++zcb/rba0/6y0s/+ttrH/rbSw/620r/+msq3/pK+r/5+no/+boKD/mZ2d/8LR
zv+us7D/2OXi/9rq5/9oZ2X/GRUStVtZVjHU1s4KCgUIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWlZSAAAAAAAjISA9BgYFz1pb
Wf7O2db/3+3o/9rn4v/I1c//x9TN/7vGwf/E087/wc/K/7K7tv+xurj/sbq4/663tf+lrq3/qbKw/7K8
uP+2wr3/v8rG/8rV0v/S09L/6evq/2tvbP8KCgrkEA8PVAAAAAChoZ4AAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI6M
iQDs6OQELi0sTAkKCdVgZWT/zNfU/97r5//L19H/ucK9/6ivq/+rsqz/tb65/6mwq/+am5n/n6Kg/7bA
vv+7xsD/ucS+/8POxv/Azcf/0dzZ/+Dp5//p6un/b3Fv/xEVEeshIiFrsbGxCKqqqgAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADe29YA8u/qBTQzMlcNDQ3aSU1M/7W/vP/h7+j/v8fC/5WXlP+WlI//lJKM/5OQ
i/+Mh4T/k5CO/77KyP/L187/ws3G/9Db0v/q8/H/7PTz/9rg4P9qbWr/ERUR6ycrJ3W+wL4MKCwoAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUFBQAP///wMmJCVCDQoNrCEfIuyChYP/r7Ow/73A
vf/O0c7/6ezo//P48//t+PT/1t/c/+Pt6v/l6ub/09fT/8XIxf/DwsL/jouL/zQuLvoOEA3RExUTZqGj
oQhKTUoA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZVVkAWVZZFSEe
IWgRERHEAAAA7SEhIfpMTEz/enx6/42Ojf+IiIj/iIeH/4eGhv9rbGv/TU5N/zAwMP0ZEhLwGBAQ2CUe
HotMTEoqBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAZmdmAKeppwI1NjUlFhYWRmdpZ89WVlb/NTQ1/xkXGf8bDhL/Gw0R/x0QFP8tLCz/TU5N/2ts
a/FQS0tgFw8PMlFLSwwAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA
AAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAADAAAAAAAAAAMAAAAAAAAAA4AAAAAAA
AAD4AAAAAAAAAP4AAAAAAAAA/4AAAAAAAAD/4AAAAAAAAP/gAAAADwAA/+AAAAD/AAD/8AAAA/8AAP/w
AAAD/wAA//gAAAf/AAD//AAAD/8AAP//AAA//wAA//+AAH//AAAoAAAAQAAAAIAAAAABACAAAAAAAABA
AADDDgAAww4AAAAAAAAAAAAACAQA/wgEAP8IBAD/CAQA/xAICP8QCAj/EAgI/xAICP8IAAD/CAAA/wgA
AP8IAAD/CAAI/wgACP8IAAj/CAAI/wgACP8IAAj/CAAI/wgACP8IAAj/CAAI/wgACP8IAAj/CAAA/wgA
AP8IAAD/CAAA/wgACP8IAAj/CAAI/wgACP8AAAD/AAAA/wAAAP8AAAD/CAAI/wgACP8IAAj/CAAI/wgE
CP8IBAj/CAQI/wgECP8IBAj/CAQI/wgECP8IBAj/CAAA/wgAAP8IAAD/CAAA/wgEAP8IBAD/CAQA/wgE
AP8IBAj/CAQI/wgECP8IBAj/CAQA/wgEAP8IBAD/CAQA/wgEAP/G5+f/xufn/8bn5/+909b/vdPW/4OP
kf+Dj5H/vdfW/73X1v+Aj47/REdH/1pdWv9aXVr/Ix8j/wgACP8IAAj/CAAI/wgACP8IAAj/EAgQ/wgA
CP8QCBD/GBAY/xgQFv8YEBb/EAgL/xgQFv8TChP/EwoT/xMKE/8IAAj/DQoN/xsVG/8NCg3/DQoN/wgA
CP8IAAj/CAAI/ykgIf9PVFT/T1RU/3N9e/9zfXv/pbK1/6Wytf9weHv/pbK1/73T1v+909b/vdPW/73T
1v+tusb/rbrG/626xv+tusb/gIuM/73Pzv+9z87/vc/O/87j5//O4+f/zuPn/wgEAP8IBAD/xufn/4ab
mv+Gm5r/vdPW/4OPkf+Dj5H/g4+R/4CPjv9ER0f/REdH/0RHR/8IAAj/CAAI/wgACP8IAAj/EwoT/xMK
E/8eFR7/HhUe/yEYIf8hGCH/IRgh/yEYIf8hGCH/IRgh/yEYIf8YEBb/KSAp/ykgKf8pICn/KSAp/ykg
Kf8pICn/KSAp/xsVG/8TChD/CAAI/xMKEP8IAAj/CAQI/wgECP8IBAj/Kywu/zw+Qf9weHv/pbK1/6Wy
tf+AjI7/gIyO/4CMjv+AjI7/dn2E/3Z9hP92fYT/dn2E/4CLjP+Ai4z/gIuM/4CLjP+MmJr/jJia/87j
5/8IBAD/CAQA/4abmv+Gm5r/hpua/4OPkf+Dj5H/g4+R/0lLTP9ER0f/REdH/0RHR/8IAAD/CAAI/wgA
CP8jHyP/Ix8j/ykgKf8pICn/KSAp/x4VHv8QCBD/CAAI/wgACP8IAAj/CAAA/wgAAP8IAAD/CAAA/wgA
CP8IAAj/CAAI/wgACP8AAAD/AAAA/xsVG/8pICn/KSAh/x4VGP8TChD/EwoQ/wgECP8IBAj/CAQI/wgE
CP8IBAj/PD5B/3B4e/+lsrX/gIyO/4CMjv+AjI7/gIyO/3Z9hP92fYT/dn2E/3Z9hP+Ai4z/gIuM/4CL
jP+Ai4z/jJia/4yYmv/O4+f/CAQA/wgIAP+109b/e4+O/3uPjv+Unpz/lJ6c/2pwbf9BQj7/QkFC/xsV
G/8IAAj/CAAI/x4VHv8pICn/CAAI/wgACP8FAAX/AAAA/wAAAP8AAAD/AAAA/wAAAP8IAAX/CAAF/wUA
Bf8KAAr/BQAF/woACv8IAQX/CAEF/wgBBf8IAQX/AAAA/wAAAP8AAAD/AAAA/wgAAP8IAAD/IRgh/yEY
If8eGB7/EwwT/wgACP8IAAj/EAQQ/xAEEP8xKTH/c3Vz/5ympf9zdnb/c3Z2/3N2dv9zeXv/foWJ/4mR
l/9+hYn/e4KE/3uChP+AiIn/jJaU/46amv+Ompr/1ufn/wAAAP8ICAD/tdPW/3uPjv97j47/lJ6c/5Se
nP9BQj7/QUI+/y4rLv8IAAj/CAAI/xsVG/8TChP/CAAI/wgACP8IAAj/AAAA/wUABf8FAAX/BQAF/wgA
Bf8IAAX/EAAK/wgABf8KAAr/CgAK/woACv8KAAr/CAEF/xACCv8QAgr/EAIK/xAACv8QAAr/EAAK/wAA
AP8IAAD/CAAA/wgAAP8IAAD/CAAI/ykkKf8pJCn/CAAI/xAEEP8QBBD/EAQQ/zEpMf9zdnb/nKal/3N2
dv9zdnb/c3l7/36Fif9zeXv/c3l7/4CIif+Gj47/ho+O/4aPjv+Ompr/jpqa/9bn5/8AAAD/CAgA/7XT
1v97j47/e4+O/5SenP9qcG3/QUI+/0FCPv8IAAj/GxUb/xsVG/8IAAj/CAAI/wgACP8IAAj/CAAI/wUA
Bf8FAAX/CgAK/woACv8QAAr/EAAK/xAACv8QAAr/CgAK/woACv8KAAr/CgAK/xACCv8QAgr/EAIK/xAC
Cv8QAAr/EAAK/xAACv8YABD/CAAA/wgAAP8IAAD/CAAA/wgACP8IAAj/Hhge/ykkKf8QBBD/EAQQ/xAE
EP8QBBD/IRgY/3N2dv+cpqX/nKal/3N5e/9+hYn/foWJ/36Fif97goT/gIiJ/4yWlP+MlpT/jpqa/46a
mv/W5+f/AAAA/wgIAP+109b/e4+O/3uPjv+Unpz/anBt/0FCPv8YFBD/GxUb/xsVG/8IAAj/CAAI/wgA
CP8IAAj/CAAI/wgACP8KAAr/BQAF/wUABf8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8FAAX/AAAA/wUA
Bf8IAQX/AAAA/wAAAP8IAQX/CAAF/wgABf8QAAr/GAAQ/xAIC/8IAAD/CAAA/wgAAP8IAAj/CAAI/wgA
CP8eGB7/MSkx/xAEEP8QBBD/EAQQ/yEYGP8hGBj/c3Z2/5ympf+UnqX/foWJ/36Fif9zeXv/e4KE/4CI
if+MlpT/jJaU/46amv+Ompr/1ufn/wAAAP8QDAj/vc/W/4OOkf+DjpH/a3Fz/0pLT/8IAAj/CAAI/wgA
CP8IAAj/CAAI/wgACP8IAAD/CAAA/wgAAP8IAAD/CAAA/wgAAP8IAAD/CAAA/wgAAP8uJSP/LiUj/y4l
I/8pHRv/KR0b/ykdG/8pHRv/EAQI/xAECP8QBAj/EAQI/wgACP8IAAj/CAAI/wgACP8IAAj/CAAI/wgA
CP8IAAj/CAAA/wgAAP8IAAD/CAAA/xsSGP9CODn/GxIY/wgACP8pJSn/CAQI/yklKf9raWv/pbq9/4GM
jv+BjI7/XV5f/3Z6e/92env/iZSU/4mUlP92hIb/doSG/63Dxv8ICAj/EAwI/4OOkf+DjpH/g46R/0pL
T/8pJSv/CAAI/wgACP8IAAj/CAAI/wgACP8IAAj/CAAA/wgAAP8IAAD/KSAe/1RQTP9UUEz/e3lz/3t5
c/97cWv/e3Fr/3txa/97cWv/a1lS/2tZUv9rWVL/a1lS/2haT/9oWk//aFpP/2haT/9aUUr/WlFK/z42
NP8+NjT/IxUe/yMVHv8VChP/CAAI/xsJDf8IAAD/CAAA/wgAAP8IAAj/LiUo/0I4Of8uJSj/KSUp/ykl
Kf8IBAj/KSUp/11eX/+lur3/gYyO/11eX/9jYWP/Y2Fj/4mUlP+JlJT/doSG/3aEhv+tw8b/CAgI/xAM
CP+DjpH/vc/W/4OOkf9KS0//KSUr/wgACP8IAAj/CAAI/wgACP8IAAj/CAAI/ykgHv9KQDz/a2Fa/2th
Wv97eXP/e3lz/3t5c/97eXP/VEtH/1RLR/9US0f/LiUj/ykdG/8pHRv/KR0b/ykdG/8QBAj/EAQI/xAE
CP8QBAj/CAAI/yMbHv8jGx7/PjY0/zEgKf8jFR7/IxUe/xUKE/8uEhv/GwkN/wgAAP8IAAD/CAAI/xsS
GP9CODn/Qjg5/yklKf8pJSn/CAQI/wgECP85MDH/XV5f/4GMjv+BjI7/Y2Fj/3Z6e/+JlJT/dnp7/3aE
hv92hIb/rcPG/wgICP8QDAj/g46R/73P1v9JTUz/SktP/yklK/8IAAj/CAAI/wgACP8IAAj/NCIj/0o0
Mf9KQDz/a2Fa/2thWv9KQDz/Ligm/wgAAP8IAAD/CAAA/wgAAP8IAAD/CAAA/wgAAP8IAAD/CAAA/wgA
AP8IAAD/EAQI/xAECP8QBAj/EAQI/wgACP8IAAj/CAAI/wgACP8IAAj/CAAI/wgACP8IAAj/CAAA/wgA
AP8IAAD/CAAA/wgACP8uJSj/LiUo/xsSGP8pJSn/KSUp/yklKf8IBAj/OTAx/zkwMf9dXl//gYyO/3Z6
e/+JlJT/nK6t/3Z6e/92hIb/doSG/63Dxv8ICAj/EAwI/3iIjP94iIz/REpK/0Q2NP8IAAj/CAAI/wgA
CP80IBv/SjAp/0owKf80IBv/OSQh/ygYGP8IAAj/CAAI/wAAAP8AAAD/AAAA/wAAAP8AAAD/CAAF/wgA
Bf8IAAX/CgAK/woACv8IAAj/CAAI/w0ACv8NAAr/DQAK/w0ACv8IAAj/CAAI/wgACP8IAAj/CAEF/wAA
AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8IAAD/Ixkb/z4zNv8jGRv/IRwh/zEtMf8xLTH/IRwh/xAE
CP8zLC7/V1RU/3t9e/97hoT/e4aE/5SanP+DjIz/c32A/3N9gP+ltr3/EAwI/xAMCP+tx87/REpK/0RK
Sv8mGx7/CAAI/wgACP8mGx7/SjAp/zQgG/80IBv/HhAN/wgACP8IAAj/CAAI/wgACP8FAAX/CgAK/woA
Cv8KAAr/EAAK/xAACv8QAAr/EAAK/woACv8KAAr/CgAK/w0ADf8NAAr/DQAK/w0ACv8NAAr/EAEN/xAB
Df8QAQ3/EAEN/xACCv8QAgr/EAIK/xACCv8AAAD/AAAA/wAAAP8AAAD/CAAA/wgAAP8+Mzb/PjM2/yEc
If8xLTH/MS0x/yEcIf8QBAj/EAQI/zMsLv97fXv/e4aE/3uGhP+DjIz/e4aE/3N9gP9zfYD/pba9/xAM
CP8QDAj/rcfO/0RKSv9ESkr/CAAI/wgACP8mGx7/RDY0/0owKf80IBv/HhAN/wgAAP8IAAj/CAAI/wgA
CP8IAAj/CgAK/woACv8KAAr/CgAK/xAACv8QAAr/EAAK/xAACv8NAA3/DQAN/woACv8KAAr/DQAK/w0A
Cv8NAAr/DQAK/xABDf8QAQ3/EAEN/xABDf8QAgr/EAIK/xACCv8QAgr/EAUK/wAAAP8AAAD/AAAA/wgA
AP8IAAD/PjM2/1pNUv9SUVL/IRwh/yEcIf8hHCH/EAQI/xAECP8zLC7/V1RU/4uTlP+DjIz/g4yM/3uG
hP9zfYD/c32A/6W2vf8QDAj/EAwI/63Hzv9ESkr/REpK/wgACP8IAAj/Y1FK/0Q2NP8eEA3/CAAA/wgA
AP8IAAD/CAAI/wgACP8IAAj/CAAI/woACv8KAAr/CgAK/woACv8QAAr/EAAK/xAACv8QAAr/DQAN/xAA
EP8QABD/DQAN/w0ACv8SAA3/EgAN/xIADf8QAQ3/EAEN/xABDf8QAQ3/EAIK/xACCv8QAgr/EAIK/xgI
EP8IAgX/AAAA/wAAAP8IAAD/CAAA/yMZG/9aTVL/UlFS/yEcIf8hHCH/IRwh/zMsLv8QBAj/EAQI/1dU
VP+DjIz/g4yM/4OMjP+Lk5T/c32A/6W2vf+ltr3/EAwI/xgMEP+tw73/SUlJ/0lJSf8IAAj/HhEY/0o0
Of8IAAj/BQAF/wUABf8KAAr/BQAF/wAAAP8AAAD/CgIK/woCCv8IAAj/CAAI/wgACP8IAAj/CAAI/wgA
CP8IAAj/CAAI/xAACP8QAAj/EAAI/xAACP8IAAj/CAAI/wgACP8IAAj/EAAQ/xAAEP8QABD/EAAQ/xAE
EP8QBBD/EAQQ/xAEEP8YBBD/EAIK/wAAAP8IAQX/CAAI/wgACP8VDRX/MSgx/zEoMf8xKDH/KB4m/yAV
G/9CPDn/CAAI/wgACP8uKCj/cHVz/4yWlP+MlpT/jJaU/4aWlP+GlpT/xt/e/wgEAP8YDBD/rcO9/0lJ
Sf9JSUn/CAAI/wgACP8IAAj/CAAI/wUABf8KAAr/CgAK/wUABf8FAQX/BQEF/woCCv8KAgr/CAAI/wgA
CP8IAAj/CAAI/wgACP8IAAj/CAAI/wgACP8QAAj/EAAI/xAACP8QAAj/CAAI/wgACP8IAAj/CAAI/xAA
EP8QABD/EAAQ/xAAEP8QBBD/EAQQ/xAEEP8QBBD/EAIK/xgEEP8IAQX/AAAA/wgACP8IAAj/FQ0V/zEo
Mf8xKDH/MSgx/ygeJv8gFRv/Qjw5/y4oKP8IAAj/GxQY/1RUUv+MlpT/jJaU/4yWlP+GlpT/hpaU/8bf
3v8IBAD/GAwQ/63Dvf9JSUn/GAwQ/wgACP8IAAj/CAAI/wgACP8KAAr/CgAK/wUABf8QABD/CgIK/xAE
EP8KAgr/AAAA/wgACP8IAAj/CAAI/wgACP8IAAj/KR8g/ykfIP8pHyD/EAAI/xAACP8QAAj/EAAI/wgA
CP8IAAj/CAAI/wgACP8QABD/EAAQ/xAAEP8QABD/EAQQ/xAEEP8dERj/HREY/xACCv8YBBD/EAIK/wAA
AP8IAAj/CAAI/xUNFf8xKDH/MSgx/zEoMf8gFRv/IBUb/0I8Of9CPDn/CAAI/xsUGP85NDH/jJaU/4yW
lP+MlpT/hpaU/4aWlP/G397/CAQA/xgMEP+tw73/SUlJ/xgMEP8IAAj/CAAI/wgACP8IAAj/CgAK/wUA
Bf8FAAX/BQAF/wUBBf8AAAD/AAAA/xAEEP8mHCD/RDg5/0Q4Of9jVVL/a11S/2tdUv9rXVL/Sj45/1pF
Of9BLij/QS4o/0EuKP8+KCP/Pigj/yMUFf8IAAj/EAAQ/xAAEP8YCBX/KRgh/zksKf8rHiD/HREY/x0R
GP8QAgr/GAQQ/xACCv8AAAD/CAAI/wgACP8VDRX/MSgx/zEoMf8xKDH/GAwQ/yAVG/9CPDn/Qjw5/wgA
CP8IAAj/OTQx/3B1c/+MlpT/jJaU/4aWlP+GlpT/xt/e/wgEAP8IAAj/jJeW/0pLT/8IAAj/CAAI/wgA
CP8IAAj/CAAI/wgACP8IAAj/CAAI/wgACP8IBBD/JiAm/0Q8PP9jWVL/a2Fa/2thWv9rYVr/a2Fa/0dA
P/8xKCn/MSgp/zEoKf9CPDn/TUdE/01HRP9NR0T/T0VE/1RPT/9PRUT/Sjw5/zwsLv8pFBj/KRQY/ykU
GP8xJSP/MSUj/zElI/8xJSP/Gw0Q/xsNEP8IAAD/CAAA/wgACP8IAAj/CAAI/ykcIf85LDH/OSwx/yEM
EP8hDBD/GxIY/0I4Of9CODn/CAAI/zw6Of88Ojn/lJ6c/5SenP+RoJ//kaCf/87n5/8YFBD/CAAI/4yX
lv9KS0//CAAI/wgACP8IAAj/CAAI/wgACP8IAAj/Sjs0/ykdHv9KOzT/Y1lS/2NZUv9jWVL/RDw8/ykg
I/8IAAj/CAAI/ykgI/8xKCn/XVhV/11YVf9dWFX/Y11a/1hST/9YUk//WFJP/1pZWv9aWVr/VE9P/1pZ
Wv9jXVr/Y11a/2NdWv9PRET/SkM+/xgICP8YCAj/GAgI/xsNEP8bDRD/CAAA/wgAAP8IAAj/CAAI/wgA
CP8pHCH/OSwx/zksMf8pFhv/OSwx/y4lKP8IAAj/Qjg5/wgACP88Ojn/PDo5/5SenP+Unpz/kaCf/5Gg
n/+RoJ//GBQQ/wgACP+Ml5b/SktP/wgACP8IAAj/CAAI/wgACP8IAAj/Sjs0/0o7NP9KOzT/a1lK/0Q8
PP9EPDz/CAQQ/wgEEP8IAAj/CAAI/wgACP8pICP/XVhV/3Nxa/9zcWv/XVhV/2NdWv9jXVr/Y11a/2Nd
Wv9aWVr/Wlla/1RPT/9aWVr/Y11a/2NdWv9jXVr/Y11a/2NhWv9jYVr/SkM+/xgICP8IAAD/CAAA/wgA
AP8IAAD/CAAI/wgACP8IAAj/HhIY/zksMf85LDH/MSEm/zksMf9CODn/GxIY/0I4Of8bEhj/EAgI/zw6
Of9obGr/lJ6c/5Ggn/9UWlf/VFpX/xgUEP8IAAj/jJeW/0pLT/8IAAj/CAAI/wgACP8IAAj/Py4x/ykd
Hv9KOzT/a1lK/0o7NP8mICb/CAQQ/wgEEP8IBBD/CAAI/wgACP8pICP/a2Fa/3Nxa/9dWFX/XVhV/11Y
Vf9jXVr/WFJP/0I8Of9YUk//VE9P/0o8Of9KPDn/Wlla/2NdWv9PRET/T0RE/09ERP9KQz7/Y2Fa/2Nh
Wv9jYVr/Qigx/xsNEP8IAAD/CAAA/wgACP8IAAj/CAAI/wgACP8xISb/OSwx/zksMf85LDH/Qjg5/y4l
KP8uJSj/LiUo/xAICP88Ojn/PDo5/5SenP+RoJ//VFpX/1RaV/8YFBD/CAAI/3N1c/9PTk//CAAI/wgE
CP8IBAj/KyQj/yskI/9HQD7/Y11a/0dAPv8rJCP/MSkr/yAWHf8QBBD/EAQQ/zEkKf8xJCn/Ylxa/2Jc
Wv9CODn/Qjg5/2BbWv9gW1r/c3Vz/1pWV/8pGCH/KRgh/zEkKf8xJCn/V1RV/2tta/9zbWv/c21r/19X
V/9MQUT/OTQ5/zk0Of85NDn/TEhJ/09HSv9PR0r/MyUp/zMlKf8QBAj/EAQI/xAECP8QBAj/MyMm/zMj
Jv8zIyb/T0JE/1pRUv9aUVL/WlFS/1pRUv8QCBD/Liwx/y4sMf9rdXP/nJ6c/2hpaP+cnpz/AAAA/wgA
CP9zdXP/T05P/wgACP8IBAj/KyQj/yskI/9PRD7/Y11a/yskI/9HQD7/R0A+/zEpK/8gFh3/EAQQ/yAW
Hf8xJCn/SUBB/0lAQf9JQEH/YFta/35+e/9+fnv/fn57/3N1c/9zdXP/WlZX/0E3PP9EPD//V1RV/2tt
a/9rbWv/c21r/3Nta/9zbWv/c21r/3Nxa/9fXFr/X1xa/0xISf9PR0r/T0dK/09HSv9PR0r/Jhwe/yYc
Hv8QBAj/EAQI/xgECP8zIyb/MyMm/09CRP9zf4v/c3+L/3N/i/9zf4v/EAgQ/xAIEP9MUFL/TFBS/5ye
nP9oaWj/nJ6c/wAAAP8IAAj/c3Vz/09OT/8IAAj/KyQj/yskI/9PRD7/c2Va/yskI/8QCAj/Y11a/0dA
Pv9CPDn/IBYd/yAWHf8xKSv/MSQp/2JcWv97eXP/e3lz/5yinP+copz/fn57/35+e/9zdXP/c3Vz/3N1
c/9zdXP/a21r/2tta/9rbWv/a21r/3Nta/9zbWv/c21r/3Nta/9zcWv/c3Fr/3Nxa/9zcWv/a2lr/2tp
a/9PR0r/T0dK/yYcHv88NDT/Uk1K/yYcHv8YBAj/MyMm/zMjJv9PQkT/c3+L/3N/i/+MrcX/jK3F/xAI
EP8QCBD/TFBS/0xQUv9oaWj/aGlo/5yenP8AAAD/CAAI/3N1c/9PTk//Kycr/09EPv9PRD7/c2Va/ysk
I/8QCAj/EAgI/2NdWv9HQD7/Qjw5/0I8Of9CPDn/MSkr/0lAQf97eXP/e3lz/3t5c/9gW1r/Qjg5/0I4
Of9gW1r/c3Vz/3N1c/9zdXP/c3Vz/2tta/9rbWv/a21r/2tta/9fV1f/X1dX/0xBRP85LDH/OTQ5/zk0
Of85NDn/X1xa/2tpa/9raWv/a2lr/09HSv8mHB7/EAQI/zw0NP9STUr/T0JE/09CRP9PQkT/a2Fj/3N/
i/9zf4v/c3+L/6Xb//9rdXP/EAgQ/y4sMf9MUFL/aGlo/2hpaP+cnpz/AAAA/wgECP9qcnD/anJw/zk7
PP88NDb/PDQ2/yYcI/8QBBD/GAwQ/y4nKP9aXVr/Wl1a/09OT/9PTk//PDc8/zw3PP97eXv/e3l7/2Jc
X/9JQET/UktK/1JLSv8xJSn/MSUp/0Q7P/9XUlX/a2lr/2tpa/9zbWv/c21r/2hhYP9dVVX/Uk9P/zkx
M/85MTP/Uk9P/1dUV/9XVFf/Mywz/zMsM/85MTP/a21r/2tta/9ST0//T0hH/xgIEP8zKCv/T0hH/09I
R/9jXVr/PDQ0/09IR/9UU1X/eIKB/3iCgf+csq3/c3Vz/xAECP8xKSv/Uk9P/2JpaP9iaWj/lJ6c/wAA
AP8IBAj/anJw/2pycP85Ozz/EAQQ/xAEEP8mHCP/Jhwj/xgMEP8uJyj/Wl1a/1pdWv9PTk//T05P/zw3
PP9PTk//e3l7/2JcX/9JQET/Ylxf/3Nxa/9zcWv/c3Fr/1JLSv8xJCn/RDs//2tpa/9raWv/c21r/3Nt
a/9dVVX/UklK/zkxM/85MTP/a21r/2tta/9XVFf/V1RX/1dUV/9XVFf/OTEz/zkxM/9rbWv/a21r/09I
R/8YCBD/Mygr/09IR/9PSEf/Y11a/zw0NP8pICH/MSQp/zEkKf8xJCn/VFNV/1JPT/9ST0//MSkr/zEp
K/9iaWj/Ymlo/5SenP8AAAD/CAQI/2pycP9qcnD/OTs8/yYcI/8mHCP/PDQ2/yYcI/8uJyj/GAwQ/xgM
EP8YDBD/PDc8/2NlY/8pICn/Y2Vj/3t5e/8xJCn/Ylxf/2JcX/8xJSn/MSUp/1JLSv9zcWv/RDs//0Q7
P/9XUlX/a2lr/3Nta/9oYWD/UklK/1JJSv85MTP/Uk9P/2tta/85MTP/EAQQ/xAEEP8zLDP/e317/1JP
T/8hFBj/Uk9P/2tta/9raWP/Mygr/zMoK/9PSEf/Y11a/2NdWv88NDT/KSAh/1RTVf8xJCn/MSQp/zEk
Kf9ST0//Uk9P/1JPT/8xKSv/MTQ0/2JpaP9iaWj/AAAA/wgECP9qcnD/anJw/zk7PP9STUr/Uk1K/1JN
Sv9STUr/REJB/xgMEP8YDBD/GAwQ/ykgKf9jZWP/KSAp/2NlY/9iXF//MSQp/3t5e/8xJCn/EAAI/xAA
CP8xJSn/c3Fr/0Q7P/9EOz//V1JV/2tpa/9oYWD/aGFg/1JJSv9SSUr/OTEz/2tta/9ST0//IRQY/zMs
M/8zLDP/EAQQ/3t9e/9rbWv/IRQY/1JPT/9rbWv/a2lj/zMoK/8zKCv/T0hH/2NdWv9jXVr/T0hH/zw0
NP9UU1X/VFNV/1RTVf9UU1X/Uk9P/1JPT/9ST0//Uk9P/zE0NP9iaWj/Ymlo/wAAAP8QCAj/e4aE/1dc
Wv8zMjH/YGFg/0pJSv9gYWD/VVVV/zk0Of8YERj/CAAI/wgACP9PTFL/a2lr/zMwOf9raWv/V1NV/ykc
If+Gi4n/KRwh/xgMEP8YDBD/GAwQ/11ZWv8YCAj/GAgI/11WVf9dVlX/Uk1K/1JNSv9STUr/Uk1K/yEU
GP9dW13/XVtd/yEUGP8YEBj/GBAY/xgQGP+Rmpb/WlBS/xgIEP9aUFL/e3Vz/2hsaP8hGCH/REJE/2hs
aP9gW1r/VUlJ/2BbWv9VSUn/R0RH/2NlY/9jZWP/Y2Vj/1pdWv9SVVL/a21r/2JlYv9EQkL/REJC/2Nh
Y/8IBAD/EAgI/3uGhP97hoT/MzIx/2BhYP9gYWD/YGFg/0pJSv85NDn/CAAI/wgACP8IAAj/a2lr/2tp
a/8zMDn/a2lr/4aLif8pHCH/V1NV/ykcIf8YDBD/GAwQ/xgMEP8YDBD/GAgI/11WVf9dVlX/XVZV/1JN
Sv9STUr/Uk1K/1JNSv8hFBj/IRQY/11bXf8hFBj/GBAY/xgQGP9UVVf/VFVX/zksMf85LDH/e3Vz/3t1
c/9EQkT/IRgh/0RCRP9obGj/VUlJ/0o4Of9gW1r/YFta/zk0Of9HREf/Y2Vj/2NlY/9iZWL/UlVS/2Jl
Yv9iZWL/Y2Fj/0RCQv9EQkL/CAQA/xAICP8zMjH/V1xa/1dcWv9rbWv/a21r/2BhYP9KSUr/KCIo/wgA
CP8IAAj/CAAI/2tpa/9PTFL/T0xS/zMwOf9XU1X/KRwh/ykcIf9XU1X/XVla/11ZWv+ipqT/oqak/6Kk
ov+ipKL/oqSi/6Kkov+AhYH/gIWB/4CFgf+AhYH/XVtd/11bXf9dW13/XVtd/1RVV/9UVVf/VFVX/xgQ
GP8YCBD/WlBS/1pQUv9aUFL/IRgh/yEYIf9obGj/aGxo/1VJSf9VSUn/VUlJ/2tta/9VVFX/OTQ5/1VU
Vf9jZWP/a21r/2JlYv9aXVr/Wl1a/0RCQv9jYWP/Y2Fj/wgEAP8QCAjMEAgI/xAICO4QCAj/a21r/2tt
a/9VVVX/SklK/xgRGP8IAAj/GBEY/wgACP9raWv/a2lr/zMwOf8YFCH/V1NV/4aLif+Gi4n/tcO9/+fz
7//n8+//5/Pv/+fz7//n8+//5/Pv/+fz7//n8+//3vfv/9737//e9+//3vfv/9br5//W6+f/1uvn/9br
5//O39b/kZqW/5Galv9UVVf/e3Vz/3t1c/9aUFL/OSwx/0RCRP9obGj/jJaM/2hsaP9VSUn/YFta/2Bb
Wv9rbWv/Y2Vj/1VUVf85NDn/Y2Vj/2tta/9rbWv/a21r/1JVUv9EQkL/Y2Fj/2NhY/8IBAD/5+PeM1JO
T3cIBAjdCAQI/4SKhP9jZWP/QkBC/0JAQv8bFRv/GxUb/xsVG/8AAAD/a2lj/46RjP9raWP/jpGM/9DW
0//v9/f/7/f3/+/39//v+/f/7/v3/73Kxf+lsq3/rba1/622tf+9y8j/rba1/7K9tf/AzMX/ztvW/8DM
xf+qt7X/qre1/7jJxf/G29b/zt/e/73My/+9zMv/vczL/6+9uv+vvbr/oaun/5SalP97eXP/p7e6/6e3
uv97eXP/a2Vj/2tlY/9rZWP/g4WE/3t8eP97fHj/QT48/wgAAP9XVlf/e317/3t9e/9XVlf/VFRU/1RU
VP97fXv/CAQI/+fj3gDn494ACAQI3QgECP+EioT/Y2Vj/0JAQv8hHCH/GxUb/ykgKf8bFRv/AAAA/2tp
Y/+yurX/1uPe/9bj3v/v9/f/7/f3/+/39//Q1tP/vcrF/73Kxf+lsq3/vcrF/83h2/+9y8j/vcvI/73L
yP+yvbX/sr21/7K9tf+lrqX/nKal/5ympf+cpqX/nKal/5ympf+cpqX/nKal/5ympf+hq6f/oaun/73P
zv+9z87/e3lz/73X3v97eXP/e3lz/2tlY/9rZWP/g4WE/4OFhP97fHj/e3x4/0E+PP8IAAD/EAgQ/1dW
V/97fXv/e317/3t9e/9UVFT/e317/wgECP/n494A5+PeEQgECO4IBAj/hIqE/0JAQv9CQEL/IRwh/xsV
G/8pICn/KSAp/wAAAP9raWP/jpGM/7K6tf/W497/srav/5SWjP+ytq//srav/6Wyrf+lsq3/1uLe/+/7
9//e9+//zeHb/73LyP+9y8j/wMzF/8DMxf/AzMX/wMzF/6q3tf+qt7X/nKal/5ympf+cpqX/nKal/5ym
pf+cpqX/lJqU/5SalP+hq6f/lJqU/3t5c/+nt7r/e3lz/5GYlv+DhYT/g4WE/5ympf+cpqX/e3x4/3t8
eP9BPjz/CAAA/xAIEP8QCBD/V1ZX/3t9e/97fXv/e317/3t9e/8IBAj/5+PeAOfj3hEIBAj/CAQI/4SK
hP9CQEL/QkBC/yEcIf8pICn/KSAp/ykgKf8AAAD/a2lj/9bj3v+yurX/srq1/7K2r/+Uloz/srav/7K2
r/+9ysX/vcrF/9bi3v/v+/f/zeHb/73LyP+9y8j/vcvI/8DMxf/AzMX/wMzF/8DMxf+4ycX/qre1/6q3
tf+cpqX/nKal/5ympf+cpqX/nKal/6Grp/+UmpT/lJqU/5SalP+9197/kZiW/5GYlv+9197/tcfG/7XH
xv+1x8b/tcfG/3t8eP97fHj/QT48/wgAAP8QCBD/EAgQ/xAIEP8zLzP/e317/3t9e/97fXv/CAQI/97b
1gDe29YiCAQI7ggECP9zcWv/TEtH/0xLR/8mJSP/KyQj/yskI/8rJCP/CAAA/xgQEP/e497/3uPe/5yc
mf+tqqX/t8K7/7fCu/+ytrD/rbe1/623tf+tt7X/vcvG/7XDvf+1w73/wM3I/7XDvf+3v7f/t7+3/7W6
tf+3v7f/tcO9/7XDvf+1w73/r7y1/6Ksp/+fp6H/n6eh/5yinP+copz/lpqW/5aalv+Znpn/1vf//5+p
rf+EgoT/n6mt/87z//+lpq3/sr/I/87z//+fq6r/n6uq/xAMEP8QDBD/Ixwe/yMcHv8IBAj/CAQI/zEs
Mf9aWVr/hIaE/wgACP/e29YA3tvWEQgECO4IBAj/c3Fr/0xLR/9MS0f/JiUj/yskI/8rJCP/KyQj/ysk
I/8YEBD/3uPe/97j3v+cnJn/t8K7/73Pxv+3wrv/sraw/6Wurf+lrq3/rbe1/7XBvf/Azcj/tcO9/8DN
yP+1w73/t7+3/7e/t/+3v7f/t7+3/7XDvf+1w73/tcO9/6+8tf+irKf/n6eh/6Ksp/+copz/mZ6Z/5aa
lv+Wmpb/lJaU/7rQ1v+fqa3/hIKE/5+prf/A2eP/sr/I/8DZ4//O8///5/v3/5+rqv8QDBD/EAwQ/yMc
Hv8xKCn/Ixwe/xUQE/8IAAj/MSwx/4SGhP8IAAj/3tvWAN7b1gAIBAiqCAQI/3Nxa/9zcWv/TEtH/0xL
R/8rJCP/KyQj/yskI/8rJCP/GBAQ/1pWVP/e497/nJyZ/73Pxv+ytrD/t8K7/7fCu/+1wb3/rbe1/73L
xv+9y8b/xtPO/7rIwv+1w73/tcO9/7rFuv+3v7f/t7+3/7e/t/+1w73/r7y1/6+8tf+1w73/pbKt/6Ks
p/+fp6H/n6eh/5memf+Wmpb/nKKc/5aalv+fqa3/n6mt/4SChP+fqa3/sr/I/8DZ4//A2eP/wNnj/+f7
9/+fq6r/EAwQ/xAMEP8jHB7/Ixwe/yMcHv8jHB7/MSwx/wgACP9aWVr/CAAI/97b1gDe29YA3tvWIggE
CO4AAAD/TEtH/0xLR/9MS0f/T0hH/yskI/8rJCP/KyQj/xgQEP8YEBD/3uPe/5ycmf+3wrv/t8K7/7fC
u/+3wrv/tcG9/7XBvf+9y8b/vcvG/8DNyP+6yML/tcO9/7XDvf+6xbr/t7+3/7e/t/+3v7f/r7y1/6Wu
pf+lrqX/r7y1/6Wyrf+irKf/n6eh/5yinP+copz/mZ6Z/5memf+Znpn/n6mt/7rQ1v+EgoT/n6mt/8DZ
4//O8///wNnj/8DZ4//n+/f/V1td/xAMEP8QDBD/Ixwe/zEoKf8xKCn/MSgp/zEsMf8xLDH/Wlla/wgA
CP////8A////AP///wAAAACZGBAQzBgQEP8YEBD/X1lX/2NhWv9jYVr/REI+/yYjI/8hGBj/IRgY/2Bh
X//e8+//uMK6/7jCuv+4wrr/uMK6/7XDvf+1w73/tcO9/7fHwP+3x8D/usvD/7XDvf+1w73/t8C6/7fA
uv+3wLr/t8C6/7fAt/+tsq3/rbKt/62yrf+lsq3/oqyn/5+nof+copz/n6Of/5+jn/+ZnJn/mZyZ/87v
9//A1t7/paat/6Wmrf+72uH/xvP//7va4f+72uH/hH1z/wgECP8IBAj/MSwr/ykkKf8zLi7/My4u/ykk
Kf8jJCP/IyQj/z5APv8ICAj/////AP///wD///8A////AKein0QYEBC7GBAQ/xgQEP9EQj7/Y2Fa/2Nh
Wv9EQj7/IRgY/yEYGP8hGBj/3vPv/7jCuv+tsq3/uMK6/7jCuv+1w73/tcO9/7XDvf+1w73/tcO9/7rL
w/+3x8D/tcO9/7fAuv+yvbf/t8C6/7K9t/+3wLf/t8C3/7fAt/+tsq3/pbKt/6Ksp/+fp6H/nKKc/5+j
n/+fo5//mZyZ/5SWlP/O7/f/wNbe/87v9/+lpq3/u9rh/7va4f+lqqX/sMLD/zEsK/8IBAj/MSwr/zEs
K/8pJCn/Likr/y4pK/8uKSv/IyQj/yMkI/9aXVr/CAgI/////wD///8A////AP///wDv6+cAp6KfMxgQ
EKoYEBD/CAQI/yYjI/9jYVr/Y2Fa/2BhX/8hGBj/IRgY/97z7//D0sj/rbKt/62yrf+4wrr/tcO9/7XD
vf+1w73/usvD/7XDvf+3x8D/t8fA/7fHwP+3wLr/sr23/7K9t/+yvbf/t8C3/7fAt/+3wLf/srmy/6Wy
rf+irKf/n6eh/5+nof+fo5//mZyZ/5mcmf+UlpT/zu/3/8DW3v+yvsX/sr7F/8bz//+72uH/paql/6Wq
pf8xLCv/CAQI/zEsK/8xLCv/Likr/zMuLv8pJCn/Likr/yMkI/8jJCP/Wl1a/wgICP////8A////AP//
/wD///8A7+vnAO/r5wDv6+cRGBAQqggECLsIBAj/CAQI/yYjI/9gYV//YGFf/2BhX//e8+//zuPW/7jC
uv+tsq3/uMK6/7XDvf+3x8D/t8fA/73Pxv+9z8b/vc/G/7rLw/+6y8P/vcO9/7fAuv+3wLr/t8C6/7fA
t/+3wLf/t8C3/7K5sv+lsq3/oqyn/5+nof+fp6H/n6Of/6Wqpf+fo5//mZyZ/87v9//A1t7/sr7F/8DW
3v/G8///xvP//7DCw/+lqqX/MSwr/wgECP8xLCv/MSwr/zMuLv8zLi7/KSQp/y4pK/8+QD7/Wl1a/1pd
Wv8ICAj/////AP///wD///8A////AP///wD///8A////AP///wDn6+ciAAAAqgAAAMwAAAD/EAgQ/xAI
EP8QCBD/5+/n//f///+3urr/t7q6/7e6uv+1w73/vc/I/73PyP/F29P/ztzT/87c0//O3NP/xs/G/73F
vf+9xb3/vcW9/73Fvf+1wr3/tcK9/626tf+lsq3/pa+q/6Wsp/+lqqX/paql/5+ppP+fqaT/lJqU/5Sa
lP/n////y9jY/6+xsv/L2Nj/3vv//977//+6zc3/lp+c/xAECP8rIyP/KyMj/ysjI/8mJCb/JiQm/0RE
RP9ERET/WFZS/1hWUv9YVlL/AAAA/////wD///8A////AP///wD///8A////AP///wD///8A5+vnAOfr
5wCanJoiAAAAqhAIEMwQCBDuEAgQ/xAIEP/3////9////7e6uv+3urr/tcO9/7XDvf/F29P/zufe/973
7//e9+//1unh/87c0/+9xb3/vcW9/8XQxf/F0MX/vcvG/7XCvf+turX/pbKt/6Wvqv+lrKf/payn/6Wq
pf+fqaT/n6mk/5SalP+fqaT/5////8vY2P+vsbL/5////977///e+///3vv//5afnP8QBAj/R0I+/0dC
Pv9HQj7/RERE/2NlY/9jZWP/Y2Vj/1hWUv9YVlL/LCsp/wAAAP////8A////AP///wD///8A////AP//
/wD///8A////AOfr5wDn6+cA5+vnAOfr5wCfop8iV1VXZhAIELsQCBD/eHV1//f///+3urr/t7q6/73P
yP+1w73/vc/I/87n3v/e9+//3vfv/9bp4f/O3NP/ztvO/73Fvf/F0MX/xdDF/7XCvf+lsq3/pbKt/6Wy
rf+lr6r/pa+q/6Wsp/+lrKf/n6mk/5+ppP+UmpT/tcfG/6+xsv+vsbL/y9jY/+f////e+///3vv//977
//9zcWv/KyMj/2NhWv9jYVr/Y2Fa/2NlY/9jZWP/RERE/0RERP8sKyn/AAAA/wAAAO4AAADM////AP//
/wD///8A////AP///wD///8A////AP///wDn6+cA5+vnAOfr5wDn6+cA5+/nAOfv5wDn7+cREAgQ3Tkw
Mf/3////9////7e6uv+9z8j/vc/I/73PyP+9z8j/ztzT/9bp4f/O3NP/ztzT/87bzv/F0MX/vcW9/7W6
tf+lsq3/pbKt/6Wyrf+lsq3/pbKt/6Wyrf+lrKf/pa+q/5+ppP+fqaT/lJqU/7XHxv+Uioz/r7Gy/+f/
///n////3vv//977///e+///c3Fr/2NhWv9jYVr/Y2Fa/0dCPv8mJCb/CAQI/wgECP8IBAj/AAAA7gAA
ALuEgntVhIJ7AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AM7H
xgDOx8YAzsfGAAAAAN0IBAD/7/v3/+/79//v+/f/zd3W/83d1v+9z8b/vc/G/8DQyP/G187/xtfO/8bX
zv/G187/xtfO/7XBvf+ttrX/rbey/620r/+ttK//rbSv/6Wyrf+irKf/oqyn/6Ksp/+fpaX/n6Wl/4SC
hP+fpaX/yNTQ/8jU0P/n+/f/5/v3////////////r66s/xAMCP8IBAj/CAQI/wgECP8IBAj/AAAA7gAA
AN0AAAC7AAAAu3VycFX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wDOx8YAzsfGAM7HxgAAAACZCAQA/6KopP/v+/f/7/v3/+/79//e7Ob/vc/G/73P
xv/A0Mj/wNDI/8DQyP/G187/xtfO/7XBvf+ttrX/rba1/623sv+ttK//rbSv/620r/+lsq3/n6eh/6Wy
rf+irKf/n6Wl/5+lpf+fpaX/1uvn/+f79//n+/f/yNTQ/+f79///////X11a/xAMCP8QDAjuCAQI7ggE
CMwIBAi7CAQIu1VVVWaqqqoi////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8AzsfGAM7HxgDOx8YAiYSERAgEAO5VVlL/7/v3/+/7
9//v+/f/7/v3/83d1v+9z8b/wNDI/7rJwv+6ycL/wNDI/8bXzv+ttrX/rba1/622tf+ttK//rbSv/620
r/+ttK//pbKt/6Wyrf+lsq3/oqyn/5+lpf+fpaX/n6Wl/9br5//I1ND/yNTQ/8jU0P/n+/f//////xAM
CP8QDAjMX11aiJaWkUTe39YR3t/WAN7f1gD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AM7HxgDOx8YAzsfGAM7H
xgAIBADMCAQA/1VWUv/v+/f/7/v3/+/79//N3db/vc/G/7rJwv+1w73/usnC/7rJwv/G187/rba1/622
tf+ttrX/rbey/620r/+ttK//rbSv/6Wyrf+lsq3/oqyn/5yinP+fpaX/hIKE/5+lpf/W6+f/jIaE/8jU
0P/n+/f/5/v3/19dWv8QDAj/X11aVf///wDe39YA3t/WAN7f1gDe39YA////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A1tPOEQAAAMwAAAD/joyJ/97r5//e6+f/3uvn/97r5//I1M7/yNTO/8jU
zv+qsa3/wtDL/8LQy/+nraf/p62n/7C5t/+wubf/sLm3/7C5t/+lrq3/pa6t/6Wurf+lrq3/tcO9/7XD
vf/L19P/y9fT/6yurP///////////1pdWv8AAAD/AAAAzP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////ANbTzgCOjIkzAAAAzAAAAP+UnJr/3uvn/97r
5//e6+f/yNTO/8jUzv/I1M7/yNTO/8LQy//e8+//3vPv/8LQy/+wubf/sLm3/7C5t/+wubf/pa6t/6Wu
rf/F0cj/1uPW/8vX0/+1w73/4evp/8vX0////////////1pdWv8IDAj/AAAAzKqqqiL///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wDW084A1tPOAI6M
iTMAAADdAAAA/5Scmv/e6+f/3uvn/8jUzv/I1M7/jI6M/4yOjP+MioT/jIqE/4yKhP+MioT/hH17/4R9
e/+am5n/xtfW/9bj1v/F0cj/tb+6/7W/uv+1w73/y9fT/+Hr6f/h6+n//////1pdWv8IDAj/CAwI3aqq
qjP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A1tPOANbTzgDW084AjoyJRAAAAN0AAAD/Sk5N/97r5//n9+//5/fv/4yOjP+Mjoz/jIqE/4yK
hP+MioT/jIqE/4R9e/+EfXv/mpuZ/8bX1v/F0cj/tb+6/8XRyP/W49b/9/////f////3////9////1pd
Wv8IDAj/CAwI3ayurDP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wCsq6wiCAQIzAgECN0IBAj/pKek//f7
9//3+/f/9/v3//f79//3+/f/9/v3//f79//v+/f/7/v3/6qurP/v+/f/5+vn/+fr5//n6+f/5+vn////
////////ZV9f/xgQEP8ABAD/AAQA3aqrqiL///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wBaV1pVCAQI3QAAAP8AAAD/AAAA/1JTUv9oaWj/r7Kv//f79//3+/f/7/v3/+/79//v+/f/7/v3/+fr
5/+anJr/mpya/01OTf8YEBD/GBAQ/xgQEP8YEBDdVVdVZv///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///xFSU1J3AAAA3QAAAN0AAAD/ISAh/yEgIf8hICH/ISAh/yEU
GP8hFBj/IRQY/yEUGP8AAAD/AAAA/wAAAP8AAAD/GBAQ3RgQEN0YEBCIsq+vIv///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A9/v3APf79wD3+/cRpKek/2hp
aP9oaWj/ISAh/yEgIf8hFBj/IRQY/yEUGP8hFBj/TU5N/01OTf+anJr/mpya/////yL///8A////AP//
/wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//
/wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAACAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAMAA
AAAAAAAAwAAAAAAAAADgAAAAAAAAAPAAAAAAAAAA+AAAAAAAAAD8AAAAAAAAAP8AAAAAAAAA/8AAAAAA
AAD/8AAAAAAAAP/8AAAAAAAB//4AAAAAAAf//gAAAAAAP//+AAAAAAP///8AAAAAH////wAAAAA/////
gAAAAD/////AAAAAf////+AAAAD/////8AAAAf/////8AAAH//////4AAA///////8AAf///
</value>
</data>
</root>

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
public enum MapType : byte
{
MAPTYPE_NONE = 0x0,
MAPTYPE_INVALID1 = 0x1,
MAPTYPE_INVALID2 = 0x2,
MAPTYPE_2D = 0x3,
MAPTYPE_3D = 0x4,
MAPTYPE_CUBE = 0x5,
MAPTYPE_COUNT = 0x6,
};
}

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace IWImgViewer
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow());
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("FFImgViewer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("FFImgViewer")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("02b056ca-bc9b-4be3-8730-f7506dabd8bb")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace IWImgViewer.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("IWImgViewer.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap cardicon_juggernaut_1 {
get {
object obj = ResourceManager.GetObject("cardicon_juggernaut_1", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="cardicon_juggernaut_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\cardicon_juggernaut_1.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace IWImgViewer.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

388
ImgFormatHelper/Reader.cs Normal file
View File

@ -0,0 +1,388 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
public class Reader
{
public string ImageName => imagePath;
public string ImageFormat { get; private set; }
public byte[] Data { get; set; }
public IImageFileHeader CurrentHeader {get; private set;}
private readonly string imagePath;
public Reader(string imagePath)
{
if (!File.Exists(imagePath))
{
throw new FileNotFoundException();
}
this.imagePath = imagePath;
string ext = System.IO.Path.GetExtension(imagePath).Substring(1).ToUpper();
switch (ext.ToUpper())
{
case "FFIMG":
DecodeFFImage();
break;
case "IW4XIMAGE":
DecodeIW4XImage();
break;
case "IWI":
DecodeIWI4();
break;
}
}
public static event Action<Bitmap> OnBitmapRead;
void DecodeIWI4()
{
using (FileStream fs = new FileStream(imagePath, FileMode.Open))
{
using (BinaryReader br = new BinaryReader(fs))
{
CoD6_GfxImageFileHeader header;
try
{
header = new CoD6_GfxImageFileHeader(Path.GetFileNameWithoutExtension(imagePath));
header.Deserialize(br);
CurrentHeader = header;
}
catch (FormatException)
{
br.Dispose();
fs.Dispose();
// Maybe cod4?
DecodeIWI3();
return;
}
bool hasMipMaps = (header.flags & (byte)IwiFlags.IMG_FLAG_NOMIPMAPS) == 0;
Data = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position));
CreateBitmap(Data, (short)header.Width, (short)header.Height, header.format, header.MapType, hasMipMaps);
}
}
}
void DecodeIWI3()
{
using (FileStream fs = new FileStream(imagePath, FileMode.Open))
{
using (BinaryReader br = new BinaryReader(fs))
{
CoD4_GfxImageFileHeader header = new CoD4_GfxImageFileHeader(Path.GetFileNameWithoutExtension(imagePath));
header.Deserialize(br);
CurrentHeader = header;
bool hasMipMaps = (header.flags & (byte)IwiFlags.IMG_FLAG_NOMIPMAPS) == 0;
Data = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position));
CreateBitmap(Data, header.dimensions[0], header.dimensions[1], header.format, header.MapType, hasMipMaps);
}
}
}
void DecodeFFImage()
{
using (FileStream fs = new FileStream(imagePath, FileMode.Open))
{
using (BinaryReader br = new BinaryReader(fs))
{
FFImgHeader header = new FFImgHeader();
header.Deserialize(br);
CurrentHeader = header;
bool hasMipMaps = (header.flags & (byte)IwiFlags.IMG_FLAG_NOMIPMAPS) == 0;
Data = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position));
if (header.format == _D3DFORMAT.D3DFMT_UNKNOWN)
{
throw new FormatException(header.format.ToString());
}
CreateBitmap(Data, (short)header.Width, (short)header.Height, header.D3dFormat, header.MapType);
}
}
}
void DecodeIW4XImage()
{
using (FileStream fs = new FileStream(imagePath, FileMode.Open))
{
using (BinaryReader br = new BinaryReader(fs))
{
if (new string(br.ReadChars(8)) != "IW4xImg0")
{
throw new FormatException();
}
IW4XImageHeader header = new IW4XImageHeader();
header.Deserialize(br);
CurrentHeader = header;
bool hasMipMaps = (header.flags & (byte)IwiFlags.IMG_FLAG_NOMIPMAPS) == 0;
Data = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position));
if (header.format == _D3DFORMAT.D3DFMT_UNKNOWN)
{
throw new FormatException(header.format.ToString());
}
CreateBitmap(Data, (short)header.Width, (short)header.Height, header.D3dFormat, header.MapType);
}
}
}
void CreateBitmap(byte[] data, short width, short height, GfxImageFileFormat format, MapType mapType=MapType.MAPTYPE_2D, bool hasMips=false)
{
if (hasMips)
{
CreateBitmapsWithMips(data, width, height, format, mapType);
return;
}
Bitmap bitmap = null;
ImageFormat = format.ToString();
byte channels;
int maxI;
switch (format)
{
case GfxImageFileFormat.IMG_FORMAT_BITMAP_ALPHA:
bitmap = new Bitmap(width, height);
BitmapSetPixels(bitmap, width, height, data, 1);
break;
case GfxImageFileFormat.IMG_FORMAT_DXT1:
case GfxImageFileFormat.IMG_FORMAT_DXT3:
case GfxImageFileFormat.IMG_FORMAT_DXT5:
byte[] pixels;
bitmap = new Bitmap(width, height);
pixels = ManagedSquish.Squish.DecompressImage(data, width, height, FormatHelper.GfxFormatToSquishFormat[format]);
channels = 4;
maxI = channels * width * height;
if (maxI > pixels.Length)
{
if (pixels.Length > (channels - 1) * width * height)
{
System.Windows.Forms.MessageBox.Show($"Too many channels! Expected {channels} channels but there is only data for {channels - 1} channels.");
channels--;
}
else
{
System.Windows.Forms.MessageBox.Show($"Wrong number of channels! For format {format}, {channels} channels is too much.");
}
}
BitmapSetPixels(bitmap, width, height, SwapChannels(pixels, new Dictionary<byte, byte>()
{
{0, 2}, // R -> B
{1, 1}, // G -> G
{2, 0}, // B -> R
{3, 3} // A -> A
}, channels), channels);
break;
//case GfxImageFileFormat.IMG_FORMAT_WAVELET_RGB:
//case GfxImageFileFormat.IMG_FORMAT_WAVELET_RGBA:
// using (OpenJpegDotNet.IO.Reader reader = new OpenJpegDotNet.IO.Reader(data))
// {
// reader.ReadHeader();
// bitmap = reader.ReadData();
// Console.WriteLine("Read data");
// }
// break;
case GfxImageFileFormat.IMG_FORMAT_BITMAP_RGB:
channels = 3;
bitmap = new Bitmap(width, height);
BitmapSetPixels(bitmap, width, height, data, channels);
break;
case GfxImageFileFormat.IMG_FORMAT_BITMAP_RGBA:
channels = 4;
bitmap = new Bitmap(width, height);
BitmapSetPixels(bitmap, width, height, data, channels);
break;
default:
throw new FormatException(format.ToString());
}
OnBitmapRead(bitmap);
}
void CreateBitmapsWithMips(byte[] data, short width, short height, GfxImageFileFormat format, MapType mapType = MapType.MAPTYPE_2D)
{
// Generate mips
List<(int width, int height)> mips = new List<(int width, int height)>();
int sides = mapType == MapType.MAPTYPE_CUBE ? 6 : 1;
short maxDimension = Math.Max(height, width);
int mipmapFactor = 1;
int minBlockSize = FormatHelper.GetBlockSize(format);
while (maxDimension != 0)
{
maxDimension >>= 1;
mipmapFactor *= 2;
mips.Add((Math.Max(width / mipmapFactor, minBlockSize), Math.Max(height / mipmapFactor, minBlockSize)));
}
mips.Reverse();
int compressedLengthToSkip = 0;
for (int i = 0; i <= mips.Count; i++)
{
for (int side = 0; side < sides; side++)
{
short thisWidth, thisHeight;
if (i < mips.Count)
{
var mip = mips[i];
thisWidth = (short)mip.width;
thisHeight = (short)mip.height;
if (thisWidth <= 16 && thisHeight <= 16)
{
// We skip them because at this point the windows form is bigger than the image
continue;
}
}
else
{
thisWidth = width;
thisHeight = height;
}
CreateBitmap(data.Skip(compressedLengthToSkip).ToArray(), thisWidth, thisHeight, format);
if (i < mips.Count)
{
compressedLengthToSkip += ManagedSquish.Squish.GetStorageRequirements(thisWidth, thisHeight, FormatHelper.GfxFormatToSquishFormat[format]);
}
}
}
}
void CreateBitmap(byte[] data, short width, short height, _D3DFORMAT format, MapType mapType = MapType.MAPTYPE_2D)
{
int sides = mapType == MapType.MAPTYPE_CUBE ? 6 : 1;
ImageFormat = format.ToString();
for (int side = 0; side < sides; side++)
{
Bitmap bitmap = new Bitmap(width, height);
byte[] truncatedData;
int sizeOfOneSide;
switch (format)
{
case _D3DFORMAT.D3DFMT_L8:
sizeOfOneSide = width * height * 1;
truncatedData = data.Skip(sizeOfOneSide * side).Take(sizeOfOneSide).ToArray();
BitmapSetPixels(bitmap, width, height, truncatedData, 1);
break;
case _D3DFORMAT.D3DFMT_A8R8G8B8:
sizeOfOneSide = width * height * 4;
truncatedData = data.Skip(sizeOfOneSide * side).Take(sizeOfOneSide).ToArray();
BitmapSetPixels(bitmap, width, height, truncatedData, 4);
break;
default:
throw new FormatException(format.ToString());
}
OnBitmapRead(bitmap);
}
}
byte[] SwapChannels(byte[] data, Dictionary<byte, byte> swapMap, byte channels)
{
byte[] newData = new byte[data.Length];
for (int i = 0; i < data.Length; i += channels)
{
try
{
for (byte channel = 0; channel < channels; channel++)
{
newData[i + channel] = data[i + swapMap[channel]];
}
}
catch (IndexOutOfRangeException)
{
System.Windows.Forms.MessageBox.Show($"Wrong number of channels! {channels} channels is not correct!");
}
}
return newData;
}
void BitmapSetPixels(Bitmap bitmap, short width, short height, byte[] pixels, byte channels)
{
int maxI = channels * width * height;
bool hasWarned = false;
int x, y;
if (pixels.Length != maxI)
{
System.Windows.Forms.MessageBox.Show($"Unexpected number of pixels: Expected {maxI} pixels, found {pixels.Length} (difference of {pixels.Length - maxI})");
}
for (int i = 0; i < pixels.Length - channels; i++)
{
if (i >= maxI)
{
if (!hasWarned)
{
hasWarned = true;
System.Windows.Forms.MessageBox.Show($"Found {pixels.Length - maxI} extra bytes of information at the end of data (?)");
}
}
else
{
if (i % channels == 0)
{
x = (i / channels) % width;
y = i / (width * channels);
bitmap.SetPixel(x, y, Color.FromArgb(
channels > 3 ? pixels[i + 3] : 255,
channels > 2 ? pixels[i + 2] : pixels[i],
channels > 1 ? pixels[i + 1] : pixels[i],
pixels[i])
);
}
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

85
ImgFormatHelper/Viewport.Designer.cs generated Normal file
View File

@ -0,0 +1,85 @@

namespace IWImgViewer
{
partial class Viewport
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.PreviewBox = new System.Windows.Forms.PictureBox();
this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
this.MetaDataLabel = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.PreviewBox)).BeginInit();
this.SuspendLayout();
//
// PreviewBox
//
this.PreviewBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.PreviewBox.BackColor = System.Drawing.Color.Transparent;
this.PreviewBox.Location = new System.Drawing.Point(0, 0);
this.PreviewBox.Name = "PreviewBox";
this.PreviewBox.Size = new System.Drawing.Size(282, 259);
this.PreviewBox.TabIndex = 1;
this.PreviewBox.TabStop = false;
//
// MetaDataLabel
//
this.MetaDataLabel.AutoSize = true;
this.MetaDataLabel.Location = new System.Drawing.Point(12, 9);
this.MetaDataLabel.Name = "MetaDataLabel";
this.MetaDataLabel.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.MetaDataLabel.Size = new System.Drawing.Size(0, 13);
this.MetaDataLabel.TabIndex = 2;
//
// Viewport
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(280, 257);
this.Controls.Add(this.MetaDataLabel);
this.Controls.Add(this.PreviewBox);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Viewport";
this.ShowIcon = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.WindowsDefaultBounds;
this.Text = "Viewport";
((System.ComponentModel.ISupportInitialize)(this.PreviewBox)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.PictureBox PreviewBox;
private System.Windows.Forms.SaveFileDialog saveFileDialog1;
private System.Windows.Forms.Label MetaDataLabel;
}
}

View File

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace IWImgViewer
{
public partial class Viewport : Form
{
MainWindow parent;
EasyFilters exportFilters = new EasyFilters(
("Portable Graphics Network", "PNG"),
("Windows Bitmap", "BMP"),
("Tag Image File Format", "TIFF"),
("Joint Photographics Experts", "JPEG"),
("Windows Icon", "ICO")
);
Dictionary<string, ImageFormat> exportFormatMap = new Dictionary<string, ImageFormat>()
{
{ "PNG", ImageFormat.Png },
{ "BMP", ImageFormat.Bmp },
{ "TIFF", ImageFormat.Tiff },
{ "JPEG", ImageFormat.Jpeg },
{ "ICO", ImageFormat.Icon }
};
public Viewport(MainWindow mainWindow)
{
parent = mainWindow;
InitializeComponent();
saveFileDialog1.FileOk += saveFileDialog1_FileOk;
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.X)
{
saveFileDialog1.DefaultExt = exportFilters.GetFilterExtensionByOneBasedIndex(1);
saveFileDialog1.FileName = System.IO.Path.GetFileNameWithoutExtension(parent.ImageName);
saveFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
saveFileDialog1.Filter = exportFilters.ToString();
saveFileDialog1.ShowDialog(this);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
public void ShowImage(Bitmap bmp)
{
PreviewBox.Image = bmp;
this.Width = PreviewBox.Image.Width + 16;
this.Height = PreviewBox.Image.Height + 39;
this.MetaDataLabel.Text = $"{bmp.Width}x{bmp.Height}";
Refresh();
}
private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
{
var format = exportFilters.GetFilterExtensionByOneBasedIndex(saveFileDialog1.FilterIndex);
PreviewBox.Image.Save(saveFileDialog1.FileName, exportFormatMap[format.ToUpper()]);
}
}
}

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="saveFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

31
ImgFormatHelper/Writer.cs Normal file
View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IWImgViewer
{
public static class Writer
{
public static void WriteIWI3(IImageFileHeader header, byte[] data, string outputPath)
{
}
public static void WriteIWI4(IImageFileHeader header, byte[] data, string outputPath)
{
}
public static void WriteFFImg(IImageFileHeader header, byte[] data, string outputPath)
{
}
public static void WriteIW4xImage(IImageFileHeader header, byte[] data, string outputPath)
{
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Costura.Fody" version="5.3.0" targetFramework="net472" developmentDependency="true" />
<package id="Fody" version="6.5.1" targetFramework="net472" developmentDependency="true" />
<package id="ManagedSquish" version="2.0.0.0" targetFramework="net472" />
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net472" />
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net472" />
<package id="NETStandard.Library" version="1.6.1" targetFramework="net472" />
<package id="System.AppContext" version="4.3.0" targetFramework="net472" />
<package id="System.Collections" version="4.3.0" targetFramework="net472" />
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net472" />
<package id="System.Console" version="4.3.0" targetFramework="net472" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net472" />
<package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net472" />
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net472" />
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net472" />
<package id="System.Drawing.Common" version="5.0.2" targetFramework="net472" />
<package id="System.Globalization" version="4.3.0" targetFramework="net472" />
<package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net472" />
<package id="System.IO" version="4.3.0" targetFramework="net472" />
<package id="System.IO.Compression" version="4.3.0" targetFramework="net472" />
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net472" />
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net472" />
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net472" />
<package id="System.Linq" version="4.3.0" targetFramework="net472" />
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net472" />
<package id="System.Net.Http" version="4.3.0" targetFramework="net472" />
<package id="System.Net.Primitives" version="4.3.0" targetFramework="net472" />
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net472" />
<package id="System.ObjectModel" version="4.3.0" targetFramework="net472" />
<package id="System.Reflection" version="4.3.0" targetFramework="net472" />
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net472" />
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net472" />
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net472" />
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net472" />
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net472" />
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net472" />
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net472" />
<package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net472" />
<package id="System.Threading" version="4.3.0" targetFramework="net472" />
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net472" />
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net472" />
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net472" />
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net472" />
</packages>