diff --git a/fxl.codes.kisekae.blazor/Components/Pages/Home.razor b/fxl.codes.kisekae.blazor/Components/Pages/Home.razor
index 7e9f85c..bfb588d 100644
--- a/fxl.codes.kisekae.blazor/Components/Pages/Home.razor
+++ b/fxl.codes.kisekae.blazor/Components/Pages/Home.razor
@@ -1,7 +1,75 @@
-@page "/"
+@page "/{configId:int?}"
+@using System.Diagnostics
+@using fxl.codes.kisekae.data
+@using fxl.codes.kisekae.data.Entities
+@inject KisekaeContext Context
+@inject IWebHostEnvironment Environment
+@rendermode InteractiveServer
Kisekae
-
Hello, world!
+@if (ConfigId.HasValue)
+{
+ @Current!.Name
+}
+else
+{
+ Existing Sets
+
+ @foreach (var set in AllConfigurations)
+ {
+ - @set.Name
+ }
+
+}
-Welcome to your new app.
\ No newline at end of file
+
+
+@code {
+ [Parameter] public int? ConfigId { get; set; }
+
+ private IEnumerable AllConfigurations { get; set; } = ArraySegment.Empty;
+ private Configuration? Current { get; set; }
+
+ protected override Task OnInitializedAsync()
+ {
+ if (ConfigId.HasValue)
+ {
+ Current = Context.Configurations.Find(ConfigId.Value);
+ }
+ else
+ {
+ AllConfigurations = Context.Configurations.ToArray();
+ }
+
+ return base.OnInitializedAsync();
+ }
+
+ private async Task Unzip(InputFileChangeEventArgs upload)
+ {
+ var path = Path.Combine(Environment.ContentRootPath, "temp");
+ if (!Directory.Exists(path)) throw new Exception("temp directory doesn't exist");
+
+ var filename = Path.Combine(path, upload.File.Name);
+ var directory = Path.Combine(path, Path.GetFileNameWithoutExtension(upload.File.Name));
+ if (!File.Exists(filename))
+ {
+ await using var stream = new FileStream(filename, FileMode.Create);
+ await upload.File.OpenReadStream().CopyToAsync(stream);
+ await stream.FlushAsync();
+ stream.Close();
+ }
+
+ if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);
+
+ if (!Directory.GetFiles(directory).Any())
+ {
+ var processName = OperatingSystem.IsWindows() ? "7z.exe" : OperatingSystem.IsMacOS() ? "7zz" : "7zzl";
+ var args = $"\"{Path.Combine(".", "Libraries", processName)}\" x {filename} -o\"{directory}\"";
+
+ var process = Process.Start(processName, args);
+ await process.WaitForExitAsync();
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/fxl.codes.kisekae.blazor/Program.cs b/fxl.codes.kisekae.blazor/Program.cs
index 775f4bb..d2cd6d6 100644
--- a/fxl.codes.kisekae.blazor/Program.cs
+++ b/fxl.codes.kisekae.blazor/Program.cs
@@ -12,10 +12,7 @@ builder.Services.AddDbContextFactory(options => { options.UseNpg
var app = builder.Build();
// Configure the HTTP request pipeline.
-if (!app.Environment.IsDevelopment())
-{
- app.UseExceptionHandler("/Error", createScopeForErrors: true);
-}
+if (!app.Environment.IsDevelopment()) app.UseExceptionHandler("/Error", true);
app.UseStaticFiles();
app.UseAntiforgery();
diff --git a/fxl.codes.kisekae.blazor/fxl.codes.kisekae.blazor.csproj b/fxl.codes.kisekae.blazor/fxl.codes.kisekae.blazor.csproj
index 3bf6020..d72cbff 100644
--- a/fxl.codes.kisekae.blazor/fxl.codes.kisekae.blazor.csproj
+++ b/fxl.codes.kisekae.blazor/fxl.codes.kisekae.blazor.csproj
@@ -7,11 +7,15 @@
-
+
-
+
+
+
+
+
diff --git a/fxl.codes.kisekae.data/Archives/LHArchiveDecoder.cs b/fxl.codes.kisekae.data/Archives/LHArchiveDecoder.cs
new file mode 100644
index 0000000..dcdafda
--- /dev/null
+++ b/fxl.codes.kisekae.data/Archives/LHArchiveDecoder.cs
@@ -0,0 +1,81 @@
+namespace fxl.codes.kisekae.data.Archives;
+
+/**
+ * Ported from https://github.com/kisekae/UltraKiss/blob/master/src/Kisekae/Lhhuf.java
+ */
+public class LhArchiveDecoder
+{
+ private const int Buffer = 4096;
+ private const int BufferSize = 60;
+ private const int Threshold = 2;
+ private const int EndOfFile = -1;
+ private const int NChar = 256 - Threshold + BufferSize; // For some reason????
+ private const int TableSize = NChar * 2 - 1;
+ private const int RootPosition = TableSize - 1;
+ private const int MaxFreq = 0x8000;
+ private readonly int[] _child = new int[TableSize];
+ private readonly int[] _frequency = new int[TableSize];
+ private readonly int[] _parent = new int[TableSize + NChar];
+
+ private int _bytesProcessed;
+ private int[] _data = new int[Buffer + 1];
+ private int _lastBytesProcessed;
+ private int[] _leftChild = new int[Buffer + 1];
+ private int[] _rightChild = new int[Buffer * 2 + 1];
+ private int[] _same = new int[Buffer + 1];
+ private byte[] _textBuffer = new byte[Buffer + BufferSize - 1];
+ private int putlen, getlen, putbuf, getbuf;
+
+ private void Initialize()
+ {
+ for (var i = 0; i < NChar; i++)
+ {
+ _frequency[i] = 1;
+ _child[i] = i + TableSize;
+ _parent[i + TableSize] = i;
+ }
+
+ for (int i = 0, j = NChar; j <= RootPosition; i += 2, j++)
+ {
+ _frequency[j] = _frequency[i] + _frequency[i + 1];
+ _child[j] = i;
+ _parent[i] = _parent[i + 1] = j;
+ }
+
+ _frequency[TableSize] = 0xffff;
+ _parent[RootPosition] = 0;
+ }
+
+ private void Reconstruct()
+ {
+ int k;
+ for (int i = 0, j = 0; i < TableSize; i++, j++)
+ {
+ if (_child[i] < TableSize) continue;
+
+ _frequency[j] = (_frequency[i] + 1) / 2;
+ _child[j] = _child[i];
+ }
+
+ for (int i = 0, j = NChar; j < TableSize; i += 2, j++)
+ {
+ k = i + 1;
+ var f = _frequency[j] = _frequency[i] + _frequency[k];
+ for (k = j - 1; f < _frequency[k]; k--);
+ k++;
+
+ for (int p = j, e = k; p > e; p--) _frequency[p] = _frequency[p - 1];
+ _frequency[k] = f;
+
+ for (var p = j; p > k; p--) _child[p] = _child[p - 1];
+ _child[k] = i;
+ }
+
+ /* link parents */
+ for (var i = 0; i < TableSize; i++)
+ if ((k = _child[i]) >= TableSize)
+ _parent[k] = i;
+ else
+ _parent[k] = _parent[k + 1] = i;
+ }
+}
\ No newline at end of file
diff --git a/fxl.codes.kisekae.data/Archives/LzhExtractor.cs b/fxl.codes.kisekae.data/Archives/LzhExtractor.cs
new file mode 100644
index 0000000..8f6aea1
--- /dev/null
+++ b/fxl.codes.kisekae.data/Archives/LzhExtractor.cs
@@ -0,0 +1,34 @@
+using System.Text;
+
+namespace fxl.codes.kisekae.data.Archives;
+
+public class LzhExtractor
+{
+ public async void Open(Stream stream, string filename)
+ {
+ var headerSize = stream.ReadByte();
+ var headerSum = stream.ReadByte();
+ var methodBytes = new byte[5];
+ await stream.ReadExactlyAsync(methodBytes);
+
+ var method = Encoding.ASCII.GetString(methodBytes);
+ var skipSize = await ReadLittleEndian(stream);
+ var origSize = await ReadLittleEndian(stream);
+ var time = await ReadLittleEndian(stream);
+ var attribute = stream.ReadByte();
+ var level = stream.ReadByte();
+ }
+
+ private static async Task ReadLittleEndian(Stream stream, int length = 4)
+ {
+ var buffer = new byte[length];
+ await stream.ReadExactlyAsync(buffer);
+ var x = BitConverter.ToInt32(buffer);
+
+ var b0 = (x >> 24) & 255;
+ var b1 = (x >> 16) & 255;
+ var b2 = (x >> 8) & 255;
+ var b3 = (x >> 0) & 255;
+ return (b0 << 0) + (b1 << 8) + (b2 << 16) + (b3 << 24);
+ }
+}
\ No newline at end of file
diff --git a/fxl.codes.kisekae.data/Libraries/7z.dll b/fxl.codes.kisekae.data/Libraries/7z.dll
deleted file mode 100755
index 9295b54..0000000
Binary files a/fxl.codes.kisekae.data/Libraries/7z.dll and /dev/null differ
diff --git a/fxl.codes.kisekae.data/Libraries/7z.exe b/fxl.codes.kisekae.data/Libraries/7z.exe
deleted file mode 100755
index 00fc388..0000000
Binary files a/fxl.codes.kisekae.data/Libraries/7z.exe and /dev/null differ
diff --git a/fxl.codes.kisekae.data/Libraries/7zz b/fxl.codes.kisekae.data/Libraries/7zz
deleted file mode 100755
index b9aaac2..0000000
Binary files a/fxl.codes.kisekae.data/Libraries/7zz and /dev/null differ
diff --git a/fxl.codes.kisekae.data/Libraries/7zzl b/fxl.codes.kisekae.data/Libraries/7zzl
deleted file mode 100755
index c63805f..0000000
Binary files a/fxl.codes.kisekae.data/Libraries/7zzl and /dev/null differ
diff --git a/fxl.codes.kisekae.data/fxl.codes.kisekae.data.csproj b/fxl.codes.kisekae.data/fxl.codes.kisekae.data.csproj
index ce9d1a5..383954d 100644
--- a/fxl.codes.kisekae.data/fxl.codes.kisekae.data.csproj
+++ b/fxl.codes.kisekae.data/fxl.codes.kisekae.data.csproj
@@ -19,27 +19,4 @@
-
-
-
-
-
-
-
- PreserveNewest
-
-
-
- PreserveNewest
-
-
-
- PreserveNewest
-
-
-
- PreserveNewest
-
-
-