diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ca2efe0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+################################################################################
+# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
+################################################################################
+
+.vs
+**/bin
+**/obj
+**/Safetensors.Inspector.UX/Properties/Resources.Designer.cs
+**/Safetensors.Inspector.UX/Properties/Resources.resx
+**/Safetensors.Inspector.UX/Properties/Settings.Designer.cs
+**/Safetensors.Inspector.UX/Properties/Settings.settings
+**/Safetensors.Inspector.UX/Properties/PublishProfiles/FolderProfile.pubxml.user
+**/publish/*
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5c1d78e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+Safetensors Inspector
+=====================
+
+Safetensors Inspector is a tool that I created to learn the file structures and workings of
+safetensors files.
+
+## Important
+
+At present, the following safetensors are supported:
+
+* LoRA
+ * Metadata
+
+## Examples
+
+### Reading a single file
+
+![](https://github.com/christogreeff/safetensors-inspector/blob/main/documentation/example01.gif)
+
+### Reading a folder full of files
+
+![](https://github.com/christogreeff/safetensors-inspector/blob/main/documentation/example02.gif)
+
+## Releases
+
+See [latest](https://github.com/christogreeff/safetensors-inspector/releases/tag/latest) releases.
+
+## Tools
+
+Additional tooling is (or will be) available in the **tools/** directory.
+
+## Documentation
+
+The offline documentation is (or will be) available in the **documentation/** directory.
+
+## License
+
+Safetensors Inspetor codebase is GPL-3.0 licensed. Please refer to the LICENSE file for detailed information.
+
+## Contributing
+
+Please do.
diff --git a/documentation/example01.gif b/documentation/example01.gif
new file mode 100644
index 0000000..0ccccf4
Binary files /dev/null and b/documentation/example01.gif differ
diff --git a/documentation/example02.gif b/documentation/example02.gif
new file mode 100644
index 0000000..10a9193
Binary files /dev/null and b/documentation/example02.gif differ
diff --git a/publish.ps1 b/publish.ps1
new file mode 100644
index 0000000..4de3e89
--- /dev/null
+++ b/publish.ps1
@@ -0,0 +1,15 @@
+$signTool="C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe"
+$certFolder = "C:\temp\cert\CodeSign\"
+$cert = "$($certFolder)kd.pfx"
+$pass = Get-Content "$($certFolder)kd.pass"
+$exe = ".\publish\Safetensors.Inspector.UX.exe"
+$md5 = ".\publish\Safetensors.Inspector.UX.md5"
+
+Remove-Item ".\publish\*" -Recurse -Force
+
+dotnet publish ".\solution\Safetensors.Inspector.sln" /p:PublishProfile=FolderProfile -v q
+
+Remove-Item ".\publish\*.config" -Force
+
+& $signTool sign /tr http://timestamp.digicert.com /f $cert /p $pass /td SHA256 /fd SHA256 $exe
+(Get-FileHash $exe -Algorithm MD5).Hash > $md5
\ No newline at end of file
diff --git a/solution/Safetensors.Core/Helpers/IntHelper.cs b/solution/Safetensors.Core/Helpers/IntHelper.cs
new file mode 100644
index 0000000..7e5f910
--- /dev/null
+++ b/solution/Safetensors.Core/Helpers/IntHelper.cs
@@ -0,0 +1,42 @@
+namespace Safetensors.Core
+{
+ ///
+ /// Int Helper
+ ///
+ public static class IntHelper
+ {
+ ///
+ /// Size suffixes for file sizes
+ ///
+ private static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
+
+ ///
+ /// Size suffix for file sizes
+ ///
+ public static string SizeSuffix(this long value, int decimalPlaces = 1)
+ {
+ if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); }
+ if (value < 0) { return "-" + SizeSuffix(-value, decimalPlaces); }
+ if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); }
+
+ // mag is 0 for bytes, 1 for KB, 2, for MB, etc.
+ int mag = (int)Math.Log(value, 1024);
+
+ // 1L << (mag * 10) == 2 ^ (10 * mag)
+ // [i.e. the number of bytes in the unit corresponding to mag]
+ decimal adjustedSize = (decimal)value / (1L << (mag * 10));
+
+ // make adjustment when the value is large enough that
+ // it would round up to 1000 or more
+ if (Math.Round(adjustedSize, decimalPlaces) >= 1000)
+ {
+ mag += 1;
+ adjustedSize /= 1024;
+ }
+
+ return string.Format("{0:n" + decimalPlaces + "} {1}",
+ adjustedSize,
+ SizeSuffixes[mag]);
+ }
+ }
+}
diff --git a/solution/Safetensors.Core/Interfaces/IConfigurationReader.cs b/solution/Safetensors.Core/Interfaces/IConfigurationReader.cs
new file mode 100644
index 0000000..d5ef9f0
--- /dev/null
+++ b/solution/Safetensors.Core/Interfaces/IConfigurationReader.cs
@@ -0,0 +1,15 @@
+namespace Safetensors.Core
+{
+ ///
+ /// Safetensor configuration reader interface
+ ///
+ public interface IConfigurationReader
+ {
+ ///
+ /// Load metadata property configuration
+ ///
+ /// List of Safetensor metadata properties
+
+ Task?> LoadMetadataPropertyConfigAsync();
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Core/Interfaces/ISafetensorsFile.cs b/solution/Safetensors.Core/Interfaces/ISafetensorsFile.cs
new file mode 100644
index 0000000..02bdb65
--- /dev/null
+++ b/solution/Safetensors.Core/Interfaces/ISafetensorsFile.cs
@@ -0,0 +1,9 @@
+namespace Safetensors.Core
+{
+ public interface ISafetensorsFile
+ {
+ string Header { get; }
+ ISafetensorsMetadata Metadata { get; }
+ string Path { get; }
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Core/Interfaces/ISafetensorsMetadata.cs b/solution/Safetensors.Core/Interfaces/ISafetensorsMetadata.cs
new file mode 100644
index 0000000..c9675d1
--- /dev/null
+++ b/solution/Safetensors.Core/Interfaces/ISafetensorsMetadata.cs
@@ -0,0 +1,10 @@
+
+namespace Safetensors.Core
+{
+ public interface ISafetensorsMetadata
+ {
+ string Description { get; set; }
+ List Properties { get; set; }
+ string PropertyName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Core/Interfaces/ISafetensorsMetadataProperty.cs b/solution/Safetensors.Core/Interfaces/ISafetensorsMetadataProperty.cs
new file mode 100644
index 0000000..c82e087
--- /dev/null
+++ b/solution/Safetensors.Core/Interfaces/ISafetensorsMetadataProperty.cs
@@ -0,0 +1,13 @@
+using System.Text.Json.Nodes;
+
+namespace Safetensors.Core
+{
+ public interface ISafetensorsMetadataProperty
+ {
+ string Description { get; set; }
+ string? MetadataType { get; set; }
+ string PropertyName { get; set; }
+ string Value { get; set; }
+ JsonNode? ValueEx { get; }
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Core/Interfaces/ISafetensorsReader.cs b/solution/Safetensors.Core/Interfaces/ISafetensorsReader.cs
new file mode 100644
index 0000000..f66216a
--- /dev/null
+++ b/solution/Safetensors.Core/Interfaces/ISafetensorsReader.cs
@@ -0,0 +1,20 @@
+namespace Safetensors.Core
+{
+ ///
+ /// Safeensor reader interface
+ ///
+ public interface ISafetensorsReader
+ {
+ ///
+ /// Initialize the Safetenso reader
+ ///
+ Task InitializeAsync();
+
+ ///
+ /// Async read of .safetensor file
+ ///
+ /// File path of the .safetensor file
+ /// SafetensorFile object
+ Task ReadAsync(string path);
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Core/Models/Safetensor/SafetensorsFile.cs b/solution/Safetensors.Core/Models/Safetensor/SafetensorsFile.cs
new file mode 100644
index 0000000..dc94f19
--- /dev/null
+++ b/solution/Safetensors.Core/Models/Safetensor/SafetensorsFile.cs
@@ -0,0 +1,28 @@
+namespace Safetensors.Core
+{
+ ///
+ /// Safetensor file
+ ///
+ ///
+ /// https://huggingface.co/docs/safetensors/en/metadata_parsing
+ /// https://cran.r-project.org/web/packages/safetensors/safetensors.pdf
+ /// https://civitai.com/articles/827/safetensors-inspector-google-colab
+ ///
+ public class SafetensorsFile(string path, string header) : ISafetensorsFile
+ {
+ ///
+ /// Safetensor file location
+ ///
+ public string Path { get; private set; } = path;
+
+ ///
+ /// Safetensor raw metadata
+ ///
+ public string Header { get; private set; } = header;
+
+ ///
+ /// Safetensor metadata
+ ///
+ public ISafetensorsMetadata Metadata { get; private set; } = new SafetensorsMetadata();
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Core/Models/Safetensor/SafetensorsMetadata.cs b/solution/Safetensors.Core/Models/Safetensor/SafetensorsMetadata.cs
new file mode 100644
index 0000000..725186d
--- /dev/null
+++ b/solution/Safetensors.Core/Models/Safetensor/SafetensorsMetadata.cs
@@ -0,0 +1,23 @@
+namespace Safetensors.Core
+{
+ ///
+ /// Safetensor metadata
+ ///
+ public class SafetensorsMetadata : ISafetensorsMetadata
+ {
+ ///
+ /// Default __metadata__ property name
+ ///
+ public string PropertyName { get; set; } = "__metadata__";
+
+ ///
+ /// Safetensor metadata description
+ ///
+ public string Description { get; set; } = string.Empty;
+
+ ///
+ /// Safeensor metadata properties
+ ///
+ public List Properties { get; set; } = [];
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Core/Models/Safetensor/SafetensorsMetadataProperty.cs b/solution/Safetensors.Core/Models/Safetensor/SafetensorsMetadataProperty.cs
new file mode 100644
index 0000000..ae9ab42
--- /dev/null
+++ b/solution/Safetensors.Core/Models/Safetensor/SafetensorsMetadataProperty.cs
@@ -0,0 +1,62 @@
+using System.Text.Json.Nodes;
+
+namespace Safetensors.Core
+{
+ ///
+ /// Safeensor metadata property
+ ///
+ public class SafetensorsMetadataProperty : ISafetensorsMetadataProperty
+ {
+ ///
+ /// Safeensor metadata property name
+ ///
+ public string PropertyName { get; set; } = string.Empty;
+
+ ///
+ /// Safetenso metadata property description
+ ///
+ public string Description { get; set; } = string.Empty;
+
+ ///
+ /// Safeensor metadata property value
+ ///
+ public string Value { get; set; } = string.Empty;
+
+ ///
+ /// Safeensor metadata property value extended
+ ///
+ public JsonNode? ValueEx
+ {
+ get
+ {
+ return Convert.ToString(MetadataType)?.ToLower() switch
+ {
+ "tagfrequency" or
+ "datasetdirs" => ParseJson(),
+ _ => null,
+ };
+ }
+ }
+
+ ///
+ /// Safeensor metadata property type
+ ///
+ public string? MetadataType { get; set; } = string.Empty;
+
+ ///
+ /// Try parse Json
+ ///
+ ///
+ private JsonNode? ParseJson()
+ {
+ if (!string.IsNullOrEmpty(Value))
+ {
+ var node = JsonNode.Parse(Value);
+
+ return node;
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Core/Safetensors.Core.csproj b/solution/Safetensors.Core/Safetensors.Core.csproj
new file mode 100644
index 0000000..b97451d
--- /dev/null
+++ b/solution/Safetensors.Core/Safetensors.Core.csproj
@@ -0,0 +1,10 @@
+
+
+
+ net8.0
+ enable
+ enable
+ none
+
+
+
diff --git a/solution/Safetensors.Inspector.UX/App.config b/solution/Safetensors.Inspector.UX/App.config
new file mode 100644
index 0000000..49cc43e
--- /dev/null
+++ b/solution/Safetensors.Inspector.UX/App.config
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/solution/Safetensors.Inspector.UX/Assets/HashGray.ico b/solution/Safetensors.Inspector.UX/Assets/HashGray.ico
new file mode 100644
index 0000000..e6785e4
Binary files /dev/null and b/solution/Safetensors.Inspector.UX/Assets/HashGray.ico differ
diff --git a/solution/Safetensors.Inspector.UX/Assets/HashMagenta.ico b/solution/Safetensors.Inspector.UX/Assets/HashMagenta.ico
new file mode 100644
index 0000000..72adc07
Binary files /dev/null and b/solution/Safetensors.Inspector.UX/Assets/HashMagenta.ico differ
diff --git a/solution/Safetensors.Inspector.UX/Assets/PropertyGray.ico b/solution/Safetensors.Inspector.UX/Assets/PropertyGray.ico
new file mode 100644
index 0000000..52b791d
Binary files /dev/null and b/solution/Safetensors.Inspector.UX/Assets/PropertyGray.ico differ
diff --git a/solution/Safetensors.Inspector.UX/Assets/PropertyGreen.ico b/solution/Safetensors.Inspector.UX/Assets/PropertyGreen.ico
new file mode 100644
index 0000000..9384931
Binary files /dev/null and b/solution/Safetensors.Inspector.UX/Assets/PropertyGreen.ico differ
diff --git a/solution/Safetensors.Inspector.UX/Assets/XtraGray.ico b/solution/Safetensors.Inspector.UX/Assets/XtraGray.ico
new file mode 100644
index 0000000..f8a2d6e
Binary files /dev/null and b/solution/Safetensors.Inspector.UX/Assets/XtraGray.ico differ
diff --git a/solution/Safetensors.Inspector.UX/Assets/XtraRed.ico b/solution/Safetensors.Inspector.UX/Assets/XtraRed.ico
new file mode 100644
index 0000000..643c4d8
Binary files /dev/null and b/solution/Safetensors.Inspector.UX/Assets/XtraRed.ico differ
diff --git a/solution/Safetensors.Inspector.UX/Assets/safetensor.ico b/solution/Safetensors.Inspector.UX/Assets/safetensor.ico
new file mode 100644
index 0000000..75d5022
Binary files /dev/null and b/solution/Safetensors.Inspector.UX/Assets/safetensor.ico differ
diff --git a/solution/Safetensors.Inspector.UX/Assets/safetensor.png b/solution/Safetensors.Inspector.UX/Assets/safetensor.png
new file mode 100644
index 0000000..9179692
Binary files /dev/null and b/solution/Safetensors.Inspector.UX/Assets/safetensor.png differ
diff --git a/solution/Safetensors.Inspector.UX/Program.cs b/solution/Safetensors.Inspector.UX/Program.cs
new file mode 100644
index 0000000..9e63980
--- /dev/null
+++ b/solution/Safetensors.Inspector.UX/Program.cs
@@ -0,0 +1,17 @@
+namespace Safetensor.Inspector.UX
+{
+ internal static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ ApplicationConfiguration.Initialize();
+ Application.Run(new formSafetensors());
+ }
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Inspector.UX/Properties/PublishProfiles/FolderProfile.pubxml b/solution/Safetensors.Inspector.UX/Properties/PublishProfiles/FolderProfile.pubxml
new file mode 100644
index 0000000..7ebbd63
--- /dev/null
+++ b/solution/Safetensors.Inspector.UX/Properties/PublishProfiles/FolderProfile.pubxml
@@ -0,0 +1,18 @@
+
+
+
+
+ Release
+ Any CPU
+ ..\..\Publish
+ FileSystem
+ <_TargetId>Folder
+ net8.0-windows
+ win-x64
+ false
+ true
+ true
+
+
\ No newline at end of file
diff --git a/solution/Safetensors.Inspector.UX/Safetensors.Inspector.UX.csproj b/solution/Safetensors.Inspector.UX/Safetensors.Inspector.UX.csproj
new file mode 100644
index 0000000..11fe269
--- /dev/null
+++ b/solution/Safetensors.Inspector.UX/Safetensors.Inspector.UX.csproj
@@ -0,0 +1,57 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ true
+ enable
+ none
+ Safetensors Inspector (LoRAs)
+ Safetensors Inspector (LoRAs)
+ True
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
+ Always
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
\ No newline at end of file
diff --git a/solution/Safetensors.Inspector.UX/Safetensors.Inspector.UX.csproj.user b/solution/Safetensors.Inspector.UX/Safetensors.Inspector.UX.csproj.user
new file mode 100644
index 0000000..3212809
--- /dev/null
+++ b/solution/Safetensors.Inspector.UX/Safetensors.Inspector.UX.csproj.user
@@ -0,0 +1,16 @@
+
+
+
+ <_LastSelectedProfileId>D:\git\private\safetensors-inspector\Safetensors.Inspector.UX\Properties\PublishProfiles\FolderProfile.pubxml
+
+
+
+ Form
+
+
+
+
+ Designer
+
+
+
\ No newline at end of file
diff --git a/solution/Safetensors.Inspector.UX/formSafetensors.Designer.cs b/solution/Safetensors.Inspector.UX/formSafetensors.Designer.cs
new file mode 100644
index 0000000..cf2a66a
--- /dev/null
+++ b/solution/Safetensors.Inspector.UX/formSafetensors.Designer.cs
@@ -0,0 +1,86 @@
+
+namespace Safetensor.Inspector.UX
+{
+ partial class formSafetensors
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(formSafetensors));
+ treeProperties = new TreeView();
+ imageList = new ImageList(components);
+ SuspendLayout();
+ //
+ // treeProperties
+ //
+ treeProperties.AllowDrop = true;
+ treeProperties.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
+ treeProperties.ImageIndex = 0;
+ treeProperties.ImageList = imageList;
+ treeProperties.Location = new Point(12, 12);
+ treeProperties.Name = "treeProperties";
+ treeProperties.SelectedImageIndex = 0;
+ treeProperties.ShowNodeToolTips = true;
+ treeProperties.Size = new Size(899, 593);
+ treeProperties.TabIndex = 0;
+ treeProperties.DragDrop += treeProperties_DragDrop;
+ treeProperties.DragEnter += treeProperties_DragEnter;
+ //
+ // imageList
+ //
+ imageList.ColorDepth = ColorDepth.Depth32Bit;
+ imageList.ImageStream = (ImageListStreamer)resources.GetObject("imageList.ImageStream");
+ imageList.TransparentColor = Color.Transparent;
+ imageList.Images.SetKeyName(0, "safetensor.ico");
+ imageList.Images.SetKeyName(1, "PropertyGray.ico");
+ imageList.Images.SetKeyName(2, "PropertyGreen.ico");
+ imageList.Images.SetKeyName(3, "XtraGray.ico");
+ imageList.Images.SetKeyName(4, "XtraRed.ico");
+ imageList.Images.SetKeyName(5, "HashGray.ico");
+ imageList.Images.SetKeyName(6, "HashMagenta.ico");
+ //
+ // formSafetensors
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(932, 617);
+ Controls.Add(treeProperties);
+ Icon = (Icon)resources.GetObject("$this.Icon");
+ MaximizeBox = false;
+ Name = "formSafetensors";
+ SizeGripStyle = SizeGripStyle.Hide;
+ StartPosition = FormStartPosition.CenterScreen;
+ Text = "Safetensors Inspector";
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private TreeView treeProperties;
+ private ImageList imageList;
+ }
+}
diff --git a/solution/Safetensors.Inspector.UX/formSafetensors.cs b/solution/Safetensors.Inspector.UX/formSafetensors.cs
new file mode 100644
index 0000000..42f7332
--- /dev/null
+++ b/solution/Safetensors.Inspector.UX/formSafetensors.cs
@@ -0,0 +1,169 @@
+using Safetensors.Core;
+using Safetensors.Storage;
+namespace Safetensor.Inspector.UX
+{
+ ///
+ /// Safetensors Inspector UX form
+ ///
+ public partial class formSafetensors : Form
+ {
+ ///
+ /// Constructor
+ ///
+ public formSafetensors()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// Drag and drop event handler for the tree view control.
+ ///
+ private void treeProperties_DragEnter(object sender, DragEventArgs e)
+ {
+ if (e?.Data != null)
+ if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
+ }
+
+ ///
+ /// Drag and drop event handler for the tree view control
+ ///
+ private async void treeProperties_DragDrop(object sender, DragEventArgs e)
+ {
+ if ((e != null) && (e.Data != null))
+ {
+ // list of potential folders/files to be added
+ List listFiles = [];
+
+ if (e.Data.GetData(DataFormats.FileDrop) is string[] droppedItems)
+ {
+ foreach (string droppedItem in droppedItems)
+ {
+ FileAttributes attr = File.GetAttributes(droppedItem);
+
+ // check if a folder/directory
+ if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
+ {
+ if (Path.Exists(droppedItem))
+ listFiles.AddRange(Directory.GetFiles(droppedItem, "*.safetensors"));
+ }
+ else if (File.Exists(droppedItem))
+ listFiles.Add(droppedItem);
+ }
+
+ // if there are files to be added
+ if (listFiles.Count > 0)
+ await PopulateTreeViewWithFilesAsync([.. listFiles]);
+ }
+ }
+ }
+
+ ///
+ /// Populate the treeview
+ ///
+ ///
+ /// Yes, this can be improved. For now it works well enough.
+ ///
+ private async Task PopulateTreeViewWithFilesAsync(string[] files)
+ {
+ // clear UX tree view
+ treeProperties.Nodes.Clear();
+
+ // create temp list of nodes
+ List nodes = [];
+
+ foreach (string file in files)
+ {
+ var fileNode = treeProperties.Nodes.Find(file, false);
+ if (fileNode.Length == 0)
+ {
+ // get file size in human readable format
+ var fiSize = new FileInfo(file).Length.SizeSuffix(2);
+
+ TreeNode safetensorsNode = new()
+ {
+ Name = file,
+ Text = $"{file} ({fiSize})",
+ ImageIndex = 0,
+ ToolTipText = $"The safetensors file {Path.GetFileName(file)} is {fiSize}"
+ };
+
+ // read a file and get its properties
+ SafetensorReader sr = new();
+ await sr.InitializeAsync();
+ var safetensor = await sr.ReadAsync(file);
+
+ if (safetensor != null)
+ {
+ foreach (var prop in safetensor.Metadata.Properties)
+ {
+ var propProps = prop?.ValueEx?.AsObject().ToList();
+ {
+ if (propProps == null)
+ {
+ TreeNode propNode = new()
+ {
+ Name = prop?.PropertyName,
+ ToolTipText = prop?.PropertyName,
+ Text = $"{prop?.Description}: {prop?.Value}",
+ ImageIndex = 1,
+ SelectedImageIndex = 2
+ };
+
+ safetensorsNode.Nodes.Add(propNode);
+ }
+ else
+ {
+ TreeNode propNode = new()
+ {
+ Name = prop?.PropertyName,
+ ToolTipText = prop?.PropertyName,
+ Text = $"{prop?.Description}",
+ ImageIndex = 3,
+ SelectedImageIndex = 4
+ };
+
+ propProps?.ForEach(propChild =>
+ {
+ TreeNode propChildNode = new()
+ {
+ Name = prop?.PropertyName,
+ ToolTipText = $"{prop?.PropertyName} : {propChild.Key}",
+ Text = $"{propChild.Key}",
+ ImageIndex = 5,
+ SelectedImageIndex = 6
+ };
+
+ propNode.Nodes.Add(propChildNode);
+
+ var propChildProps = propChild.Value?.AsObject().ToList();
+ propChildProps?
+ .Select(z => new KeyValuePair(Convert.ToString(z.Key).Trim(), Convert.ToInt32(z.Value?.GetValue())))
+ .OrderByDescending(z => z.Value).ThenBy(z => z.Key).ToList()
+ .ForEach(y =>
+ {
+ propChildNode.Nodes.Add(new TreeNode()
+ {
+ Name = prop?.PropertyName,
+ ToolTipText = $"{y.Key}",
+ Text = $"({y.Value}) {y.Key}",
+ ImageIndex = 5,
+ SelectedImageIndex = 6
+ });
+ });
+ });
+
+ safetensorsNode.Nodes.Add(propNode);
+ }
+ }
+ }
+ }
+
+ nodes.Add(safetensorsNode);
+ }
+ }
+
+ // add list of nodes to UX tree
+ treeProperties.Nodes.AddRange([.. nodes]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/solution/Safetensors.Inspector.UX/formSafetensors.resx b/solution/Safetensors.Inspector.UX/formSafetensors.resx
new file mode 100644
index 0000000..2b3ba06
--- /dev/null
+++ b/solution/Safetensors.Inspector.UX/formSafetensors.resx
@@ -0,0 +1,778 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+
+ AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
+ LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
+ SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAiAwAAAJNU0Z0AUkBTAIBAQcB
+ AAEwAQABMAEAARABAAEQAQAD/wEAASEBAAj/AUIBTQE2BwABNgMAASgDAAFAAwABIAMAAQEBAAEgBgAB
+ IP8A/wBoAAMdASgDEgEYBAADHQEoAwwBECwAAx0BKAMSARgEAAMdASgDDAEQZAADGwElAgAB/gH/AkoB
+ eAHADAACSQFRAY8CAAH9Af8oAAM3AVgDVAGXBAADdgHlAz8BaCwAATkBNQE5AVgBZAFFAWQBlwQAAccB
+ JAHHAeUBQgE8AUIBaGgAAyABLgIAAf4B/wMgAS0IAAJNAWcBrwJAAZAB0igAAzcBWAOAAf8EAANNAYcD
+ UgGSLAABOQE1ATkBWAH/AQAC/wQAAVcBQwFXAYcBYAFFAWABkmwAAyQBNAIAAf4B/wMiATEDHwEsAgAB
+ /QH/AyoBPyQAAzcBWAM3AVgDfwH/AzcBWANgAbEDgAH/AzcBWAM3AVggAAE5ATUBOQFYATkBNQE5AVgB
+ /gEAAf4B/wE5ATUBOQFYAX4BQwF+AbEB/wEAAv8BOQE1ATkBWAE5ATUBOQFYaAADOgFgAgAB/gH/Ak0B
+ awGzAkkBfQHFKAADVQGXA1UBlwOAAf8DVQGXA1UBlwOAAf8DVQGXA1UBlwMYASEcAAFkAUUBZAGXAWQB
+ RQFkAZcB/wEAAv8BZAFFAWQBlwFkAUUBZAGXAf8BAAL/AWQBRQFkAZcBZAFFAWQBlwMYASFoAAJKAXIB
+ vAIAAf4B/wJAAUEBcDAAA38B/wNNAYcEAAOAAf8DNwFYLAAB/gEAAf4B/wFXAUMBVwGHBAAB/wEAAv8B
+ OQE1ATkBWHAAAkABQQFwAgAC/wJKAXIBvDAAAz8BaANNAYcEAANVAZcDNwFYLAABQgE8AUIBaAFXAUMB
+ VwGHBAABZAFFAWQBlwE5ATUBOQFYcgAB/gH/AkUBSQGAAkoBcgG8AksBdgG+JAADLwFIA4AB/wOAAf8D
+ gAH/A38B/wOAAf8DfwH/A4AB/wNfAa4cAAEwAS4BMAFIAf8BAAP/AQAD/wEAAv8B/gEAAf4C/wEAAv8B
+ /gEAAf4C/wEAAv8BegFDAXoBrmQAAzoBYAIAAf4B/wgAAkoBeAHAAkkBfAHDKAADGgEkA4AB/wQAAyQB
+ NAN/Af8sAAMaASQB/wEAAv8EAAMkATQB/gEAAf4B/24AAv8CSQFRAY8IAAMgAS0CAAH+Af8DIAEuKAAD
+ gAH/AzYBVgQAA38B/zAAAf8BAAL/ATgBNQE4AVYEAAH+AQAB/gH/bAADJgE4AxcBHwwAAxsEJgE4KAAD
+ gAH/A0cBeAQAA38B/wMvAUgsAAH/AQAC/wFNAUABTQF4BAAB/gEAAf4B/wEwAS4BMAFI/wD/AP8AXwAD
+ EQEWATsCPAFkAz0BZwQCDAADJQE3AUECQgFyAy4BR9AAAVUBVwFaAbEBDAGfAv8BFwG9Av8BHgHQAv8B
+ HgHQAv8BDgGmAv8BEQGRAfMB/gELAZ0C/wEfAY8B2AH5ARkBwgL/AR4B0gL/ARsByQL/ARIBrwL/AREB
+ kQHzAf4DHgEqwAADTwGZAR0BzgL/ARIBrgL/AR4B0gL/AR4B0gL/AR4B0gL/AR4B0gL/AQ0BogL/AR4B
+ 0gL/ARIBsgL/AR4B0gL/AR4B0gL/AR4B0gL/ARgBuwL/ARsByQL/AQ4BpAL/wAADUQGeARwBzAL/ARYB
+ ugL/ARkBxgL/AR4B0gL/AR4B0gL/ARsBywL/ARIBsgL/AR4B0gL/AQsBnwL/AR4B0gL/AR4B0gL/AR0B
+ 0QL/AQ4BpQL/AR0B0AL/AQ4BpAL/FAADKQE+PAADCAEKAyABLTAAAw4BEgM6AWADKwFCDAADJQE2AzoB
+ YBQAAx8BLAEOAaUC/wEdAdEC/wENAaUC/wESAbAC/wEdAdEC/wEMAZ8C/wEeAdIC/wEeAdIC/wEbAcoC
+ /wEQAawC/wESAbAC/wEcAc0C/wEVAboC/wEbAcgC/wELAZ0C/xgAA8AB/z0AAZkBAAH/NAADVQGgA38B
+ /wwAA00BjwN/Af8UAAMQARUBDQGiAv8BCwGeAv8BHQHQAv8BEAGtAv8BEAGrAv8BHQHRAv8BJgGkAv8B
+ KgGPAv8BHgHSAv8BDgGoAv8BHgHSAv8BDQGkAv8BGwHKAv8BCwGeAv8BKwGFAcIB9RgAA8AB/zwAAVEB
+ XwFRAbwBJgEnASYBOTQAA04BkgNsAdsIAAN/Af8DOgFgGAADSQGHAQsBnQL/AQsBnQL/AREBrwL/ARMB
+ tQL/AUABTQFSAf8BPwE0AcUB/wFAATUBqgH/AUQBOgFCAf8BHQHRAv8BDQGjAv8BFgG9Av8BCwGeAv8B
+ CwGdAv8cAAPAAf8DwAH/A8AB/wPAAf8wAAMuAUcBAAGZAQAB/wEAAZkBAAH/AQABmQEAAf8DFgEeLAAD
+ SgGIA28B4wNHBH8B/xwAAVUBaQF5AdoBHQHRAf4B/wEdAdEB/gH/AR0B0QH+Af8BHQHRAf4B/wFEAToB
+ OQH/ATUBcAGBAf8BLwGHAZ8B/wFDATsBOgH/ASwBkwGuAf8BHQHRAf4B/wEdAdEB/gH/AR0B0QH+Af8B
+ EAGqAf4B/yAAA8AB/wQAA0gBgwPAAf8xAAGZAQAB/wQAAzMBUAFCAXIBQgHdAxABFSgAAwkBDAN/Af8D
+ gAH/A0EBcBwAAUwBbwGJAeMBHQHRAf4B/wEdAdEB/gH/AR0B0QH+Af8BHQHRAf4B/wEdAdEB/gH/AR0B
+ 0QH+Af8BHQHRAf4B/wEdAdEB/gH/AR0B0QH+Af8BHQHRAf4B/wEdAdEB/gH/AR0B0QH+Af8BEQGsAf4B
+ /yAAA8AB/wwAA8AB/ywAAVEBVwFRAaoBLQEuAS0BRgkAAZkBAAH/LAADQQFwA4AB/wNFAXkcAANSAaAB
+ HQHRAf4B/wEVAbsB/gH/AQ0BpAH+Af8BNgFtAXwB/wEfAcYB7wH/AR0B0QH+Af8BHQHRAf4B/wEeAcoB
+ 9QH/AS0BkAGpAf8BHQHRAf4B/wEKAZwB/gH/AR0B0QH+Af8BCwGeAf4B/yAAA8AB/wgAA1IBmwPAAf8s
+ AAM7AWMDRgF/BAABQAFBAUABcAEAAZkBAAH/LAADfgH/A0cBgANyAeoDRwF+GAADEAIVAbgB/gH/AR0B
+ 0QH+Af8BHQHRAf4B/wFEAToBOQH/AUABSQFNAf8BHQHRAf4B/wEdAdEB/gH/ASwBlAGvAf8BRAE6ATkB
+ /wEdAdEB/gH/AR0B0QH+Af8BHQHRAf4B/wFIAXUBkgHnJAADwAH/A8AB/wPAAf8DNQFVMQABmQEAAf8B
+ AAGZAQAB/wEAAZkBAAH/AUABQQFAAXEoAAM6AWADfgH/CAADbwHhA0oBhxgAAR0BjQHbAfoBHgHSAv8B
+ HgHSAv8BHgHSAv8BHgHSAv8BHgHSAv8BHgHSAv8BHgHSAv8BHgHSAv8BHgHSAv8BHgHSAv8BEgGuAv8D
+ DQERnAADfwH/A00BjwgAAzYBWQN+Af8DFQEcFAADAwEEAQwBnwL/AR4B0gL/AR4B0gL/AR4B0gL/AR4B
+ 0gL/AR4B0gL/AR4B0gL/AR4B0gL/AR4B0gL/ARgBwAL/AVACUQGdoAADQQFwAyoBPwwAAzEBTQNBAXAY
+ AAMJAQwBCwGdAv8BHAHKAv8BHgHSAv8BHgHSAv8BHgHSAv8BHgHSAv8BHgHSAv8BEAGpAv8DTQGS4AAB
+ QAJBAXABCwGcAf4B/wEMAZ4B/gH/AQ4BogH+Af8BCgGcAf4B/wFYAV0BYwHFAwUBBv8A0QABQgFNAT4H
+ AAE+AwABKAMAAUADAAEgAwABAQEAAQEGAAEBFgAD/wEABv8CAAb/AgAC/wH5AT8B+QE/AgAB4wGfAfkB
+ PwH5AT8CAAHxAZ8B+QE/AfkBPwIAAfgBHwHwAQ8B8AEPAgAB/AE/AfABBwHwAQcCAAH+AT8B/AGfAfwB
+ nwIAAf4BPwH8AZ8B/AGfAgAB/gEfAfABBwHwAQcCAAH8Ac8B/AGfAfwBnwIAAfwBxwH+AV8B/gFfAgAB
+ /AHnAf4BTwH+AU8CAAb/AgAG/wIABv8CAAHhAccG/wGAAQAG/wIABv8CAAH7Af8B+QH/AeMBnwIAAf0B
+ /wH9Af8B8wGfAgAB/QH/AfwB/wH5AZ8BgAEBAfwBPwH8AR8B/AE/AYABAQH+AZ8B/gGPAfwBPwGAAQEB
+ /gHvAf4BbwH+AT8BgAEBAf4BzwH+AU8B/gEfAYABAQH/AQ8B/wEPAfwBzwHAAQEE/wH8AccBwAEDBP8B
+ /AHnAeABBwb/AfgBDw7/Cw==
+
+
+
+ True
+
+
+
+
+ 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
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGqL+AhWg/i4Rn/6CDp7+zwud/v4KnP7/
+ Cpz+/wqc/v8KnP7/Cpz+/wqc/v8KnP7/Cpz+/wyd/uISn/5aI6b+AQAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAWof5SDZ7+3Qqc/v8KnP7/Cpz+/wqc/v8KnP7/Cpz+/wqc/v8KnP7/C53+/g+e/tQRn/6H
+ F6H+MySm/gMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyp/gsWof5kDp7+ywud/v4KnP7/
+ Cpz+/wud/v8Oov7/Eav+/xSz/v8WuP7/F7n+/xW2/v8Srv7/DaD+/wqc/v8Lnf7+EJ7+mBKf/oQPnv6c
+ C53+pAyd/qQPnv6XFKD+fheh/o0Lnf79Cpz+/wyg/v8Rrf7/Fbb+/xe5/v8WuP7/FLP+/xGs/v8Oo/7/
+ C53+/wqc/v8KnP7/C53+/w6e/tEUoP5qI6b+DQAAAAAAAAAAAAAAAAAAAAAAAAAAFKD+VBCf/uEKnP7/
+ Cpz+/wud/v8Rq/7/F7z+/xzL/v8e0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/Hc7+/xKy/v8Knf7/
+ Cpz+/wqc/v8KnP7/Cpz+/wqc/v8KnP7/Cpz+/wqc/v8KnP7/EbD+/x3O/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8e0f7/HMv+/xi9/v8SrP7/C57+/wqc/v8KnP7/DZ7+5ROg/l0AAAAAAAAAAAAAAAARn/6A
+ C53+/gqc/v8Nof7/Frf+/x3M/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8Rr/7/Cpz+/wue/v8Utf7/Frj+/xa3/v8UtP7/DJ/+/wqc/v8QrP7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/Hc3+/xa4/v8Nov7/Cpz+/wud/v8Qn/6N
+ JKf+ARSg/jILnf78C53+/xSz/v8dzv7/HdH+/x3Q/v8ZwP7/G8f+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8by/7/C57+/wud/v8ayP7/HdH+/x3R/v8byv7/C53+/wud/v8ayf7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/xvI/v8Yv/7/HdD+/x3R/v8dz/7/
+ FbX+/wud/v8Lnf7+G6P+QBuj/nIKnP7/Ear+/x7R/v8e0f7/GcD+/w+l/v8Oov7/G8b+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/D6j+/wqc/v8Wvv7/HdH+/x3R/v8Xwf7/
+ Cpz+/w6l/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/xzI/v8OpP7/
+ DqP+/xi+/v8e0f7/HtH+/xKt/v8KnP7/E6D+gRKf/lMKnP7/DJ/+/xOx/v8Ppf7/Ear+/xm//v8e0P7/
+ HtH+/x3M/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/D6n+/wqc/v8Wvf7/
+ HdH+/x3R/v8XwP7/Cpz+/w6m/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ Hcz+/x7R/v8e0P7/GcD+/xGr/v8PpP7/E7H+/wyg/v8KnP7/FKD+YRyj/jQLnf7+Cpz+/xKs/v8byP7/
+ HtH+/x3R/v8cyv7/Eq3+/w6n/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8byv7/
+ C57+/wud/v8ax/7/HdH+/x3R/v8byv7/C53+/wud/v8ayP7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/D6n+/xKs/v8cyf7/HdH+/x7R/v8cyf7/Eq7+/wqc/v8KnP7/GKH+QxGf/n4KnP7/
+ Eav+/x7R/v8d0f7/Hc/+/xa2/v8Mn/7/D6n+/xvL/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3Q/v8Pq/7/Cpz+/w+o/v8d0f7/HdH+/x3R/v8d0f7/EKv+/wqc/v8PqP7/Hc/+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HMz+/w+r/v8Mnv7/FbT+/x3O/v8d0f7/HtH+/xKt/v8KnP7/
+ EJ/+jhCf/nsKnP7/EKf+/xrD/v8Vtv7/DaH+/w2h/v8WvP7/HdH+/x3R/v8Ttv7/D6r+/x3R/v8ayP7/
+ F77+/x3R/v8d0f7/HdH+/xGv/v8KnP7/C57+/xrH/v8d0f7/HdH+/x3R/v8d0f7/Gsn+/wuf/v8KnP7/
+ EKz+/x3Q/v8d0f7/HdH+/xe//v8ax/7/HdH+/xCs/v8Ts/7/HdD+/x3R/v8Yvv7/DaL+/w2g/v8Vtf7/
+ GcP+/xGp/v8KnP7/EJ7+ihKf/iUMnf70Cpz+/wqc/v8Lnf7/E7H+/x3N/v8d0f7/Hc/+/xGv/v8MoP7/
+ Gsf+/xzN/v8Mof7/C57+/xzN/v8d0f7/FLj+/wqc/v8Lnf7/F7/+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/xjB/v8Lnv7/Cpz+/xO0/v8d0f7/Hc/+/wuf/v8MoP7/G8z+/xrJ/v8Mof7/EKz+/xzP/v8d0f7/
+ Hc7+/xSy/v8Lnf7/Cpz+/wqc/v8Mnf74G6P+MQAAAAAQn/6pCpz+/w2g/v8awv7/HtH+/x3R/v8by/7/
+ Dqj+/wuf/v8ZxP7/HdH+/xKz/v8Ln/7/GMH+/x3R/v8ax/7/C57+/wud/v8Vuf7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8WvP7/C53+/wud/v8Zxf7/HdH+/xjD/v8MoP7/EbD+/x3R/v8Zxv7/
+ DKD+/w6m/v8byv7/HdH+/x7R/v8axP7/DaL+/wqc/v8Qn/64AAAAACKm/gINnf7iCpz+/xnB/v8d0f7/
+ HdH+/xe//v8MoP7/C5/+/xnE/v8d0f7/Gsf+/wud/v8WvP7/HdH+/x3R/v8Pqf7/Cpz+/xCr/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/Ea7+/wqc/v8Op/7/HdH+/x3R/v8Xv/7/
+ C53+/xnF/v8d0f7/Gcb+/wyg/v8Mn/7/Fr3+/x3R/v8d0f7/GsT+/wqc/v8Mnf7rF6H+BjSt/gEPnv7W
+ Cpz+/xW0/v8ZwP7/D6r+/wud/v8Lnf7/F8H+/x3R/v8d0P7/Dqj+/wue/v8czv7/HdH+/xjD/v8Lnf7/
+ C57+/xvJ/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/G8z+/wuf/v8KnP7/
+ F8D+/x3R/v8d0P7/C5/+/w6m/v8d0P7/HdH+/xjD/v8Lnv7/Cpz+/w+p/v8Zv/7/Frb+/wqc/v8Onv7i
+ I6b+BAAAAAARn/5tCpz+/wqc/v8KnP7/Cpz+/wqc/v8Ttf7/HdH+/x3R/v8UuP7/C53+/wue/v8czf7/
+ HdH+/xCt/v8KnP7/EbD+/x3R/v8d0f7/H8v+/yiY/v8wcv7/M2T+/zJo/v8tgf7/I7P+/x3R/v8d0f7/
+ HdH+/xOz/v8KnP7/D6r+/x3R/v8cz/7/C5/+/wqc/v8Ttf7/HdH+/x3R/v8Ut/7/Cpz+/wqc/v8KnP7/
+ Cpz+/wuc/v8UoP59AAAAAAAAAAAKnP4BEJ/+bBGf/tILnf78Cpz+/wqc/v8ZxP7/HdH+/xjC/v8Lnv7/
+ Cpz+/wqc/v8Ssf7/Fbr+/wud/v8Lnf7/Gcb+/x7R/v8ootb/OUH+/zwx/v88Mf7/PDH+/zwx/v88Mf7/
+ PDL+/zJo9/8gx/L/HdH+/xrJ/v8Lnf7/Cp3+/xS4/v8Ss/7/Cpz+/wqc/v8Lnf7/F8D+/x3R/v8ax/7/
+ Cpz+/wqc/v8Lnf73D57+1BOg/ncvqv4DAAAAAAAAAAAAAAAAAAAAABeh/h0Lnf78Cpz+/wqc/v8Rrv7/
+ E7X+/wuf/v8KnP7/DqX+/wud/v8KnP7/Cpz+/wqc/v8Ssf7/HdH+/yuevP9EPT7/QDWw/zwx/v88Mf7/
+ PjPV/z0z5v88Mf7/PTL9/0E3iv88WWP/H8n0/x3R/v8TtP7/Cp3+/wqc/v8KnP7/Cp3+/w6m/v8KnP7/
+ C57+/xO0/v8RsP7/Cpz+/wqc/v8Nnv7fHaT+BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABih/loKnP7/
+ DJ/+/wqd/v8KnP7/Cpz+/wqc/v8Qq/7/Hc/+/xe+/v8PqP7/Dqb+/xS3/v8d0P7/IsHq/0JCRP9EOjn/
+ RDo8/0E2kP8+M9v/QzlS/0M4Z/8+M9b/Qjh4/0Q6Ov9EOjn/NHqN/x3R/v8d0f7/Fbn+/w6m/v8OqP7/
+ Fr3+/x3Q/v8Qrf7/Cpz+/wqc/v8KnP7/Cpz+/wud/v8Lnf7/IKX+JQAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAABGf/o4KnP7/E7H+/xfB/v8Qrf7/EK3+/xa9/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ NHuP/0Q6Of9EOjn/RDo5/0Q6Of9EOjn/RDo5/0Q6Of9EOjn/RDo5/0Q6Of9EOjn/RD09/yLA6f8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/F7/+/xGu/v8Qrf7/F7/+/w+l/v8KnP7/E5/+VwAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAABCe/rMKnP7/Frn+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8dzvr/QEhM/0Q6Of9EOjn/RDo5/0Q6Of9EOjn/RDo5/0Q6Of9EOjn/RDo5/0Q6Of9EOjn/
+ RDo5/y6OqP8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/xKt/v8KnP7/
+ E6D+fQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+e/c0Jm/3/GL/9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/
+ HND9/xzQ/f8c0P3/HND9/xzQ/f8ivOP/Qzo6/0M5OP9DOTj/P0tR/zGCmP8nqMr/Irvi/yS02v8rmLX/
+ N2l4/0M8PP9DOTj/Qzk4/zZtfv8c0P3/HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/
+ HND9/xSz/f8Jm/3/DZ39lwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6d/dsJm/3/GcL9/xzQ/f8c0P3/
+ HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/HND9/xzQ/f8ktNr/Qzo5/z1VXv8qnLr/Hc77/xzQ/f8c0P3/
+ HND9/xzQ/f8c0P3/HND9/yG+5v8zeIz/QkBC/zhldP8c0P3/HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/
+ HND9/xzQ/f8c0P3/HND9/xW2/f8Jm/3/FqD9pAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyd/tsKnP7/
+ GcL+/x3Q/v8d0f7/HdH+/x3Q/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8dz/v/I7bd/x3P+/8d0f7/
+ HdH+/x3R/v8d0f7/HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/IMTv/yG/6P8c0P3/HND9/xzQ/f8c0P3/
+ HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/HND9/xW3/f8Jm/3/G6P9pgAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAABOf/tEKnP7/GL/+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/
+ HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/HND9/xS0/f8Jm/3/C5z9mgAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAA2d/rkKnP7/Frr+/x3R/v8d0f7/HdH+/x3R/v8bzP7/Fr7+/xrK/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/
+ HND9/xzQ/f8c0P3/HND9/xzQ/f8c0P3/G8v9/xa+/f8by/3/HND9/xzQ/f8c0P3/HND9/xKv/f8Jm/3/
+ EJ79gwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6d/pUKnP7/E7L+/x3Q/v8d0f7/HdH+/xzP/v8Mo/7/
+ Cpz+/wug/v8by/7/HdH+/yDF7/8ey/f/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HND9/xzQ/f8c0P3/
+ HND9/xzQ/f8c0P3/HND9/x3Q/f8hwen/HdD9/xzQ/f8bzf3/C6H9/wmb/f8Mov3/G879/xzQ/f8c0P3/
+ HND9/w+m/f8Jm/3/D579XgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOf/mUKnP7/D6b+/x3R/v8d0f7/
+ HdH+/xrJ/v8KnP7/Cpz+/wqc/v8Xwv7/Irrg/0BHSv82b37/Hc/8/yHA5/8fyfT/HdH+/x3R/v8d0f7/
+ HND9/xzQ/f8c0P3/HND9/x3Q/P8juuD/HdD9/yyVsP9CPj7/Kpy5/xzQ/f8Yxf3/CZv9/wmb/f8Jm/3/
+ Gcb9/xzQ/f8c0P3/Hc/9/wud/f8Jm/3/FqD9LgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmh/icKnP7+
+ Cpz+/xzM/v8d0f7/HdH+/xzQ/v8Qrf7/Cpz+/w6o/v8czv7/NXOD/0Q6Of9EOjn/P0xQ/0M7Ov8whp3/
+ HdH+/x3R/v8d0f7/HND9/xzQ/f8c0P3/HND9/yWv0f9DOjn/P0tP/0M7O/9DOTj/P0pP/x3Q/f8cz/3/
+ D6r9/wqc/f8Pq/3/HND9/xzQ/f8c0P3/GcH9/wmb/f8Mnf3oH6P9BgAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAACio/gMPnv7XCpz+/xa7/v8d0f7/HdH+/x3Q/v8c0P7/G8z+/xzQ/v8d0f7/OGVy/0Q6Of9EOjn/
+ RDo5/0Q6Of8zeYv/HdH+/x3R/v8d0f7/HND9/xzQ/f8c0P3/HND9/ymhwP9DOTj/Qzk4/0M5OP9DOTj/
+ Qz09/x3Q/f8c0P3/HND9/xvM/f8c0P3/HND9/xzQ/f8c0P3/ErD9/wmb/f8Onf2iAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAVoP6ACpz+/w+m/v8d0P7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ LJSv/0Q6Of9EOjn/RDo5/0M6Ov8op8f/HdH+/x3R/v8d0f7/HND9/xzQ/f8c0P3/HND9/yDF7v9BRUf/
+ Qzk4/0M5OP9DOTj/N2x6/xzQ/f8c0P3/HND9/xzQ/f8c0P3/HND9/xzQ/f8czf3/C579/wqc/f8WoP1J
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXof4dC5z+9wqc/v8Zwf7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdD9/y+Kov8+UFb/PVNa/yuYtP8d0P3/HdH+/x3R/v8d0f7/HND9/xzQ/f8c0P3/
+ HND9/xzQ/f8lsdT/Ol9p/z9LT/81dIX/H8fx/xzQ/f8c0P3/HND9/xzQ/f8c0P3/HND9/xzQ/f8Vtv3/
+ CZv9/w2d/dkqqP0FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEp/+mwqc/v8Ppv7/
+ HdD+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/xzM/v8MoP7/Cpz+/x2j/mQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ Jab/Gwyd//MLnf//Frn//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//
+ HtL//x7S//8e0v//HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HtH+/xKu/v8KnP7/Dp7+1B6k/gUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAABmi/m8Lnf7/C57+/xvG/v8d0f7/HdH+/x7S//8e0v//HtL//x7S//8e0v//
+ HtL//x7S//8e0v//HtL//x7S//8e0v//HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/GLz+/wqc/v8Lnf77FqH+PQAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABeh/gMPnv63Cpz+/w2i/v8cyv7/HdH+/x7S//8e0v//
+ HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8aw/7/C57+/wqc/v8VoP6FAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfpP4VDp7+2gqc/v8OpP7/
+ HMr+/x7S//8e0f//HtL//x7S//8e0f//HtL//x7S//8e0f//HtL//x7S//8e0f//HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/xrE/v8Mn/7/Cpz+/xCf/rQaov4F
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ FaD+Ig2e/uQKnP7/DaH+/xvF//8e0f//HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8e0f7/GL7+/wue/v8KnP7/
+ DJ3+wiio/gwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAABWh/iQNnv7YCpz+/wue//8WuP//HdD//x7S//8e0v//HtL//x7S//8e0v//
+ HtL//x7S//8e0v//HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3N/v8TsP7/
+ C53+/wqc/v8Pnv63GKL+DgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXof4UE6D+tgud//8Lnf//D6b//xnB//8e0f//
+ HtL//x7S//8e0f//HtL//x7S//8e0f//HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0P7/
+ F7v+/w2h/v8KnP7/C53+/w+e/o4kpv4GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJqb+ARGf/2wMnf/v
+ C53//wud//8Ppf//F7r//xzL//8e0f//HtL//x7S//8e0v//HdH+/x3R/v8d0f7/HdH+/x3R/v8e0f7/
+ G8j+/xW2/v8Nov7/Cpz+/wqc/v8Onv7dGqL+SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAgpf4aEZ/+lAyd/vUKnP7/Cpz+/wud/v8Ppf7/E7D+/xa5/v8Yvv7/GcD+/xnA/v8Xvf7/
+ Fbf+/xKu/v8Oo/7/Cpz+/wqc/v8KnP7/DJ3+6ROg/ngipv4MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+k/hkPnv52Dp3+0Quc/v8KnP7/Cpz+/wqc/v8KnP7/
+ Cpz+/wqc/v8KnP7/Cpz+/wqc/v8KnP7/C5z+/A+e/r8Pnv5iHaP+DAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACSm/h4Rn/5a
+ Ep/+iw+e/q8Pnv7GEJ7+0g6d/s8Sn/7DDp3+qROf/oIUoP5PHqT+EgAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAP///////+AE////////4AT/gB/4Af/gBPgAB/AAH+AE4AAAAAAH4ATAAAAA
+ AAPgBIAAAAAAAOAEAAAAAAAA4AQAAAAAAADgBAAAAAAAAOAEAAAAAAAA4AQAAAAAAADgBAAAAAAAAOAE
+ AAAAAAAA4ASAAAAAAAHgBAAAAAAAAOAEAAAAAAAA4ASAAAAAAAHgBIAAAAAAAeAE4AAAAAAH4ATgAAAA
+ AAfgBOAAAAAAB+AE4AAAAAAH4ATgAAAAAAfgBOAAAAAAB+AE4AAAAAAH4ATgAAAAAAfgBOAAAAAAB+AE
+ 4AAAAAAH4ATgAAAAAAfgBOAAAAAAB+AE4AAAAAAP4ATwAAAAAA/gBPAAAAAAD+AE+AAAAAAf4AT4AAAA
+ AB/gBPwAAAAAP+AE/AAAAAB/4AT+AAAAAH/gBP8AAAAA/+AE/4AAAAH/4AT/wAAAA//gBP/gAAAP/+AE
+ //gAAB//4AT//gAAf//gBP//wAP//+AE////////4AT////////gBCgAAAAgAAAAQAAAAAEAIAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCl/xYToP9F
+ E6D/ZA2e/3IRn/9nE6D/OSOm/wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAao/8BE6D/Nw+e/2YNnv9y
+ Ep//ZRKf/0chpv8YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFqH/JA+e/4ENnv/T
+ C53//wud//8Lnf//DJ7//wud//8Lnf//DZ3/1xOg/zUkp/8IEZ//GBKf/xcsqv8GHaT/MA6e/9MLnf//
+ C53//wye//8Lnf//C53//wud//8Onv/WEZ//hRmi/ygAAAAAAAAAAAAAAAAAAAAAFKD/JhOg/7ELnf/+
+ DJ///xKv//8Xvf//G8j//x7Q//8e0v//HtD//xnD//8Opv//C53/+wud//4Lnf//C53//wud//0Lnf/5
+ DqX//xnC//8dz///HtL//x7Q//8byf//F77//xKv//8Mn///C53//g+e/7YToP8qAAAAABOg/y4Lnf/x
+ DaP//xe8//8dz///HtH//x7S//8e0v//HtL//x7S//8e0v//HtL//xzN//8Mof//D6f//xjA//8YwP//
+ D6j//wyg//8czP//HtL//x7S//8e0v//HtL//x7S//8e0v//HtH//x3P//8Xvf//DqP//wud//QZov81
+ E6D/mQ2i//8dzv//HMn//xKu//8Xuf//HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//xO0//8Nov//
+ HtL//x7S//8NpP//ErL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8Yu///Eq3//xvJ//8dz///
+ DqT//w+e/6MQn/+AC53//xGr//8UtP//HMj//x3N//8ZxP//HtL//x7S//8e0v//HtL//x7S//8e0v//
+ E7T//w2i//8e0v//HtL//w2k//8Ssv//HtL//x7S//8e0v//HtL//x7S//8e0v//GsX//x3M//8cyf//
+ FbX//xGr//8Lnv//EJ//iRCf/54Oo///HMz//x7Q//8Wuv//DqX//xnG//8d0f//HtL//x7S//8e0v//
+ HtL//xvL//8MoP//ErL//x7S//8e0v//E7T//wuf//8byv//HtL//x7S//8e0v//HtL//x3R//8ax///
+ DqX//xa5//8d0P//Hc3//w6k//8Pnv+pDZ7/mg2h//8UtP//DqT//xSz//8czv//GMP//xCt//8czf//
+ E7T//x3Q//8czv//DaX//w2i//8czf//HtL//x7S//8czv//DaP//w2j//8czf//HdH//xO0//8bzP//
+ Ea///xjB//8dz///FLT//w6j//8UtP//DaL//w+e/6QXof8sC53//w6l//8bx///HdH//xW7//8Npf//
+ HMz//xKw//8Rrv//HdH//xGu//8Mn///Gsn//x7S//8e0v//HtL//x7S//8byv//DKD//xCs//8d0f//
+ ErD//xGv//8czf//Dqb//xW6//8d0f//G8j//w+m//8Lnf//FaH/NhOg/0QLnf//G8f//xvM//8Rrv//
+ DaP//xvM//8Zxf//DaX//x3R//8YxP//C53//xa9//8e0v//HtL//x7S//8e0v//HtL//x7S//8Xv///
+ C53//xjC//8d0f//Dqb//xjE//8czP//DaT//xCs//8by///G8j//wud//8Pnv9MF6H/FQud//ENov//
+ C57//wue//8ayP//HdD//w6l//8Qrf//HtL//xCr//8Opv//HdH//x7P//8mpP//K4r//yqP//8jtP//
+ HtL//x3R//8OqP//D6n//x7S//8Rr///DaT//x3P//8byv//C57//wue//8Nov//C53/9R+k/xwAAAAA
+ EJ//MBCf/7MLnP//DaT//x3Q//8Rr///C53//wue//8Ssf//C53//xa9//8kueD/OUzU/z0y//89Mv7/
+ PTL//zwy//8za9D/H834/xe///8Lnf//ErD//wuf//8Lnf//EK3//x3Q//8Opv//C53//w6e/6UUoP82
+ AAAAAAAAAAAAAAAAEZ//hwue//8Lnf//C57//wud//8WvP//Ea///w2i//8Ttf//H8r1/0BNUv9EOkv/
+ PzTF/0E2mP9ANar/PzW2/0Q6Qv81dYj/HdH//xS2//8No///Ea7//xa9//8Lnv//C57//wud//8Lnf//
+ E6D/YwAAAAAAAAAAAAAAAAAAAAAPnv66Eav+/xjC/v8Uuf7/Gsj+/x3R/v8d0f7/HdH+/x3R/v8ujqf/
+ RDo5/0Q6Of9EOjn/RDo5/0Q6Of9EOjn/RDo5/0Q7O/8iveX/HdH+/x3R/v8d0f7/HdH+/xrJ/v8Uuf7/
+ F8H+/w6k/v8Qn/6VAAAAAAAAAAAAAAAAAAAAAA2d/toTsv7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/zljb/9EOjn/QUFE/zVwgf8ujab/L4ef/zlhbv9DOzr/RDo5/yyTrv8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/EKr+/wyd/rYAAAAAAAAAAAAAAAAAAAAAC5z+5xS1/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/NHWH/y+Jof8fyPP/HdH+/x3R/v8d0f7/HdH+/yO54P81c4X/K5m3/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8Rrv7/FKD+xAAAAAAAAAAAAAAAAAAAAAAPnv7jE7T+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/xGs/v8Nnf69AAAAAAAAAAAAAAAAAAAAAAyd/ssRrv7/
+ HdH+/x3R/v8czv7/E7X+/xjD/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x3R/v8d0f7/HdH+/xjE/v8Ttf7/G83+/x3R/v8d0f7/D6f+/w2d/qYAAAAAAAAAAAAAAAAAAAAA
+ Dp3+oA6l/v8d0f7/HdH+/xW7/v8KnP7/DaT+/x/H8f82bXz/IMTt/x/G7/8d0f7/HdH+/x3R/v8d0f7/
+ HdH+/x7K9f8ezPj/LZCp/yuXsv8d0f7/Dab+/wqc/v8Uuf7/HdH+/x3Q/v8Lnv7/D57+fAAAAAAAAAAA
+ AAAAAAAAAAASn/5iCpz+/xvL/v8d0f7/G8v+/xCt/v8Wvf7/Lo6n/0Q6Of9BQkP/Qz09/x7L9v8d0f7/
+ HdH+/x3R/v8d0f7/MISZ/0JBQ/9DOjr/QkFC/x3Q/f8Wv/7/EKz+/xrK/v8d0f7/GcT+/wqc/v8Rn/4+
+ AAAAAAAAAAAAAAAAAAAAACWn/hUKnP75Fbj+/x3R/v8d0f7/HdH+/x3R/v8pn73/RDo5/0Q6Of9ASU3/
+ Hc/7/x3R/v8d0f7/HdH+/x3R/v8slK//RDo5/0Q6Of89Ulj/HdH+/x3R/v8d0f7/HdH+/x3R/v8SsP7/
+ DJ3+5yOm/gMAAAAAAAAAAAAAAAAAAAAAAAAAAA6d/qUMof7/HM/+/x3R/v8d0f7/HdH+/x3R/f8slrL/
+ M3uO/yO43f8d0f7/HdH+/x3R/v8d0f7/HdH+/x3Q/P8tkav/M32Q/yK84/8d0f7/HdH+/x3R/v8d0f7/
+ G8v+/wud/v8Rn/6BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHaT/Jwud//oUtf//HtL//x7S//8e0v//
+ HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//
+ HtL//x7R//8Srv//DJ3/7CGl/xEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE6D/ggud//8Zw///
+ HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//
+ HtL//x7S//8e0v//F7z//wud//8Sn/9eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjpv8E
+ D57/vQyf//8axv//HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//
+ HtL//x7S//8e0v//HtL//xjA//8Lnf//EJ//nQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAVoP8PDZ7/ygyf//8Yv///HtL//x7S//8e0v//HtL//x7S//8e0v//HtL//x7S//8e0v//
+ HtL//x7S//8e0v//HtL//x7R//8Wuf//C53//w2d/68pqP8GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAbo/8MD57/rgud//8Srv//HMr//x7S//8e0v//HtL//x7S//8e0v//
+ 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
+
+
+
\ No newline at end of file
diff --git a/solution/Safetensors.Inspector.UX/metadata.json b/solution/Safetensors.Inspector.UX/metadata.json
new file mode 100644
index 0000000..f1a6d4c
--- /dev/null
+++ b/solution/Safetensors.Inspector.UX/metadata.json
@@ -0,0 +1,217 @@
+[
+ {
+ "PropertyName": "ss_sd_model_name",
+ "Description": "Model Name",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_clip_skip",
+ "Description": "Clip Skip",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_num_train_images",
+ "Description": "Number of Training Images",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_tag_frequency",
+ "Description": "Tag Frequency",
+ "MetadataType": "TagFrequency"
+ },
+ {
+ "PropertyName": "ss_epoch",
+ "Description": "Epochs",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_face_crop_aug_range",
+ "Description": "Face Crop Augmentation Range",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_full_fp16",
+ "Description": "Full FP16",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_gradient_accumulation_steps",
+ "Description": "Gradient Accumulation Steps",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_gradient_checkpointing",
+ "Description": "Gradient Checkpointing",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_learning_rate",
+ "Description": "Learning Rate",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_lowram",
+ "Description": "Low RAM",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_lr_scheduler",
+ "Description": "Learning Rate Scheduler",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_lr_warmup_steps",
+ "Description": "Learning Rate Warmup Steps",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_max_grad_norm",
+ "Description": "Max Gradient Norm",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_max_token_length",
+ "Description": "Max Token Length",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_max_train_steps",
+ "Description": "Max Training Steps",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_min_snr_gamma",
+ "Description": "Min SNR Gamma",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_mixed_precision",
+ "Description": "Mixed Precision",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_network_alpha",
+ "Description": "Network Alpha",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_network_dim",
+ "Description": "Network Dimension",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_network_module",
+ "Description": "Network Module",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_new_sd_model_hash",
+ "Description": "New SD Model Hash",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_noise_offset",
+ "Description": "Noise Offset",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_num_batches_per_epoch",
+ "Description": "Number of Batches per Epoch",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_cache_latents",
+ "Description": "Cache Latents",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_caption_dropout_every_n_epochs",
+ "Description": "Caption Dropout Every N Epochs",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_caption_dropout_rate",
+ "Description": "Caption Dropout Rate",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_caption_tag_dropout_rate",
+ "Description": "Caption Tag Dropout Rate",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_dataset_dirs",
+ "Description": "Dataset Directories",
+ "MetadataType": "DatasetDirs"
+ },
+ {
+ "PropertyName": "ss_num_epochs",
+ "Description": "Number of Epochs",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_num_reg_images",
+ "Description": "Number of Regression Images",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_optimizer",
+ "Description": "Optimizer",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_output_name",
+ "Description": "Output Name",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_prior_loss_weight",
+ "Description": "Prior Loss Weight",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_sd_model_hash",
+ "Description": "SD Model Hash",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_sd_scripts_commit_hash",
+ "Description": "SD Scripts Commit Hash",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_seed",
+ "Description": "Seed",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_session_id",
+ "Description": "Session ID",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_text_encoder_lr",
+ "Description": "Text Encoder Learning Rate",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_unet_lr",
+ "Description": "UNet Learning Rate",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "ss_v2",
+ "Description": "Version 2",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "sshs_legacy_hash",
+ "Description": "SSHS Legacy Hash",
+ "MetadataType": null
+ },
+ {
+ "PropertyName": "sshs_model_hash",
+ "Description": "SSHS Model Hash",
+ "MetadataType": null
+ }
+]
diff --git a/solution/Safetensors.Inspector.sln b/solution/Safetensors.Inspector.sln
new file mode 100644
index 0000000..aa53b6a
--- /dev/null
+++ b/solution/Safetensors.Inspector.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.9.34622.214
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Safetensors.Core", "Safetensors.Core\Safetensors.Core.csproj", "{54B18D7C-81C8-4A7D-B76A-7D7D7E56DCA4}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Safetensors.Storage", "Safetensors.Storage\Safetensors.Storage.csproj", "{5F68C471-F3AB-4CE9-9B9B-4C4B7E64620B}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Safetensors.Inspector.UX", "Safetensors.Inspector.UX\Safetensors.Inspector.UX.csproj", "{C8AE8BE9-3348-4266-ACE7-41135095C77C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {54B18D7C-81C8-4A7D-B76A-7D7D7E56DCA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {54B18D7C-81C8-4A7D-B76A-7D7D7E56DCA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {54B18D7C-81C8-4A7D-B76A-7D7D7E56DCA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {54B18D7C-81C8-4A7D-B76A-7D7D7E56DCA4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5F68C471-F3AB-4CE9-9B9B-4C4B7E64620B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5F68C471-F3AB-4CE9-9B9B-4C4B7E64620B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5F68C471-F3AB-4CE9-9B9B-4C4B7E64620B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5F68C471-F3AB-4CE9-9B9B-4C4B7E64620B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C8AE8BE9-3348-4266-ACE7-41135095C77C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C8AE8BE9-3348-4266-ACE7-41135095C77C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C8AE8BE9-3348-4266-ACE7-41135095C77C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C8AE8BE9-3348-4266-ACE7-41135095C77C}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {E916A7EE-2FD7-4833-86C8-17746EE48951}
+ EndGlobalSection
+EndGlobal
diff --git a/solution/Safetensors.Storage/ConfigurationReader.cs b/solution/Safetensors.Storage/ConfigurationReader.cs
new file mode 100644
index 0000000..463cbe9
--- /dev/null
+++ b/solution/Safetensors.Storage/ConfigurationReader.cs
@@ -0,0 +1,24 @@
+using Safetensors.Core;
+using System.Text.Json;
+
+namespace Safetensors.Storage
+{
+ ///
+ /// Configuration reader
+ ///
+ public class ConfigurationReader : IConfigurationReader
+ {
+ ///
+ /// Load metadata property configuration
+ ///
+ /// List of Safetensor metadata properties
+ public async Task?> LoadMetadataPropertyConfigAsync()
+ {
+ using var reader = new StreamReader(@"./metadata.json");
+
+ var results = await JsonSerializer.DeserializeAsync>(reader.BaseStream);
+
+ return results;
+ }
+ }
+}
diff --git a/solution/Safetensors.Storage/Safetensors.Storage.csproj b/solution/Safetensors.Storage/Safetensors.Storage.csproj
new file mode 100644
index 0000000..faaad8a
--- /dev/null
+++ b/solution/Safetensors.Storage/Safetensors.Storage.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net8.0
+ enable
+ enable
+ none
+
+
+
+
+
+
+
diff --git a/solution/Safetensors.Storage/SafetensorsReader.cs b/solution/Safetensors.Storage/SafetensorsReader.cs
new file mode 100644
index 0000000..5956dee
--- /dev/null
+++ b/solution/Safetensors.Storage/SafetensorsReader.cs
@@ -0,0 +1,107 @@
+using Safetensors.Core;
+using System.Text.Json.Nodes;
+
+namespace Safetensors.Storage
+{
+ ///
+ /// Safeensor reader
+ ///
+ public class SafetensorReader : ISafetensorsReader
+ {
+ ///
+ /// Safetensor header size in bytes
+ ///
+ private const int HEADER_SIZE = 8;
+
+ ///
+ /// Metadata configuration
+ ///
+ private IList? _metadataConfig { get; set; }
+
+ ///
+ /// Initialize the Safetenso reader
+ ///
+ public async Task InitializeAsync()
+ {
+ var cr = new ConfigurationReader();
+ _metadataConfig = await cr.LoadMetadataPropertyConfigAsync();
+ }
+
+ ///
+ /// Async read of .safetensor file
+ ///
+ /// File path of the .safetensor file
+ /// SafetensorFile object
+ public async Task ReadAsync(string path)
+ {
+ if (File.Exists(path))
+ {
+ // open file
+ using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+
+ // get size of the header from first 8 bytes
+ byte[] arrHeaderSize = new byte[HEADER_SIZE];
+ await fs.ReadAsync(arrHeaderSize);
+
+ // get header size
+ UInt64 headerSize = BitConverter.ToUInt64(arrHeaderSize, 0);
+
+ // reader header into buffer
+ byte[] arrHeader = new byte[headerSize];
+ await fs.ReadAsync(arrHeader);
+
+ // convert header to string
+ var strHeader = System.Text.Encoding.ASCII.GetString(arrHeader);
+
+ // create safetensor file object
+ var sf = new SafetensorsFile(path, strHeader);
+
+ // parse the header
+ JsonNode? jsonNode = JsonNode.Parse(strHeader);
+ if (jsonNode != null)
+ {
+ // get the default __metadata__ property
+ var nodeMetadata = jsonNode[sf.Metadata.PropertyName];
+
+ // if property exists and metadata configuration exists
+ if ((nodeMetadata != null) && (_metadataConfig != null))
+ {
+ await PopulateMetadataProperties(sf.Metadata, nodeMetadata);
+ }
+ }
+
+ return sf;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Populate metadata properties for the safetensor file object
+ ///
+ /// Safetensor metadata
+ /// Json node data loaded from the safetensor file
+ ///
+ private async Task PopulateMetadataProperties(ISafetensorsMetadata metadata, JsonNode nodeMetadata)
+ {
+ await Task.Run(() =>
+ _metadataConfig?.ToList().ForEach(p =>
+ {
+ // try to get string value
+ var data = nodeMetadata[p.PropertyName]?.ToString();
+
+ // check if data exists and add if it does
+ if (!string.IsNullOrEmpty(data))
+ metadata.Properties.Add(
+ new SafetensorsMetadataProperty
+ {
+ PropertyName = p.PropertyName,
+ Description = p.Description,
+ Value = data,
+ MetadataType = p.MetadataType
+ });
+ })
+ );
+ }
+ }
+}