From 9481380a288be0fce191372d52585acb05cdcc8f Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 6 Aug 2024 21:06:17 +0200
Subject: [PATCH 01/55] Don't use BuiltinType.I/U128, use AlgebraicType.I/U128
 (#116)

## Description of Changes

Required to make "SDK Tests" pass in
https://github.com/clockworklabs/SpacetimeDB/pull/1559.

## API

Not breaking.

## Requires SpacetimeDB PRs

- https://github.com/clockworklabs/SpacetimeDB/pull/1559

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 src/Primitives.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/Primitives.cs b/src/Primitives.cs
index 9466cca5..93ba5e98 100644
--- a/src/Primitives.cs
+++ b/src/Primitives.cs
@@ -39,7 +39,7 @@ public void Write(BinaryWriter writer, I128 value)
             }
 
             public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>
-                new AlgebraicType.Builtin(new BuiltinType.I128(new Unit()));
+                new AlgebraicType.I128(new Unit());
         }
     }
 
@@ -76,7 +76,7 @@ public void Write(BinaryWriter writer, U128 value)
             }
 
             public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>
-                new AlgebraicType.Builtin(new BuiltinType.U128(new Unit()));
+                new AlgebraicType.U128(new Unit());
         }
     }
 

From ae7c531e79bde2bb8902175432373d2440523dd7 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <196249+bfops@users.noreply.github.com>
Date: Tue, 6 Aug 2024 12:28:53 -0700
Subject: [PATCH 02/55] Restore `dotnet pack` functionality (#118)

## Description of Changes
Single-line change so that `dotnet pack` stops complaining that nothing
was generated.

Per @RReverser this brings this package more in line with our other C#
packages.

## API
Nah nothing breaking.

## Requires SpacetimeDB PRs
Nope

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 SpacetimeDB.ClientSDK.csproj | 1 -
 1 file changed, 1 deletion(-)

diff --git a/SpacetimeDB.ClientSDK.csproj b/SpacetimeDB.ClientSDK.csproj
index 72a34580..058f8101 100644
--- a/SpacetimeDB.ClientSDK.csproj
+++ b/SpacetimeDB.ClientSDK.csproj
@@ -5,7 +5,6 @@
     <LangVersion>9</LangVersion>
     <ImplicitUsings>disable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
     <PackageId>SpacetimeDB.ClientSDK</PackageId>
     <Title>SpacetimeDB SDK</Title>
     <Authors>jdetter</Authors>

From 5e612f37dcd5137284cbd2c140f861eb53958c7c Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Wed, 7 Aug 2024 13:39:13 -0400
Subject: [PATCH 03/55] Update DEVELOP.md to reflect new codegen (#119)

Also ran it again, committing a few generation changes too :)
---
 DEVELOP.md                                    | 17 +++-------------
 src/SpacetimeDB/ClientApi/CallReducer.cs      |  5 ++---
 src/SpacetimeDB/ClientApi/ClientMessage.cs    |  1 +
 src/SpacetimeDB/ClientApi/DatabaseUpdate.cs   |  3 ++-
 src/SpacetimeDB/ClientApi/EnergyQuanta.cs     |  3 ++-
 src/SpacetimeDB/ClientApi/IdentityToken.cs    |  5 ++---
 .../ClientApi/InitialSubscription.cs          |  5 ++---
 src/SpacetimeDB/ClientApi/OneOffQuery.cs      |  4 ++--
 .../ClientApi/OneOffQueryResponse.cs          |  8 +++-----
 src/SpacetimeDB/ClientApi/OneOffTable.cs      |  6 +++---
 src/SpacetimeDB/ClientApi/ReducerCallInfo.cs  |  6 ++----
 src/SpacetimeDB/ClientApi/ServerMessage.cs    |  1 +
 src/SpacetimeDB/ClientApi/Subscribe.cs        |  4 ++--
 src/SpacetimeDB/ClientApi/TableUpdate.cs      | 10 ++++------
 .../ClientApi/TransactionUpdate.cs            |  7 +------
 tools/gen-client-api.bat                      | 20 +++++++++++++++++++
 tools/gen-client-api.sh                       | 15 ++++++++++++++
 17 files changed, 67 insertions(+), 53 deletions(-)
 create mode 100644 tools/gen-client-api.bat
 create mode 100644 tools/gen-client-api.sh

diff --git a/DEVELOP.md b/DEVELOP.md
index de08bc70..4f24f4d6 100644
--- a/DEVELOP.md
+++ b/DEVELOP.md
@@ -1,17 +1,6 @@
 # Notes for maintainers
 
-## `ClientApi.cs`
+## `SpacetimeDB.ClientApi`
 
-The file `ClientApi.cs` is generated by [ProtoBuf](https://protobuf.dev/)
-from [the SpacetimeDB client-api-messages proto definition](https://github.com/clockworklabs/SpacetimeDB/blob/master/crates/client-api-messages/protobuf/client_api.proto).
-This is not automated.
-Whenever the `client_api.proto` changes, you'll have to manually re-run `protoc` to re-generate the definitions.
-
-```sh
-cd ~/clockworklabs/SpacetimeDB/crates/client-api-messages/protobuf
-protoc --csharp_out=/absolute/path/to/spacetimedb-csharp-sdk/src \
-  ./client_api.proto
-```
-
-Note that `protoc` cannot understand paths that start with `~`;
-you must write the absolute path starting from `/`.
+To regenerate this namespace, run the `tools/gen-client-api.sh` or the
+`tools/gen-client-api.bat` script.
diff --git a/src/SpacetimeDB/ClientApi/CallReducer.cs b/src/SpacetimeDB/ClientApi/CallReducer.cs
index 0d065d40..d3f56f38 100644
--- a/src/SpacetimeDB/ClientApi/CallReducer.cs
+++ b/src/SpacetimeDB/ClientApi/CallReducer.cs
@@ -12,17 +12,16 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class CallReducer
 	{
 		[DataMember(Name = "reducer")]
 		public string Reducer = "";
-
 		[DataMember(Name = "args")]
 		public SpacetimeDB.ClientApi.EncodedValue Args = null!;
-
 		[DataMember(Name = "request_id")]
 		public uint RequestId;
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/ClientMessage.cs b/src/SpacetimeDB/ClientApi/ClientMessage.cs
index 4badf680..9cb1c4c7 100644
--- a/src/SpacetimeDB/ClientApi/ClientMessage.cs
+++ b/src/SpacetimeDB/ClientApi/ClientMessage.cs
@@ -5,6 +5,7 @@
 #nullable enable
 
 using System;
+using SpacetimeDB;
 
 namespace SpacetimeDB.ClientApi
 {
diff --git a/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs b/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs
index 0cf2567e..245117ad 100644
--- a/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs
@@ -12,11 +12,12 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class DatabaseUpdate
 	{
 		[DataMember(Name = "tables")]
 		public System.Collections.Generic.List<SpacetimeDB.ClientApi.TableUpdate> Tables = new();
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/EnergyQuanta.cs b/src/SpacetimeDB/ClientApi/EnergyQuanta.cs
index 7cd07b36..ba142cb3 100644
--- a/src/SpacetimeDB/ClientApi/EnergyQuanta.cs
+++ b/src/SpacetimeDB/ClientApi/EnergyQuanta.cs
@@ -12,11 +12,12 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class EnergyQuanta
 	{
 		[DataMember(Name = "quanta")]
 		public U128 Quanta;
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/IdentityToken.cs b/src/SpacetimeDB/ClientApi/IdentityToken.cs
index b1bbd183..344cbbba 100644
--- a/src/SpacetimeDB/ClientApi/IdentityToken.cs
+++ b/src/SpacetimeDB/ClientApi/IdentityToken.cs
@@ -12,17 +12,16 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class IdentityToken
 	{
 		[DataMember(Name = "identity")]
 		public SpacetimeDB.Identity Identity = new();
-
 		[DataMember(Name = "token")]
 		public string Token = "";
-
 		[DataMember(Name = "address")]
 		public SpacetimeDB.Address Address = new();
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/InitialSubscription.cs b/src/SpacetimeDB/ClientApi/InitialSubscription.cs
index ed704238..06ae7ba8 100644
--- a/src/SpacetimeDB/ClientApi/InitialSubscription.cs
+++ b/src/SpacetimeDB/ClientApi/InitialSubscription.cs
@@ -12,17 +12,16 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class InitialSubscription
 	{
 		[DataMember(Name = "database_update")]
 		public SpacetimeDB.ClientApi.DatabaseUpdate DatabaseUpdate = new();
-
 		[DataMember(Name = "request_id")]
 		public uint RequestId;
-
 		[DataMember(Name = "total_host_execution_duration_micros")]
 		public ulong TotalHostExecutionDurationMicros;
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/OneOffQuery.cs b/src/SpacetimeDB/ClientApi/OneOffQuery.cs
index c4625fe5..c103c829 100644
--- a/src/SpacetimeDB/ClientApi/OneOffQuery.cs
+++ b/src/SpacetimeDB/ClientApi/OneOffQuery.cs
@@ -12,14 +12,14 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class OneOffQuery
 	{
 		[DataMember(Name = "message_id")]
 		public byte[] MessageId = Array.Empty<byte>();
-
 		[DataMember(Name = "query_string")]
 		public string QueryString = "";
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs b/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs
index 4e98289f..35c1d0eb 100644
--- a/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs
+++ b/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs
@@ -12,20 +12,18 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class OneOffQueryResponse
 	{
 		[DataMember(Name = "message_id")]
 		public byte[] MessageId = Array.Empty<byte>();
-
 		[DataMember(Name = "error")]
 		public string? Error;
-
 		[DataMember(Name = "tables")]
-		public List<SpacetimeDB.ClientApi.OneOffTable> Tables = new();
-
+		public System.Collections.Generic.List<SpacetimeDB.ClientApi.OneOffTable> Tables = new();
 		[DataMember(Name = "total_host_execution_duration_micros")]
 		public ulong TotalHostExecutionDurationMicros;
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/OneOffTable.cs b/src/SpacetimeDB/ClientApi/OneOffTable.cs
index 84fa81bf..12f7e0f9 100644
--- a/src/SpacetimeDB/ClientApi/OneOffTable.cs
+++ b/src/SpacetimeDB/ClientApi/OneOffTable.cs
@@ -12,14 +12,14 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class OneOffTable
 	{
 		[DataMember(Name = "table_name")]
 		public string TableName = "";
-
 		[DataMember(Name = "rows")]
-		public List<SpacetimeDB.ClientApi.EncodedValue> Rows = new();
+		public System.Collections.Generic.List<SpacetimeDB.ClientApi.EncodedValue> Rows = new();
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs b/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs
index 86a67416..44bc8865 100644
--- a/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs
+++ b/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs
@@ -12,20 +12,18 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class ReducerCallInfo
 	{
 		[DataMember(Name = "reducer_name")]
 		public string ReducerName = "";
-
 		[DataMember(Name = "reducer_id")]
 		public uint ReducerId;
-
 		[DataMember(Name = "args")]
 		public SpacetimeDB.ClientApi.EncodedValue Args = null!;
-
 		[DataMember(Name = "request_id")]
 		public uint RequestId;
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/ServerMessage.cs b/src/SpacetimeDB/ClientApi/ServerMessage.cs
index 7f4bf714..46b5be3a 100644
--- a/src/SpacetimeDB/ClientApi/ServerMessage.cs
+++ b/src/SpacetimeDB/ClientApi/ServerMessage.cs
@@ -5,6 +5,7 @@
 #nullable enable
 
 using System;
+using SpacetimeDB;
 
 namespace SpacetimeDB.ClientApi
 {
diff --git a/src/SpacetimeDB/ClientApi/Subscribe.cs b/src/SpacetimeDB/ClientApi/Subscribe.cs
index e844a347..d5eaba81 100644
--- a/src/SpacetimeDB/ClientApi/Subscribe.cs
+++ b/src/SpacetimeDB/ClientApi/Subscribe.cs
@@ -12,14 +12,14 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class Subscribe
 	{
 		[DataMember(Name = "query_strings")]
 		public System.Collections.Generic.List<string> QueryStrings = new();
-
 		[DataMember(Name = "request_id")]
 		public uint RequestId;
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/TableUpdate.cs b/src/SpacetimeDB/ClientApi/TableUpdate.cs
index 63400ee6..b9b47ea5 100644
--- a/src/SpacetimeDB/ClientApi/TableUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/TableUpdate.cs
@@ -12,20 +12,18 @@
 
 namespace SpacetimeDB.ClientApi
 {
-	[DataContract]
 	[SpacetimeDB.Type]
+	[DataContract]
 	public partial class TableUpdate
 	{
 		[DataMember(Name = "table_id")]
 		public uint TableId;
-
 		[DataMember(Name = "table_name")]
 		public string TableName = "";
-
 		[DataMember(Name = "deletes")]
-		public List<SpacetimeDB.ClientApi.EncodedValue> Deletes = new();
-
+		public System.Collections.Generic.List<SpacetimeDB.ClientApi.EncodedValue> Deletes = new();
 		[DataMember(Name = "inserts")]
-		public List<SpacetimeDB.ClientApi.EncodedValue> Inserts = new();
+		public System.Collections.Generic.List<SpacetimeDB.ClientApi.EncodedValue> Inserts = new();
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/TransactionUpdate.cs b/src/SpacetimeDB/ClientApi/TransactionUpdate.cs
index 5861e9ee..fb71dd9e 100644
--- a/src/SpacetimeDB/ClientApi/TransactionUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/TransactionUpdate.cs
@@ -18,23 +18,18 @@ public partial class TransactionUpdate
 	{
 		[DataMember(Name = "status")]
 		public SpacetimeDB.ClientApi.UpdateStatus Status = null!;
-
 		[DataMember(Name = "timestamp")]
 		public SpacetimeDB.ClientApi.Timestamp Timestamp = new();
-
 		[DataMember(Name = "caller_identity")]
 		public SpacetimeDB.Identity CallerIdentity = new();
-
 		[DataMember(Name = "caller_address")]
 		public SpacetimeDB.Address CallerAddress = new();
-
 		[DataMember(Name = "reducer_call")]
 		public SpacetimeDB.ClientApi.ReducerCallInfo ReducerCall = new();
-
 		[DataMember(Name = "energy_quanta_used")]
 		public SpacetimeDB.ClientApi.EnergyQuanta EnergyQuantaUsed = new();
-
 		[DataMember(Name = "host_execution_duration_micros")]
 		public ulong HostExecutionDurationMicros;
+
 	}
 }
diff --git a/tools/gen-client-api.bat b/tools/gen-client-api.bat
new file mode 100644
index 00000000..9eb66c49
--- /dev/null
+++ b/tools/gen-client-api.bat
@@ -0,0 +1,20 @@
+@echo off
+setlocal
+
+if "%CL_HOME%"=="" (
+  echo "Variable CL_HOME not set"
+  exit /b 1
+)
+
+cd %CL_HOME%\SpacetimeDB\crates\client-api-messages
+cargo run --example get_ws_schema > %CL_HOME%/schema.json
+
+cd %CL_HOME%\SpacetimeDB\crates\cli
+cargo run -- generate -l csharp -n SpacetimeDB.ClientApi ^
+  --json-module %CL_HOME%\schema.json ^
+  -o %CL_HOME%\spacetimedb-csharp-sdk\src\SpacetimeDB\ClientApi
+
+cd %CL_HOME%\spacetimedb-csharp-sdk\src\SpacetimeDB\ClientApi
+del /q _Globals
+
+del %CL_HOME%\schema.json
diff --git a/tools/gen-client-api.sh b/tools/gen-client-api.sh
new file mode 100644
index 00000000..91fbe3da
--- /dev/null
+++ b/tools/gen-client-api.sh
@@ -0,0 +1,15 @@
+#!/bin/sh -eu
+: $CL_HOME
+
+cd $CL_HOME/SpacetimeDB/crates/client-api-messages
+cargo run --example get_ws_schema > $CL_HOME/schema.json
+
+cd $CL_HOME/SpacetimeDB/crates/cli
+cargo run -- generate -l csharp -n SpacetimeDB.ClientApi \
+  --json-module $CL_HOME/schema.json \
+  -o $CL_HOME/spacetimedb-csharp-sdk/src/SpacetimeDB/ClientApi
+
+cd $CL_HOME/spacetimedb-csharp-sdk/src/SpacetimeDB/ClientApi
+rm -rf _Globals
+
+rm -f $CL_HOME/schema.json

From 9904a0232ba77cdccc75b769e8a5003dffff6da6 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 13 Aug 2024 22:02:39 +0200
Subject: [PATCH 04/55] Nix `Primitives.cs` - types now defined in main repo
 (#120)

## Description of Changes

These types have been moved to the main repo, where they are used by
bindings-csharp as well.

## Requires SpacetimeDB PRs

- https://github.com/clockworklabs/SpacetimeDB/pull/1477

---------

Co-authored-by: Ingvar Stepanyan <me@rreverser.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 SpacetimeDB.ClientSDK.csproj |  4 +-
 src/Primitives.cs            | 83 ------------------------------------
 tests~/SnapshotTests.cs      | 16 ++-----
 3 files changed, 6 insertions(+), 97 deletions(-)
 delete mode 100644 src/Primitives.cs

diff --git a/SpacetimeDB.ClientSDK.csproj b/SpacetimeDB.ClientSDK.csproj
index 058f8101..1c2158b2 100644
--- a/SpacetimeDB.ClientSDK.csproj
+++ b/SpacetimeDB.ClientSDK.csproj
@@ -16,7 +16,7 @@
     <PackageIcon>logo.png</PackageIcon>
     <PackageReadmeFile>README.md</PackageReadmeFile>
     <RepositoryUrl>https://github.com/clockworklabs/spacetimedb-csharp-sdk</RepositoryUrl>
-    <AssemblyVersion>0.11.0</AssemblyVersion>
+    <AssemblyVersion>0.12.0</AssemblyVersion>
     <Version>$(AssemblyVersion)</Version>
     <DefaultItemExcludes>$(DefaultItemExcludes);*~/**</DefaultItemExcludes>
     <!-- We want to save DLLs for Unity which doesn't support NuGet. -->
@@ -24,7 +24,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="SpacetimeDB.BSATN.Runtime" Version="0.11.*" />
+    <PackageReference Include="SpacetimeDB.BSATN.Runtime" Version="0.12.*" />
 
     <InternalsVisibleTo Include="SpacetimeDB.Tests" />
   </ItemGroup>
diff --git a/src/Primitives.cs b/src/Primitives.cs
deleted file mode 100644
index 93ba5e98..00000000
--- a/src/Primitives.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-using SpacetimeDB.BSATN;
-
-using System;
-using System.IO;
-
-namespace SpacetimeDB
-{
-
-    public struct I128 : IEquatable<I128>
-    {
-        public long hi;
-        public ulong lo;
-
-        public I128(long hi, ulong lo)
-        {
-            this.hi = hi;
-            this.lo = lo;
-        }
-
-        public readonly bool Equals(I128 x) => hi == x.hi && lo == x.lo;
-
-        public override readonly bool Equals(object? o) => o is I128 x && Equals(x);
-
-        public static bool operator ==(I128 a, I128 b) => a.Equals(b);
-        public static bool operator !=(I128 a, I128 b) => !a.Equals(b);
-
-        public override readonly int GetHashCode() => hi.GetHashCode() ^ lo.GetHashCode();
-
-        public override readonly string ToString() => $"I128({hi},{lo})";
-
-        public readonly struct BSATN : IReadWrite<I128>
-        {
-            public I128 Read(BinaryReader reader) => new(reader.ReadInt64(), reader.ReadUInt64());
-
-            public void Write(BinaryWriter writer, I128 value)
-            {
-                writer.Write(value.hi);
-                writer.Write(value.lo);
-            }
-
-            public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>
-                new AlgebraicType.I128(new Unit());
-        }
-    }
-
-    public struct U128 : IEquatable<U128>
-    {
-        public ulong hi;
-        public ulong lo;
-
-        public U128(ulong hi, ulong lo)
-        {
-            this.lo = lo;
-            this.hi = hi;
-        }
-
-        public readonly bool Equals(U128 x) => hi == x.hi && lo == x.lo;
-
-        public override readonly bool Equals(object? o) => o is U128 x && Equals(x);
-
-        public static bool operator ==(U128 a, U128 b) => a.Equals(b);
-        public static bool operator !=(U128 a, U128 b) => !a.Equals(b);
-
-        public override readonly int GetHashCode() => hi.GetHashCode() ^ lo.GetHashCode();
-
-        public override readonly string ToString() => $"U128({hi},{lo})";
-
-        public readonly struct BSATN : IReadWrite<U128>
-        {
-            public U128 Read(BinaryReader reader) => new(reader.ReadUInt64(), reader.ReadUInt64());
-
-            public void Write(BinaryWriter writer, U128 value)
-            {
-                writer.Write(value.hi);
-                writer.Write(value.lo);
-            }
-
-            public AlgebraicType GetAlgebraicType(ITypeRegistrar registrar) =>
-                new AlgebraicType.U128(new Unit());
-        }
-    }
-
-}
diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs
index 8f722b3c..af4364c1 100644
--- a/tests~/SnapshotTests.cs
+++ b/tests~/SnapshotTests.cs
@@ -43,23 +43,15 @@ class EnergyQuantaConverter : WriteOnlyJsonConverter<EnergyQuanta>
     {
         public override void Write(VerifyJsonWriter writer, EnergyQuanta value)
         {
-            Assert.Equal(0uL, value.Quanta.hi);
-            writer.WriteValue(value.Quanta.lo);
+            writer.WriteRawValueIfNoStrict(value.Quanta.ToString());
         }
     }
 
-    class EncodedValueConverter : WriteOnlyJsonConverter<EncodedValue>
+    class EncodedValueConverter : WriteOnlyJsonConverter<EncodedValue.Binary>
     {
-        public override void Write(VerifyJsonWriter writer, EncodedValue value)
+        public override void Write(VerifyJsonWriter writer, EncodedValue.Binary value)
         {
-            if (value is EncodedValue.Binary(var bytes))
-            {
-                writer.WriteValue(bytes);
-            }
-            else
-            {
-                throw new InvalidOperationException();
-            }
+            writer.WriteValue(value.Binary_);
         }
     }
 

From 7941798b97108a3a20027b5b32180abb4f8b52b6 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <196249+bfops@users.noreply.github.com>
Date: Mon, 9 Sep 2024 17:27:55 -0700
Subject: [PATCH 05/55] Copy files from old repo (#127)

## Description of Changes
For some reason, this repo was not quite properly synced up with the
state of
https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk-archive
after https://github.com/clockworklabs/spacetimedb-csharp-sdk/pull/117.

It's unclear to me how this happened, since the current state seems to
be compatible with 0.11, but the [0.11 release
commit/PR](https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk-archive/commit/382cce05fecbc00caf7c7d060fbde9a2854ad981)
also bumped the `package.json` version, which didn't happen in this
repo.

I re-copied files over. Fortunately, the only real changes were to
`package.json` and `README.md`.

## API
No breaking changes.

## Requires SpacetimeDB PRs
None

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 README.md    | 3 +--
 package.json | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 189d6612..18cb6f04 100644
--- a/README.md
+++ b/README.md
@@ -6,10 +6,9 @@ This repository contains the [Unity](https://unity.com/) SDK for SpacetimeDB. Th
 
 ## Documentation
 
-The Unity SDK uses the same code as the C# SDK. You can find the documentation for the C# SDK in the [C# SDK Reference](README.dotnet.md).
+The Unity SDK uses the same code as the C# SDK. You can find the documentation for the C# SDK in the [C# SDK Reference](https://spacetimedb.com/docs/sdks/c-sharp)
 
 There is also a comprehensive Unity tutorial/demo available:
-
 - [Unity Tutorial](https://spacetimedb.com/docs/unity/part-1) Doc
 - [Unity Demo](https://github.com/clockworklabs/SpacetimeDBUnityTutorial) Repo
 
diff --git a/package.json b/package.json
index 8f6aa864..86f04059 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "com.clockworklabs.spacetimedbsdk",
   "displayName": "SpacetimeDB SDK",
-  "version": "0.10.0",
+  "version": "0.11.0",
   "description": "The SpacetimeDB Client SDK is a software development kit (SDK) designed to interact with and manipulate SpacetimeDB modules..",
   "keywords": [],
   "author": {

From 65c97adf29be57082d60d2b898a85553aa15bb6a Mon Sep 17 00:00:00 2001
From: SteveGibson <100594800+SteveBoytsun@users.noreply.github.com>
Date: Mon, 23 Sep 2024 13:52:50 -0400
Subject: [PATCH 06/55] Logging API (#132)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

Changed logging based on [this
proposal](https://github.com/clockworklabs/SpacetimeDBPrivate/pull/981)

## API

 - [x] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*

Logging interface is different now. `Logger` has been renamed to `Log`,
and its methods have been renamed as well (ex. `Logger.LogError` is now
`Log.Error`)


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

---------

Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
Co-authored-by: Jeremie Pelletier <jeremiep@gmail.com>
Co-authored-by: Steve Boytsun <steve@clockwokrlabs.io>
Co-authored-by: Ingvar Stepanyan <me@rreverser.com>
---
 .github/workflows/check-pr-base.yml | 22 ++++++++++++
 DEVELOP.md                          |  4 +--
 src/ClientCache.cs                  |  6 ++--
 src/ConsoleLogger.cs                | 52 +++++++++++++++++++++--------
 src/ISpacetimeDBLogger.cs           | 24 ++++++++-----
 src/SpacetimeDBClient.cs            | 50 +++++++++++++--------------
 src/UnityDebugLogger.cs             | 27 +++++++++++----
 src/WebSocket.cs                    |  2 +-
 tests~/SnapshotTests.cs             | 25 +++++++++++---
 tools~/gen-client-api.bat           | 20 +++++++++++
 tools~/gen-client-api.sh            | 15 +++++++++
 11 files changed, 183 insertions(+), 64 deletions(-)
 create mode 100644 .github/workflows/check-pr-base.yml
 create mode 100644 tools~/gen-client-api.bat
 create mode 100644 tools~/gen-client-api.sh

diff --git a/.github/workflows/check-pr-base.yml b/.github/workflows/check-pr-base.yml
new file mode 100644
index 00000000..73b71c27
--- /dev/null
+++ b/.github/workflows/check-pr-base.yml
@@ -0,0 +1,22 @@
+name: Git tree checks
+
+on:
+  pull_request:
+    types: [opened, edited, reopened, synchronize]
+  merge_group:
+permissions: read-all
+
+jobs:
+  check_base_ref:
+    name: Only release branches may merge into master
+    runs-on: ubuntu-latest
+    steps:
+      - id: not_based_on_master
+        if: |
+          github.event_name == 'pull_request' &&
+          github.event.pull_request.base.ref == 'master' &&
+          ! startsWith(github.event.pull_request.head.ref, 'release/')
+        run: |
+          echo 'Only `release/*` branches are allowed to merge into `master`.'
+          echo 'Maybe your PR should be merging into `staging`?'
+          exit 1
diff --git a/DEVELOP.md b/DEVELOP.md
index 4f24f4d6..2b9ac7d9 100644
--- a/DEVELOP.md
+++ b/DEVELOP.md
@@ -2,5 +2,5 @@
 
 ## `SpacetimeDB.ClientApi`
 
-To regenerate this namespace, run the `tools/gen-client-api.sh` or the
-`tools/gen-client-api.bat` script.
+To regenerate this namespace, run the `tools~/gen-client-api.sh` or the
+`tools~/gen-client-api.bat` script.
diff --git a/src/ClientCache.cs b/src/ClientCache.cs
index ec0a7212..3b47f0fe 100644
--- a/src/ClientCache.cs
+++ b/src/ClientCache.cs
@@ -44,7 +44,7 @@ public bool DeleteEntry(byte[] rowBytes)
                     return true;
                 }
 
-                Logger.LogWarning("Deleting value that we don't have (no cached value available)");
+                Log.Warn("Deleting value that we don't have (no cached value available)");
                 return false;
             }
 
@@ -65,7 +65,7 @@ public void AddTable<T>()
 
             if (!tables.TryAdd(name, new TableCache<T>()))
             {
-                Logger.LogError($"Table with name already exists: {name}");
+                Log.Error($"Table with name already exists: {name}");
             }
         }
 
@@ -76,7 +76,7 @@ public void AddTable<T>()
                 return table;
             }
 
-            Logger.LogError($"We don't know that this table is: {name}");
+            Log.Error($"We don't know that this table is: {name}");
             return null;
         }
 
diff --git a/src/ConsoleLogger.cs b/src/ConsoleLogger.cs
index 08f2ce06..1711899c 100644
--- a/src/ConsoleLogger.cs
+++ b/src/ConsoleLogger.cs
@@ -9,10 +9,12 @@ public enum LogLevel
         {
             None = 0,
             Debug = 1,
-            Warning = 2,
-            Error = 4,
-            Exception = 8,
-            All = Debug | Warning | Error | Exception
+            Trace = 2,
+            Info = 4,
+            Warning = 8,
+            Error = 16,
+            Exception = 32,
+            All = ~0
         }
         LogLevel _logLevel;
 
@@ -21,35 +23,59 @@ public ConsoleLogger(LogLevel logLevel = LogLevel.All)
             _logLevel = logLevel;
         }
 
-        public void Log(string message)
+        public void Debug(string message)
         {
             if (_logLevel.HasFlag(LogLevel.Debug))
             {
-                Console.WriteLine(message);
+                Console.WriteLine($"[D] {message}");
             }
         }
 
-        public void LogError(string message)
+        public void Trace(string message)
+        {
+            if (_logLevel.HasFlag(LogLevel.Trace))
+            {
+                Console.WriteLine($"[T] {message}");
+            }
+        }
+
+        public void Info(string message)
+        {
+            if (_logLevel.HasFlag(LogLevel.Info))
+            {
+                Console.WriteLine($"[I] {message}");
+            }
+        }
+
+        public void Warn(string message)
+        {
+            if (_logLevel.HasFlag(LogLevel.Warning))
+            {
+                Console.WriteLine($"[W] {message}");
+            }
+        }
+
+        public void Error(string message)
         {
             if (_logLevel.HasFlag(LogLevel.Error))
             {
-                Console.WriteLine($"Error: {message}");
+                Console.WriteLine($"[E] {message}");
             }
         }
 
-        public void LogException(Exception e)
+        public void Exception(string message)
         {
             if (_logLevel.HasFlag(LogLevel.Exception))
             {
-                Console.WriteLine($"Exception: {e.Message}");
+                Console.WriteLine($"[X] {message}");
             }
         }
 
-        public void LogWarning(string message)
+        public void Exception(Exception exception)
         {
-            if (_logLevel.HasFlag(LogLevel.Warning))
+            if (_logLevel.HasFlag(LogLevel.Exception))
             {
-                Console.WriteLine($"Warning: {message}");
+                Console.WriteLine($"[X] {exception}");
             }
         }
     }
diff --git a/src/ISpacetimeDBLogger.cs b/src/ISpacetimeDBLogger.cs
index 33d99cda..5223a628 100644
--- a/src/ISpacetimeDBLogger.cs
+++ b/src/ISpacetimeDBLogger.cs
@@ -4,13 +4,16 @@ namespace SpacetimeDB
 {
     public interface ISpacetimeDBLogger
     {
-        void Log(string message);
-        void LogError(string message);
-        void LogWarning(string message);
-        void LogException(Exception e);
+        void Debug(string message);
+        void Trace(string message);
+        void Info(string message);
+        void Warn(string message);
+        void Error(string message);
+        void Exception(string message);
+        void Exception(Exception e);
     }
 
-    public static class Logger
+    public static class Log
     {
         public static ISpacetimeDBLogger Current =
 
@@ -20,9 +23,12 @@ public static class Logger
             new ConsoleLogger();
 #endif
 
-        public static void Log(string message) => Current.Log(message);
-        public static void LogError(string message) => Current.LogError(message);
-        public static void LogWarning(string message) => Current.LogWarning(message);
-        public static void LogException(Exception e) => Current.LogException(e);
+        public static void Debug(string message) => Current.Debug(message);
+        public static void Trace(string message) => Current.Trace(message);
+        public static void Info(string message) => Current.Info(message);
+        public static void Warn(string message) => Current.Warn(message);
+        public static void Error(string message) => Current.Error(message);
+        public static void Exception(string message) => Current.Exception(message);
+        public static void Exception(Exception exception) => Current.Exception(exception);
     }
 }
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index e0a9daa4..59773506 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -207,13 +207,13 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                             var table = clientDB.GetTable(tableName);
                             if (table == null)
                             {
-                                Logger.LogError($"Unknown table name: {tableName}");
+                                Log.Error($"Unknown table name: {tableName}");
                                 continue;
                             }
 
                             if (update.Deletes.Count != 0)
                             {
-                                Logger.LogWarning("Non-insert during a subscription update!");
+                                Log.Warn("Non-insert during a subscription update!");
                             }
 
                             var hashSet = GetInsertHashSet(table.ClientTableType, initialSubscription.DatabaseUpdate.Tables.Count);
@@ -240,7 +240,7 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                                         break;
 
                                     case EncodedValue.Text(var txt):
-                                        Logger.LogWarning("JavaScript messages are unsupported.");
+                                        Log.Warn("JavaScript messages are unsupported.");
                                         break;
                                 }
                             }
@@ -261,7 +261,7 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                                     var table = clientDB.GetTable(tableName);
                                     if (table == null)
                                     {
-                                        Logger.LogError($"Unknown table name: {tableName}");
+                                        Log.Error($"Unknown table name: {tableName}");
                                         continue;
                                     }
 
@@ -279,7 +279,7 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                                             {
                                                 if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
                                                 {
-                                                    Logger.LogWarning($"Update with the same primary key was applied multiple times! tableName={tableName}");
+                                                    Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
                                                     // TODO(jdetter): Is this a correctable error? This would be a major error on the
                                                     // SpacetimeDB side.
                                                     continue;
@@ -315,7 +315,7 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                                             {
                                                 if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
                                                 {
-                                                    Logger.LogWarning($"Update with the same primary key was applied multiple times! tableName={tableName}");
+                                                    Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
                                                     // TODO(jdetter): Is this a correctable error? This would be a major error on the
                                                     // SpacetimeDB side.
                                                     continue;
@@ -348,13 +348,13 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                                 }
                                 catch (Exception e)
                                 {
-                                    Logger.LogException(e);
+                                    Log.Exception(e);
                                 }
                                 break;
                             case UpdateStatus.Failed(var failed):
                                 break;
                             case UpdateStatus.OutOfEnergy(var outOfEnergy):
-                                Logger.LogWarning("Failed to execute reducer: out of energy.");
+                                Log.Warn("Failed to execute reducer: out of energy.");
                                 break;
                             default:
                                 throw new InvalidOperationException();
@@ -368,7 +368,7 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
 
                         if (!waitingOneOffQueries.Remove(messageId, out var resultSource))
                         {
-                            Logger.LogError($"Response to unknown one-off-query: {messageId}");
+                            Log.Error($"Response to unknown one-off-query: {messageId}");
                             break;
                         }
 
@@ -442,7 +442,7 @@ public void Connect(string? token, string uri, string addressOrName)
                 uri = $"ws://{uri}";
             }
 
-            Logger.Log($"SpacetimeDBClient: Connecting to {uri} {addressOrName}");
+            Log.Info($"SpacetimeDBClient: Connecting to {uri} {addressOrName}");
             Task.Run(async () =>
             {
                 try
@@ -453,11 +453,11 @@ public void Connect(string? token, string uri, string addressOrName)
                 {
                     if (connectionClosed)
                     {
-                        Logger.Log("Connection closed gracefully.");
+                        Log.Info("Connection closed gracefully.");
                         return;
                     }
 
-                    Logger.LogException(e);
+                    Log.Exception(e);
                 }
             });
         }
@@ -476,7 +476,7 @@ private void OnMessageProcessCompleteUpdate(ReducerEvent? dbEvent, List<DbOp> db
                     }
                     catch (Exception e)
                     {
-                        Logger.LogException(e);
+                        Log.Exception(e);
                     }
                 }
             }
@@ -541,7 +541,7 @@ private void OnMessageProcessCompleteUpdate(ReducerEvent? dbEvent, List<DbOp> db
                 }
                 catch (Exception e)
                 {
-                    Logger.LogException(e);
+                    Log.Exception(e);
                 }
             }
         }
@@ -566,7 +566,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                     }
                     catch (Exception e)
                     {
-                        Logger.LogException(e);
+                        Log.Exception(e);
                     }
                     break;
                 case ServerMessage.TransactionUpdate(var transactionUpdate):
@@ -581,7 +581,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                         var requestId = transactionUpdate.ReducerCall.RequestId;
                         if (!stats.ReducerRequestTracker.FinishTrackingRequest(requestId))
                         {
-                            Logger.LogWarning($"Failed to finish tracking reducer request: {requestId}");
+                            Log.Warn($"Failed to finish tracking reducer request: {requestId}");
                         }
                     }
                     OnMessageProcessCompleteUpdate(processed.reducerEvent, dbOps);
@@ -591,7 +591,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                     }
                     catch (Exception e)
                     {
-                        Logger.LogException(e);
+                        Log.Exception(e);
                     }
 
                     if (processed.reducerEvent is not { } reducerEvent)
@@ -607,7 +607,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                     }
                     catch (Exception e)
                     {
-                        Logger.LogException(e);
+                        Log.Exception(e);
                     }
 
                     if (!reducerFound && transactionUpdate.Status is UpdateStatus.Failed(var failed))
@@ -618,7 +618,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                         }
                         catch (Exception e)
                         {
-                            Logger.LogException(e);
+                            Log.Exception(e);
                         }
                     }
                     break;
@@ -631,7 +631,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                     }
                     catch (Exception e)
                     {
-                        Logger.LogException(e);
+                        Log.Exception(e);
                     }
                     break;
                 case ServerMessage.OneOffQueryResponse:
@@ -641,7 +641,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                     }
                     catch (Exception e)
                     {
-                        Logger.LogException(e);
+                        Log.Exception(e);
                     }
 
                     break;
@@ -659,7 +659,7 @@ public void InternalCallReducer<T>(T args)
         {
             if (!webSocket.IsConnected)
             {
-                Logger.LogError("Cannot call reducer, not connected to server!");
+                Log.Error("Cannot call reducer, not connected to server!");
                 return;
             }
 
@@ -677,7 +677,7 @@ public void Subscribe(List<string> queries)
         {
             if (!webSocket.IsConnected)
             {
-                Logger.LogError("Cannot subscribe, not connected to server!");
+                Log.Error("Cannot subscribe, not connected to server!");
                 return;
             }
 
@@ -714,13 +714,13 @@ public async Task<T[]> OneOffQuery<T>(string query)
 
             if (!stats.OneOffRequestTracker.FinishTrackingRequest(requestId))
             {
-                Logger.LogWarning($"Failed to finish tracking one off request: {requestId}");
+                Log.Warn($"Failed to finish tracking one off request: {requestId}");
             }
 
             T[] LogAndThrow(string error)
             {
                 error = $"While processing one-off-query `{queryString}`, ID {messageId}: {error}";
-                Logger.LogError(error);
+                Log.Error(error);
                 throw new Exception(error);
             }
 
diff --git a/src/UnityDebugLogger.cs b/src/UnityDebugLogger.cs
index e78154bd..114079f0 100644
--- a/src/UnityDebugLogger.cs
+++ b/src/UnityDebugLogger.cs
@@ -10,25 +10,40 @@ namespace SpacetimeDB
 {
     public class UnityDebugLogger : ISpacetimeDBLogger
     {
-        public void Log(string message)
+        public void Debug(string message)
         {
             Debug.Log(message);
         }
 
-        public void LogError(string message)
+        public void Trace(string message)
         {
-            Debug.LogError(message);
+            Debug.Log(message);
         }
 
-        public void LogException(Exception e)
+        public void Info(string message)
         {
-            Debug.LogException(e);
+            Debug.Log(message);
         }
 
-        public void LogWarning(string message)
+        public void Warn(string message)
         {
             Debug.LogWarning(message);
         }
+
+        public void Error(string message)
+        {
+            Debug.LogError(message);
+        }
+
+        public void Exception(string message)
+        {
+            Debug.LogError(message);
+        }
+
+        public void Exception(Exception e)
+        {
+            Debug.LogException(e);
+        }
     }
 }
 #endif
diff --git a/src/WebSocket.cs b/src/WebSocket.cs
index 99445528..73d23e9a 100644
--- a/src/WebSocket.cs
+++ b/src/WebSocket.cs
@@ -75,7 +75,7 @@ public async Task Connect(string? auth, string host, string nameOrAddress, Addre
             }
             catch (Exception ex)
             {
-                Logger.LogException(ex);
+                Log.Exception(ex);
                 if (OnConnectError != null)
                 {
                     var message = ex.Message;
diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs
index af4364c1..8aeacaa3 100644
--- a/tests~/SnapshotTests.cs
+++ b/tests~/SnapshotTests.cs
@@ -57,22 +57,37 @@ public override void Write(VerifyJsonWriter writer, EncodedValue.Binary value)
 
     class TestLogger(Events events) : ISpacetimeDBLogger
     {
-        public void Log(string message)
+        public void Debug(string message)
+        {
+            events.Add("Debug", message);
+        }
+
+        public void Trace(string message)
+        {
+            events.Add("Trace", message);
+        }
+
+        public void Info(string message)
         {
             events.Add("Log", message);
         }
 
-        public void LogWarning(string message)
+        public void Warn(string message)
         {
             events.Add("LogWarning", message);
         }
 
-        public void LogError(string message)
+        public void Error(string message)
         {
             events.Add("LogError", message);
         }
 
-        public void LogException(Exception e)
+        public void Exception(string message)
+        {
+            events.Add("LogException", message);
+        }
+
+        public void Exception(Exception e)
         {
             events.Add("LogException", e.Message);
         }
@@ -238,7 +253,7 @@ public async Task VerifyAllTablesParsed()
     {
         var events = new Events();
 
-        Logger.Current = new TestLogger(events);
+        Log.Current = new TestLogger(events);
 
         var client = SpacetimeDBClient.instance;
 
diff --git a/tools~/gen-client-api.bat b/tools~/gen-client-api.bat
new file mode 100644
index 00000000..9eb66c49
--- /dev/null
+++ b/tools~/gen-client-api.bat
@@ -0,0 +1,20 @@
+@echo off
+setlocal
+
+if "%CL_HOME%"=="" (
+  echo "Variable CL_HOME not set"
+  exit /b 1
+)
+
+cd %CL_HOME%\SpacetimeDB\crates\client-api-messages
+cargo run --example get_ws_schema > %CL_HOME%/schema.json
+
+cd %CL_HOME%\SpacetimeDB\crates\cli
+cargo run -- generate -l csharp -n SpacetimeDB.ClientApi ^
+  --json-module %CL_HOME%\schema.json ^
+  -o %CL_HOME%\spacetimedb-csharp-sdk\src\SpacetimeDB\ClientApi
+
+cd %CL_HOME%\spacetimedb-csharp-sdk\src\SpacetimeDB\ClientApi
+del /q _Globals
+
+del %CL_HOME%\schema.json
diff --git a/tools~/gen-client-api.sh b/tools~/gen-client-api.sh
new file mode 100644
index 00000000..91fbe3da
--- /dev/null
+++ b/tools~/gen-client-api.sh
@@ -0,0 +1,15 @@
+#!/bin/sh -eu
+: $CL_HOME
+
+cd $CL_HOME/SpacetimeDB/crates/client-api-messages
+cargo run --example get_ws_schema > $CL_HOME/schema.json
+
+cd $CL_HOME/SpacetimeDB/crates/cli
+cargo run -- generate -l csharp -n SpacetimeDB.ClientApi \
+  --json-module $CL_HOME/schema.json \
+  -o $CL_HOME/spacetimedb-csharp-sdk/src/SpacetimeDB/ClientApi
+
+cd $CL_HOME/spacetimedb-csharp-sdk/src/SpacetimeDB/ClientApi
+rm -rf _Globals
+
+rm -f $CL_HOME/schema.json

From 7bef4483ac9c496a9c7da68a7369aa39acc74e23 Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Mon, 30 Sep 2024 21:06:33 -0400
Subject: [PATCH 07/55] c# client SDK (DbConnection + SDK Callbacks) (#131)

Implementation of the db connection proposal for C#

---------

Co-authored-by: Ingvar Stepanyan <me@rreverser.com>
---
 SpacetimeDB.ClientSDK.csproj                  |   2 +-
 examples~/quickstart/client/Program.cs        | 123 +++---
 .../client/module_bindings/Message.cs         |  28 +-
 .../module_bindings/SendMessageReducer.cs     |  26 +-
 .../client/module_bindings/SetNameReducer.cs  |  26 +-
 .../quickstart/client/module_bindings/User.cs |  42 +-
 .../_Globals/SpacetimeDBClient.cs             | 164 ++++++--
 examples~/quickstart/server/src/lib.rs        |  18 +-
 src/ClientCache.cs                            |  36 +-
 src/Event.cs                                  |  38 ++
 src/{IDatabaseTable.cs.meta => Event.cs.meta} |   6 +-
 src/IDatabaseTable.cs                         |  82 ----
 src/Primitives.cs.meta                        |  11 -
 src/SpacetimeDBClient.cs                      | 344 +++++++++-------
 src/Stubs.cs                                  |  34 --
 src/Table.cs                                  |  72 ++++
 src/{Stubs.cs.meta => Table.cs.meta}          |   4 +-
 ...otTests.VerifyAllTablesParsed.verified.txt | 367 ++++++++++++------
 tests~/SnapshotTests.cs                       |  45 ++-
 tests~/VerifyInit.cs                          |   2 -
 20 files changed, 849 insertions(+), 621 deletions(-)
 create mode 100644 src/Event.cs
 rename src/{IDatabaseTable.cs.meta => Event.cs.meta} (65%)
 delete mode 100644 src/IDatabaseTable.cs
 delete mode 100644 src/Primitives.cs.meta
 delete mode 100644 src/Stubs.cs
 create mode 100644 src/Table.cs
 rename src/{Stubs.cs.meta => Table.cs.meta} (81%)

diff --git a/SpacetimeDB.ClientSDK.csproj b/SpacetimeDB.ClientSDK.csproj
index 1c2158b2..006a68bf 100644
--- a/SpacetimeDB.ClientSDK.csproj
+++ b/SpacetimeDB.ClientSDK.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <TargetFramework>netstandard2.1</TargetFramework>
diff --git a/examples~/quickstart/client/Program.cs b/examples~/quickstart/client/Program.cs
index 056d940e..7a1fb412 100644
--- a/examples~/quickstart/client/Program.cs
+++ b/examples~/quickstart/client/Program.cs
@@ -2,11 +2,17 @@
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Linq;
+using System.Net.WebSockets;
 using System.Threading;
 using SpacetimeDB;
 using SpacetimeDB.ClientApi;
 using SpacetimeDB.Types;
 
+const string HOST = "http://localhost:3000";
+const string DBNAME = "chatqs";
+
+DbConnection? conn = null;
+
 // our local client SpacetimeDB identity
 Identity? local_identity = null;
 // declare a thread safe queue to store commands
@@ -18,7 +24,25 @@ void Main()
 {
     AuthToken.Init(".spacetime_csharp_quickstart");
 
-    RegisterCallbacks();
+    conn = DbConnection.Builder()
+        .WithUri(HOST)
+        .WithModuleName(DBNAME)
+        //.WithCredentials((null, AuthToken.Token))
+        .OnConnect(OnConnect)
+        .OnConnectError(OnConnectError)
+        .OnDisconnect(OnDisconnect)
+        .Build();
+
+    conn.RemoteTables.User.OnInsert += User_OnInsert;
+    conn.RemoteTables.User.OnUpdate += User_OnUpdate;
+
+    conn.RemoteTables.Message.OnInsert += Message_OnInsert;
+
+    conn.RemoteReducers.OnSetName += Reducer_OnSetNameEvent;
+    conn.RemoteReducers.OnSendMessage += Reducer_OnSendMessageEvent;
+
+    conn.onSubscriptionApplied += OnSubscriptionApplied;
+    conn.onUnhandledReducerError += onUnhandledReducerError;
 
     // spawn a thread to call process updates and process commands
     var thread = new Thread(ProcessThread);
@@ -31,25 +55,9 @@ void Main()
     thread.Join();
 }
 
-void RegisterCallbacks()
-{
-    SpacetimeDBClient.instance.onConnect += OnConnect;
-    SpacetimeDBClient.instance.onIdentityReceived += OnIdentityReceived;
-    SpacetimeDBClient.instance.onSubscriptionApplied += OnSubscriptionApplied;
-    SpacetimeDBClient.instance.onUnhandledReducerError += onUnhandledReducerError;
-
-    User.OnInsert += User_OnInsert;
-    User.OnUpdate += User_OnUpdate;
-
-    Message.OnInsert += Message_OnInsert;
-
-    Reducer.OnSetNameEvent += Reducer_OnSetNameEvent;
-    Reducer.OnSendMessageEvent += Reducer_OnSendMessageEvent;
-}
-
 string UserNameOrIdentity(User user) => user.Name ?? user.Identity.ToString()[..8];
 
-void User_OnInsert(User insertedValue, ReducerEvent? dbEvent)
+void User_OnInsert(EventContext ctx, User insertedValue)
 {
     if (insertedValue.Online)
     {
@@ -57,7 +65,7 @@ void User_OnInsert(User insertedValue, ReducerEvent? dbEvent)
     }
 }
 
-void User_OnUpdate(User oldValue, User newValue, ReducerEvent? dbEvent)
+void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
 {
     if (oldValue.Name != newValue.Name)
     {
@@ -78,7 +86,7 @@ void User_OnUpdate(User oldValue, User newValue, ReducerEvent? dbEvent)
 
 void PrintMessage(Message message)
 {
-    var sender = User.FindByIdentity(message.Sender);
+    var sender = conn.RemoteTables.User.FindByIdentity(message.Sender);
     var senderName = "unknown";
     if (sender != null)
     {
@@ -88,44 +96,59 @@ void PrintMessage(Message message)
     Console.WriteLine($"{senderName}: {message.Text}");
 }
 
-void Message_OnInsert(Message insertedValue, ReducerEvent? dbEvent)
+void Message_OnInsert(EventContext ctx, Message insertedValue)
 {
-    if (dbEvent != null)
+    if (ctx.Reducer is not Event<Reducer>.SubscribeApplied)
     {
         PrintMessage(insertedValue);
     }
 }
 
-void Reducer_OnSetNameEvent(ReducerEvent reducerEvent, string name)
+void Reducer_OnSetNameEvent(EventContext ctx, string name)
 {
-    if (reducerEvent.Identity == local_identity && reducerEvent.Status is UpdateStatus.Failed)
+    if (ctx.Reducer is Event<Reducer>.Reducer reducer)
     {
-        Console.Write($"Failed to change name to {name}");
+        var e = reducer.ReducerEvent;
+        if (e.CallerIdentity == local_identity && e.Status is Status.Failed(var error))
+        {
+            Console.Write($"Failed to change name to {name}: {error}");
+        }
     }
 }
 
-void Reducer_OnSendMessageEvent(ReducerEvent reducerEvent, string text)
+void Reducer_OnSendMessageEvent(EventContext ctx, string text)
 {
-    if (reducerEvent.Identity == local_identity && reducerEvent.Status is UpdateStatus.Failed)
+    if (ctx.Reducer is Event<Reducer>.Reducer reducer)
     {
-        Console.Write($"Failed to send message {text}");
+        var e = reducer.ReducerEvent;
+        if (e.CallerIdentity == local_identity && e.Status is Status.Failed(var error))
+        {
+            Console.Write($"Failed to send message {text}: {error}");
+        }
     }
 }
 
-void OnConnect()
+void OnConnect(Identity identity, string authToken)
 {
-    SpacetimeDBClient.instance.Subscribe(new List<string> { "SELECT * FROM User", "SELECT * FROM Message" });
+    local_identity = identity;
+    AuthToken.SaveToken(authToken);
+
+    conn!.Subscribe(new List<string> { "SELECT * FROM User", "SELECT * FROM Message" });
 }
 
-void OnIdentityReceived(string authToken, Identity identity, Address _address)
+void OnConnectError(WebSocketError? error, string message)
 {
-    local_identity = identity;
-    AuthToken.SaveToken(authToken);
+
+}
+
+void OnDisconnect(DbConnection conn, WebSocketCloseStatus? status, WebSocketError? error)
+{
+
 }
 
 void PrintMessagesInOrder()
 {
-    foreach (Message message in Message.Iter().OrderBy(item => item.Sent))
+    foreach (Message message in conn.RemoteTables.Message.Iter().OrderBy(item => item.Sent))
     {
         PrintMessage(message);
     }
@@ -137,29 +160,29 @@ void OnSubscriptionApplied()
     PrintMessagesInOrder();
 }
 
-void onUnhandledReducerError(ReducerEvent reducerEvent)
+void onUnhandledReducerError(ReducerEvent<Reducer> reducerEvent)
 {
-    Console.WriteLine($"Unhandled reducer error in {reducerEvent.ReducerName}: {reducerEvent.ErrMessage}");
+    Console.WriteLine($"Unhandled reducer error in {reducerEvent.Reducer}: {reducerEvent.Status}");
 }
 
-const string HOST = "http://localhost:3000";
-const string DBNAME = "chatqs";
-
 void ProcessThread()
 {
-    SpacetimeDBClient.instance.Connect(AuthToken.Token, HOST, DBNAME);
-
-    // loop until cancellation token
-    while (!cancel_token.IsCancellationRequested)
+    try
     {
-        SpacetimeDBClient.instance.Update();
+        // loop until cancellation token
+        while (!cancel_token.IsCancellationRequested)
+        {
+            conn.Update();
 
-        ProcessCommands();
+            ProcessCommands();
 
-        Thread.Sleep(100);
+            Thread.Sleep(100);
+        }
+    }
+    finally
+    {
+        conn.Close();
     }
-
-    SpacetimeDBClient.instance.Close();
 }
 
 void InputLoop()
@@ -192,10 +215,10 @@ void ProcessCommands()
         switch (command.Command)
         {
             case "message":
-                Reducer.SendMessage(command.Args);
+                conn.RemoteReducers.SendMessage(command.Args);
                 break;
             case "name":
-                Reducer.SetName(command.Args);
+                conn.RemoteReducers.SetName(command.Args);
                 break;
         }
     }
diff --git a/examples~/quickstart/client/module_bindings/Message.cs b/examples~/quickstart/client/module_bindings/Message.cs
index 4676194e..c0e52cf0 100644
--- a/examples~/quickstart/client/module_bindings/Message.cs
+++ b/examples~/quickstart/client/module_bindings/Message.cs
@@ -14,30 +14,30 @@ namespace SpacetimeDB.Types
 {
 	[SpacetimeDB.Type]
 	[DataContract]
-	public partial class Message : SpacetimeDB.DatabaseTable<Message, SpacetimeDB.Types.ReducerEvent>
+	public partial class Message : IDatabaseRow
 	{
 		[DataMember(Name = "sender")]
-		public SpacetimeDB.Identity Sender = new();
+		public SpacetimeDB.Identity Sender;
 		[DataMember(Name = "sent")]
 		public ulong Sent;
 		[DataMember(Name = "text")]
-		public string Text = "";
+		public string Text;
 
-		public static IEnumerable<Message> FilterBySender(SpacetimeDB.Identity value)
+		public Message(
+			SpacetimeDB.Identity Sender,
+			ulong Sent,
+			string Text
+		)
 		{
-			return Query(x => x.Sender == value);
+			this.Sender = Sender;
+			this.Sent = Sent;
+			this.Text = Text;
 		}
 
-		public static IEnumerable<Message> FilterBySent(ulong value)
+		public Message()
 		{
-			return Query(x => x.Sent == value);
+			this.Sender = new();
+			this.Text = "";
 		}
-
-		public static IEnumerable<Message> FilterByText(string value)
-		{
-			return Query(x => x.Text == value);
-		}
-
-
 	}
 }
diff --git a/examples~/quickstart/client/module_bindings/SendMessageReducer.cs b/examples~/quickstart/client/module_bindings/SendMessageReducer.cs
index ffb537b6..45dd29f3 100644
--- a/examples~/quickstart/client/module_bindings/SendMessageReducer.cs
+++ b/examples~/quickstart/client/module_bindings/SendMessageReducer.cs
@@ -12,32 +12,8 @@ namespace SpacetimeDB.Types
 	[SpacetimeDB.Type]
 	public partial class SendMessageArgsStruct : IReducerArgs
 	{
-		ReducerType IReducerArgs.ReducerType => ReducerType.SendMessage;
-		string IReducerArgsBase.ReducerName => "send_message";
-		bool IReducerArgs.InvokeHandler(ReducerEvent reducerEvent) => Reducer.OnSendMessage(reducerEvent, this);
+		string IReducerArgs.ReducerName => "send_message";
 
 		public string Text = "";
 	}
-
-	public static partial class Reducer
-	{
-		public delegate void SendMessageHandler(ReducerEvent reducerEvent, string text);
-		public static event SendMessageHandler? OnSendMessageEvent;
-
-		public static void SendMessage(string text)
-		{
-			SpacetimeDBClient.instance.InternalCallReducer(new SendMessageArgsStruct { Text = text });
-		}
-
-		public static bool OnSendMessage(ReducerEvent reducerEvent, SendMessageArgsStruct args)
-		{
-			if (OnSendMessageEvent == null) return false;
-			OnSendMessageEvent(
-				reducerEvent,
-				args.Text
-			);
-			return true;
-		}
-	}
-
 }
diff --git a/examples~/quickstart/client/module_bindings/SetNameReducer.cs b/examples~/quickstart/client/module_bindings/SetNameReducer.cs
index bdc3efd2..0f96ad9e 100644
--- a/examples~/quickstart/client/module_bindings/SetNameReducer.cs
+++ b/examples~/quickstart/client/module_bindings/SetNameReducer.cs
@@ -12,32 +12,8 @@ namespace SpacetimeDB.Types
 	[SpacetimeDB.Type]
 	public partial class SetNameArgsStruct : IReducerArgs
 	{
-		ReducerType IReducerArgs.ReducerType => ReducerType.SetName;
-		string IReducerArgsBase.ReducerName => "set_name";
-		bool IReducerArgs.InvokeHandler(ReducerEvent reducerEvent) => Reducer.OnSetName(reducerEvent, this);
+		string IReducerArgs.ReducerName => "set_name";
 
 		public string Name = "";
 	}
-
-	public static partial class Reducer
-	{
-		public delegate void SetNameHandler(ReducerEvent reducerEvent, string name);
-		public static event SetNameHandler? OnSetNameEvent;
-
-		public static void SetName(string name)
-		{
-			SpacetimeDBClient.instance.InternalCallReducer(new SetNameArgsStruct { Name = name });
-		}
-
-		public static bool OnSetName(ReducerEvent reducerEvent, SetNameArgsStruct args)
-		{
-			if (OnSetNameEvent == null) return false;
-			OnSetNameEvent(
-				reducerEvent,
-				args.Name
-			);
-			return true;
-		}
-	}
-
 }
diff --git a/examples~/quickstart/client/module_bindings/User.cs b/examples~/quickstart/client/module_bindings/User.cs
index 94442532..a6d6d1b9 100644
--- a/examples~/quickstart/client/module_bindings/User.cs
+++ b/examples~/quickstart/client/module_bindings/User.cs
@@ -14,47 +14,29 @@ namespace SpacetimeDB.Types
 {
 	[SpacetimeDB.Type]
 	[DataContract]
-	public partial class User : SpacetimeDB.DatabaseTableWithPrimaryKey<User, SpacetimeDB.Types.ReducerEvent>
+	public partial class User : IDatabaseRow
 	{
 		[DataMember(Name = "identity")]
-		public SpacetimeDB.Identity Identity = new();
+		public SpacetimeDB.Identity Identity;
 		[DataMember(Name = "name")]
 		public string? Name;
 		[DataMember(Name = "online")]
 		public bool Online;
 
-		private static Dictionary<SpacetimeDB.Identity, User> Identity_Index = new(16);
-
-		public override void InternalOnValueInserted()
-		{
-			Identity_Index[Identity] = this;
-		}
-
-		public override void InternalOnValueDeleted()
-		{
-			Identity_Index.Remove(Identity);
-		}
-
-		public static User? FindByIdentity(SpacetimeDB.Identity value)
-		{
-			Identity_Index.TryGetValue(value, out var r);
-			return r;
-		}
-
-		public static IEnumerable<User> FilterByIdentity(SpacetimeDB.Identity value)
+		public User(
+			SpacetimeDB.Identity Identity,
+			string? Name,
+			bool Online
+		)
 		{
-			if (FindByIdentity(value) is {} found)
-			{
-				yield return found;
-			}
+			this.Identity = Identity;
+			this.Name = Name;
+			this.Online = Online;
 		}
 
-		public static IEnumerable<User> FilterByOnline(bool value)
+		public User()
 		{
-			return Query(x => x.Online == value);
+			this.Identity = new();
 		}
-
-		public override object GetPrimaryKeyValue() => Identity;
-
 	}
 }
diff --git a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
index 49dae53e..270481a2 100644
--- a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
+++ b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
@@ -5,64 +5,158 @@
 #nullable enable
 
 using System;
-using SpacetimeDB;
+using System.Collections.Generic;
+
 using SpacetimeDB.ClientApi;
 
 namespace SpacetimeDB.Types
 {
-	public enum ReducerType
+	public sealed class RemoteTables
 	{
-		None,
-		SendMessage,
-		SetName,
-	}
+		public class MessageHandle : RemoteTableHandle<EventContext, Message> {
+            public IEnumerable<Message> FilterBySender(SpacetimeDB.Identity value) {
+                return Query(x => x.Sender == value);
+            }
 
-	public interface IReducerArgs : IReducerArgsBase
-	{
-		ReducerType ReducerType { get; }
-		bool InvokeHandler(ReducerEvent reducerEvent);
+            public IEnumerable<Message> FilterBySent(ulong value) {
+                return Query(x => x.Sent == value);
+            }
+
+            public IEnumerable<Message> FilterByText(string value) {
+                return Query(x => x.Text == value);
+            }
+        }
+
+        public class UserHandle : RemoteTableHandle<EventContext, User> {
+			public override object? GetPrimaryKey(IDatabaseRow row) => ((User)row).Identity;
+
+            private Dictionary<SpacetimeDB.Identity, User> Identity_Index = new(16);
+
+            public override void InternalInvokeValueInserted(IDatabaseRow row) {
+                var value = (User)row;
+                Identity_Index[value.Identity] = value;
+            }
+
+            public override void InternalInvokeValueDeleted(IDatabaseRow row) {
+                Identity_Index.Remove(((User)row).Identity);
+            }
+
+            public User? FindByIdentity(SpacetimeDB.Identity value) {
+                Identity_Index.TryGetValue(value, out var r);
+                return r;
+            }
+
+            public IEnumerable<User> FilterByIdentity(SpacetimeDB.Identity value) {
+                if (FindByIdentity(value) is { } found) {
+                    yield return found;
+                }
+            }
+
+            public IEnumerable<User> FilterByOnline(bool value) {
+                return Query(x => x.Online == value);
+            }
+        }
+
+        public readonly MessageHandle Message = new();
+		public readonly UserHandle User = new();
 	}
 
-	public partial class ReducerEvent : ReducerEventBase
+	public sealed class RemoteReducers : RemoteBase<DbConnection>
 	{
-		public IReducerArgs? Args { get; }
+		internal RemoteReducers(DbConnection conn) : base(conn) {}
 
-		public string ReducerName => Args?.ReducerName ?? "<none>";
+		public delegate void SendMessageHandler(EventContext ctx, string text);
+		public event SendMessageHandler? OnSendMessage;
 
-		[Obsolete("ReducerType is deprecated, please match directly on type of .Args instead.")]
-		public ReducerType Reducer => Args?.ReducerType ?? ReducerType.None;
+		public void SendMessage(string text)
+		{
+			conn.InternalCallReducer(new SendMessageArgsStruct { Text = text });
+		}
 
-		public ReducerEvent(IReducerArgs? args) : base() => Args = args;
-		public ReducerEvent(TransactionUpdate dbEvent, IReducerArgs? args) : base(dbEvent) => Args = args;
+		public bool InvokeSendMessage(EventContext ctx, SendMessageArgsStruct args)
+		{
+			if (OnSendMessage == null) return false;
+			OnSendMessage(
+				ctx,
+				args.Text
+			);
+			return true;
+		}
+		public delegate void SetNameHandler(EventContext ctx, string name);
+		public event SetNameHandler? OnSetName;
 
-		[Obsolete("Accessors that implicitly cast `Args` are deprecated, please match `Args` against the desired type explicitly instead.")]
-		public SendMessageArgsStruct SendMessageArgs => (SendMessageArgsStruct)Args!;
-		[Obsolete("Accessors that implicitly cast `Args` are deprecated, please match `Args` against the desired type explicitly instead.")]
-		public SetNameArgsStruct SetNameArgs => (SetNameArgsStruct)Args!;
+		public void SetName(string name)
+		{
+			conn.InternalCallReducer(new SetNameArgsStruct { Name = name });
+		}
+
+		public bool InvokeSetName(EventContext ctx, SetNameArgsStruct args)
+		{
+			if (OnSetName == null) return false;
+			OnSetName(
+				ctx,
+				args.Name
+			);
+			return true;
+		}
+	}
+
+	public partial record EventContext : DbContext<RemoteTables>, IEventContext {
+		public readonly RemoteReducers Reducers;
+		public readonly Event<Reducer> Reducer;
 
-		public override bool InvokeHandler() => Args?.InvokeHandler(this) ?? false;
+		internal EventContext(DbConnection conn, Event<Reducer> reducer) : base(conn.RemoteTables) {
+			Reducers = conn.RemoteReducers;
+			Reducer = reducer;
+		}
 	}
 
-	public class SpacetimeDBClient : SpacetimeDBClientBase<ReducerEvent>
+	[Type]
+	public partial record Reducer : TaggedEnum<(
+		SendMessageArgsStruct SendMessage,
+		SetNameArgsStruct SetName,
+		Unit IdentityConnected,
+		Unit IdentityDisconnected
+    )>;
+
+	public class DbConnection : DbConnectionBase<DbConnection, Reducer>
 	{
-		protected SpacetimeDBClient()
+		public readonly RemoteTables RemoteTables = new();
+		public readonly RemoteReducers RemoteReducers;
+
+		public DbConnection()
 		{
-			clientDB.AddTable<Message>();
-			clientDB.AddTable<User>();
-		}
+			RemoteReducers = new(this);
 
-		public static readonly SpacetimeDBClient instance = new();
+			clientDB.AddTable<Message>("Message", RemoteTables.Message);
+			clientDB.AddTable<User>("User", RemoteTables.User);
+		}
 
-		protected override ReducerEvent ReducerEventFromDbEvent(TransactionUpdate update)
+		protected override Reducer ToReducer(TransactionUpdate update)
 		{
-			var argBytes = update.ReducerCall.Args;
-			IReducerArgs? args = update.ReducerCall.ReducerName switch {
-				"send_message" => BSATNHelpers.Decode<SendMessageArgsStruct>(argBytes),
-				"set_name" => BSATNHelpers.Decode<SetNameArgsStruct>(argBytes),
-				"<none>" => null,
+			var encodedArgs = update.ReducerCall.Args;
+			return update.ReducerCall.ReducerName switch {
+				"send_message" => new Reducer.SendMessage(BSATNHelpers.Decode<SendMessageArgsStruct>(encodedArgs)),
+				"set_name" => new Reducer.SetName(BSATNHelpers.Decode<SetNameArgsStruct>(encodedArgs)),
+				"__identity_connected__" => new Reducer.IdentityConnected(default),
+				"__identity_disconnected__" => new Reducer.IdentityDisconnected(default),
 				var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}")
 			};
-			return new ReducerEvent(update, args);
+		}
+
+		protected override IEventContext ToEventContext(Event<Reducer> reducerEvent) {
+			return new EventContext(this, reducerEvent);
+		}
+
+		protected override bool Dispatch(IEventContext context, Reducer reducer) {
+			var eventContext = (EventContext)context;
+			return reducer switch {
+				Reducer.SendMessage(var args) => RemoteReducers.InvokeSendMessage(eventContext, args),
+				Reducer.SetName(var args) => RemoteReducers.InvokeSetName(eventContext, args),
+				Reducer.IdentityConnected => true,
+				Reducer.IdentityDisconnected => true,
+				_ => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}")
+			};
 		}
 	}
 }
diff --git a/examples~/quickstart/server/src/lib.rs b/examples~/quickstart/server/src/lib.rs
index d47c6592..0c6572e1 100644
--- a/examples~/quickstart/server/src/lib.rs
+++ b/examples~/quickstart/server/src/lib.rs
@@ -1,27 +1,27 @@
-use spacetimedb::{spacetimedb, ReducerContext, Identity, Timestamp};
+use spacetimedb::{ReducerContext, Identity, Timestamp};
 use anyhow::{Result, anyhow};
 
-#[spacetimedb(table(public))]
+#[spacetimedb::table(name = User, public)]
 pub struct User {
-    #[primarykey]
+    #[primary_key]
     identity: Identity,
     name: Option<String>,
     online: bool,
 }
 
-#[spacetimedb(table(public))]
+#[spacetimedb::table(name = Message, public)]
 pub struct Message {
     sender: Identity,
     sent: Timestamp,
     text: String,
 }
 
-#[spacetimedb(init)]
+#[spacetimedb::reducer(init)]
 pub fn init() {
     // Called when the module is initially published
 }
 
-#[spacetimedb(connect)]
+#[spacetimedb::reducer(client_connected)]
 pub fn identity_connected(ctx: ReducerContext) {
     if let Some(user) = User::filter_by_identity(&ctx.sender) {
         // If this is a returning user, i.e. we already have a `User` with this `Identity`,
@@ -38,7 +38,7 @@ pub fn identity_connected(ctx: ReducerContext) {
     }
 }
 
-#[spacetimedb(disconnect)]
+#[spacetimedb::reducer(client_disconnected)]
 pub fn identity_disconnected(ctx: ReducerContext) {
     if let Some(user) = User::filter_by_identity(&ctx.sender) {
         User::update_by_identity(&ctx.sender, User { online: false, ..user });
@@ -57,7 +57,7 @@ fn validate_name(name: String) -> Result<String> {
     }
 }
 
-#[spacetimedb(reducer)]
+#[spacetimedb::reducer]
 pub fn set_name(ctx: ReducerContext, name: String) -> Result<()> {
     let name = validate_name(name)?;
     if let Some(user) = User::filter_by_identity(&ctx.sender) {
@@ -76,7 +76,7 @@ fn validate_message(text: String) -> Result<String> {
     }
 }
 
-#[spacetimedb(reducer)]
+#[spacetimedb::reducer]
 pub fn send_message(ctx: ReducerContext, text: String) -> Result<()> {
     // Things to consider:
     // - Rate-limit messages per-user.
diff --git a/src/ClientCache.cs b/src/ClientCache.cs
index 3b47f0fe..9992f0cb 100644
--- a/src/ClientCache.cs
+++ b/src/ClientCache.cs
@@ -2,27 +2,31 @@
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
-using SpacetimeDB.BSATN;
 using SpacetimeDB.Internal;
 
 namespace SpacetimeDB
 {
     public class ClientCache
     {
-        public interface ITableCache : IEnumerable<KeyValuePair<byte[], IDatabaseTable>>
+        public interface ITableCache : IEnumerable<KeyValuePair<byte[], IDatabaseRow>>
         {
             Type ClientTableType { get; }
-            bool InsertEntry(byte[] rowBytes, IDatabaseTable value);
+            bool InsertEntry(byte[] rowBytes, IDatabaseRow value);
             bool DeleteEntry(byte[] rowBytes);
-            IDatabaseTable DecodeValue(byte[] bytes);
+            IDatabaseRow DecodeValue(byte[] bytes);
+            IRemoteTableHandle Handle { get; }
         }
 
-        public class TableCache<T> : ITableCache
-            where T : IDatabaseTable, IStructuralReadWrite, new()
+        public class TableCache<Row> : ITableCache
+            where Row : IDatabaseRow, new()
         {
-            public Type ClientTableType => typeof(T);
+            public TableCache(IRemoteTableHandle handle) => Handle = handle;
 
-            public static readonly Dictionary<byte[], T> Entries = new(ByteArrayComparer.Instance);
+            public IRemoteTableHandle Handle { get; init; }
+
+            public Type ClientTableType => typeof(Row);
+
+            public readonly Dictionary<byte[], Row> Entries = new(ByteArrayComparer.Instance);
 
             /// <summary>
             /// Inserts the value into the table. There can be no existing value with the provided BSATN bytes.
@@ -30,7 +34,7 @@ public class TableCache<T> : ITableCache
             /// <param name="rowBytes">The BSATN encoded bytes of the row to retrieve.</param>
             /// <param name="value">The parsed row encoded by the <paramref>rowBytes</paramref>.</param>
             /// <returns>True if the row was inserted, false if the row wasn't inserted because it was a duplicate.</returns>
-            public bool InsertEntry(byte[] rowBytes, IDatabaseTable value) => Entries.TryAdd(rowBytes, (T)value);
+            public bool InsertEntry(byte[] rowBytes, IDatabaseRow value) => Entries.TryAdd(rowBytes, (Row)value);
 
             /// <summary>
             /// Deletes a value from the table.
@@ -49,21 +53,21 @@ public bool DeleteEntry(byte[] rowBytes)
             }
 
             // The function to use for decoding a type value.
-            public IDatabaseTable DecodeValue(byte[] bytes) => BSATNHelpers.Decode<T>(bytes);
+            public IDatabaseRow DecodeValue(byte[] bytes) => BSATNHelpers.Decode<Row>(bytes);
 
-            public IEnumerator<KeyValuePair<byte[], IDatabaseTable>> GetEnumerator() => Entries.Select(kv => new KeyValuePair<byte[], IDatabaseTable>(kv.Key, kv.Value)).GetEnumerator();
+            public IEnumerator<KeyValuePair<byte[], IDatabaseRow>> GetEnumerator() => Entries.Select(kv => new KeyValuePair<byte[], IDatabaseRow>(kv.Key, kv.Value)).GetEnumerator();
 
             IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
         }
 
         private readonly Dictionary<string, ITableCache> tables = new();
 
-        public void AddTable<T>()
-            where T : IDatabaseTable, IStructuralReadWrite, new()
+        public void AddTable<Row>(string name, IRemoteTableHandle handle)
+            where Row : IDatabaseRow, new()
         {
-            string name = typeof(T).Name;
-
-            if (!tables.TryAdd(name, new TableCache<T>()))
+            var cache = new TableCache<Row>(handle);
+            handle.SetCache(cache);
+            if (!tables.TryAdd(name, cache))
             {
                 Log.Error($"Table with name already exists: {name}");
             }
diff --git a/src/Event.cs b/src/Event.cs
new file mode 100644
index 00000000..131cf3f7
--- /dev/null
+++ b/src/Event.cs
@@ -0,0 +1,38 @@
+using System;
+
+namespace SpacetimeDB
+{
+    public interface IEventContext { }
+
+    public interface IReducerArgs : BSATN.IStructuralReadWrite
+    {
+        string ReducerName { get; }
+    }
+
+    [Type]
+    public partial record Status : TaggedEnum<(
+        Unit Committed,
+        string Failed,
+        Unit OutOfEnergy
+    )>;
+
+    public record ReducerEvent<R>(
+        DateTimeOffset Timestamp,
+        Status Status,
+        Identity CallerIdentity,
+        Address? CallerAddress,
+        U128? EnergyConsumed,
+        R Reducer
+    );
+
+    public record Event<R>
+    {
+        private Event() { }
+
+        public record Reducer(ReducerEvent<R> ReducerEvent) : Event<R>;
+        public record SubscribeApplied : Event<R>;
+        public record UnsubscribeApplied : Event<R>;
+        public record SubscribeError(Exception Exception) : Event<R>;
+        public record UnknownTransaction : Event<R>;
+    }
+}
\ No newline at end of file
diff --git a/src/IDatabaseTable.cs.meta b/src/Event.cs.meta
similarity index 65%
rename from src/IDatabaseTable.cs.meta
rename to src/Event.cs.meta
index a3227154..c1de3421 100644
--- a/src/IDatabaseTable.cs.meta
+++ b/src/Event.cs.meta
@@ -1,5 +1,5 @@
-fileFormatVersion: 2
-guid: 11f729b0583a241499850598f6d9c870
+fileFormatVersion: 2
+guid: 3c8f2bbd66a24c0f8710b2825daeba1d
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
@@ -8,4 +8,4 @@ MonoImporter:
   icon: {instanceID: 0}
   userData: 
   assetBundleName: 
-  assetBundleVariant: 
+  assetBundleVariant: 
\ No newline at end of file
diff --git a/src/IDatabaseTable.cs b/src/IDatabaseTable.cs
deleted file mode 100644
index a028771a..00000000
--- a/src/IDatabaseTable.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using SpacetimeDB.BSATN;
-
-namespace SpacetimeDB
-{
-    public interface IDatabaseTable
-    {
-        void InternalOnValueInserted();
-        void InternalOnValueDeleted();
-        void OnInsertEvent(ReducerEventBase? update);
-        void OnBeforeDeleteEvent(ReducerEventBase? update);
-        void OnDeleteEvent(ReducerEventBase? update);
-    }
-
-    public abstract class DatabaseTable<T, ReducerEvent> : IDatabaseTable
-        where T : DatabaseTable<T, ReducerEvent>, IStructuralReadWrite, new()
-        where ReducerEvent : ReducerEventBase
-    {
-        public virtual void InternalOnValueInserted() { }
-
-        public virtual void InternalOnValueDeleted() { }
-
-        public static IEnumerable<T> Iter()
-        {
-            return ClientCache.TableCache<T>.Entries.Values;
-        }
-
-        public static IEnumerable<T> Query(Func<T, bool> filter)
-        {
-            return Iter().Where(filter);
-        }
-
-        public static int Count()
-        {
-            return ClientCache.TableCache<T>.Entries.Count;
-        }
-
-        public delegate void InsertEventHandler(T insertedValue, ReducerEvent? dbEvent);
-        public delegate void DeleteEventHandler(T deletedValue, ReducerEvent? dbEvent);
-        public static event InsertEventHandler? OnInsert;
-        public static event DeleteEventHandler? OnBeforeDelete;
-        public static event DeleteEventHandler? OnDelete;
-
-        public void OnInsertEvent(ReducerEventBase? dbEvent)
-        {
-            OnInsert?.Invoke((T)this, (ReducerEvent?)dbEvent);
-        }
-
-        public void OnBeforeDeleteEvent(ReducerEventBase? dbEvent)
-        {
-            OnBeforeDelete?.Invoke((T)this, (ReducerEvent?)dbEvent);
-        }
-
-        public void OnDeleteEvent(ReducerEventBase? dbEvent)
-        {
-            OnDelete?.Invoke((T)this, (ReducerEvent?)dbEvent);
-        }
-    }
-
-    public interface IDatabaseTableWithPrimaryKey : IDatabaseTable
-    {
-        void OnUpdateEvent(IDatabaseTableWithPrimaryKey newValue, ReducerEventBase? update);
-        object GetPrimaryKeyValue();
-    }
-
-    public abstract class DatabaseTableWithPrimaryKey<T, ReducerEvent> : DatabaseTable<T, ReducerEvent>, IDatabaseTableWithPrimaryKey
-        where T : DatabaseTableWithPrimaryKey<T, ReducerEvent>, IStructuralReadWrite, new()
-        where ReducerEvent : ReducerEventBase
-    {
-        public abstract object GetPrimaryKeyValue();
-
-        public delegate void UpdateEventHandler(T oldValue, T newValue, ReducerEvent? update);
-        public static event UpdateEventHandler? OnUpdate;
-
-        public void OnUpdateEvent(IDatabaseTableWithPrimaryKey newValue, ReducerEventBase? dbEvent)
-        {
-            OnUpdate?.Invoke((T)this, (T)newValue, (ReducerEvent?)dbEvent);
-        }
-    }
-}
diff --git a/src/Primitives.cs.meta b/src/Primitives.cs.meta
deleted file mode 100644
index 3ed18da1..00000000
--- a/src/Primitives.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 565602d5968368295b6cf26721a8890a
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 59773506..932cf5b9 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -11,18 +11,83 @@
 using SpacetimeDB.Internal;
 using SpacetimeDB.ClientApi;
 using Thread = System.Threading.Thread;
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("SpacetimeDB.Tests")]
 
 namespace SpacetimeDB
 {
-    public abstract class SpacetimeDBClientBase<ReducerEvent>
-        where ReducerEvent : ReducerEventBase
+    public sealed class DbConnectionBuilder<DbConnection, Reducer>
+        where DbConnection : DbConnectionBase<DbConnection, Reducer>, new()
     {
+        readonly DbConnection conn = new();
+
+        string? uri;
+        string? nameOrAddress;
+        string? token;
+
+        public DbConnection Build()
+        {
+            if (uri == null)
+            {
+                throw new InvalidOperationException("Building DbConnection with a null uri. Call WithUri() first.");
+            }
+            if (nameOrAddress == null)
+            {
+                throw new InvalidOperationException("Building DbConnection with a null nameOrAddress. Call WithModuleName() first.");
+            }
+            conn.Connect(token, uri, nameOrAddress);
+            return conn;
+        }
+
+        public DbConnectionBuilder<DbConnection, Reducer> WithUri(string uri)
+        {
+            this.uri = uri;
+            return this;
+        }
+
+        public DbConnectionBuilder<DbConnection, Reducer> WithModuleName(string nameOrAddress)
+        {
+            this.nameOrAddress = nameOrAddress;
+            return this;
+        }
+
+        public DbConnectionBuilder<DbConnection, Reducer> WithCredentials(in (Identity identity, string token)? creds)
+        {
+            token = creds?.token;
+            return this;
+        }
+
+        public DbConnectionBuilder<DbConnection, Reducer> OnConnect(Action<Identity, string> cb)
+        {
+            conn.onConnect += cb;
+            return this;
+        }
+
+        public DbConnectionBuilder<DbConnection, Reducer> OnConnectError(Action<WebSocketError?, string> cb)
+        {
+            conn.webSocket.OnConnectError += (a, b) => cb.Invoke(a, b);
+            return this;
+        }
+
+        public DbConnectionBuilder<DbConnection, Reducer> OnDisconnect(Action<DbConnection, WebSocketCloseStatus?, WebSocketError?> cb)
+        {
+            conn.webSocket.OnClose += (code, error) => cb.Invoke(conn, code, error);
+            return this;
+        }
+    }
+
+    public abstract class DbConnectionBase<DbConnection, Reducer>
+        where DbConnection : DbConnectionBase<DbConnection, Reducer>, new()
+    {
+        public static DbConnectionBuilder<DbConnection, Reducer> Builder() => new();
+
         struct DbValue
         {
-            public IDatabaseTable value;
+            public IDatabaseRow value;
             public byte[] bytes;
 
-            public DbValue(IDatabaseTable value, byte[] bytes)
+            public DbValue(IDatabaseRow value, byte[] bytes)
             {
                 this.value = value;
                 this.bytes = bytes;
@@ -36,26 +101,13 @@ struct DbOp
             public DbValue? insert;
         }
 
-        /// <summary>
-        /// Called when a connection is established to a spacetimedb instance.
-        /// </summary>
-        public event Action? onConnect;
-
-        /// <summary>
-        /// Called when a connection attempt fails.
-        /// </summary>
-        public event Action<WebSocketError?, string>? onConnectError;
+        internal event Action<Identity, string>? onConnect;
 
         /// <summary>
         /// Called when an exception occurs when sending a message.
         /// </summary>
         public event Action<Exception>? onSendError;
 
-        /// <summary>
-        /// Called when a connection that was established has disconnected.
-        /// </summary>
-        public event Action<WebSocketCloseStatus?, WebSocketError?>? onDisconnect;
-
         /// <summary>
         /// Invoked when a subscription is about to start being processed. This is called even before OnBeforeDelete.
         /// </summary>
@@ -69,12 +121,7 @@ struct DbOp
         /// <summary>
         /// Invoked when a reducer is returned with an error and has no client-side handler.
         /// </summary>
-        public event Action<ReducerEvent>? onUnhandledReducerError;
-
-        /// <summary>
-        /// Called when we receive an identity from the server
-        /// </summary>
-        public event Action<string, Identity, Address>? onIdentityReceived;
+        public event Action<ReducerEvent<Reducer>>? onUnhandledReducerError;
 
         /// <summary>
         /// Invoked when an event message is received or at the end of a transaction update.
@@ -84,11 +131,12 @@ struct DbOp
         public readonly Address clientAddress = Address.Random();
         public Identity? clientIdentity { get; private set; }
 
-        private SpacetimeDB.WebSocket webSocket;
+        internal WebSocket webSocket;
         private bool connectionClosed;
         protected readonly ClientCache clientDB = new();
 
-        protected abstract ReducerEvent ReducerEventFromDbEvent(TransactionUpdate dbEvent);
+        protected abstract Reducer ToReducer(TransactionUpdate update);
+        protected abstract IEventContext ToEventContext(Event<Reducer> reducerEvent);
 
         private readonly Dictionary<Guid, TaskCompletionSource<OneOffQueryResponse>> waitingOneOffQueries = new();
 
@@ -96,7 +144,7 @@ struct DbOp
         private readonly Thread networkMessageProcessThread;
         public readonly Stats stats = new();
 
-        protected SpacetimeDBClientBase()
+        protected DbConnectionBase()
         {
             var options = new ConnectOptions
             {
@@ -106,9 +154,6 @@ protected SpacetimeDBClientBase()
             };
             webSocket = new WebSocket(options);
             webSocket.OnMessage += OnMessageReceived;
-            webSocket.OnClose += (code, error) => onDisconnect?.Invoke(code, error);
-            webSocket.OnConnect += () => onConnect?.Invoke();
-            webSocket.OnConnectError += (a, b) => onConnectError?.Invoke(a, b);
             webSocket.OnSendError += a => onSendError?.Invoke(a);
 
             networkMessageProcessThread = new Thread(PreProcessMessages);
@@ -126,7 +171,7 @@ struct ProcessedMessage
             public ServerMessage message;
             public List<DbOp> dbOps;
             public DateTime timestamp;
-            public ReducerEvent? reducerEvent;
+            public ReducerEvent<Reducer>? reducerEvent;
         }
 
         struct PreProcessedMessage
@@ -153,6 +198,9 @@ struct PreProcessedMessage
             _ => throw new InvalidOperationException(),
         };
 
+        private static readonly Status Committed = new Status.Committed(default);
+        private static readonly Status OutOfEnergy = new Status.OutOfEnergy(default);
+
         void PreProcessMessages()
         {
             while (!isClosing)
@@ -177,7 +225,7 @@ PreProcessedMessage PreProcessMessage(UnprocessedMessage unprocessed)
                 using var binaryReader = new BinaryReader(decompressedStream);
                 var message = new ServerMessage.BSATN().Read(binaryReader);
 
-                ReducerEvent? reducerEvent = null;
+                ReducerEvent<Reducer>? reducerEvent = default;
 
                 // This is all of the inserts
                 Dictionary<System.Type, HashSet<byte[]>>? subscriptionInserts = null;
@@ -245,119 +293,121 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                                 }
                             }
                         }
-
                         break;
 
                     case ServerMessage.TransactionUpdate(var transactionUpdate):
-                        switch (transactionUpdate.Status)
+                        // Convert the generic event arguments in to a domain specific event object
+                        try
+                        {
+                            reducerEvent = new(
+                                DateTimeOffset.FromUnixTimeMilliseconds((long)transactionUpdate.Timestamp.Microseconds / 1000),
+                                transactionUpdate.Status switch
+                                {
+                                    UpdateStatus.Committed => Committed,
+                                    UpdateStatus.OutOfEnergy => OutOfEnergy,
+                                    UpdateStatus.Failed(var reason) => new Status.Failed(reason),
+                                    _ => throw new InvalidOperationException()
+                                },
+                                transactionUpdate.CallerIdentity,
+                                transactionUpdate.CallerAddress,
+                                transactionUpdate.EnergyQuantaUsed.Quanta,
+                                ToReducer(transactionUpdate));
+                        }
+                        catch (Exception e)
+                        {
+                            Log.Exception(e);
+                        }
+
+                        if (transactionUpdate.Status is UpdateStatus.Committed(var committed))
                         {
-                            case UpdateStatus.Committed(var committed):
-                                primaryKeyChanges = new();
+                            primaryKeyChanges = new();
 
-                                // First apply all of the state
-                                foreach (var update in committed.Tables)
+                            // First apply all of the state
+                            foreach (var update in committed.Tables)
+                            {
+                                var tableName = update.TableName;
+                                var table = clientDB.GetTable(tableName);
+                                if (table == null)
                                 {
-                                    var tableName = update.TableName;
-                                    var table = clientDB.GetTable(tableName);
-                                    if (table == null)
-                                    {
-                                        Log.Error($"Unknown table name: {tableName}");
-                                        continue;
-                                    }
+                                    Log.Error($"Unknown table name: {tableName}");
+                                    continue;
+                                }
 
-                                    foreach (var row in update.Inserts)
+                                foreach (var row in update.Inserts)
+                                {
+                                    var op = new DbOp { table = table, insert = Decode(table, row) };
+                                    var pk = table.Handle.GetPrimaryKey(op.insert.Value.value);
+                                    if (pk != null)
                                     {
-                                        var op = new DbOp { table = table, insert = Decode(table, row) };
+                                        // Compound key that we use for lookup.
+                                        // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
+                                        var key = (table.ClientTableType, pk);
 
-                                        if (op.insert.Value.value is IDatabaseTableWithPrimaryKey objWithPk)
+                                        if (primaryKeyChanges.TryGetValue(key, out var oldOp))
                                         {
-                                            // Compound key that we use for lookup.
-                                            // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
-                                            var key = (table.ClientTableType, objWithPk.GetPrimaryKeyValue());
-
-                                            if (primaryKeyChanges.TryGetValue(key, out var oldOp))
+                                            if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
                                             {
-                                                if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
-                                                {
-                                                    Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
-                                                    // TODO(jdetter): Is this a correctable error? This would be a major error on the
-                                                    // SpacetimeDB side.
-                                                    continue;
-                                                }
-
-                                                var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
-                                                op = new DbOp
-                                                {
-                                                    table = insertOp.table,
-                                                    delete = deleteOp.delete,
-                                                    insert = insertOp.insert,
-                                                };
+                                                Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
+                                                // TODO(jdetter): Is this a correctable error? This would be a major error on the
+                                                // SpacetimeDB side.
+                                                continue;
                                             }
-                                            primaryKeyChanges[key] = op;
-                                        }
-                                        else
-                                        {
-                                            dbOps.Add(op);
+
+                                            var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
+                                            op = new DbOp
+                                            {
+                                                table = insertOp.table,
+                                                delete = deleteOp.delete,
+                                                insert = insertOp.insert,
+                                            };
                                         }
+                                        primaryKeyChanges[key] = op;
+                                    }
+                                    else
+                                    {
+                                        dbOps.Add(op);
                                     }
+                                }
 
-                                    foreach (var row in update.Deletes)
+                                foreach (var row in update.Deletes)
+                                {
+                                    var op = new DbOp { table = table, delete = Decode(table, row) };
+                                    var pk = table.Handle.GetPrimaryKey(op.delete.Value.value);
+                                    if (pk != null)
                                     {
-                                        var op = new DbOp { table = table, delete = Decode(table, row) };
+                                        // Compound key that we use for lookup.
+                                        // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
+                                        var key = (table.ClientTableType, pk);
 
-                                        if (op.delete.Value.value is IDatabaseTableWithPrimaryKey objWithPk)
+                                        if (primaryKeyChanges.TryGetValue(key, out var oldOp))
                                         {
-                                            // Compound key that we use for lookup.
-                                            // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
-                                            var key = (table.ClientTableType, objWithPk.GetPrimaryKeyValue());
-
-                                            if (primaryKeyChanges.TryGetValue(key, out var oldOp))
+                                            if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
                                             {
-                                                if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
-                                                {
-                                                    Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
-                                                    // TODO(jdetter): Is this a correctable error? This would be a major error on the
-                                                    // SpacetimeDB side.
-                                                    continue;
-                                                }
-
-                                                var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
-                                                op = new DbOp
-                                                {
-                                                    table = insertOp.table,
-                                                    delete = deleteOp.delete,
-                                                    insert = insertOp.insert,
-                                                };
+                                                Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
+                                                // TODO(jdetter): Is this a correctable error? This would be a major error on the
+                                                // SpacetimeDB side.
+                                                continue;
                                             }
-                                            primaryKeyChanges[key] = op;
-                                        }
-                                        else
-                                        {
-                                            dbOps.Add(op);
+
+                                            var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
+                                            op = new DbOp
+                                            {
+                                                table = insertOp.table,
+                                                delete = deleteOp.delete,
+                                                insert = insertOp.insert,
+                                            };
                                         }
+                                        primaryKeyChanges[key] = op;
+                                    }
+                                    else
+                                    {
+                                        dbOps.Add(op);
                                     }
                                 }
+                            }
 
-                                // Combine primary key updates and non-primary key updates
-                                dbOps.AddRange(primaryKeyChanges.Values);
-
-                                // Convert the generic event arguments in to a domain specific event object
-                                try
-                                {
-                                    reducerEvent = ReducerEventFromDbEvent(transactionUpdate);
-                                }
-                                catch (Exception e)
-                                {
-                                    Log.Exception(e);
-                                }
-                                break;
-                            case UpdateStatus.Failed(var failed):
-                                break;
-                            case UpdateStatus.OutOfEnergy(var outOfEnergy):
-                                Log.Warn("Failed to execute reducer: out of energy.");
-                                break;
-                            default:
-                                throw new InvalidOperationException();
+                            // Combine primary key updates and non-primary key updates
+                            dbOps.AddRange(primaryKeyChanges.Values);
                         }
                         break;
                     case ServerMessage.IdentityToken(var identityToken):
@@ -462,8 +512,7 @@ public void Connect(string? token, string uri, string addressOrName)
             });
         }
 
-
-        private void OnMessageProcessCompleteUpdate(ReducerEvent? dbEvent, List<DbOp> dbOps)
+        private void OnMessageProcessCompleteUpdate(IEventContext eventContext, List<DbOp> dbOps)
         {
             // First trigger OnBeforeDelete
             foreach (var update in dbOps)
@@ -472,7 +521,7 @@ private void OnMessageProcessCompleteUpdate(ReducerEvent? dbEvent, List<DbOp> db
                 {
                     try
                     {
-                        oldValue.OnBeforeDeleteEvent(dbEvent!);
+                        update.table.Handle.InvokeBeforeDelete(eventContext, oldValue);
                     }
                     catch (Exception e)
                     {
@@ -491,7 +540,7 @@ private void OnMessageProcessCompleteUpdate(ReducerEvent? dbEvent, List<DbOp> db
                 {
                     if (update.table.DeleteEntry(delete.bytes))
                     {
-                        delete.value.InternalOnValueDeleted();
+                        update.table.Handle.InternalInvokeValueDeleted(delete.value);
                     }
                     else
                     {
@@ -504,7 +553,7 @@ private void OnMessageProcessCompleteUpdate(ReducerEvent? dbEvent, List<DbOp> db
                 {
                     if (update.table.InsertEntry(insert.bytes, insert.value))
                     {
-                        insert.value.InternalOnValueInserted();
+                        update.table.Handle.InternalInvokeValueInserted(insert.value);
                     }
                     else
                     {
@@ -523,19 +572,16 @@ private void OnMessageProcessCompleteUpdate(ReducerEvent? dbEvent, List<DbOp> db
                     {
                         case { insert: { value: var newValue }, delete: { value: var oldValue } }:
                             {
-                                // If we matched an update, these values must have primary keys.
-                                var newValue_ = (IDatabaseTableWithPrimaryKey)newValue;
-                                var oldValue_ = (IDatabaseTableWithPrimaryKey)oldValue;
-                                oldValue_.OnUpdateEvent(newValue_, dbEvent);
+                                dbOp.table.Handle.InvokeUpdate(eventContext, oldValue, newValue);
                                 break;
                             }
 
                         case { insert: { value: var newValue } }:
-                            newValue.OnInsertEvent(dbEvent);
+                            dbOp.table.Handle.InvokeInsert(eventContext, newValue);
                             break;
 
                         case { delete: { value: var oldValue } }:
-                            oldValue.OnDeleteEvent(dbEvent);
+                            dbOp.table.Handle.InvokeDelete(eventContext, oldValue);
                             break;
                     }
                 }
@@ -546,6 +592,8 @@ private void OnMessageProcessCompleteUpdate(ReducerEvent? dbEvent, List<DbOp> db
             }
         }
 
+        protected abstract bool Dispatch(IEventContext context, Reducer reducer);
+
         private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
         {
             var processed = CalculateStateDiff(preProcessed);
@@ -559,7 +607,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                     onBeforeSubscriptionApplied?.Invoke();
                     stats.ParseMessageTracker.InsertRequest(timestamp, $"type={nameof(ServerMessage.InitialSubscription)}");
                     stats.SubscriptionRequestTracker.FinishTrackingRequest(initialSubscription.RequestId);
-                    OnMessageProcessCompleteUpdate(null, dbOps);
+                    OnMessageProcessCompleteUpdate(ToEventContext(new Event<Reducer>.SubscribeApplied()), dbOps);
                     try
                     {
                         onSubscriptionApplied?.Invoke();
@@ -569,6 +617,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                         Log.Exception(e);
                     }
                     break;
+
                 case ServerMessage.TransactionUpdate(var transactionUpdate):
                     var reducer = transactionUpdate.ReducerCall.ReducerName;
                     stats.ParseMessageTracker.InsertRequest(timestamp, $"type={nameof(ServerMessage.TransactionUpdate)},reducer={reducer}");
@@ -584,7 +633,15 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                             Log.Warn($"Failed to finish tracking reducer request: {requestId}");
                         }
                     }
-                    OnMessageProcessCompleteUpdate(processed.reducerEvent, dbOps);
+
+                    if (processed.reducerEvent is not { } reducerEvent)
+                    {
+                        // If we are here, an error about unknown reducer should have already been logged, so nothing to do.
+                        break;
+                    }
+
+                    var eventContext = ToEventContext(new Event<Reducer>.Reducer(reducerEvent));
+                    OnMessageProcessCompleteUpdate(eventContext, dbOps);
                     try
                     {
                         onEvent?.Invoke(message);
@@ -594,16 +651,10 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                         Log.Exception(e);
                     }
 
-                    if (processed.reducerEvent is not { } reducerEvent)
-                    {
-                        // If we are here, an error about unknown reducer should have already been logged, so nothing to do.
-                        break;
-                    }
-
                     var reducerFound = false;
                     try
                     {
-                        reducerFound = reducerEvent.InvokeHandler();
+                        reducerFound = Dispatch(eventContext, reducerEvent.Reducer);
                     }
                     catch (Exception e)
                     {
@@ -622,18 +673,19 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                         }
                     }
                     break;
+
                 case ServerMessage.IdentityToken(var identityToken):
                     try
                     {
                         clientIdentity = identityToken.Identity;
-                        var address = identityToken.Address;
-                        onIdentityReceived?.Invoke(identityToken.Token, clientIdentity, address);
+                        onConnect?.Invoke(identityToken.Identity, identityToken.Token);
                     }
                     catch (Exception e)
                     {
                         Log.Exception(e);
                     }
                     break;
+
                 case ServerMessage.OneOffQueryResponse:
                     try
                     {
@@ -643,8 +695,8 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                     {
                         Log.Exception(e);
                     }
-
                     break;
+
                 default:
                     throw new InvalidOperationException();
             }
@@ -655,7 +707,7 @@ internal void OnMessageReceived(byte[] bytes, DateTime timestamp) =>
             _messageQueue.Add(new UnprocessedMessage { bytes = bytes, timestamp = timestamp });
 
         public void InternalCallReducer<T>(T args)
-            where T : IReducerArgsBase, new()
+            where T : IReducerArgs, new()
         {
             if (!webSocket.IsConnected)
             {
@@ -691,7 +743,7 @@ public void Subscribe(List<string> queries)
 
         /// Usage: SpacetimeDBClientBase.instance.OneOffQuery<Message>("WHERE sender = \"bob\"");
         public async Task<T[]> OneOffQuery<T>(string query)
-            where T : IDatabaseTable, IStructuralReadWrite, new()
+            where T : IDatabaseRow, new()
         {
             var messageId = Guid.NewGuid();
             var type = typeof(T);
diff --git a/src/Stubs.cs b/src/Stubs.cs
deleted file mode 100644
index f9ba6202..00000000
--- a/src/Stubs.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using SpacetimeDB.ClientApi;
-
-namespace SpacetimeDB
-{
-    public interface IReducerArgsBase : BSATN.IStructuralReadWrite
-    {
-        string ReducerName { get; }
-    }
-
-    public abstract class ReducerEventBase
-    {
-        public ulong Timestamp { get; }
-        public Identity? Identity { get; }
-        public Address? CallerAddress { get; }
-        public string? ErrMessage { get; }
-        public UpdateStatus? Status { get; }
-
-        public ReducerEventBase() { }
-
-        public ReducerEventBase(TransactionUpdate update)
-        {
-            Timestamp = update.Timestamp.Microseconds;
-            Identity = update.CallerIdentity;
-            CallerAddress = update.CallerAddress;
-            Status = update.Status;
-            if (update.Status is UpdateStatus.Failed(var err))
-            {
-                ErrMessage = err;
-            }
-        }
-
-        public abstract bool InvokeHandler();
-    }
-}
diff --git a/src/Table.cs b/src/Table.cs
new file mode 100644
index 00000000..b2764028
--- /dev/null
+++ b/src/Table.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using SpacetimeDB.BSATN;
+
+namespace SpacetimeDB
+{
+    public interface IDatabaseRow : IStructuralReadWrite { }
+
+    public abstract class RemoteBase<DbConnection>
+    {
+        protected readonly DbConnection conn;
+
+        protected RemoteBase(DbConnection conn)
+        {
+            this.conn = conn;
+        }
+    }
+
+    public interface IRemoteTableHandle
+    {
+        void SetCache(ClientCache.ITableCache cache);
+
+        object? GetPrimaryKey(IDatabaseRow row);
+
+        void InternalInvokeValueInserted(IDatabaseRow row);
+        void InternalInvokeValueDeleted(IDatabaseRow row);
+        void InvokeInsert(IEventContext context, IDatabaseRow row);
+        void InvokeDelete(IEventContext context, IDatabaseRow row);
+        void InvokeBeforeDelete(IEventContext context, IDatabaseRow row);
+        void InvokeUpdate(IEventContext context, IDatabaseRow oldRow, IDatabaseRow newRow);
+    }
+
+    public abstract class RemoteTableHandle<EventContext, Row> : IRemoteTableHandle
+        where EventContext : class, IEventContext
+        where Row : IDatabaseRow, new()
+    {
+        public void SetCache(ClientCache.ITableCache cache) => Cache = (ClientCache.TableCache<Row>)cache;
+
+        internal ClientCache.TableCache<Row>? Cache;
+
+        public event Action<EventContext, Row>? OnInsert;
+        public event Action<EventContext, Row>? OnDelete;
+        public event Action<EventContext, Row>? OnBeforeDelete;
+        public event Action<EventContext, Row, Row>? OnUpdate;
+
+        public virtual object? GetPrimaryKey(IDatabaseRow row) => null;
+
+        public virtual void InternalInvokeValueInserted(IDatabaseRow row) { }
+
+        public virtual void InternalInvokeValueDeleted(IDatabaseRow row) { }
+
+        public int Count => Cache!.Entries.Count;
+
+        public IEnumerable<Row> Iter() => Cache!.Entries.Values;
+
+        public IEnumerable<Row> Query(Func<Row, bool> filter) => Iter().Where(filter);
+
+        public void InvokeInsert(IEventContext context, IDatabaseRow row) =>
+            OnInsert?.Invoke((EventContext)context, (Row)row);
+
+        public void InvokeDelete(IEventContext context, IDatabaseRow row) =>
+            OnDelete?.Invoke((EventContext)context, (Row)row);
+
+        public void InvokeBeforeDelete(IEventContext context, IDatabaseRow row) =>
+            OnBeforeDelete?.Invoke((EventContext)context, (Row)row);
+
+        public void InvokeUpdate(IEventContext context, IDatabaseRow oldRow, IDatabaseRow newRow) =>
+            OnUpdate?.Invoke((EventContext)context, (Row)oldRow, (Row)newRow);
+    }
+}
\ No newline at end of file
diff --git a/src/Stubs.cs.meta b/src/Table.cs.meta
similarity index 81%
rename from src/Stubs.cs.meta
rename to src/Table.cs.meta
index da0198c0..09681bfa 100644
--- a/src/Stubs.cs.meta
+++ b/src/Table.cs.meta
@@ -1,4 +1,4 @@
-fileFormatVersion: 2
+fileFormatVersion: 2
 guid: 0de7dc78e75a21a428bfa6e3dd520ba9
 MonoImporter:
   externalObjects: {}
@@ -8,4 +8,4 @@ MonoImporter:
   icon: {instanceID: 0}
   userData: 
   assetBundleName: 
-  assetBundleVariant: 
+  assetBundleVariant: 
\ No newline at end of file
diff --git a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
index 12aa9234..fd948740 100644
--- a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
+++ b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
@@ -1,17 +1,33 @@
 {
   Events: {
-    OnIdentityReceived: {
-      identity: Identity_1,
-      address: Guid_1
-    },
+    OnIdentityReceived: Identity_1,
     OnInsertUser: {
+      eventContext: {
+        Reducers: {Scrubbed},
+        Reducer: {},
+        Db: {Scrubbed}
+      },
       user: {
         identity: Identity_1,
         online: true
       }
     },
-    LogException: Unknown reducer __identity_connected__ (Parameter 'Reducer'),
+    LogException: Unknown reducer unknown-reducer (Parameter 'Reducer'),
     OnInsertUser: {
+      eventContext: {
+        Reducers: {Scrubbed},
+        Reducer: {
+          ReducerEvent: {
+            Timestamp: DateTimeOffset_1,
+            Status: {},
+            CallerIdentity: Identity_2,
+            CallerAddress: Guid_1,
+            EnergyConsumed: {},
+            Reducer: {}
+          }
+        },
+        Db: {Scrubbed}
+      },
       user: {
         identity: Identity_2,
         online: true
@@ -20,8 +36,8 @@
     OnEvent: {
       status: {Scrubbed},
       timestamp: 1718487763059031,
-      caller_identity: {Scrubbed},
-      caller_address: Guid_2,
+      caller_identity: Identity_2,
+      caller_address: Guid_1,
       reducer_call: {
         reducer_name: __identity_connected__,
         args: 
@@ -30,6 +46,24 @@
       host_execution_duration_micros: 66
     },
     OnUpdateUser: {
+      eventContext: {
+        Reducers: {Scrubbed},
+        Reducer: {
+          ReducerEvent: {
+            Timestamp: DateTimeOffset_2,
+            Status: {},
+            CallerIdentity: Identity_1,
+            CallerAddress: Guid_2,
+            EnergyConsumed: {},
+            Reducer: {
+              SetName_: {
+                Name: A
+              }
+            }
+          }
+        },
+        Db: {Scrubbed}
+      },
       oldUser: {
         identity: Identity_1,
         online: true
@@ -38,22 +72,13 @@
         identity: Identity_1,
         name: A,
         online: true
-      },
-      reducerEvent: {
-        Args: {
-          Name: A
-        },
-        Timestamp: 1718487768057579,
-        Identity: Identity_1,
-        CallerAddress: Guid_1,
-        Status: {Scrubbed}
       }
     },
     OnEvent: {
       status: {Scrubbed},
       timestamp: 1718487768057579,
-      caller_identity: {Scrubbed},
-      caller_address: Guid_1,
+      caller_identity: Identity_1,
+      caller_address: Guid_2,
       reducer_call: {
         reducer_name: set_name,
         args: AQAAAEE=,
@@ -63,35 +88,53 @@
       host_execution_duration_micros: 70
     },
     OnSetName: {
-      Args: {
-        Name: A
+      Reducers: {Scrubbed},
+      Reducer: {
+        ReducerEvent: {
+          Timestamp: DateTimeOffset_2,
+          Status: {},
+          CallerIdentity: Identity_1,
+          CallerAddress: Guid_2,
+          EnergyConsumed: {},
+          Reducer: {
+            SetName_: {
+              Name: A
+            }
+          }
+        }
       },
-      Timestamp: 1718487768057579,
-      Identity: Identity_1,
-      CallerAddress: Guid_1,
-      Status: {Scrubbed}
+      Db: {Scrubbed}
     },
     OnInsertMessage: {
+      eventContext: {
+        Reducers: {Scrubbed},
+        Reducer: {
+          ReducerEvent: {
+            Timestamp: DateTimeOffset_3,
+            Status: {},
+            CallerIdentity: Identity_2,
+            CallerAddress: Guid_1,
+            EnergyConsumed: {},
+            Reducer: {
+              SendMessage_: {
+                Text: Hello, A!
+              }
+            }
+          }
+        },
+        Db: {Scrubbed}
+      },
       message: {
         sender: Identity_2,
         sent: 1718487775346381,
         text: Hello, A!
-      },
-      reducerEvent: {
-        Args: {
-          Text: Hello, A!
-        },
-        Timestamp: 1718487775346381,
-        Identity: Identity_2,
-        CallerAddress: Guid_2,
-        Status: {Scrubbed}
       }
     },
     OnEvent: {
       status: {Scrubbed},
       timestamp: 1718487775346381,
-      caller_identity: {Scrubbed},
-      caller_address: Guid_2,
+      caller_identity: Identity_2,
+      caller_address: Guid_1,
       reducer_call: {
         reducer_name: send_message,
         args: CQAAAEhlbGxvLCBBIQ==,
@@ -101,15 +144,42 @@
       host_execution_duration_micros: 57
     },
     OnSendMessage: {
-      Args: {
-        Text: Hello, A!
+      Reducers: {Scrubbed},
+      Reducer: {
+        ReducerEvent: {
+          Timestamp: DateTimeOffset_3,
+          Status: {},
+          CallerIdentity: Identity_2,
+          CallerAddress: Guid_1,
+          EnergyConsumed: {},
+          Reducer: {
+            SendMessage_: {
+              Text: Hello, A!
+            }
+          }
+        }
       },
-      Timestamp: 1718487775346381,
-      Identity: Identity_2,
-      CallerAddress: Guid_2,
-      Status: {Scrubbed}
+      Db: {Scrubbed}
     },
     OnUpdateUser: {
+      eventContext: {
+        Reducers: {Scrubbed},
+        Reducer: {
+          ReducerEvent: {
+            Timestamp: DateTimeOffset_4,
+            Status: {},
+            CallerIdentity: Identity_2,
+            CallerAddress: Guid_1,
+            EnergyConsumed: {},
+            Reducer: {
+              SetName_: {
+                Name: B
+              }
+            }
+          }
+        },
+        Db: {Scrubbed}
+      },
       oldUser: {
         identity: Identity_2,
         online: true
@@ -118,22 +188,13 @@
         identity: Identity_2,
         name: B,
         online: true
-      },
-      reducerEvent: {
-        Args: {
-          Name: B
-        },
-        Timestamp: 1718487777307855,
-        Identity: Identity_2,
-        CallerAddress: Guid_2,
-        Status: {Scrubbed}
       }
     },
     OnEvent: {
       status: {Scrubbed},
       timestamp: 1718487777307855,
-      caller_identity: {Scrubbed},
-      caller_address: Guid_2,
+      caller_identity: Identity_2,
+      caller_address: Guid_1,
       reducer_call: {
         reducer_name: set_name,
         args: AQAAAEI=,
@@ -143,35 +204,53 @@
       host_execution_duration_micros: 98
     },
     OnSetName: {
-      Args: {
-        Name: B
+      Reducers: {Scrubbed},
+      Reducer: {
+        ReducerEvent: {
+          Timestamp: DateTimeOffset_4,
+          Status: {},
+          CallerIdentity: Identity_2,
+          CallerAddress: Guid_1,
+          EnergyConsumed: {},
+          Reducer: {
+            SetName_: {
+              Name: B
+            }
+          }
+        }
       },
-      Timestamp: 1718487777307855,
-      Identity: Identity_2,
-      CallerAddress: Guid_2,
-      Status: {Scrubbed}
+      Db: {Scrubbed}
     },
     OnInsertMessage: {
+      eventContext: {
+        Reducers: {Scrubbed},
+        Reducer: {
+          ReducerEvent: {
+            Timestamp: DateTimeOffset_5,
+            Status: {},
+            CallerIdentity: Identity_1,
+            CallerAddress: Guid_2,
+            EnergyConsumed: {},
+            Reducer: {
+              SendMessage_: {
+                Text: Hello, B!
+              }
+            }
+          }
+        },
+        Db: {Scrubbed}
+      },
       message: {
         sender: Identity_1,
         sent: 1718487783175083,
         text: Hello, B!
-      },
-      reducerEvent: {
-        Args: {
-          Text: Hello, B!
-        },
-        Timestamp: 1718487783175083,
-        Identity: Identity_1,
-        CallerAddress: Guid_1,
-        Status: {Scrubbed}
       }
     },
     OnEvent: {
       status: {Scrubbed},
       timestamp: 1718487783175083,
-      caller_identity: {Scrubbed},
-      caller_address: Guid_1,
+      caller_identity: Identity_1,
+      caller_address: Guid_2,
       reducer_call: {
         reducer_name: send_message,
         args: CQAAAEhlbGxvLCBCIQ==,
@@ -181,35 +260,53 @@
       host_execution_duration_micros: 40
     },
     OnSendMessage: {
-      Args: {
-        Text: Hello, B!
+      Reducers: {Scrubbed},
+      Reducer: {
+        ReducerEvent: {
+          Timestamp: DateTimeOffset_5,
+          Status: {},
+          CallerIdentity: Identity_1,
+          CallerAddress: Guid_2,
+          EnergyConsumed: {},
+          Reducer: {
+            SendMessage_: {
+              Text: Hello, B!
+            }
+          }
+        }
       },
-      Timestamp: 1718487783175083,
-      Identity: Identity_1,
-      CallerAddress: Guid_1,
-      Status: {Scrubbed}
+      Db: {Scrubbed}
     },
     OnInsertMessage: {
+      eventContext: {
+        Reducers: {Scrubbed},
+        Reducer: {
+          ReducerEvent: {
+            Timestamp: DateTimeOffset_6,
+            Status: {},
+            CallerIdentity: Identity_2,
+            CallerAddress: Guid_1,
+            EnergyConsumed: {},
+            Reducer: {
+              SendMessage_: {
+                Text: Goodbye!
+              }
+            }
+          }
+        },
+        Db: {Scrubbed}
+      },
       message: {
         sender: Identity_2,
         sent: 1718487787645364,
         text: Goodbye!
-      },
-      reducerEvent: {
-        Args: {
-          Text: Goodbye!
-        },
-        Timestamp: 1718487787645364,
-        Identity: Identity_2,
-        CallerAddress: Guid_2,
-        Status: {Scrubbed}
       }
     },
     OnEvent: {
       status: {Scrubbed},
       timestamp: 1718487787645364,
-      caller_identity: {Scrubbed},
-      caller_address: Guid_2,
+      caller_identity: Identity_2,
+      caller_address: Guid_1,
       reducer_call: {
         reducer_name: send_message,
         args: CAAAAEdvb2RieWUh,
@@ -219,16 +316,38 @@
       host_execution_duration_micros: 28
     },
     OnSendMessage: {
-      Args: {
-        Text: Goodbye!
+      Reducers: {Scrubbed},
+      Reducer: {
+        ReducerEvent: {
+          Timestamp: DateTimeOffset_6,
+          Status: {},
+          CallerIdentity: Identity_2,
+          CallerAddress: Guid_1,
+          EnergyConsumed: {},
+          Reducer: {
+            SendMessage_: {
+              Text: Goodbye!
+            }
+          }
+        }
       },
-      Timestamp: 1718487787645364,
-      Identity: Identity_2,
-      CallerAddress: Guid_2,
-      Status: {Scrubbed}
+      Db: {Scrubbed}
     },
-    LogException: Unknown reducer __identity_disconnected__ (Parameter 'Reducer'),
     OnUpdateUser: {
+      eventContext: {
+        Reducers: {Scrubbed},
+        Reducer: {
+          ReducerEvent: {
+            Timestamp: DateTimeOffset_7,
+            Status: {},
+            CallerIdentity: Identity_2,
+            CallerAddress: Guid_1,
+            EnergyConsumed: {},
+            Reducer: {}
+          }
+        },
+        Db: {Scrubbed}
+      },
       oldUser: {
         identity: Identity_2,
         name: B,
@@ -243,8 +362,8 @@
     OnEvent: {
       status: {Scrubbed},
       timestamp: 1718487791901504,
-      caller_identity: {Scrubbed},
-      caller_address: Guid_2,
+      caller_identity: Identity_2,
+      caller_address: Guid_1,
       reducer_call: {
         reducer_name: __identity_disconnected__,
         args: 
@@ -253,26 +372,35 @@
       host_execution_duration_micros: 75
     },
     OnInsertMessage: {
+      eventContext: {
+        Reducers: {Scrubbed},
+        Reducer: {
+          ReducerEvent: {
+            Timestamp: DateTimeOffset_8,
+            Status: {},
+            CallerIdentity: Identity_1,
+            CallerAddress: Guid_2,
+            EnergyConsumed: {},
+            Reducer: {
+              SendMessage_: {
+                Text: Goodbye!
+              }
+            }
+          }
+        },
+        Db: {Scrubbed}
+      },
       message: {
         sender: Identity_1,
         sent: 1718487794937841,
         text: Goodbye!
-      },
-      reducerEvent: {
-        Args: {
-          Text: Goodbye!
-        },
-        Timestamp: 1718487794937841,
-        Identity: Identity_1,
-        CallerAddress: Guid_1,
-        Status: {Scrubbed}
       }
     },
     OnEvent: {
       status: {Scrubbed},
       timestamp: 1718487794937841,
-      caller_identity: {Scrubbed},
-      caller_address: Guid_1,
+      caller_identity: Identity_1,
+      caller_address: Guid_2,
       reducer_call: {
         reducer_name: send_message,
         args: CAAAAEdvb2RieWUh,
@@ -282,13 +410,22 @@
       host_execution_duration_micros: 34
     },
     OnSendMessage: {
-      Args: {
-        Text: Goodbye!
+      Reducers: {Scrubbed},
+      Reducer: {
+        ReducerEvent: {
+          Timestamp: DateTimeOffset_8,
+          Status: {},
+          CallerIdentity: Identity_1,
+          CallerAddress: Guid_2,
+          EnergyConsumed: {},
+          Reducer: {
+            SendMessage_: {
+              Text: Goodbye!
+            }
+          }
+        }
       },
-      Timestamp: 1718487794937841,
-      Identity: Identity_1,
-      CallerAddress: Guid_1,
-      Status: {Scrubbed}
+      Db: {Scrubbed}
     }
   },
   FinalSnapshot: {
@@ -330,7 +467,7 @@
   Stats: {
     ReducerRequestTracker: {
       sampleCount: 3,
-      requestsAwaitingResponse: 5,
+      requestsAwaitingResponse: 6,
       Min: sample#4,
       Max: sample#2
     },
@@ -341,12 +478,12 @@
       Max: sample#1
     },
     AllReducersTracker: {
-      sampleCount: 8,
+      sampleCount: 9,
       Min: reducer=send_message,
       Max: reducer=set_name
     },
     ParseMessageTracker: {
-      sampleCount: 9,
+      sampleCount: 10,
       Min: type=TransactionUpdate,reducer=send_message,
       Max: type=InitialSubscription
     }
diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs
index 8aeacaa3..72486fa6 100644
--- a/tests~/SnapshotTests.cs
+++ b/tests~/SnapshotTests.cs
@@ -206,6 +206,9 @@ private static ServerMessage[] SampleDump() => [
         SampleSubscriptionUpdate(
             1, 366, [SampleUserInsert("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", null, true)]
         ),
+        SampleTransactionUpdate(0, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==",
+            0, "unknown-reducer", 0, 40, [], null
+        ),
         SampleTransactionUpdate(
             1718487763059031, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==",
             0, "__identity_connected__", 1957615, 66, [SampleUserInsert("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", null, true)],
@@ -255,7 +258,7 @@ public async Task VerifyAllTablesParsed()
 
         Log.Current = new TestLogger(events);
 
-        var client = SpacetimeDBClient.instance;
+        var client = new DbConnection();
 
         var sampleDumpParsed = SampleDump();
 
@@ -292,35 +295,35 @@ public async Task VerifyAllTablesParsed()
             ServerMessage.OneOffQueryResponse(var o) => o,
             _ => throw new InvalidOperationException()
         });
-        client.onIdentityReceived += (_authToken, identity, address) =>
-            events.Add("OnIdentityReceived", new { identity, address });
+        client.onConnect += (identity, _token) =>
+            events.Add("OnIdentityReceived", identity);
         client.onSubscriptionApplied += () => events.Add("OnSubscriptionApplied");
         client.onUnhandledReducerError += (exception) =>
             events.Add("OnUnhandledReducerError", exception);
 
-        Reducer.OnSendMessageEvent += (reducerEvent, _text) =>
-            events.Add("OnSendMessage", reducerEvent);
-        Reducer.OnSetNameEvent += (reducerEvent, _name) => events.Add("OnSetName", reducerEvent);
+        client.RemoteReducers.OnSendMessage += (eventContext, _text) =>
+            events.Add("OnSendMessage", eventContext);
+        client.RemoteReducers.OnSetName += (eventContext, _name) => events.Add("OnSetName", eventContext);
 
-        User.OnDelete += (user, reducerEvent) =>
-            events.Add("OnDeleteUser", new { user, reducerEvent });
-        User.OnInsert += (user, reducerEvent) =>
-            events.Add("OnInsertUser", new { user, reducerEvent });
-        User.OnUpdate += (oldUser, newUser, reducerEvent) =>
+        client.RemoteTables.User.OnDelete += (eventContext, user) =>
+            events.Add("OnDeleteUser", new { eventContext, user });
+        client.RemoteTables.User.OnInsert += (eventContext, user) =>
+            events.Add("OnInsertUser", new { eventContext, user });
+        client.RemoteTables.User.OnUpdate += (eventContext, oldUser, newUser) =>
             events.Add(
                 "OnUpdateUser",
                 new
                 {
+                    eventContext,
                     oldUser,
-                    newUser,
-                    reducerEvent
+                    newUser
                 }
             );
 
-        Message.OnDelete += (message, reducerEvent) =>
-            events.Add("OnDeleteMessage", new { message, reducerEvent });
-        Message.OnInsert += (message, reducerEvent) =>
-            events.Add("OnInsertMessage", new { message, reducerEvent });
+        client.RemoteTables.Message.OnDelete += (eventContext, message) =>
+            events.Add("OnDeleteMessage", new { eventContext, message });
+        client.RemoteTables.Message.OnInsert += (eventContext, message) =>
+            events.Add("OnInsertMessage", new { eventContext, message });
 
         // Simulate receiving WebSocket messages.
         foreach (var sample in sampleDumpBinary)
@@ -340,8 +343,8 @@ await Verify(
                     Events = events,
                     FinalSnapshot = new
                     {
-                        User = User.Iter().ToList(),
-                        Message = Message.Iter().ToList()
+                        User = client.RemoteTables.User.Iter().ToList(),
+                        Message = client.RemoteTables.Message.Iter().ToList()
                     },
                     Stats = client.stats
                 }
@@ -352,8 +355,8 @@ await Verify(
                 new EnergyQuantaConverter(),
                 new EncodedValueConverter()
             ]))
-            .ScrubMember<TransactionUpdate>(x => x.CallerIdentity)
             .ScrubMember<TransactionUpdate>(x => x.Status)
-            .ScrubMember<ReducerEventBase>(x => x.Status);
+            .ScrubMember<DbContext<RemoteTables>>(x => x.Db)
+            .ScrubMember<EventContext>(x => x.Reducers);
     }
 }
diff --git a/tests~/VerifyInit.cs b/tests~/VerifyInit.cs
index bc75d5e5..58d37d65 100644
--- a/tests~/VerifyInit.cs
+++ b/tests~/VerifyInit.cs
@@ -81,7 +81,5 @@ public static void Init()
                 ]
             )
         );
-
-        VerifierSettings.IgnoreMember<ReducerEvent>(_ => _.ReducerName);
     }
 }

From f8ddab7047ae06447c5b1d7678cd929f9f452d6c Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Tue, 1 Oct 2024 17:17:45 +0100
Subject: [PATCH 08/55] Subscription API (#137)

## Description of Changes

Implements the subscription builder (at least, the parts that are
possible to implement).

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 examples~/quickstart/client/Program.cs        |  57 ++++---
 .../_Globals/SpacetimeDBClient.cs             |   2 +
 src/Event.cs                                  |  60 +++++++-
 src/SpacetimeDBClient.cs                      | 143 ++++++++++--------
 tests~/SnapshotTests.cs                       |   1 -
 5 files changed, 170 insertions(+), 93 deletions(-)

diff --git a/examples~/quickstart/client/Program.cs b/examples~/quickstart/client/Program.cs
index 7a1fb412..cd378c59 100644
--- a/examples~/quickstart/client/Program.cs
+++ b/examples~/quickstart/client/Program.cs
@@ -5,30 +5,29 @@
 using System.Net.WebSockets;
 using System.Threading;
 using SpacetimeDB;
-using SpacetimeDB.ClientApi;
 using SpacetimeDB.Types;
 
 const string HOST = "http://localhost:3000";
 const string DBNAME = "chatqs";
 
-DbConnection? conn = null;
-
 // our local client SpacetimeDB identity
 Identity? local_identity = null;
 // declare a thread safe queue to store commands
 var input_queue = new ConcurrentQueue<(string Command, string Args)>();
-// declare a threadsafe cancel token to cancel the process loop
-var cancel_token = new CancellationTokenSource();
 
 void Main()
 {
     AuthToken.Init(".spacetime_csharp_quickstart");
 
+    // TODO: just do `var conn = DbConnection...` when OnConnect signature is fixed.
+    DbConnection? conn = null;
+
     conn = DbConnection.Builder()
         .WithUri(HOST)
         .WithModuleName(DBNAME)
         //.WithCredentials((null, AuthToken.Token))
-        .OnConnect(OnConnect)
+        // TODO: change this to just `(OnConnect)` when signature is fixed in #131.
+        .OnConnect((identity, authToken) => OnConnect(conn!, identity, authToken))
         .OnConnectError(OnConnectError)
         .OnDisconnect(OnDisconnect)
         .Build();
@@ -41,17 +40,19 @@ void Main()
     conn.RemoteReducers.OnSetName += Reducer_OnSetNameEvent;
     conn.RemoteReducers.OnSendMessage += Reducer_OnSendMessageEvent;
 
-    conn.onSubscriptionApplied += OnSubscriptionApplied;
     conn.onUnhandledReducerError += onUnhandledReducerError;
 
+    // declare a threadsafe cancel token to cancel the process loop
+    var cancellationTokenSource = new CancellationTokenSource();
+
     // spawn a thread to call process updates and process commands
-    var thread = new Thread(ProcessThread);
+    var thread = new Thread(() => ProcessThread(conn, cancellationTokenSource.Token));
     thread.Start();
 
     InputLoop();
 
     // this signals the ProcessThread to stop
-    cancel_token.Cancel();
+    cancellationTokenSource.Cancel();
     thread.Join();
 }
 
@@ -84,9 +85,9 @@ void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
     }
 }
 
-void PrintMessage(Message message)
+void PrintMessage(RemoteTables tables, Message message)
 {
-    var sender = conn.RemoteTables.User.FindByIdentity(message.Sender);
+    var sender = tables.User.FindByIdentity(message.Sender);
     var senderName = "unknown";
     if (sender != null)
     {
@@ -100,7 +101,7 @@ void Message_OnInsert(EventContext ctx, Message insertedValue)
 {
     if (ctx.Reducer is not Event<Reducer>.SubscribeApplied)
     {
-        PrintMessage(insertedValue);
+        PrintMessage(ctx.Db, insertedValue);
     }
 }
 
@@ -128,12 +129,18 @@ void Reducer_OnSendMessageEvent(EventContext ctx, string text)
     }
 }
 
-void OnConnect(Identity identity, string authToken)
+void OnConnect(DbConnection conn, Identity identity, string authToken)
 {
     local_identity = identity;
     AuthToken.SaveToken(authToken);
 
-    conn!.Subscribe(new List<string> { "SELECT * FROM User", "SELECT * FROM Message" });
+    conn.SubscriptionBuilder()
+        .OnApplied(OnSubscriptionApplied)
+        .Subscribe("SELECT * FROM User");
+
+    conn.SubscriptionBuilder()
+        .OnApplied(OnSubscriptionApplied)
+        .Subscribe("SELECT * FROM Message");
 }
 
 void OnConnectError(WebSocketError? error, string message)
@@ -146,18 +153,18 @@ void OnDisconnect(DbConnection conn, WebSocketCloseStatus? status, WebSocketErro
 
 }
 
-void PrintMessagesInOrder()
+void PrintMessagesInOrder(RemoteTables tables)
 {
-    foreach (Message message in conn.RemoteTables.Message.Iter().OrderBy(item => item.Sent))
+    foreach (Message message in tables.Message.Iter().OrderBy(item => item.Sent))
     {
-        PrintMessage(message);
+        PrintMessage(tables, message);
     }
 }
 
-void OnSubscriptionApplied()
+void OnSubscriptionApplied(EventContext ctx)
 {
     Console.WriteLine("Connected");
-    PrintMessagesInOrder();
+    PrintMessagesInOrder(ctx.Db);
 }
 
 void onUnhandledReducerError(ReducerEvent<Reducer> reducerEvent)
@@ -165,16 +172,16 @@ void onUnhandledReducerError(ReducerEvent<Reducer> reducerEvent)
     Console.WriteLine($"Unhandled reducer error in {reducerEvent.Reducer}: {reducerEvent.Status}");
 }
 
-void ProcessThread()
+void ProcessThread(DbConnection conn, CancellationToken ct)
 {
     try
     {
         // loop until cancellation token
-        while (!cancel_token.IsCancellationRequested)
+        while (!ct.IsCancellationRequested)
         {
             conn.Update();
 
-            ProcessCommands();
+            ProcessCommands(conn.RemoteReducers);
 
             Thread.Sleep(100);
         }
@@ -207,7 +214,7 @@ void InputLoop()
     }
 }
 
-void ProcessCommands()
+void ProcessCommands(RemoteReducers reducers)
 {
     // process input queue commands
     while (input_queue.TryDequeue(out var command))
@@ -215,10 +222,10 @@ void ProcessCommands()
         switch (command.Command)
         {
             case "message":
-                conn.RemoteReducers.SendMessage(command.Args);
+                reducers.SendMessage(command.Args);
                 break;
             case "name":
-                conn.RemoteReducers.SetName(command.Args);
+                reducers.SetName(command.Args);
                 break;
         }
     }
diff --git a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
index 270481a2..cf4f4e95 100644
--- a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
+++ b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
@@ -158,5 +158,7 @@ protected override bool Dispatch(IEventContext context, Reducer reducer) {
 				_ => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}")
 			};
 		}
+
+        public SubscriptionBuilder<EventContext> SubscriptionBuilder() => new(this);
 	}
 }
diff --git a/src/Event.cs b/src/Event.cs
index 131cf3f7..ff687c0f 100644
--- a/src/Event.cs
+++ b/src/Event.cs
@@ -35,4 +35,62 @@ public record UnsubscribeApplied : Event<R>;
         public record SubscribeError(Exception Exception) : Event<R>;
         public record UnknownTransaction : Event<R>;
     }
-}
\ No newline at end of file
+
+    // TODO: Move those classes into EventContext, so that we wouldn't need repetitive generics.
+    public sealed class SubscriptionBuilder<EventContext>
+        where EventContext : IEventContext
+    {
+        private readonly IDbConnection conn;
+        private event Action<EventContext>? Applied;
+        private event Action<EventContext>? Error;
+
+        public SubscriptionBuilder(IDbConnection conn)
+        {
+            this.conn = conn;
+        }
+
+        public SubscriptionBuilder<EventContext> OnApplied(Action<EventContext> callback)
+        {
+            Applied += callback;
+            return this;
+        }
+
+        public SubscriptionBuilder<EventContext> OnError(Action<EventContext> callback)
+        {
+            Error += callback;
+            return this;
+        }
+
+        public SubscriptionHandle<EventContext> Subscribe(string querySql) => new(conn, Applied, Error, querySql);
+    }
+
+    public interface ISubscriptionHandle
+    {
+        void OnApplied(IEventContext ctx);
+    }
+
+    public class SubscriptionHandle<EventContext> : ISubscriptionHandle
+        where EventContext : IEventContext
+    {
+        private readonly Action<EventContext>? onApplied;
+
+        void ISubscriptionHandle.OnApplied(IEventContext ctx)
+        {
+            IsActive = true;
+            onApplied?.Invoke((EventContext)ctx);
+        }
+
+        internal SubscriptionHandle(IDbConnection conn, Action<EventContext>? onApplied, Action<EventContext>? onError, string querySql)
+        {
+            this.onApplied = onApplied;
+            conn.Subscribe(this, querySql);
+        }
+
+        public void Unsubscribe() => throw new NotImplementedException();
+
+        public void UnsuscribeThen(Action<EventContext> onEnd) => throw new NotImplementedException();
+
+        public bool IsEnded => false;
+        public bool IsActive { get; private set; }
+    }
+}
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 932cf5b9..ca18cd84 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -77,7 +77,12 @@ public DbConnectionBuilder<DbConnection, Reducer> OnDisconnect(Action<DbConnecti
         }
     }
 
-    public abstract class DbConnectionBase<DbConnection, Reducer>
+    public interface IDbConnection
+    {
+        void Subscribe(ISubscriptionHandle handle, string query);
+    }
+
+    public abstract class DbConnectionBase<DbConnection, Reducer> : IDbConnection
         where DbConnection : DbConnectionBase<DbConnection, Reducer>, new()
     {
         public static DbConnectionBuilder<DbConnection, Reducer> Builder() => new();
@@ -108,16 +113,13 @@ struct DbOp
         /// </summary>
         public event Action<Exception>? onSendError;
 
+        private readonly Dictionary<uint, ISubscriptionHandle> subscriptions = new();
+
         /// <summary>
         /// Invoked when a subscription is about to start being processed. This is called even before OnBeforeDelete.
         /// </summary>
         public event Action? onBeforeSubscriptionApplied;
 
-        /// <summary>
-        /// Invoked when the local client cache is updated as a result of changes made to the subscription queries.
-        /// </summary>
-        public event Action? onSubscriptionApplied;
-
         /// <summary>
         /// Invoked when a reducer is returned with an error and has no client-side handler.
         /// </summary>
@@ -604,76 +606,82 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
             switch (message)
             {
                 case ServerMessage.InitialSubscription(var initialSubscription):
-                    onBeforeSubscriptionApplied?.Invoke();
-                    stats.ParseMessageTracker.InsertRequest(timestamp, $"type={nameof(ServerMessage.InitialSubscription)}");
-                    stats.SubscriptionRequestTracker.FinishTrackingRequest(initialSubscription.RequestId);
-                    OnMessageProcessCompleteUpdate(ToEventContext(new Event<Reducer>.SubscribeApplied()), dbOps);
-                    try
-                    {
-                        onSubscriptionApplied?.Invoke();
-                    }
-                    catch (Exception e)
                     {
-                        Log.Exception(e);
+                        onBeforeSubscriptionApplied?.Invoke();
+                        stats.ParseMessageTracker.InsertRequest(timestamp, $"type={nameof(ServerMessage.InitialSubscription)}");
+                        stats.SubscriptionRequestTracker.FinishTrackingRequest(initialSubscription.RequestId);
+                        var eventContext = ToEventContext(new Event<Reducer>.SubscribeApplied());
+                        OnMessageProcessCompleteUpdate(eventContext, dbOps);
+                        if (subscriptions.TryGetValue(initialSubscription.RequestId, out var subscription))
+                        {
+                            try
+                            {
+                                subscription.OnApplied(eventContext);
+                            }
+                            catch (Exception e)
+                            {
+                                Log.Exception(e);
+                            }
+                        }
+                        break;
                     }
-                    break;
-
                 case ServerMessage.TransactionUpdate(var transactionUpdate):
-                    var reducer = transactionUpdate.ReducerCall.ReducerName;
-                    stats.ParseMessageTracker.InsertRequest(timestamp, $"type={nameof(ServerMessage.TransactionUpdate)},reducer={reducer}");
-                    var hostDuration = TimeSpan.FromMilliseconds(transactionUpdate.HostExecutionDurationMicros / 1000.0d);
-                    stats.AllReducersTracker.InsertRequest(hostDuration, $"reducer={reducer}");
-                    var callerIdentity = transactionUpdate.CallerIdentity;
-                    if (callerIdentity == clientIdentity)
                     {
-                        // This was a request that we initiated
-                        var requestId = transactionUpdate.ReducerCall.RequestId;
-                        if (!stats.ReducerRequestTracker.FinishTrackingRequest(requestId))
+                        var reducer = transactionUpdate.ReducerCall.ReducerName;
+                        stats.ParseMessageTracker.InsertRequest(timestamp, $"type={nameof(ServerMessage.TransactionUpdate)},reducer={reducer}");
+                        var hostDuration = TimeSpan.FromMilliseconds(transactionUpdate.HostExecutionDurationMicros / 1000.0d);
+                        stats.AllReducersTracker.InsertRequest(hostDuration, $"reducer={reducer}");
+                        var callerIdentity = transactionUpdate.CallerIdentity;
+                        if (callerIdentity == clientIdentity)
                         {
-                            Log.Warn($"Failed to finish tracking reducer request: {requestId}");
+                            // This was a request that we initiated
+                            var requestId = transactionUpdate.ReducerCall.RequestId;
+                            if (!stats.ReducerRequestTracker.FinishTrackingRequest(requestId))
+                            {
+                                Log.Warn($"Failed to finish tracking reducer request: {requestId}");
+                            }
                         }
-                    }
 
-                    if (processed.reducerEvent is not { } reducerEvent)
-                    {
-                        // If we are here, an error about unknown reducer should have already been logged, so nothing to do.
-                        break;
-                    }
-
-                    var eventContext = ToEventContext(new Event<Reducer>.Reducer(reducerEvent));
-                    OnMessageProcessCompleteUpdate(eventContext, dbOps);
-                    try
-                    {
-                        onEvent?.Invoke(message);
-                    }
-                    catch (Exception e)
-                    {
-                        Log.Exception(e);
-                    }
+                        if (processed.reducerEvent is not { } reducerEvent)
+                        {
+                            // If we are here, an error about unknown reducer should have already been logged, so nothing to do.
+                            break;
+                        }
 
-                    var reducerFound = false;
-                    try
-                    {
-                        reducerFound = Dispatch(eventContext, reducerEvent.Reducer);
-                    }
-                    catch (Exception e)
-                    {
-                        Log.Exception(e);
-                    }
+                        var eventContext = ToEventContext(new Event<Reducer>.Reducer(reducerEvent));
+                        OnMessageProcessCompleteUpdate(eventContext, dbOps);
+                        try
+                        {
+                            onEvent?.Invoke(message);
+                        }
+                        catch (Exception e)
+                        {
+                            Log.Exception(e);
+                        }
 
-                    if (!reducerFound && transactionUpdate.Status is UpdateStatus.Failed(var failed))
-                    {
+                        var reducerFound = false;
                         try
                         {
-                            onUnhandledReducerError?.Invoke(reducerEvent);
+                            reducerFound = Dispatch(eventContext, reducerEvent.Reducer);
                         }
                         catch (Exception e)
                         {
                             Log.Exception(e);
                         }
-                    }
-                    break;
 
+                        if (!reducerFound && transactionUpdate.Status is UpdateStatus.Failed(var failed))
+                        {
+                            try
+                            {
+                                onUnhandledReducerError?.Invoke(reducerEvent);
+                            }
+                            catch (Exception e)
+                            {
+                                Log.Exception(e);
+                            }
+                        }
+                        break;
+                    }
                 case ServerMessage.IdentityToken(var identityToken):
                     try
                     {
@@ -725,7 +733,7 @@ public void InternalCallReducer<T>(T args)
             ));
         }
 
-        public void Subscribe(List<string> queries)
+        void IDbConnection.Subscribe(ISubscriptionHandle handle, string query)
         {
             if (!webSocket.IsConnected)
             {
@@ -733,12 +741,15 @@ public void Subscribe(List<string> queries)
                 return;
             }
 
-            var request = new Subscribe
-            {
-                RequestId = stats.SubscriptionRequestTracker.StartTrackingRequest(),
-            };
-            request.QueryStrings.AddRange(queries);
-            webSocket.Send(new ClientMessage.Subscribe(request));
+            var id = stats.SubscriptionRequestTracker.StartTrackingRequest();
+            subscriptions[id] = handle;
+            webSocket.Send(new ClientMessage.Subscribe(
+                new Subscribe
+                {
+                    RequestId = id,
+                    QueryStrings = { query }
+                }
+            ));
         }
 
         /// Usage: SpacetimeDBClientBase.instance.OneOffQuery<Message>("WHERE sender = \"bob\"");
diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs
index 72486fa6..e99e601c 100644
--- a/tests~/SnapshotTests.cs
+++ b/tests~/SnapshotTests.cs
@@ -297,7 +297,6 @@ public async Task VerifyAllTablesParsed()
         });
         client.onConnect += (identity, _token) =>
             events.Add("OnIdentityReceived", identity);
-        client.onSubscriptionApplied += () => events.Add("OnSubscriptionApplied");
         client.onUnhandledReducerError += (exception) =>
             events.Add("OnUnhandledReducerError", exception);
 

From 0981b8917e4b9f3ed59c8b608c5a17dc76d589f5 Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Tue, 1 Oct 2024 17:37:42 +0100
Subject: [PATCH 09/55] Merge table cache into table handle (#139)

## Description of Changes

Merges cache into the table handle as suggested on the original PR +
hides most table methods that shouldn't be part of the stable API.

Few remaining methods will need a codegen change to be available only to
subclasses, so for now that's out of scope.

Same for merging ClientCache into RemoteTables - we shouldn't need a
separate collection, and instead could autogenerate a switch expression
over table name.

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 src/ClientCache.cs       | 66 ++++----------------------------
 src/SpacetimeDBClient.cs | 44 ++++++++++-----------
 src/Table.cs             | 82 +++++++++++++++++++++++++++++-----------
 3 files changed, 87 insertions(+), 105 deletions(-)

diff --git a/src/ClientCache.cs b/src/ClientCache.cs
index 9992f0cb..824ca34b 100644
--- a/src/ClientCache.cs
+++ b/src/ClientCache.cs
@@ -6,74 +6,22 @@
 
 namespace SpacetimeDB
 {
+    // TODO: merge this into `RemoteTables`.
+    // It should just provide auto-generated `GetTable` and `GetTables` methods.
     public class ClientCache
     {
-        public interface ITableCache : IEnumerable<KeyValuePair<byte[], IDatabaseRow>>
-        {
-            Type ClientTableType { get; }
-            bool InsertEntry(byte[] rowBytes, IDatabaseRow value);
-            bool DeleteEntry(byte[] rowBytes);
-            IDatabaseRow DecodeValue(byte[] bytes);
-            IRemoteTableHandle Handle { get; }
-        }
-
-        public class TableCache<Row> : ITableCache
-            where Row : IDatabaseRow, new()
-        {
-            public TableCache(IRemoteTableHandle handle) => Handle = handle;
-
-            public IRemoteTableHandle Handle { get; init; }
-
-            public Type ClientTableType => typeof(Row);
-
-            public readonly Dictionary<byte[], Row> Entries = new(ByteArrayComparer.Instance);
-
-            /// <summary>
-            /// Inserts the value into the table. There can be no existing value with the provided BSATN bytes.
-            /// </summary>
-            /// <param name="rowBytes">The BSATN encoded bytes of the row to retrieve.</param>
-            /// <param name="value">The parsed row encoded by the <paramref>rowBytes</paramref>.</param>
-            /// <returns>True if the row was inserted, false if the row wasn't inserted because it was a duplicate.</returns>
-            public bool InsertEntry(byte[] rowBytes, IDatabaseRow value) => Entries.TryAdd(rowBytes, (Row)value);
-
-            /// <summary>
-            /// Deletes a value from the table.
-            /// </summary>
-            /// <param name="rowBytes">The BSATN encoded bytes of the row to remove.</param>
-            /// <returns>True if and only if the value was previously resident and has been deleted.</returns>
-            public bool DeleteEntry(byte[] rowBytes)
-            {
-                if (Entries.Remove(rowBytes))
-                {
-                    return true;
-                }
-
-                Log.Warn("Deleting value that we don't have (no cached value available)");
-                return false;
-            }
-
-            // The function to use for decoding a type value.
-            public IDatabaseRow DecodeValue(byte[] bytes) => BSATNHelpers.Decode<Row>(bytes);
-
-            public IEnumerator<KeyValuePair<byte[], IDatabaseRow>> GetEnumerator() => Entries.Select(kv => new KeyValuePair<byte[], IDatabaseRow>(kv.Key, kv.Value)).GetEnumerator();
-
-            IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-        }
-
-        private readonly Dictionary<string, ITableCache> tables = new();
+        private readonly Dictionary<string, IRemoteTableHandle> tables = new();
 
-        public void AddTable<Row>(string name, IRemoteTableHandle handle)
+        public void AddTable<Row>(string name, IRemoteTableHandle table)
             where Row : IDatabaseRow, new()
         {
-            var cache = new TableCache<Row>(handle);
-            handle.SetCache(cache);
-            if (!tables.TryAdd(name, cache))
+            if (!tables.TryAdd(name, table))
             {
                 Log.Error($"Table with name already exists: {name}");
             }
         }
 
-        public ITableCache? GetTable(string name)
+        public IRemoteTableHandle? GetTable(string name)
         {
             if (tables.TryGetValue(name, out var table))
             {
@@ -84,6 +32,6 @@ public void AddTable<Row>(string name, IRemoteTableHandle handle)
             return null;
         }
 
-        public IEnumerable<ITableCache> GetTables() => tables.Values;
+        public IEnumerable<IRemoteTableHandle> GetTables() => tables.Values;
     }
 }
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index ca18cd84..fcdcdce8 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -87,10 +87,10 @@ public abstract class DbConnectionBase<DbConnection, Reducer> : IDbConnection
     {
         public static DbConnectionBuilder<DbConnection, Reducer> Builder() => new();
 
-        struct DbValue
+        readonly struct DbValue
         {
-            public IDatabaseRow value;
-            public byte[] bytes;
+            public readonly IDatabaseRow value;
+            public readonly byte[] bytes;
 
             public DbValue(IDatabaseRow value, byte[] bytes)
             {
@@ -101,7 +101,7 @@ public DbValue(IDatabaseRow value, byte[] bytes)
 
         struct DbOp
         {
-            public ClientCache.ITableCache table;
+            public IRemoteTableHandle table;
             public DbValue? delete;
             public DbValue? insert;
         }
@@ -193,12 +193,14 @@ struct PreProcessedMessage
         private readonly CancellationTokenSource _preProcessCancellationTokenSource = new();
         private CancellationToken _preProcessCancellationToken => _preProcessCancellationTokenSource.Token;
 
-        static DbValue Decode(ClientCache.ITableCache table, EncodedValue value) => value switch
+        static DbValue Decode(IRemoteTableHandle table, EncodedValue value, out object? primaryKey)
         {
-            EncodedValue.Binary(var bin) => new DbValue(table.DecodeValue(bin), bin),
-            EncodedValue.Text(var text) => throw new InvalidOperationException("JavaScript messages aren't supported."),
-            _ => throw new InvalidOperationException(),
-        };
+            // We expect only binary messages here; let type cast exception take care of any others.
+            var bin = ((EncodedValue.Binary)value).Binary_;
+            var obj = table.DecodeValue(bin);
+            primaryKey = table.GetPrimaryKey(obj);
+            return new(obj, bin);
+        }
 
         private static readonly Status Committed = new Status.Committed(default);
         private static readonly Status OutOfEnergy = new Status.OutOfEnergy(default);
@@ -337,8 +339,7 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
 
                                 foreach (var row in update.Inserts)
                                 {
-                                    var op = new DbOp { table = table, insert = Decode(table, row) };
-                                    var pk = table.Handle.GetPrimaryKey(op.insert.Value.value);
+                                    var op = new DbOp { table = table, insert = Decode(table, row, out var pk) };
                                     if (pk != null)
                                     {
                                         // Compound key that we use for lookup.
@@ -373,8 +374,7 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
 
                                 foreach (var row in update.Deletes)
                                 {
-                                    var op = new DbOp { table = table, delete = Decode(table, row) };
-                                    var pk = table.Handle.GetPrimaryKey(op.delete.Value.value);
+                                    var op = new DbOp { table = table, delete = Decode(table, row, out var pk) };
                                     if (pk != null)
                                     {
                                         // Compound key that we use for lookup.
@@ -454,7 +454,7 @@ ProcessedMessage CalculateStateDiff(PreProcessedMessage preProcessedMessage)
                         continue;
                     }
 
-                    foreach (var (rowBytes, oldValue) in table.Where(kv => !hashSet.Contains(kv.Key)))
+                    foreach (var (rowBytes, oldValue) in table.IterEntries().Where(kv => !hashSet.Contains(kv.Key)))
                     {
                         processed.dbOps.Add(new DbOp
                         {
@@ -523,7 +523,7 @@ private void OnMessageProcessCompleteUpdate(IEventContext eventContext, List<DbO
                 {
                     try
                     {
-                        update.table.Handle.InvokeBeforeDelete(eventContext, oldValue);
+                        update.table.InvokeBeforeDelete(eventContext, oldValue);
                     }
                     catch (Exception e)
                     {
@@ -542,7 +542,7 @@ private void OnMessageProcessCompleteUpdate(IEventContext eventContext, List<DbO
                 {
                     if (update.table.DeleteEntry(delete.bytes))
                     {
-                        update.table.Handle.InternalInvokeValueDeleted(delete.value);
+                        update.table.InternalInvokeValueDeleted(delete.value);
                     }
                     else
                     {
@@ -555,7 +555,7 @@ private void OnMessageProcessCompleteUpdate(IEventContext eventContext, List<DbO
                 {
                     if (update.table.InsertEntry(insert.bytes, insert.value))
                     {
-                        update.table.Handle.InternalInvokeValueInserted(insert.value);
+                        update.table.InternalInvokeValueInserted(insert.value);
                     }
                     else
                     {
@@ -573,17 +573,15 @@ private void OnMessageProcessCompleteUpdate(IEventContext eventContext, List<DbO
                     switch (dbOp)
                     {
                         case { insert: { value: var newValue }, delete: { value: var oldValue } }:
-                            {
-                                dbOp.table.Handle.InvokeUpdate(eventContext, oldValue, newValue);
-                                break;
-                            }
+                            dbOp.table.InvokeUpdate(eventContext, oldValue, newValue);
+                            break;
 
                         case { insert: { value: var newValue } }:
-                            dbOp.table.Handle.InvokeInsert(eventContext, newValue);
+                            dbOp.table.InvokeInsert(eventContext, newValue);
                             break;
 
                         case { delete: { value: var oldValue } }:
-                            dbOp.table.Handle.InvokeDelete(eventContext, oldValue);
+                            dbOp.table.InvokeDelete(eventContext, oldValue);
                             break;
                     }
                 }
diff --git a/src/Table.cs b/src/Table.cs
index b2764028..2f5f3c6e 100644
--- a/src/Table.cs
+++ b/src/Table.cs
@@ -20,53 +20,89 @@ protected RemoteBase(DbConnection conn)
 
     public interface IRemoteTableHandle
     {
-        void SetCache(ClientCache.ITableCache cache);
-
+        // These methods need to be overridden by autogen.
         object? GetPrimaryKey(IDatabaseRow row);
-
         void InternalInvokeValueInserted(IDatabaseRow row);
         void InternalInvokeValueDeleted(IDatabaseRow row);
-        void InvokeInsert(IEventContext context, IDatabaseRow row);
-        void InvokeDelete(IEventContext context, IDatabaseRow row);
-        void InvokeBeforeDelete(IEventContext context, IDatabaseRow row);
-        void InvokeUpdate(IEventContext context, IDatabaseRow oldRow, IDatabaseRow newRow);
+
+        // These are provided by RemoteTableHandle.
+        internal Type ClientTableType { get; }
+        internal IEnumerable<KeyValuePair<byte[], IDatabaseRow>> IterEntries();
+        internal bool InsertEntry(byte[] rowBytes, IDatabaseRow value);
+        internal bool DeleteEntry(byte[] rowBytes);
+        internal IDatabaseRow DecodeValue(byte[] bytes);
+
+        internal void InvokeInsert(IEventContext context, IDatabaseRow row);
+        internal void InvokeDelete(IEventContext context, IDatabaseRow row);
+        internal void InvokeBeforeDelete(IEventContext context, IDatabaseRow row);
+        internal void InvokeUpdate(IEventContext context, IDatabaseRow oldRow, IDatabaseRow newRow);
     }
 
     public abstract class RemoteTableHandle<EventContext, Row> : IRemoteTableHandle
         where EventContext : class, IEventContext
         where Row : IDatabaseRow, new()
     {
-        public void SetCache(ClientCache.ITableCache cache) => Cache = (ClientCache.TableCache<Row>)cache;
+        // These methods need to be overridden by autogen.
+        public virtual object? GetPrimaryKey(IDatabaseRow row) => null;
+        public virtual void InternalInvokeValueInserted(IDatabaseRow row) { }
+        public virtual void InternalInvokeValueDeleted(IDatabaseRow row) { }
+
+        // These are provided by RemoteTableHandle.
+        Type IRemoteTableHandle.ClientTableType => typeof(Row);
+
+        private readonly Dictionary<byte[], Row> Entries = new(Internal.ByteArrayComparer.Instance);
+
+        IEnumerable<KeyValuePair<byte[], IDatabaseRow>> IRemoteTableHandle.IterEntries() =>
+            Entries.Select(kv => new KeyValuePair<byte[], IDatabaseRow>(kv.Key, kv.Value));
+
+        /// <summary>
+        /// Inserts the value into the table. There can be no existing value with the provided BSATN bytes.
+        /// </summary>
+        /// <param name="rowBytes">The BSATN encoded bytes of the row to retrieve.</param>
+        /// <param name="value">The parsed row encoded by the <paramref>rowBytes</paramref>.</param>
+        /// <returns>True if the row was inserted, false if the row wasn't inserted because it was a duplicate.</returns>
+        bool IRemoteTableHandle.InsertEntry(byte[] rowBytes, IDatabaseRow value) => Entries.TryAdd(rowBytes, (Row)value);
 
-        internal ClientCache.TableCache<Row>? Cache;
+        /// <summary>
+        /// Deletes a value from the table.
+        /// </summary>
+        /// <param name="rowBytes">The BSATN encoded bytes of the row to remove.</param>
+        /// <returns>True if and only if the value was previously resident and has been deleted.</returns>
+        bool IRemoteTableHandle.DeleteEntry(byte[] rowBytes)
+        {
+            if (Entries.Remove(rowBytes))
+            {
+                return true;
+            }
+
+            Log.Warn("Deleting value that we don't have (no cached value available)");
+            return false;
+        }
+
+        // The function to use for decoding a type value.
+        IDatabaseRow IRemoteTableHandle.DecodeValue(byte[] bytes) => BSATNHelpers.Decode<Row>(bytes);
 
         public event Action<EventContext, Row>? OnInsert;
         public event Action<EventContext, Row>? OnDelete;
         public event Action<EventContext, Row>? OnBeforeDelete;
         public event Action<EventContext, Row, Row>? OnUpdate;
 
-        public virtual object? GetPrimaryKey(IDatabaseRow row) => null;
-
-        public virtual void InternalInvokeValueInserted(IDatabaseRow row) { }
-
-        public virtual void InternalInvokeValueDeleted(IDatabaseRow row) { }
-
-        public int Count => Cache!.Entries.Count;
+        public int Count => Entries.Count;
 
-        public IEnumerable<Row> Iter() => Cache!.Entries.Values;
+        public IEnumerable<Row> Iter() => Entries.Values;
 
-        public IEnumerable<Row> Query(Func<Row, bool> filter) => Iter().Where(filter);
+        protected IEnumerable<Row> Query(Func<Row, bool> filter) => Iter().Where(filter);
 
-        public void InvokeInsert(IEventContext context, IDatabaseRow row) =>
+        void IRemoteTableHandle.InvokeInsert(IEventContext context, IDatabaseRow row) =>
             OnInsert?.Invoke((EventContext)context, (Row)row);
 
-        public void InvokeDelete(IEventContext context, IDatabaseRow row) =>
+        void IRemoteTableHandle.InvokeDelete(IEventContext context, IDatabaseRow row) =>
             OnDelete?.Invoke((EventContext)context, (Row)row);
 
-        public void InvokeBeforeDelete(IEventContext context, IDatabaseRow row) =>
+        void IRemoteTableHandle.InvokeBeforeDelete(IEventContext context, IDatabaseRow row) =>
             OnBeforeDelete?.Invoke((EventContext)context, (Row)row);
 
-        public void InvokeUpdate(IEventContext context, IDatabaseRow oldRow, IDatabaseRow newRow) =>
+        void IRemoteTableHandle.InvokeUpdate(IEventContext context, IDatabaseRow oldRow, IDatabaseRow newRow) =>
             OnUpdate?.Invoke((EventContext)context, (Row)oldRow, (Row)newRow);
     }
-}
\ No newline at end of file
+}

From 2aae961ec1448551b1be40ffdcef3197f6c6f16c Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Tue, 1 Oct 2024 13:02:54 -0400
Subject: [PATCH 10/55] Add DbConnection argument to OnConnect (#138)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 examples~/quickstart/client/Program.cs | 3 +--
 src/SpacetimeDBClient.cs               | 4 ++--
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/examples~/quickstart/client/Program.cs b/examples~/quickstart/client/Program.cs
index cd378c59..0f62f3d4 100644
--- a/examples~/quickstart/client/Program.cs
+++ b/examples~/quickstart/client/Program.cs
@@ -26,8 +26,7 @@ void Main()
         .WithUri(HOST)
         .WithModuleName(DBNAME)
         //.WithCredentials((null, AuthToken.Token))
-        // TODO: change this to just `(OnConnect)` when signature is fixed in #131.
-        .OnConnect((identity, authToken) => OnConnect(conn!, identity, authToken))
+        .OnConnect(OnConnect)
         .OnConnectError(OnConnectError)
         .OnDisconnect(OnDisconnect)
         .Build();
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index fcdcdce8..b7c405f8 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -58,9 +58,9 @@ public DbConnectionBuilder<DbConnection, Reducer> WithCredentials(in (Identity i
             return this;
         }
 
-        public DbConnectionBuilder<DbConnection, Reducer> OnConnect(Action<Identity, string> cb)
+        public DbConnectionBuilder<DbConnection, Reducer> OnConnect(Action<DbConnection, Identity, string> cb)
         {
-            conn.onConnect += cb;
+            conn.onConnect += (identity, token) => cb.Invoke(conn, identity, token);
             return this;
         }
 

From 95b9d1756ccb6667a52b63b8fede1d884c176f49 Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Tue, 1 Oct 2024 20:00:32 +0100
Subject: [PATCH 11/55] Hide more APIs (#140)

## Description of Changes

Removing unstable APIs that are not used by BitCraft; marking others
with [Obsolete] and renaming few others to match the proposal.

One exception is InternalCallReducer - it would need some further
changes to codegen; marking it as Obsolete right now would cause all
generated clients to show noisy warnings.

## API

 - [x] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 examples~/quickstart/client/Program.cs        |   6 +-
 src/ClientCache.cs                            |   4 +-
 src/ConsoleLogger.cs                          |   2 +-
 src/SpacetimeDBClient.cs                      |  50 +++-----
 src/UnityDebugLogger.cs                       |   2 +-
 src/WebSocket.cs                              |  33 +++---
 ...otTests.VerifyAllTablesParsed.verified.txt | 108 +-----------------
 tests~/SnapshotTests.cs                       |  23 ++--
 tests~/tests.csproj                           |   2 +-
 9 files changed, 52 insertions(+), 178 deletions(-)

diff --git a/examples~/quickstart/client/Program.cs b/examples~/quickstart/client/Program.cs
index 0f62f3d4..29ad6c95 100644
--- a/examples~/quickstart/client/Program.cs
+++ b/examples~/quickstart/client/Program.cs
@@ -39,7 +39,9 @@ void Main()
     conn.RemoteReducers.OnSetName += Reducer_OnSetNameEvent;
     conn.RemoteReducers.OnSendMessage += Reducer_OnSendMessageEvent;
 
+#pragma warning disable CS0612 // Using obsolete API
     conn.onUnhandledReducerError += onUnhandledReducerError;
+#pragma warning restore CS0612 // Using obsolete API
 
     // declare a threadsafe cancel token to cancel the process loop
     var cancellationTokenSource = new CancellationTokenSource();
@@ -178,7 +180,7 @@ void ProcessThread(DbConnection conn, CancellationToken ct)
         // loop until cancellation token
         while (!ct.IsCancellationRequested)
         {
-            conn.Update();
+            conn.FrameTick();
 
             ProcessCommands(conn.RemoteReducers);
 
@@ -187,7 +189,7 @@ void ProcessThread(DbConnection conn, CancellationToken ct)
     }
     finally
     {
-        conn.Close();
+        conn.Disconnect();
     }
 }
 
diff --git a/src/ClientCache.cs b/src/ClientCache.cs
index 824ca34b..0ec8ad91 100644
--- a/src/ClientCache.cs
+++ b/src/ClientCache.cs
@@ -21,7 +21,7 @@ public void AddTable<Row>(string name, IRemoteTableHandle table)
             }
         }
 
-        public IRemoteTableHandle? GetTable(string name)
+        internal IRemoteTableHandle? GetTable(string name)
         {
             if (tables.TryGetValue(name, out var table))
             {
@@ -32,6 +32,6 @@ public void AddTable<Row>(string name, IRemoteTableHandle table)
             return null;
         }
 
-        public IEnumerable<IRemoteTableHandle> GetTables() => tables.Values;
+        internal IEnumerable<IRemoteTableHandle> GetTables() => tables.Values;
     }
 }
diff --git a/src/ConsoleLogger.cs b/src/ConsoleLogger.cs
index 1711899c..2fda0ab5 100644
--- a/src/ConsoleLogger.cs
+++ b/src/ConsoleLogger.cs
@@ -2,7 +2,7 @@
 
 namespace SpacetimeDB
 {
-    public class ConsoleLogger : ISpacetimeDBLogger
+    internal class ConsoleLogger : ISpacetimeDBLogger
     {
         [Flags]
         public enum LogLevel
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index b7c405f8..88c85ccc 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -111,27 +111,19 @@ struct DbOp
         /// <summary>
         /// Called when an exception occurs when sending a message.
         /// </summary>
+        [Obsolete]
         public event Action<Exception>? onSendError;
 
         private readonly Dictionary<uint, ISubscriptionHandle> subscriptions = new();
 
-        /// <summary>
-        /// Invoked when a subscription is about to start being processed. This is called even before OnBeforeDelete.
-        /// </summary>
-        public event Action? onBeforeSubscriptionApplied;
-
         /// <summary>
         /// Invoked when a reducer is returned with an error and has no client-side handler.
         /// </summary>
+        [Obsolete]
         public event Action<ReducerEvent<Reducer>>? onUnhandledReducerError;
 
-        /// <summary>
-        /// Invoked when an event message is received or at the end of a transaction update.
-        /// </summary>
-        public event Action<ServerMessage>? onEvent;
-
-        public readonly Address clientAddress = Address.Random();
-        public Identity? clientIdentity { get; private set; }
+        public readonly Address Address = Address.Random();
+        public Identity? Identity { get; private set; }
 
         internal WebSocket webSocket;
         private bool connectionClosed;
@@ -148,7 +140,7 @@ struct DbOp
 
         protected DbConnectionBase()
         {
-            var options = new ConnectOptions
+            var options = new WebSocket.ConnectOptions
             {
                 //v1.bin.spacetimedb
                 //v1.text.spacetimedb
@@ -470,7 +462,7 @@ ProcessedMessage CalculateStateDiff(PreProcessedMessage preProcessedMessage)
             return processed;
         }
 
-        public void Close()
+        public void Disconnect()
         {
             isClosing = true;
             connectionClosed = true;
@@ -483,7 +475,7 @@ public void Close()
         /// </summary>
         /// <param name="uri"> URI of the SpacetimeDB server (ex: https://testnet.spacetimedb.com)
         /// <param name="addressOrName">The name or address of the database to connect to</param>
-        public void Connect(string? token, string uri, string addressOrName)
+        internal void Connect(string? token, string uri, string addressOrName)
         {
             isClosing = false;
 
@@ -499,7 +491,7 @@ public void Connect(string? token, string uri, string addressOrName)
             {
                 try
                 {
-                    await webSocket.Connect(token, uri, addressOrName, clientAddress);
+                    await webSocket.Connect(token, uri, addressOrName, Address);
                 }
                 catch (Exception e)
                 {
@@ -605,7 +597,6 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
             {
                 case ServerMessage.InitialSubscription(var initialSubscription):
                     {
-                        onBeforeSubscriptionApplied?.Invoke();
                         stats.ParseMessageTracker.InsertRequest(timestamp, $"type={nameof(ServerMessage.InitialSubscription)}");
                         stats.SubscriptionRequestTracker.FinishTrackingRequest(initialSubscription.RequestId);
                         var eventContext = ToEventContext(new Event<Reducer>.SubscribeApplied());
@@ -630,7 +621,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                         var hostDuration = TimeSpan.FromMilliseconds(transactionUpdate.HostExecutionDurationMicros / 1000.0d);
                         stats.AllReducersTracker.InsertRequest(hostDuration, $"reducer={reducer}");
                         var callerIdentity = transactionUpdate.CallerIdentity;
-                        if (callerIdentity == clientIdentity)
+                        if (callerIdentity == Identity)
                         {
                             // This was a request that we initiated
                             var requestId = transactionUpdate.ReducerCall.RequestId;
@@ -648,14 +639,6 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
 
                         var eventContext = ToEventContext(new Event<Reducer>.Reducer(reducerEvent));
                         OnMessageProcessCompleteUpdate(eventContext, dbOps);
-                        try
-                        {
-                            onEvent?.Invoke(message);
-                        }
-                        catch (Exception e)
-                        {
-                            Log.Exception(e);
-                        }
 
                         var reducerFound = false;
                         try
@@ -683,7 +666,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                 case ServerMessage.IdentityToken(var identityToken):
                     try
                     {
-                        clientIdentity = identityToken.Identity;
+                        Identity = identityToken.Identity;
                         onConnect?.Invoke(identityToken.Identity, identityToken.Token);
                     }
                     catch (Exception e)
@@ -693,14 +676,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                     break;
 
                 case ServerMessage.OneOffQueryResponse:
-                    try
-                    {
-                        onEvent?.Invoke(message);
-                    }
-                    catch (Exception e)
-                    {
-                        Log.Exception(e);
-                    }
+                    /* OneOffQuery is async and handles its own responses */
                     break;
 
                 default:
@@ -807,9 +783,9 @@ T[] LogAndThrow(string error)
             return resultTable.Rows.Select(BSATNHelpers.Decode<T>).ToArray();
         }
 
-        public bool IsConnected() => webSocket.IsConnected;
+        public bool IsActive => webSocket.IsConnected;
 
-        public void Update()
+        public void FrameTick()
         {
             webSocket.Update();
             while (_preProcessedNetworkMessages.TryTake(out var preProcessedMessage))
diff --git a/src/UnityDebugLogger.cs b/src/UnityDebugLogger.cs
index 114079f0..218cde18 100644
--- a/src/UnityDebugLogger.cs
+++ b/src/UnityDebugLogger.cs
@@ -8,7 +8,7 @@
 
 namespace SpacetimeDB
 {
-    public class UnityDebugLogger : ISpacetimeDBLogger
+    internal class UnityDebugLogger : ISpacetimeDBLogger
     {
         public void Debug(string message)
         {
diff --git a/src/WebSocket.cs b/src/WebSocket.cs
index 73d23e9a..cd22c26f 100644
--- a/src/WebSocket.cs
+++ b/src/WebSocket.cs
@@ -11,23 +11,22 @@
 
 namespace SpacetimeDB
 {
-    public delegate void WebSocketOpenEventHandler();
-
-    public delegate void WebSocketMessageEventHandler(byte[] message, DateTime timestamp);
+    internal class WebSocket
+    {
+        public delegate void OpenEventHandler();
 
-    public delegate void WebSocketCloseEventHandler(WebSocketCloseStatus? code, WebSocketError? error);
+        public delegate void MessageEventHandler(byte[] message, DateTime timestamp);
 
-    public delegate void WebSocketConnectErrorEventHandler(WebSocketError? error, string message);
-    public delegate void WebSocketSendErrorEventHandler(Exception e);
+        public delegate void CloseEventHandler(WebSocketCloseStatus? code, WebSocketError? error);
 
-    public struct ConnectOptions
-    {
-        public string Protocol;
-    }
+        public delegate void ConnectErrorEventHandler(WebSocketError? error, string message);
+        public delegate void SendErrorEventHandler(Exception e);
 
+        public struct ConnectOptions
+        {
+            public string Protocol;
+        }
 
-    public class WebSocket
-    {
         // WebSocket buffer for incoming messages
         private static readonly int MAXMessageSize = 0x4000000; // 64MB
 
@@ -43,11 +42,11 @@ public WebSocket(ConnectOptions options)
             _options = options;
         }
 
-        public event WebSocketOpenEventHandler? OnConnect;
-        public event WebSocketConnectErrorEventHandler? OnConnectError;
-        public event WebSocketSendErrorEventHandler? OnSendError;
-        public event WebSocketMessageEventHandler? OnMessage;
-        public event WebSocketCloseEventHandler? OnClose;
+        public event OpenEventHandler? OnConnect;
+        public event ConnectErrorEventHandler? OnConnectError;
+        public event SendErrorEventHandler? OnSendError;
+        public event MessageEventHandler? OnMessage;
+        public event CloseEventHandler? OnClose;
 
         public bool IsConnected { get { return Ws != null && Ws.State == WebSocketState.Open; } }
 
diff --git a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
index fd948740..513aa66c 100644
--- a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
+++ b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
@@ -1,6 +1,10 @@
 {
   Events: {
-    OnIdentityReceived: Identity_1,
+    Log: SpacetimeDBClient: Connecting to wss://spacetimedb.com example,
+    OnConnect: {
+      identity: Identity_1,
+      token: eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJoZXhfaWRlbnRpdHkiOiI4ZjkwY2M5NGE5OTY4ZGY2ZDI5N2JhYTY2NTAzYTg5M2IxYzM0YjBiMDAyNjhhNTE0ODk4ZGQ5NTRiMGRhMjBiIiwiaWF0IjoxNzE4NDg3NjY4LCJleHAiOm51bGx9.PSn481bLRqtFwIh46nOXDY14X3GKbz8t4K4GmBmz50loU6xzeL7zDdCh1V2cmiQsoGq8Erxg0r_6b6Y5SqKoBA
+    },
     OnInsertUser: {
       eventContext: {
         Reducers: {Scrubbed},
@@ -33,18 +37,6 @@
         online: true
       }
     },
-    OnEvent: {
-      status: {Scrubbed},
-      timestamp: 1718487763059031,
-      caller_identity: Identity_2,
-      caller_address: Guid_1,
-      reducer_call: {
-        reducer_name: __identity_connected__,
-        args: 
-      },
-      energy_quanta_used: 1957615,
-      host_execution_duration_micros: 66
-    },
     OnUpdateUser: {
       eventContext: {
         Reducers: {Scrubbed},
@@ -74,19 +66,6 @@
         online: true
       }
     },
-    OnEvent: {
-      status: {Scrubbed},
-      timestamp: 1718487768057579,
-      caller_identity: Identity_1,
-      caller_address: Guid_2,
-      reducer_call: {
-        reducer_name: set_name,
-        args: AQAAAEE=,
-        request_id: 1
-      },
-      energy_quanta_used: 4345615,
-      host_execution_duration_micros: 70
-    },
     OnSetName: {
       Reducers: {Scrubbed},
       Reducer: {
@@ -130,19 +109,6 @@
         text: Hello, A!
       }
     },
-    OnEvent: {
-      status: {Scrubbed},
-      timestamp: 1718487775346381,
-      caller_identity: Identity_2,
-      caller_address: Guid_1,
-      reducer_call: {
-        reducer_name: send_message,
-        args: CQAAAEhlbGxvLCBBIQ==,
-        request_id: 1
-      },
-      energy_quanta_used: 2779615,
-      host_execution_duration_micros: 57
-    },
     OnSendMessage: {
       Reducers: {Scrubbed},
       Reducer: {
@@ -190,19 +156,6 @@
         online: true
       }
     },
-    OnEvent: {
-      status: {Scrubbed},
-      timestamp: 1718487777307855,
-      caller_identity: Identity_2,
-      caller_address: Guid_1,
-      reducer_call: {
-        reducer_name: set_name,
-        args: AQAAAEI=,
-        request_id: 2
-      },
-      energy_quanta_used: 4268615,
-      host_execution_duration_micros: 98
-    },
     OnSetName: {
       Reducers: {Scrubbed},
       Reducer: {
@@ -246,19 +199,6 @@
         text: Hello, B!
       }
     },
-    OnEvent: {
-      status: {Scrubbed},
-      timestamp: 1718487783175083,
-      caller_identity: Identity_1,
-      caller_address: Guid_2,
-      reducer_call: {
-        reducer_name: send_message,
-        args: CQAAAEhlbGxvLCBCIQ==,
-        request_id: 2
-      },
-      energy_quanta_used: 2677615,
-      host_execution_duration_micros: 40
-    },
     OnSendMessage: {
       Reducers: {Scrubbed},
       Reducer: {
@@ -302,19 +242,6 @@
         text: Goodbye!
       }
     },
-    OnEvent: {
-      status: {Scrubbed},
-      timestamp: 1718487787645364,
-      caller_identity: Identity_2,
-      caller_address: Guid_1,
-      reducer_call: {
-        reducer_name: send_message,
-        args: CAAAAEdvb2RieWUh,
-        request_id: 3
-      },
-      energy_quanta_used: 2636615,
-      host_execution_duration_micros: 28
-    },
     OnSendMessage: {
       Reducers: {Scrubbed},
       Reducer: {
@@ -359,18 +286,6 @@
         online: false
       }
     },
-    OnEvent: {
-      status: {Scrubbed},
-      timestamp: 1718487791901504,
-      caller_identity: Identity_2,
-      caller_address: Guid_1,
-      reducer_call: {
-        reducer_name: __identity_disconnected__,
-        args: 
-      },
-      energy_quanta_used: 3595615,
-      host_execution_duration_micros: 75
-    },
     OnInsertMessage: {
       eventContext: {
         Reducers: {Scrubbed},
@@ -396,19 +311,6 @@
         text: Goodbye!
       }
     },
-    OnEvent: {
-      status: {Scrubbed},
-      timestamp: 1718487794937841,
-      caller_identity: Identity_1,
-      caller_address: Guid_2,
-      reducer_call: {
-        reducer_name: send_message,
-        args: CAAAAEdvb2RieWUh,
-        request_id: 3
-      },
-      energy_quanta_used: 2636615,
-      host_execution_duration_micros: 34
-    },
     OnSendMessage: {
       Reducers: {Scrubbed},
       Reducer: {
diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs
index e99e601c..dd08dfe6 100644
--- a/tests~/SnapshotTests.cs
+++ b/tests~/SnapshotTests.cs
@@ -258,7 +258,12 @@ public async Task VerifyAllTablesParsed()
 
         Log.Current = new TestLogger(events);
 
-        var client = new DbConnection();
+        var client =
+            DbConnection.Builder()
+            .WithUri("wss://spacetimedb.com")
+            .WithModuleName("example")
+            .OnConnect((conn, identity, token) => events.Add("OnConnect", new { identity, token }))
+            .Build();
 
         var sampleDumpParsed = SampleDump();
 
@@ -286,20 +291,10 @@ public async Task VerifyAllTablesParsed()
             }
         );
 
-        client.onBeforeSubscriptionApplied += () => events.Add("OnBeforeSubscriptionApplied");
-        client.onEvent += (ev) => events.Add("OnEvent", ev switch
-        {
-            ServerMessage.IdentityToken(var o) => o,
-            ServerMessage.InitialSubscription(var o) => o,
-            ServerMessage.TransactionUpdate(var o) => o,
-            ServerMessage.OneOffQueryResponse(var o) => o,
-            _ => throw new InvalidOperationException()
-        });
-        client.onConnect += (identity, _token) =>
-            events.Add("OnIdentityReceived", identity);
+#pragma warning disable CS0612 // Using obsolete API
         client.onUnhandledReducerError += (exception) =>
             events.Add("OnUnhandledReducerError", exception);
-
+#pragma warning restore CS0612 // Using obsolete API
         client.RemoteReducers.OnSendMessage += (eventContext, _text) =>
             events.Add("OnSendMessage", eventContext);
         client.RemoteReducers.OnSetName += (eventContext, _name) => events.Add("OnSetName", eventContext);
@@ -332,7 +327,7 @@ public async Task VerifyAllTablesParsed()
             // Otherwise we'll get inconsistent output order between test reruns.
             while (!client.HasPreProcessedMessage) { }
             // Once the message is in the preprocessed queue, we can invoke Update() to handle events on the main thread.
-            client.Update();
+            client.FrameTick();
         }
 
         // Verify dumped events and the final client state.
diff --git a/tests~/tests.csproj b/tests~/tests.csproj
index 23735fb4..804fa736 100644
--- a/tests~/tests.csproj
+++ b/tests~/tests.csproj
@@ -23,7 +23,7 @@
     <PackageReference Include="xunit" Version="2.8.1" />
     <ProjectReference Include="../SpacetimeDB.ClientSDK.csproj" />
 
-    <Compile Include="../examples~/quickstart/client/module_bindings/**/*.cs" />
+    <ProjectReference Include="../examples~/quickstart/client/client.csproj" />
   </ItemGroup>
 
 </Project>

From 8df6d15a2bf9921acc2004d455e2db403b02aa9d Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Wed, 2 Oct 2024 17:18:24 +0200
Subject: [PATCH 12/55] Implement websocket changes atop C# sdk changes (#136)

## Requires SpacetimeDB PRs

This is the C# side of
https://github.com/clockworklabs/SpacetimeDB/pull/1761.
---
 src/BSATNHelpers.cs                           |   7 -
 src/SpacetimeDB/ClientApi/BsatnRowList.cs     |  40 +++
 src/SpacetimeDB/ClientApi/CallReducer.cs      |  21 +-
 .../ClientApi/CompressableQueryUpdate.cs      |  17 ++
 src/SpacetimeDB/ClientApi/DatabaseUpdate.cs   |  14 +-
 .../ClientApi/EncodedValue.cs.meta            |  11 -
 src/SpacetimeDB/ClientApi/EnergyQuanta.cs     |  11 +
 src/SpacetimeDB/ClientApi/IdentityToken.cs    |  24 +-
 .../ClientApi/InitialSubscription.cs          |  18 +-
 src/SpacetimeDB/ClientApi/OneOffQuery.cs      |  19 +-
 .../ClientApi/OneOffQueryResponse.cs          |  23 +-
 src/SpacetimeDB/ClientApi/OneOffTable.cs      |  19 +-
 src/SpacetimeDB/ClientApi/QueryUpdate.cs      |  40 +++
 src/SpacetimeDB/ClientApi/ReducerCallInfo.cs  |  23 +-
 .../{EncodedValue.cs => RowSizeHint.cs}       |   6 +-
 src/SpacetimeDB/ClientApi/Subscribe.cs        |  16 +-
 src/SpacetimeDB/ClientApi/TableUpdate.cs      |  29 +-
 src/SpacetimeDB/ClientApi/Timestamp.cs        |  11 +
 .../ClientApi/TransactionUpdate.cs            |  41 ++-
 src/SpacetimeDBClient.cs                      | 277 ++++++++++++------
 ...otTests.VerifyAllTablesParsed.verified.txt |   2 +-
 tests~/SnapshotTests.cs                       |  64 ++--
 22 files changed, 567 insertions(+), 166 deletions(-)
 create mode 100644 src/SpacetimeDB/ClientApi/BsatnRowList.cs
 create mode 100644 src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
 delete mode 100644 src/SpacetimeDB/ClientApi/EncodedValue.cs.meta
 create mode 100644 src/SpacetimeDB/ClientApi/QueryUpdate.cs
 rename src/SpacetimeDB/ClientApi/{EncodedValue.cs => RowSizeHint.cs} (66%)

diff --git a/src/BSATNHelpers.cs b/src/BSATNHelpers.cs
index 31f15628..46c4cb64 100644
--- a/src/BSATNHelpers.cs
+++ b/src/BSATNHelpers.cs
@@ -25,12 +25,5 @@ public static T Decode<T>(string json)
         {
             throw new InvalidOperationException("JSON isn't supported at the moment");
         }
-
-        public static T Decode<T>(EncodedValue value) where T : IStructuralReadWrite, new() => value switch
-        {
-            EncodedValue.Binary(var bin) => Decode<T>(bin),
-            EncodedValue.Text(var text) => Decode<T>(text),
-            _ => throw new InvalidOperationException()
-        };
     }
 }
diff --git a/src/SpacetimeDB/ClientApi/BsatnRowList.cs b/src/SpacetimeDB/ClientApi/BsatnRowList.cs
new file mode 100644
index 00000000..5df43d6b
--- /dev/null
+++ b/src/SpacetimeDB/ClientApi/BsatnRowList.cs
@@ -0,0 +1,40 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN RUST INSTEAD.
+// <auto-generated />
+
+#nullable enable
+
+using System;
+using SpacetimeDB;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization;
+
+namespace SpacetimeDB.ClientApi
+{
+	[SpacetimeDB.Type]
+	[DataContract]
+	public partial class BsatnRowList
+	{
+		[DataMember(Name = "size_hint")]
+		public SpacetimeDB.ClientApi.RowSizeHint SizeHint;
+		[DataMember(Name = "rows_data")]
+		public byte[] RowsData;
+
+		public BsatnRowList(
+			SpacetimeDB.ClientApi.RowSizeHint SizeHint,
+			byte[] RowsData
+		)
+		{
+			this.SizeHint = SizeHint;
+			this.RowsData = RowsData;
+		}
+
+		public BsatnRowList()
+		{
+			this.SizeHint = null!;
+			this.RowsData = Array.Empty<byte>();
+		}
+
+	}
+}
diff --git a/src/SpacetimeDB/ClientApi/CallReducer.cs b/src/SpacetimeDB/ClientApi/CallReducer.cs
index d3f56f38..7c3ce90e 100644
--- a/src/SpacetimeDB/ClientApi/CallReducer.cs
+++ b/src/SpacetimeDB/ClientApi/CallReducer.cs
@@ -17,11 +17,28 @@ namespace SpacetimeDB.ClientApi
 	public partial class CallReducer
 	{
 		[DataMember(Name = "reducer")]
-		public string Reducer = "";
+		public string Reducer;
 		[DataMember(Name = "args")]
-		public SpacetimeDB.ClientApi.EncodedValue Args = null!;
+		public byte[] Args;
 		[DataMember(Name = "request_id")]
 		public uint RequestId;
 
+		public CallReducer(
+			string Reducer,
+			byte[] Args,
+			uint RequestId
+		)
+		{
+			this.Reducer = Reducer;
+			this.Args = Args;
+			this.RequestId = RequestId;
+		}
+
+		public CallReducer()
+		{
+			this.Reducer = "";
+			this.Args = Array.Empty<byte>();
+		}
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
new file mode 100644
index 00000000..af397a58
--- /dev/null
+++ b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
@@ -0,0 +1,17 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN RUST INSTEAD.
+// <auto-generated />
+
+#nullable enable
+
+using System;
+using SpacetimeDB;
+
+namespace SpacetimeDB.ClientApi
+{
+	[SpacetimeDB.Type]
+	public partial record CompressableQueryUpdate : SpacetimeDB.TaggedEnum<(
+		SpacetimeDB.ClientApi.QueryUpdate Uncompressed,
+		byte[] Brotli
+	)>;
+}
diff --git a/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs b/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs
index 245117ad..3294c6b7 100644
--- a/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs
@@ -17,7 +17,19 @@ namespace SpacetimeDB.ClientApi
 	public partial class DatabaseUpdate
 	{
 		[DataMember(Name = "tables")]
-		public System.Collections.Generic.List<SpacetimeDB.ClientApi.TableUpdate> Tables = new();
+		public System.Collections.Generic.List<SpacetimeDB.ClientApi.TableUpdate> Tables;
+
+		public DatabaseUpdate(
+			System.Collections.Generic.List<SpacetimeDB.ClientApi.TableUpdate> Tables
+		)
+		{
+			this.Tables = Tables;
+		}
+
+		public DatabaseUpdate()
+		{
+			this.Tables = new();
+		}
 
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/EncodedValue.cs.meta b/src/SpacetimeDB/ClientApi/EncodedValue.cs.meta
deleted file mode 100644
index c89e37b1..00000000
--- a/src/SpacetimeDB/ClientApi/EncodedValue.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 16581799d308744cbba931760b17b64c
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/src/SpacetimeDB/ClientApi/EnergyQuanta.cs b/src/SpacetimeDB/ClientApi/EnergyQuanta.cs
index ba142cb3..476712e9 100644
--- a/src/SpacetimeDB/ClientApi/EnergyQuanta.cs
+++ b/src/SpacetimeDB/ClientApi/EnergyQuanta.cs
@@ -19,5 +19,16 @@ public partial class EnergyQuanta
 		[DataMember(Name = "quanta")]
 		public U128 Quanta;
 
+		public EnergyQuanta(
+			U128 Quanta
+		)
+		{
+			this.Quanta = Quanta;
+		}
+
+		public EnergyQuanta()
+		{
+		}
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/IdentityToken.cs b/src/SpacetimeDB/ClientApi/IdentityToken.cs
index 344cbbba..4a53ad2f 100644
--- a/src/SpacetimeDB/ClientApi/IdentityToken.cs
+++ b/src/SpacetimeDB/ClientApi/IdentityToken.cs
@@ -17,11 +17,29 @@ namespace SpacetimeDB.ClientApi
 	public partial class IdentityToken
 	{
 		[DataMember(Name = "identity")]
-		public SpacetimeDB.Identity Identity = new();
+		public SpacetimeDB.Identity Identity;
 		[DataMember(Name = "token")]
-		public string Token = "";
+		public string Token;
 		[DataMember(Name = "address")]
-		public SpacetimeDB.Address Address = new();
+		public SpacetimeDB.Address Address;
+
+		public IdentityToken(
+			SpacetimeDB.Identity Identity,
+			string Token,
+			SpacetimeDB.Address Address
+		)
+		{
+			this.Identity = Identity;
+			this.Token = Token;
+			this.Address = Address;
+		}
+
+		public IdentityToken()
+		{
+			this.Identity = new();
+			this.Token = "";
+			this.Address = new();
+		}
 
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/InitialSubscription.cs b/src/SpacetimeDB/ClientApi/InitialSubscription.cs
index 06ae7ba8..cdbc73de 100644
--- a/src/SpacetimeDB/ClientApi/InitialSubscription.cs
+++ b/src/SpacetimeDB/ClientApi/InitialSubscription.cs
@@ -17,11 +17,27 @@ namespace SpacetimeDB.ClientApi
 	public partial class InitialSubscription
 	{
 		[DataMember(Name = "database_update")]
-		public SpacetimeDB.ClientApi.DatabaseUpdate DatabaseUpdate = new();
+		public SpacetimeDB.ClientApi.DatabaseUpdate DatabaseUpdate;
 		[DataMember(Name = "request_id")]
 		public uint RequestId;
 		[DataMember(Name = "total_host_execution_duration_micros")]
 		public ulong TotalHostExecutionDurationMicros;
 
+		public InitialSubscription(
+			SpacetimeDB.ClientApi.DatabaseUpdate DatabaseUpdate,
+			uint RequestId,
+			ulong TotalHostExecutionDurationMicros
+		)
+		{
+			this.DatabaseUpdate = DatabaseUpdate;
+			this.RequestId = RequestId;
+			this.TotalHostExecutionDurationMicros = TotalHostExecutionDurationMicros;
+		}
+
+		public InitialSubscription()
+		{
+			this.DatabaseUpdate = new();
+		}
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/OneOffQuery.cs b/src/SpacetimeDB/ClientApi/OneOffQuery.cs
index c103c829..5ee2c66d 100644
--- a/src/SpacetimeDB/ClientApi/OneOffQuery.cs
+++ b/src/SpacetimeDB/ClientApi/OneOffQuery.cs
@@ -17,9 +17,24 @@ namespace SpacetimeDB.ClientApi
 	public partial class OneOffQuery
 	{
 		[DataMember(Name = "message_id")]
-		public byte[] MessageId = Array.Empty<byte>();
+		public byte[] MessageId;
 		[DataMember(Name = "query_string")]
-		public string QueryString = "";
+		public string QueryString;
+
+		public OneOffQuery(
+			byte[] MessageId,
+			string QueryString
+		)
+		{
+			this.MessageId = MessageId;
+			this.QueryString = QueryString;
+		}
+
+		public OneOffQuery()
+		{
+			this.MessageId = Array.Empty<byte>();
+			this.QueryString = "";
+		}
 
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs b/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs
index 35c1d0eb..f539516f 100644
--- a/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs
+++ b/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs
@@ -17,13 +17,32 @@ namespace SpacetimeDB.ClientApi
 	public partial class OneOffQueryResponse
 	{
 		[DataMember(Name = "message_id")]
-		public byte[] MessageId = Array.Empty<byte>();
+		public byte[] MessageId;
 		[DataMember(Name = "error")]
 		public string? Error;
 		[DataMember(Name = "tables")]
-		public System.Collections.Generic.List<SpacetimeDB.ClientApi.OneOffTable> Tables = new();
+		public System.Collections.Generic.List<SpacetimeDB.ClientApi.OneOffTable> Tables;
 		[DataMember(Name = "total_host_execution_duration_micros")]
 		public ulong TotalHostExecutionDurationMicros;
 
+		public OneOffQueryResponse(
+			byte[] MessageId,
+			string? Error,
+			System.Collections.Generic.List<SpacetimeDB.ClientApi.OneOffTable> Tables,
+			ulong TotalHostExecutionDurationMicros
+		)
+		{
+			this.MessageId = MessageId;
+			this.Error = Error;
+			this.Tables = Tables;
+			this.TotalHostExecutionDurationMicros = TotalHostExecutionDurationMicros;
+		}
+
+		public OneOffQueryResponse()
+		{
+			this.MessageId = Array.Empty<byte>();
+			this.Tables = new();
+		}
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/OneOffTable.cs b/src/SpacetimeDB/ClientApi/OneOffTable.cs
index 12f7e0f9..d1f48f3f 100644
--- a/src/SpacetimeDB/ClientApi/OneOffTable.cs
+++ b/src/SpacetimeDB/ClientApi/OneOffTable.cs
@@ -17,9 +17,24 @@ namespace SpacetimeDB.ClientApi
 	public partial class OneOffTable
 	{
 		[DataMember(Name = "table_name")]
-		public string TableName = "";
+		public string TableName;
 		[DataMember(Name = "rows")]
-		public System.Collections.Generic.List<SpacetimeDB.ClientApi.EncodedValue> Rows = new();
+		public SpacetimeDB.ClientApi.BsatnRowList Rows;
+
+		public OneOffTable(
+			string TableName,
+			SpacetimeDB.ClientApi.BsatnRowList Rows
+		)
+		{
+			this.TableName = TableName;
+			this.Rows = Rows;
+		}
+
+		public OneOffTable()
+		{
+			this.TableName = "";
+			this.Rows = new();
+		}
 
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/QueryUpdate.cs b/src/SpacetimeDB/ClientApi/QueryUpdate.cs
new file mode 100644
index 00000000..858dea65
--- /dev/null
+++ b/src/SpacetimeDB/ClientApi/QueryUpdate.cs
@@ -0,0 +1,40 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN RUST INSTEAD.
+// <auto-generated />
+
+#nullable enable
+
+using System;
+using SpacetimeDB;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization;
+
+namespace SpacetimeDB.ClientApi
+{
+	[SpacetimeDB.Type]
+	[DataContract]
+	public partial class QueryUpdate
+	{
+		[DataMember(Name = "deletes")]
+		public SpacetimeDB.ClientApi.BsatnRowList Deletes;
+		[DataMember(Name = "inserts")]
+		public SpacetimeDB.ClientApi.BsatnRowList Inserts;
+
+		public QueryUpdate(
+			SpacetimeDB.ClientApi.BsatnRowList Deletes,
+			SpacetimeDB.ClientApi.BsatnRowList Inserts
+		)
+		{
+			this.Deletes = Deletes;
+			this.Inserts = Inserts;
+		}
+
+		public QueryUpdate()
+		{
+			this.Deletes = new();
+			this.Inserts = new();
+		}
+
+	}
+}
diff --git a/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs b/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs
index 44bc8865..0ca52252 100644
--- a/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs
+++ b/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs
@@ -17,13 +17,32 @@ namespace SpacetimeDB.ClientApi
 	public partial class ReducerCallInfo
 	{
 		[DataMember(Name = "reducer_name")]
-		public string ReducerName = "";
+		public string ReducerName;
 		[DataMember(Name = "reducer_id")]
 		public uint ReducerId;
 		[DataMember(Name = "args")]
-		public SpacetimeDB.ClientApi.EncodedValue Args = null!;
+		public byte[] Args;
 		[DataMember(Name = "request_id")]
 		public uint RequestId;
 
+		public ReducerCallInfo(
+			string ReducerName,
+			uint ReducerId,
+			byte[] Args,
+			uint RequestId
+		)
+		{
+			this.ReducerName = ReducerName;
+			this.ReducerId = ReducerId;
+			this.Args = Args;
+			this.RequestId = RequestId;
+		}
+
+		public ReducerCallInfo()
+		{
+			this.ReducerName = "";
+			this.Args = Array.Empty<byte>();
+		}
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/EncodedValue.cs b/src/SpacetimeDB/ClientApi/RowSizeHint.cs
similarity index 66%
rename from src/SpacetimeDB/ClientApi/EncodedValue.cs
rename to src/SpacetimeDB/ClientApi/RowSizeHint.cs
index 16793ca5..71c04c1b 100644
--- a/src/SpacetimeDB/ClientApi/EncodedValue.cs
+++ b/src/SpacetimeDB/ClientApi/RowSizeHint.cs
@@ -10,8 +10,8 @@
 namespace SpacetimeDB.ClientApi
 {
 	[SpacetimeDB.Type]
-	public partial record EncodedValue : SpacetimeDB.TaggedEnum<(
-		byte[] Binary,
-		string Text
+	public partial record RowSizeHint : SpacetimeDB.TaggedEnum<(
+		ushort FixedSize,
+		System.Collections.Generic.List<ulong> RowOffsets
 	)>;
 }
diff --git a/src/SpacetimeDB/ClientApi/Subscribe.cs b/src/SpacetimeDB/ClientApi/Subscribe.cs
index d5eaba81..0adad9b2 100644
--- a/src/SpacetimeDB/ClientApi/Subscribe.cs
+++ b/src/SpacetimeDB/ClientApi/Subscribe.cs
@@ -17,9 +17,23 @@ namespace SpacetimeDB.ClientApi
 	public partial class Subscribe
 	{
 		[DataMember(Name = "query_strings")]
-		public System.Collections.Generic.List<string> QueryStrings = new();
+		public System.Collections.Generic.List<string> QueryStrings;
 		[DataMember(Name = "request_id")]
 		public uint RequestId;
 
+		public Subscribe(
+			System.Collections.Generic.List<string> QueryStrings,
+			uint RequestId
+		)
+		{
+			this.QueryStrings = QueryStrings;
+			this.RequestId = RequestId;
+		}
+
+		public Subscribe()
+		{
+			this.QueryStrings = new();
+		}
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/TableUpdate.cs b/src/SpacetimeDB/ClientApi/TableUpdate.cs
index b9b47ea5..cc2586d3 100644
--- a/src/SpacetimeDB/ClientApi/TableUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/TableUpdate.cs
@@ -19,11 +19,30 @@ public partial class TableUpdate
 		[DataMember(Name = "table_id")]
 		public uint TableId;
 		[DataMember(Name = "table_name")]
-		public string TableName = "";
-		[DataMember(Name = "deletes")]
-		public System.Collections.Generic.List<SpacetimeDB.ClientApi.EncodedValue> Deletes = new();
-		[DataMember(Name = "inserts")]
-		public System.Collections.Generic.List<SpacetimeDB.ClientApi.EncodedValue> Inserts = new();
+		public string TableName;
+		[DataMember(Name = "num_rows")]
+		public ulong NumRows;
+		[DataMember(Name = "updates")]
+		public System.Collections.Generic.List<SpacetimeDB.ClientApi.CompressableQueryUpdate> Updates;
+
+		public TableUpdate(
+			uint TableId,
+			string TableName,
+			ulong NumRows,
+			System.Collections.Generic.List<SpacetimeDB.ClientApi.CompressableQueryUpdate> Updates
+		)
+		{
+			this.TableId = TableId;
+			this.TableName = TableName;
+			this.NumRows = NumRows;
+			this.Updates = Updates;
+		}
+
+		public TableUpdate()
+		{
+			this.TableName = "";
+			this.Updates = new();
+		}
 
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/Timestamp.cs b/src/SpacetimeDB/ClientApi/Timestamp.cs
index 4dd2535c..c0f53ba1 100644
--- a/src/SpacetimeDB/ClientApi/Timestamp.cs
+++ b/src/SpacetimeDB/ClientApi/Timestamp.cs
@@ -19,5 +19,16 @@ public partial class Timestamp
 		[DataMember(Name = "microseconds")]
 		public ulong Microseconds;
 
+		public Timestamp(
+			ulong Microseconds
+		)
+		{
+			this.Microseconds = Microseconds;
+		}
+
+		public Timestamp()
+		{
+		}
+
 	}
 }
diff --git a/src/SpacetimeDB/ClientApi/TransactionUpdate.cs b/src/SpacetimeDB/ClientApi/TransactionUpdate.cs
index fb71dd9e..e4925bf4 100644
--- a/src/SpacetimeDB/ClientApi/TransactionUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/TransactionUpdate.cs
@@ -17,19 +17,48 @@ namespace SpacetimeDB.ClientApi
 	public partial class TransactionUpdate
 	{
 		[DataMember(Name = "status")]
-		public SpacetimeDB.ClientApi.UpdateStatus Status = null!;
+		public SpacetimeDB.ClientApi.UpdateStatus Status;
 		[DataMember(Name = "timestamp")]
-		public SpacetimeDB.ClientApi.Timestamp Timestamp = new();
+		public SpacetimeDB.ClientApi.Timestamp Timestamp;
 		[DataMember(Name = "caller_identity")]
-		public SpacetimeDB.Identity CallerIdentity = new();
+		public SpacetimeDB.Identity CallerIdentity;
 		[DataMember(Name = "caller_address")]
-		public SpacetimeDB.Address CallerAddress = new();
+		public SpacetimeDB.Address CallerAddress;
 		[DataMember(Name = "reducer_call")]
-		public SpacetimeDB.ClientApi.ReducerCallInfo ReducerCall = new();
+		public SpacetimeDB.ClientApi.ReducerCallInfo ReducerCall;
 		[DataMember(Name = "energy_quanta_used")]
-		public SpacetimeDB.ClientApi.EnergyQuanta EnergyQuantaUsed = new();
+		public SpacetimeDB.ClientApi.EnergyQuanta EnergyQuantaUsed;
 		[DataMember(Name = "host_execution_duration_micros")]
 		public ulong HostExecutionDurationMicros;
 
+		public TransactionUpdate(
+			SpacetimeDB.ClientApi.UpdateStatus Status,
+			SpacetimeDB.ClientApi.Timestamp Timestamp,
+			SpacetimeDB.Identity CallerIdentity,
+			SpacetimeDB.Address CallerAddress,
+			SpacetimeDB.ClientApi.ReducerCallInfo ReducerCall,
+			SpacetimeDB.ClientApi.EnergyQuanta EnergyQuantaUsed,
+			ulong HostExecutionDurationMicros
+		)
+		{
+			this.Status = Status;
+			this.Timestamp = Timestamp;
+			this.CallerIdentity = CallerIdentity;
+			this.CallerAddress = CallerAddress;
+			this.ReducerCall = ReducerCall;
+			this.EnergyQuantaUsed = EnergyQuantaUsed;
+			this.HostExecutionDurationMicros = HostExecutionDurationMicros;
+		}
+
+		public TransactionUpdate()
+		{
+			this.Status = null!;
+			this.Timestamp = new();
+			this.CallerIdentity = new();
+			this.CallerAddress = new();
+			this.ReducerCall = new();
+			this.EnergyQuantaUsed = new();
+		}
+
 	}
 }
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 88c85ccc..c01bb9b9 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -144,7 +144,7 @@ protected DbConnectionBase()
             {
                 //v1.bin.spacetimedb
                 //v1.text.spacetimedb
-                Protocol = "v1.bin.spacetimedb",
+                Protocol = "v1.bsatn.spacetimedb"
             };
             webSocket = new WebSocket(options);
             webSocket.OnMessage += OnMessageReceived;
@@ -185,10 +185,8 @@ struct PreProcessedMessage
         private readonly CancellationTokenSource _preProcessCancellationTokenSource = new();
         private CancellationToken _preProcessCancellationToken => _preProcessCancellationTokenSource.Token;
 
-        static DbValue Decode(IRemoteTableHandle table, EncodedValue value, out object? primaryKey)
+        static DbValue Decode(IRemoteTableHandle table, byte[] bin, out object? primaryKey)
         {
-            // We expect only binary messages here; let type cast exception take care of any others.
-            var bin = ((EncodedValue.Binary)value).Binary_;
             var obj = table.DecodeValue(bin);
             primaryKey = table.GetPrimaryKey(obj);
             return new(obj, bin);
@@ -197,6 +195,104 @@ static DbValue Decode(IRemoteTableHandle table, EncodedValue value, out object?
         private static readonly Status Committed = new Status.Committed(default);
         private static readonly Status OutOfEnergy = new Status.OutOfEnergy(default);
 
+        enum CompressionAlgos : byte
+        {
+            None = 0,
+            Brotli = 1,
+        }
+
+        private static ServerMessage DecompressDecodeMessage(byte[] bytes)
+        {
+            using var stream = new MemoryStream(bytes, 1, bytes.Length - 1);
+
+            // The stream will never be empty. It will at least contain the compression algo.
+            var compression = (CompressionAlgos)bytes[0];
+            // Conditionally decompress and decode.
+            switch (compression)
+            {
+                case CompressionAlgos.None:
+                    {
+                        using var binaryReader = new BinaryReader(stream);
+                        return new ServerMessage.BSATN().Read(binaryReader);
+                    }
+                case CompressionAlgos.Brotli:
+                    {
+                        using var decompressedStream = new BrotliStream(stream, CompressionMode.Decompress);
+                        using var binaryReader = new BinaryReader(decompressedStream);
+                        return new ServerMessage.BSATN().Read(binaryReader);
+                    }
+                default:
+                    throw new InvalidOperationException("Unknown compression type");
+            }
+        }
+
+        private static QueryUpdate DecompressDecodeQueryUpdate(CompressableQueryUpdate update)
+        {
+            switch (update)
+            {
+                case CompressableQueryUpdate.Uncompressed(var qu):
+                    return qu;
+
+                case CompressableQueryUpdate.Brotli(var bytes):
+                    {
+                        using var stream = new MemoryStream(bytes);
+                        using var decompressedStream = new BrotliStream(stream, CompressionMode.Decompress);
+                        using var binaryReader = new BinaryReader(decompressedStream);
+                        return new QueryUpdate.BSATN().Read(binaryReader);
+                    }
+                default:
+                    throw new InvalidOperationException();
+            }
+        }
+
+        private static int BsatnRowListCount(BsatnRowList list)
+        {
+            switch (list.SizeHint)
+            {
+                case RowSizeHint.FixedSize(var size):
+                    return list.RowsData.Length / size;
+                case RowSizeHint.RowOffsets(var offsets):
+                    return offsets.Count;
+                default:
+                    throw new InvalidOperationException("Unknown RowSizeHint variant");
+            }
+        }
+
+        private static IEnumerable<byte[]> BsatnRowListIter(BsatnRowList list)
+        {
+            var count = BsatnRowListCount(list);
+            for (int index = 0; index < count; index += 1)
+            {
+                switch (list.SizeHint)
+                {
+                    case RowSizeHint.FixedSize(var size):
+                        {
+                            int start = index * size;
+                            int elemLen = size;
+                            yield return new ReadOnlySpan<byte>(list.RowsData, start, elemLen).ToArray();
+                            break;
+                        }
+                    case RowSizeHint.RowOffsets(var offsets):
+                        {
+                            int start = (int)offsets[index];
+                            // The end is either the start of the next element or the end.
+                            int end;
+                            if (index + 1 == count)
+                            {
+                                end = list.RowsData.Length;
+                            }
+                            else
+                            {
+                                end = (int)offsets[index + 1];
+                            }
+                            int elemLen = end - start;
+                            yield return new ReadOnlyMemory<byte>(list.RowsData, start, elemLen).ToArray();
+                            break;
+                        }
+                }
+            }
+        }
+
         void PreProcessMessages()
         {
             while (!isClosing)
@@ -216,10 +312,8 @@ void PreProcessMessages()
             PreProcessedMessage PreProcessMessage(UnprocessedMessage unprocessed)
             {
                 var dbOps = new List<DbOp>();
-                using var compressedStream = new MemoryStream(unprocessed.bytes);
-                using var decompressedStream = new BrotliStream(compressedStream, CompressionMode.Decompress);
-                using var binaryReader = new BinaryReader(decompressedStream);
-                var message = new ServerMessage.BSATN().Read(binaryReader);
+
+                var message = DecompressDecodeMessage(unprocessed.bytes);
 
                 ReducerEvent<Reducer>? reducerEvent = default;
 
@@ -242,7 +336,8 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                 switch (message)
                 {
                     case ServerMessage.InitialSubscription(var initialSubscription):
-                        subscriptionInserts = new(capacity: initialSubscription.DatabaseUpdate.Tables.Sum(a => a.Inserts.Count));
+                        int cap = initialSubscription.DatabaseUpdate.Tables.Sum(a => (int)a.NumRows);
+                        subscriptionInserts = new(capacity: cap);
 
                         // First apply all of the state
                         foreach (var update in initialSubscription.DatabaseUpdate.Tables)
@@ -255,37 +350,33 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                                 continue;
                             }
 
-                            if (update.Deletes.Count != 0)
-                            {
-                                Log.Warn("Non-insert during a subscription update!");
-                            }
-
-                            var hashSet = GetInsertHashSet(table.ClientTableType, initialSubscription.DatabaseUpdate.Tables.Count);
+                            var hashSet = GetInsertHashSet(table.ClientTableType, (int)update.NumRows);
 
-                            foreach (var row in update.Inserts)
+                            foreach (var cqu in update.Updates)
                             {
-                                switch (row)
+                                var qu = DecompressDecodeQueryUpdate(cqu);
+                                if (BsatnRowListCount(qu.Deletes) != 0)
                                 {
-                                    case EncodedValue.Binary(var bin):
-                                        if (!hashSet.Add(bin))
-                                        {
-                                            // Ignore duplicate inserts in the same subscription update.
-                                            continue;
-                                        }
+                                    Log.Warn("Non-insert during a subscription update!");
+                                }
 
-                                        var obj = table.DecodeValue(bin);
-                                        var op = new DbOp
-                                        {
-                                            table = table,
-                                            insert = new(obj, bin),
-                                        };
+                                foreach (var bin in BsatnRowListIter(qu.Inserts))
+                                {
+                                    if (!hashSet.Add(bin))
+                                    {
+                                        // Ignore duplicate inserts in the same subscription update.
+                                        continue;
+                                    }
 
-                                        dbOps.Add(op);
-                                        break;
+                                    var obj = table.DecodeValue(bin);
+                                    var op = new DbOp
+                                    {
+                                        table = table,
+                                        insert = new(obj, bin),
+                                    };
 
-                                    case EncodedValue.Text(var txt):
-                                        Log.Warn("JavaScript messages are unsupported.");
-                                        break;
+                                    dbOps.Add(op);
+                                    break;
                                 }
                             }
                         }
@@ -329,73 +420,77 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                                     continue;
                                 }
 
-                                foreach (var row in update.Inserts)
+                                foreach (var cqu in update.Updates)
                                 {
-                                    var op = new DbOp { table = table, insert = Decode(table, row, out var pk) };
-                                    if (pk != null)
+                                    var qu = DecompressDecodeQueryUpdate(cqu);
+                                    foreach (var row in BsatnRowListIter(qu.Inserts))
                                     {
-                                        // Compound key that we use for lookup.
-                                        // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
-                                        var key = (table.ClientTableType, pk);
-
-                                        if (primaryKeyChanges.TryGetValue(key, out var oldOp))
+                                        var op = new DbOp { table = table, insert = Decode(table, row, out var pk) };
+                                        if (pk != null)
                                         {
-                                            if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
-                                            {
-                                                Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
-                                                // TODO(jdetter): Is this a correctable error? This would be a major error on the
-                                                // SpacetimeDB side.
-                                                continue;
-                                            }
+                                            // Compound key that we use for lookup.
+                                            // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
+                                            var key = (table.ClientTableType, pk);
 
-                                            var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
-                                            op = new DbOp
+                                            if (primaryKeyChanges.TryGetValue(key, out var oldOp))
                                             {
-                                                table = insertOp.table,
-                                                delete = deleteOp.delete,
-                                                insert = insertOp.insert,
-                                            };
+                                                if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
+                                                {
+                                                    Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
+                                                    // TODO(jdetter): Is this a correctable error? This would be a major error on the
+                                                    // SpacetimeDB side.
+                                                    continue;
+                                                }
+
+                                                var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
+                                                op = new DbOp
+                                                {
+                                                    table = insertOp.table,
+                                                    delete = deleteOp.delete,
+                                                    insert = insertOp.insert,
+                                                };
+                                            }
+                                            primaryKeyChanges[key] = op;
+                                        }
+                                        else
+                                        {
+                                            dbOps.Add(op);
                                         }
-                                        primaryKeyChanges[key] = op;
-                                    }
-                                    else
-                                    {
-                                        dbOps.Add(op);
                                     }
-                                }
 
-                                foreach (var row in update.Deletes)
-                                {
-                                    var op = new DbOp { table = table, delete = Decode(table, row, out var pk) };
-                                    if (pk != null)
+                                    foreach (var row in BsatnRowListIter(qu.Deletes))
                                     {
-                                        // Compound key that we use for lookup.
-                                        // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
-                                        var key = (table.ClientTableType, pk);
-
-                                        if (primaryKeyChanges.TryGetValue(key, out var oldOp))
+                                        var op = new DbOp { table = table, delete = Decode(table, row, out var pk) };
+                                        if (pk != null)
                                         {
-                                            if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
-                                            {
-                                                Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
-                                                // TODO(jdetter): Is this a correctable error? This would be a major error on the
-                                                // SpacetimeDB side.
-                                                continue;
-                                            }
+                                            // Compound key that we use for lookup.
+                                            // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
+                                            var key = (table.ClientTableType, pk);
 
-                                            var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
-                                            op = new DbOp
+                                            if (primaryKeyChanges.TryGetValue(key, out var oldOp))
                                             {
-                                                table = insertOp.table,
-                                                delete = deleteOp.delete,
-                                                insert = insertOp.insert,
-                                            };
+                                                if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
+                                                {
+                                                    Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
+                                                    // TODO(jdetter): Is this a correctable error? This would be a major error on the
+                                                    // SpacetimeDB side.
+                                                    continue;
+                                                }
+
+                                                var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
+                                                op = new DbOp
+                                                {
+                                                    table = insertOp.table,
+                                                    delete = deleteOp.delete,
+                                                    insert = insertOp.insert,
+                                                };
+                                            }
+                                            primaryKeyChanges[key] = op;
+                                        }
+                                        else
+                                        {
+                                            dbOps.Add(op);
                                         }
-                                        primaryKeyChanges[key] = op;
-                                    }
-                                    else
-                                    {
-                                        dbOps.Add(op);
                                     }
                                 }
                             }
@@ -702,7 +797,7 @@ public void InternalCallReducer<T>(T args)
                 {
                     RequestId = stats.ReducerRequestTracker.StartTrackingRequest(args.ReducerName),
                     Reducer = args.ReducerName,
-                    Args = new EncodedValue.Binary(IStructuralReadWrite.ToBytes(args))
+                    Args = IStructuralReadWrite.ToBytes(args)
                 }
             ));
         }
@@ -780,7 +875,9 @@ T[] LogAndThrow(string error)
                 return LogAndThrow($"Mismatched result type, expected {type} but got {resultTable.TableName}");
             }
 
-            return resultTable.Rows.Select(BSATNHelpers.Decode<T>).ToArray();
+            return BsatnRowListIter(resultTable.Rows)
+                .Select(row => BSATNHelpers.Decode<T>(row))
+                .ToArray();
         }
 
         public bool IsActive => webSocket.IsConnected;
diff --git a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
index 513aa66c..53528975 100644
--- a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
+++ b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
@@ -390,4 +390,4 @@
       Max: type=InitialSubscription
     }
   }
-}
\ No newline at end of file
+}
diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs
index dd08dfe6..c429d07b 100644
--- a/tests~/SnapshotTests.cs
+++ b/tests~/SnapshotTests.cs
@@ -47,14 +47,6 @@ public override void Write(VerifyJsonWriter writer, EnergyQuanta value)
         }
     }
 
-    class EncodedValueConverter : WriteOnlyJsonConverter<EncodedValue.Binary>
-    {
-        public override void Write(VerifyJsonWriter writer, EncodedValue.Binary value)
-        {
-            writer.WriteValue(value.Binary_);
-        }
-    }
-
     class TestLogger(Events events) : ISpacetimeDBLogger
     {
         public void Debug(string message)
@@ -124,7 +116,7 @@ private static ServerMessage.TransactionUpdate SampleTransactionUpdate(
         ulong energyQuantaUsed,
         ulong hostExecutionDuration,
         List<TableUpdate> updates,
-        EncodedValue? args
+        byte[]? args
     ) => new(new()
     {
         Timestamp = new Timestamp { Microseconds = timestamp },
@@ -139,7 +131,7 @@ private static ServerMessage.TransactionUpdate SampleTransactionUpdate(
         {
             RequestId = requestId,
             ReducerName = reducerName,
-            Args = args ?? new EncodedValue.Binary([])
+            Args = args ?? []
         },
         Status = new UpdateStatus.Committed(new()
         {
@@ -147,55 +139,73 @@ private static ServerMessage.TransactionUpdate SampleTransactionUpdate(
         })
     });
 
-    private static TableUpdate SampleUpdate(
+    private static TableUpdate SampleUpdate<T>(
         uint tableId,
         string tableName,
-        List<EncodedValue> inserts,
-        List<EncodedValue> deletes
-    ) => new()
+        List<T> inserts,
+        List<T> deletes
+    ) where T : IStructuralReadWrite => new()
     {
         TableId = tableId,
         TableName = tableName,
-        Inserts = inserts,
-        Deletes = deletes
+        NumRows = (ulong)(inserts.Count + deletes.Count),
+        Updates = [new CompressableQueryUpdate.Uncompressed(new QueryUpdate(
+            EncodeRowList<T>(deletes), EncodeRowList<T>(inserts)))]
     };
 
-    private static EncodedValue.Binary Encode<T>(in T value) where T : IStructuralReadWrite
+    private static BsatnRowList EncodeRowList<T>(in List<T> list) where T : IStructuralReadWrite
+    {
+        var offsets = new List<ulong>();
+        var stream = new MemoryStream();
+        var writer = new BinaryWriter(stream);
+        foreach (var elem in list)
+        {
+            offsets.Add((ulong)stream.Length);
+            elem.WriteFields(writer);
+        }
+        return new BsatnRowList
+        {
+            RowsData = stream.ToArray(),
+            SizeHint = new RowSizeHint.RowOffsets(offsets)
+        };
+    }
+
+    private static byte[] Encode<T>(in T value) where T : IStructuralReadWrite
     {
         var o = new MemoryStream();
         var w = new BinaryWriter(o);
         value.WriteFields(w);
-        return new EncodedValue.Binary(o.ToArray());
+        return o.ToArray();
     }
 
     private static TableUpdate SampleUserInsert(string identity, string? name, bool online) =>
-        SampleUpdate(4097, "User", [Encode(new User
+        SampleUpdate(4097, "User", [new User
         {
             Identity = Identity.From(Convert.FromBase64String(identity)),
             Name = name,
             Online = online
-        })], []);
+        }], []);
 
     private static TableUpdate SampleUserUpdate(string identity, string? oldName, string? newName, bool oldOnline, bool newOnline) =>
-        SampleUpdate(4097, "User", [Encode(new User
+        SampleUpdate(4097, "User", [new User
         {
             Identity = Identity.From(Convert.FromBase64String(identity)),
             Name = newName,
             Online = newOnline
-        })], [Encode(new User
+        }], [new User
         {
             Identity = Identity.From(Convert.FromBase64String(identity)),
             Name = oldName,
             Online = oldOnline
-        })]);
+        }]);
 
     private static TableUpdate SampleMessage(string identity, ulong sent, string text) =>
-        SampleUpdate(4098, "Message", [Encode(new Message
+        SampleUpdate(4098, "Message", [new Message
         {
             Sender = Identity.From(Convert.FromBase64String(identity)),
             Sent = sent,
             Text = text
-        })], []);
+        }], []);
 
     private static ServerMessage[] SampleDump() => [
         SampleId(
@@ -282,6 +292,7 @@ public async Task VerifyAllTablesParsed()
                         break;
                 }
                 using var output = new MemoryStream();
+                output.WriteByte(1); // Write compression tag.
                 using (var brotli = new BrotliStream(output, CompressionMode.Compress))
                 {
                     using var w = new BinaryWriter(brotli);
@@ -346,8 +357,7 @@ await Verify(
             .AddExtraSettings(settings => settings.Converters.AddRange([
                 new EventsConverter(),
                 new TimestampConverter(),
-                new EnergyQuantaConverter(),
-                new EncodedValueConverter()
+                new EnergyQuantaConverter()
             ]))
             .ScrubMember<TransactionUpdate>(x => x.Status)
             .ScrubMember<DbContext<RemoteTables>>(x => x.Db)

From 63e6f79da0926114c373dbb2c1ef3a3be74ce223 Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Wed, 2 Oct 2024 21:56:57 +0100
Subject: [PATCH 13/55] Fix UnityDebugLogger implementation (#143)

## Description of Changes

Without explicit reference these result in

> error CS0119: 'UnityDebugLogger.Debug(string)' is a method, which is
not valid in the given context

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 src/UnityDebugLogger.cs | 43 ++++++++++++++---------------------------
 1 file changed, 14 insertions(+), 29 deletions(-)

diff --git a/src/UnityDebugLogger.cs b/src/UnityDebugLogger.cs
index 218cde18..94d21aee 100644
--- a/src/UnityDebugLogger.cs
+++ b/src/UnityDebugLogger.cs
@@ -4,46 +4,31 @@
  */
 #if UNITY_5_3_OR_NEWER
 using System;
-using UnityEngine;
 
 namespace SpacetimeDB
 {
     internal class UnityDebugLogger : ISpacetimeDBLogger
     {
-        public void Debug(string message)
-        {
-            Debug.Log(message);
-        }
+        public void Debug(string message) =>
+            UnityEngine.Debug.Log(message);
 
-        public void Trace(string message)
-        {
-            Debug.Log(message);
-        }
+        public void Trace(string message) =>
+            UnityEngine.Debug.Log(message);
 
-        public void Info(string message)
-        {
-            Debug.Log(message);
-        }
+        public void Info(string message) =>
+            UnityEngine.Debug.Log(message);
 
-        public void Warn(string message)
-        {
-            Debug.LogWarning(message);
-        }
+        public void Warn(string message) =>
+            UnityEngine.Debug.LogWarning(message);
 
-        public void Error(string message)
-        {
-            Debug.LogError(message);
-        }
+        public void Error(string message) =>
+            UnityEngine.Debug.LogError(message);
 
-        public void Exception(string message)
-        {
-            Debug.LogError(message);
-        }
+        public void Exception(string message) =>
+            UnityEngine.Debug.LogError(message);
 
-        public void Exception(Exception e)
-        {
-            Debug.LogException(e);
-        }
+        public void Exception(Exception e) =>
+            UnityEngine.Debug.LogException(e);
     }
 }
 #endif

From 2bed3c3dde7c7e3d676821d37ae44b3076c34a01 Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Wed, 2 Oct 2024 22:52:03 +0100
Subject: [PATCH 14/55] Tighten package sources in C# smoketests (#133)

## Description of Changes

Same as https://github.com/clockworklabs/SpacetimeDB/pull/1735 but for
this repo.

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 .github/workflows/dotnet.yml | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 9733140e..69d6b8b1 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -44,9 +44,18 @@ jobs:
           <packageSources>
             <!-- Local NuGet repositories -->
             <add key="Local SpacetimeDB.BSATN.Runtime" value="../SpacetimeDB/crates/bindings-csharp/BSATN.Runtime/bin/Release" />
-            <!-- Official NuGet.org server -->
-            <add key="NuGet.org" value="https://api.nuget.org/v3/index.json" />
           </packageSources>
+          <packageSourceMapping>
+            <!-- Ensure that SpacetimeDB.BSATN.Runtime is used from the local folder. -->
+            <!-- Otherwise we risk an outdated version being quietly pulled from NuGet for testing. -->
+            <packageSource key="Local SpacetimeDB.BSATN.Runtime">
+              <package pattern="SpacetimeDB.BSATN.Runtime" />
+            </packageSource>
+            <!-- Fallback for other packages (e.g. test deps). -->
+            <packageSource key="nuget.org">
+              <package pattern="*" />
+            </packageSource>
+          </packageSourceMapping>
         </configuration>
         EOF
     - name: Restore dependencies

From 00d2741d9027b04d3b559baad4f5efacbf7dc5ec Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Thu, 3 Oct 2024 00:18:06 +0100
Subject: [PATCH 15/55] Reduce public API surface further (#145)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

## API

 - [x] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 src/BSATNHelpers.cs       | 18 ++----------------
 src/ISpacetimeDBLogger.cs |  4 ++--
 src/SpacetimeDBClient.cs  |  1 +
 src/Stats.cs              | 18 +++++++++---------
 4 files changed, 14 insertions(+), 27 deletions(-)

diff --git a/src/BSATNHelpers.cs b/src/BSATNHelpers.cs
index 46c4cb64..9c227e13 100644
--- a/src/BSATNHelpers.cs
+++ b/src/BSATNHelpers.cs
@@ -1,29 +1,15 @@
-using System;
 using SpacetimeDB.BSATN;
 using System.IO;
-using SpacetimeDB.ClientApi;
 
 namespace SpacetimeDB
 {
     public static class BSATNHelpers
     {
-        public static T FromStream<T>(Stream stream)
-            where T : IStructuralReadWrite, new()
-        {
-            using var reader = new BinaryReader(stream);
-            return IStructuralReadWrite.Read<T>(reader);
-        }
-
         public static T Decode<T>(byte[] bsatn) where T : IStructuralReadWrite, new()
         {
             using var stream = new MemoryStream(bsatn);
-            return FromStream<T>(stream);
-        }
-
-        public static T Decode<T>(string json)
-            where T : IStructuralReadWrite, new()
-        {
-            throw new InvalidOperationException("JSON isn't supported at the moment");
+            using var reader = new BinaryReader(stream);
+            return IStructuralReadWrite.Read<T>(reader);
         }
     }
 }
diff --git a/src/ISpacetimeDBLogger.cs b/src/ISpacetimeDBLogger.cs
index 5223a628..e8f01cec 100644
--- a/src/ISpacetimeDBLogger.cs
+++ b/src/ISpacetimeDBLogger.cs
@@ -2,7 +2,7 @@
 
 namespace SpacetimeDB
 {
-    public interface ISpacetimeDBLogger
+    internal interface ISpacetimeDBLogger
     {
         void Debug(string message);
         void Trace(string message);
@@ -15,7 +15,7 @@ public interface ISpacetimeDBLogger
 
     public static class Log
     {
-        public static ISpacetimeDBLogger Current =
+        internal static ISpacetimeDBLogger Current =
 
 #if UNITY_5_3_OR_NEWER
             new UnityDebugLogger();
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index c01bb9b9..48b76086 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -783,6 +783,7 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
         internal void OnMessageReceived(byte[] bytes, DateTime timestamp) =>
             _messageQueue.Add(new UnprocessedMessage { bytes = bytes, timestamp = timestamp });
 
+        // TODO: this should become [Obsolete] but for now is used by autogenerated code.
         public void InternalCallReducer<T>(T args)
             where T : IReducerArgs, new()
         {
diff --git a/src/Stats.cs b/src/Stats.cs
index 0d0ff3fc..bac011d0 100644
--- a/src/Stats.cs
+++ b/src/Stats.cs
@@ -12,7 +12,7 @@ public class NetworkRequestTracker
         private uint _nextRequestId;
         private readonly Dictionary<uint, (DateTime Start, string Metadata)> _requests = new();
 
-        public uint StartTrackingRequest(string metadata = "")
+        internal uint StartTrackingRequest(string metadata = "")
         {
             // Record the start time of the request
             var newRequestId = ++_nextRequestId;
@@ -20,7 +20,7 @@ public uint StartTrackingRequest(string metadata = "")
             return newRequestId;
         }
 
-        public bool FinishTrackingRequest(uint requestId)
+        internal bool FinishTrackingRequest(uint requestId)
         {
             if (!_requests.Remove(requestId, out var entry))
             {
@@ -40,12 +40,12 @@ public bool FinishTrackingRequest(uint requestId)
             return true;
         }
 
-        public void InsertRequest(TimeSpan duration, string metadata)
+        internal void InsertRequest(TimeSpan duration, string metadata)
         {
             _requestDurations.Enqueue((DateTime.UtcNow, duration, metadata));
         }
 
-        public void InsertRequest(DateTime start, string metadata)
+        internal void InsertRequest(DateTime start, string metadata)
         {
             InsertRequest(DateTime.UtcNow - start, metadata);
         }
@@ -69,10 +69,10 @@ public void InsertRequest(DateTime start, string metadata)
 
     public class Stats
     {
-        public NetworkRequestTracker ReducerRequestTracker = new();
-        public NetworkRequestTracker OneOffRequestTracker = new();
-        public NetworkRequestTracker SubscriptionRequestTracker = new();
-        public NetworkRequestTracker AllReducersTracker = new();
-        public NetworkRequestTracker ParseMessageTracker = new();
+        public readonly NetworkRequestTracker ReducerRequestTracker = new();
+        public readonly NetworkRequestTracker OneOffRequestTracker = new();
+        public readonly NetworkRequestTracker SubscriptionRequestTracker = new();
+        public readonly NetworkRequestTracker AllReducersTracker = new();
+        public readonly NetworkRequestTracker ParseMessageTracker = new();
     }
 }

From f9c71c011a89f2a6f3bc0365acf3853ad5670da2 Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Thu, 3 Oct 2024 00:19:12 +0100
Subject: [PATCH 16/55] Don't actually try to connect to network in tests
 (#144)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 src/SpacetimeDBClient.cs | 31 ++++++++++++++++---------------
 tests~/SnapshotTests.cs  |  2 ++
 2 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 48b76086..e8d815c9 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -11,9 +11,6 @@
 using SpacetimeDB.Internal;
 using SpacetimeDB.ClientApi;
 using Thread = System.Threading.Thread;
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("SpacetimeDB.Tests")]
 
 namespace SpacetimeDB
 {
@@ -180,6 +177,7 @@ struct PreProcessedMessage
         private readonly BlockingCollection<PreProcessedMessage> _preProcessedNetworkMessages =
             new(new ConcurrentQueue<PreProcessedMessage>());
 
+        internal static bool IsTesting;
         internal bool HasPreProcessedMessage => _preProcessedNetworkMessages.Count > 0;
 
         private readonly CancellationTokenSource _preProcessCancellationTokenSource = new();
@@ -582,23 +580,26 @@ internal void Connect(string? token, string uri, string addressOrName)
             }
 
             Log.Info($"SpacetimeDBClient: Connecting to {uri} {addressOrName}");
-            Task.Run(async () =>
+            if (!IsTesting)
             {
-                try
-                {
-                    await webSocket.Connect(token, uri, addressOrName, Address);
-                }
-                catch (Exception e)
+                Task.Run(async () =>
                 {
-                    if (connectionClosed)
+                    try
                     {
-                        Log.Info("Connection closed gracefully.");
-                        return;
+                        await webSocket.Connect(token, uri, addressOrName, Address);
                     }
+                    catch (Exception e)
+                    {
+                        if (connectionClosed)
+                        {
+                            Log.Info("Connection closed gracefully.");
+                            return;
+                        }
 
-                    Log.Exception(e);
-                }
-            });
+                        Log.Exception(e);
+                    }
+                });
+            }
         }
 
         private void OnMessageProcessCompleteUpdate(IEventContext eventContext, List<DbOp> dbOps)
diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs
index c429d07b..079644d1 100644
--- a/tests~/SnapshotTests.cs
+++ b/tests~/SnapshotTests.cs
@@ -268,6 +268,8 @@ public async Task VerifyAllTablesParsed()
 
         Log.Current = new TestLogger(events);
 
+        DbConnection.IsTesting = true;
+
         var client =
             DbConnection.Builder()
             .WithUri("wss://spacetimedb.com")

From f04e2fd102cee881e1df5d00b7044d6417dc1dc0 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <196249+bfops@users.noreply.github.com>
Date: Thu, 3 Oct 2024 05:03:29 -0700
Subject: [PATCH 17/55] Add script to generate `nuget.config` (#115)

## Description of Changes
Adds a utility script to generate `nuget.config` given a path to the
`SpacetimeDB` repo.

## API
No

## Requires SpacetimeDB PRs
None

## Testing
- [x] CI
- [x] Ran locally

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 .github/workflows/dotnet.yml | 25 +++----------------------
 tests~/README.md             | 20 ++++++++++++++++++++
 tools~/write-nuget-config.sh | 35 +++++++++++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 22 deletions(-)
 create mode 100644 tests~/README.md
 create mode 100755 tools~/write-nuget-config.sh

diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 69d6b8b1..643a1628 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -36,28 +36,9 @@ jobs:
         # available. Otherwise, `spacetimedb-csharp-sdk` will use the NuGet versions of the packages.
         # This means that (if version numbers match) we will test the local versions of the C# packages, even
         # if they're not pushed to NuGet.
-        # See https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file for more info on the config file,
-        # and https://tldp.org/LDP/abs/html/here-docs.html for more info on this bash feature.
-        cat >nuget.config <<EOF
-        <?xml version="1.0" encoding="utf-8"?>
-        <configuration>
-          <packageSources>
-            <!-- Local NuGet repositories -->
-            <add key="Local SpacetimeDB.BSATN.Runtime" value="../SpacetimeDB/crates/bindings-csharp/BSATN.Runtime/bin/Release" />
-          </packageSources>
-          <packageSourceMapping>
-            <!-- Ensure that SpacetimeDB.BSATN.Runtime is used from the local folder. -->
-            <!-- Otherwise we risk an outdated version being quietly pulled from NuGet for testing. -->
-            <packageSource key="Local SpacetimeDB.BSATN.Runtime">
-              <package pattern="SpacetimeDB.BSATN.Runtime" />
-            </packageSource>
-            <!-- Fallback for other packages (e.g. test deps). -->
-            <packageSource key="nuget.org">
-              <package pattern="*" />
-            </packageSource>
-          </packageSourceMapping>
-        </configuration>
-        EOF
+        # See https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file for more info on the config file.
+        ./tools~/write-nuget-config.sh ../SpacetimeDB
+
     - name: Restore dependencies
       working-directory: spacetimedb-csharp-sdk
       run: dotnet restore
diff --git a/tests~/README.md b/tests~/README.md
new file mode 100644
index 00000000..95f9a400
--- /dev/null
+++ b/tests~/README.md
@@ -0,0 +1,20 @@
+# Running tests
+You can use `dotnet test` (either in this directory or in the project root directory) to run the tests.
+
+# Using a different SpacetimeDB version
+To run tests using a local version of the `SpacetimeDB` repo, you can add a `nuget.config` file in the **root** of this repository.
+
+The `tools/write-nuget-config.sh` script can generate the `nuget.config`. It takes one parameter: the path to the root SpacetimeDB repository (relative or absolute).
+
+Then, you need to `dotnet pack` the `BSATN.Runtime` package in the `SpacetimeDB` repo.
+
+Lastly, before running `dotnet test`, you should `dotnet nuget locals all --clear` to clear out any cached packages. This ensures you're actually testing with the new package you just built.
+
+Example:
+```bash
+$ export SPACETIMEDB_REPO_PATH="../SpacetimeDB"
+$ tools/write-nuget-config.sh "${SPACETIMEDB_REPO_PATH}"
+$ ( cd "${SPACETIMEDB_REPO_PATH}"/crates/bindings-csharp/BSATN.Runtime && dotnet pack )
+$ dotnet nuget locals all --clear
+$ dotnet test
+```
diff --git a/tools~/write-nuget-config.sh b/tools~/write-nuget-config.sh
new file mode 100755
index 00000000..1655fc96
--- /dev/null
+++ b/tools~/write-nuget-config.sh
@@ -0,0 +1,35 @@
+set -ueo pipefail
+
+SPACETIMEDB_REPO_PATH="$1"
+
+cd "$(dirname "$(readlink -f "$0")")"
+cd ..
+
+# Write out the nuget config file to `nuget.config`. This causes the spacetimedb-csharp-sdk repository
+# to be aware of the local versions of the `bindings-csharp` packages in SpacetimeDB, and use them if
+# available.
+# See https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file for more info on the config file,
+# and https://tldp.org/LDP/abs/html/here-docs.html for more info on this bash feature.
+cat >nuget.config <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <packageSources>
+    <!-- Local NuGet repositories -->
+    <add key="Local SpacetimeDB.BSATN.Runtime" value="${SPACETIMEDB_REPO_PATH}/crates/bindings-csharp/BSATN.Runtime/bin/Release" />
+  </packageSources>
+  <packageSourceMapping>
+    <!-- Ensure that SpacetimeDB.BSATN.Runtime is used from the local folder. -->
+    <!-- Otherwise we risk an outdated version being quietly pulled from NuGet for testing. -->
+    <packageSource key="Local SpacetimeDB.BSATN.Runtime">
+      <package pattern="SpacetimeDB.BSATN.Runtime" />
+    </packageSource>
+    <!-- Fallback for other packages (e.g. test deps). -->
+    <packageSource key="nuget.org">
+      <package pattern="*" />
+    </packageSource>
+  </packageSourceMapping>
+</configuration>
+EOF
+
+echo "Wrote nuget.config contents:"
+cat nuget.config

From 19e89795154a099c4a59fa8f384501aeddfb84a4 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <196249+bfops@users.noreply.github.com>
Date: Thu, 3 Oct 2024 09:48:54 -0700
Subject: [PATCH 18/55] Fix `gen-client-api` scripts for new CLI API (#151)

## Description of Changes
The CLI arg changes in
https://github.com/clockworklabs/SpacetimeDB/pull/1741 broke these
scripts. This PR incorporates the param renames.

## API
No changes to how things are used.

## Requires SpacetimeDB PRs
I guess https://github.com/clockworklabs/SpacetimeDB/pull/1741

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 tools~/gen-client-api.bat | 4 ++--
 tools~/gen-client-api.sh  | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tools~/gen-client-api.bat b/tools~/gen-client-api.bat
index 9eb66c49..23196f94 100644
--- a/tools~/gen-client-api.bat
+++ b/tools~/gen-client-api.bat
@@ -10,8 +10,8 @@ cd %CL_HOME%\SpacetimeDB\crates\client-api-messages
 cargo run --example get_ws_schema > %CL_HOME%/schema.json
 
 cd %CL_HOME%\SpacetimeDB\crates\cli
-cargo run -- generate -l csharp -n SpacetimeDB.ClientApi ^
-  --json-module %CL_HOME%\schema.json ^
+cargo run -- generate -l csharp --namespace SpacetimeDB.ClientApi ^
+  --module-def %CL_HOME%\schema.json ^
   -o %CL_HOME%\spacetimedb-csharp-sdk\src\SpacetimeDB\ClientApi
 
 cd %CL_HOME%\spacetimedb-csharp-sdk\src\SpacetimeDB\ClientApi
diff --git a/tools~/gen-client-api.sh b/tools~/gen-client-api.sh
index 91fbe3da..5f118176 100644
--- a/tools~/gen-client-api.sh
+++ b/tools~/gen-client-api.sh
@@ -5,8 +5,8 @@ cd $CL_HOME/SpacetimeDB/crates/client-api-messages
 cargo run --example get_ws_schema > $CL_HOME/schema.json
 
 cd $CL_HOME/SpacetimeDB/crates/cli
-cargo run -- generate -l csharp -n SpacetimeDB.ClientApi \
-  --json-module $CL_HOME/schema.json \
+cargo run -- generate -l csharp --namespace SpacetimeDB.ClientApi \
+  --module-def $CL_HOME/schema.json \
   -o $CL_HOME/spacetimedb-csharp-sdk/src/SpacetimeDB/ClientApi
 
 cd $CL_HOME/spacetimedb-csharp-sdk/src/SpacetimeDB/ClientApi

From 8ce9b7b6ba0d45ceaec82448f78b27b148ad1535 Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Thu, 3 Oct 2024 18:13:59 +0100
Subject: [PATCH 19/55] Remove obsolete tools folder (#149)

## Description of Changes

Not sure when or how this was added (it's not on master), but this
folder shouldn't be here - we have `tools~` instead.

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 tools/gen-client-api.bat | 20 --------------------
 tools/gen-client-api.sh  | 15 ---------------
 2 files changed, 35 deletions(-)
 delete mode 100644 tools/gen-client-api.bat
 delete mode 100644 tools/gen-client-api.sh

diff --git a/tools/gen-client-api.bat b/tools/gen-client-api.bat
deleted file mode 100644
index 9eb66c49..00000000
--- a/tools/gen-client-api.bat
+++ /dev/null
@@ -1,20 +0,0 @@
-@echo off
-setlocal
-
-if "%CL_HOME%"=="" (
-  echo "Variable CL_HOME not set"
-  exit /b 1
-)
-
-cd %CL_HOME%\SpacetimeDB\crates\client-api-messages
-cargo run --example get_ws_schema > %CL_HOME%/schema.json
-
-cd %CL_HOME%\SpacetimeDB\crates\cli
-cargo run -- generate -l csharp -n SpacetimeDB.ClientApi ^
-  --json-module %CL_HOME%\schema.json ^
-  -o %CL_HOME%\spacetimedb-csharp-sdk\src\SpacetimeDB\ClientApi
-
-cd %CL_HOME%\spacetimedb-csharp-sdk\src\SpacetimeDB\ClientApi
-del /q _Globals
-
-del %CL_HOME%\schema.json
diff --git a/tools/gen-client-api.sh b/tools/gen-client-api.sh
deleted file mode 100644
index 91fbe3da..00000000
--- a/tools/gen-client-api.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh -eu
-: $CL_HOME
-
-cd $CL_HOME/SpacetimeDB/crates/client-api-messages
-cargo run --example get_ws_schema > $CL_HOME/schema.json
-
-cd $CL_HOME/SpacetimeDB/crates/cli
-cargo run -- generate -l csharp -n SpacetimeDB.ClientApi \
-  --json-module $CL_HOME/schema.json \
-  -o $CL_HOME/spacetimedb-csharp-sdk/src/SpacetimeDB/ClientApi
-
-cd $CL_HOME/spacetimedb-csharp-sdk/src/SpacetimeDB/ClientApi
-rm -rf _Globals
-
-rm -f $CL_HOME/schema.json

From ce76890ab6f6d103ff8834e5bbdede9d65a53270 Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Thu, 3 Oct 2024 18:17:06 +0100
Subject: [PATCH 20/55] Try to catch flaky bugs (#150)

## Description of Changes

We have some flaky bug where Events are getting modified while we're
already iterating over them in the snapshot.

I think this might've been fixed by #144, but add extra checks just in
case so that the exception is thrown in a concrete event that causes it,
and not inside snapshot serialization.

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 tests~/SnapshotTests.cs | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs
index 079644d1..8e99242e 100644
--- a/tests~/SnapshotTests.cs
+++ b/tests~/SnapshotTests.cs
@@ -12,10 +12,21 @@ public class SnapshotTests
 {
     class Events : List<KeyValuePair<string, object?>>
     {
+        private bool frozen;
+
         public void Add(string name, object? value = null)
         {
+            if (frozen)
+            {
+                throw new InvalidOperationException("This is a bug. We have snapshotted the events and don't expect any more to arrive.");
+            }
             base.Add(new(name, value));
         }
+
+        public void Freeze()
+        {
+            frozen = true;
+        }
     }
 
     class EventsConverter : WriteOnlyJsonConverter<Events>
@@ -344,6 +355,7 @@ public async Task VerifyAllTablesParsed()
         }
 
         // Verify dumped events and the final client state.
+        events.Freeze();
         await Verify(
                 new
                 {

From 62a092e19efc77e99231821cf3b8fd886827913a Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Thu, 3 Oct 2024 19:00:10 -0400
Subject: [PATCH 21/55] Jeremie/remove break (#154)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 src/SpacetimeDBClient.cs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index e8d815c9..11237718 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -374,7 +374,6 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                                     };
 
                                     dbOps.Add(op);
-                                    break;
                                 }
                             }
                         }

From 8f9614dcf625c1472cafd2621b478d6e92df373d Mon Sep 17 00:00:00 2001
From: Zeke Foppa <196249+bfops@users.noreply.github.com>
Date: Thu, 3 Oct 2024 16:31:14 -0700
Subject: [PATCH 22/55] Update DLLs for 0.12.0 (#152)

## Description of Changes
Updated the DLLs for 0.12.0 from the PR:
```
commit 0a7512d2a8db0dcff05aaee92f260e53d71cdc80 (HEAD -> release/v0.12.0-beta, origin/release/v0.12.0-beta)
Author: Zeke Foppa <bfops@users.noreply.github.com>
Date:   Thu Oct 3 09:35:27 2024 -0700

    [release/v0.12.0-beta]: Manually apply open PR #1707: c# client generate
```

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
---
 .../dotnet/cs/SpacetimeDB.BSATN.Codegen.dll     | Bin 47616 -> 0 bytes
 .../SpacetimeDB.BSATN.Runtime.dll               | Bin 52736 -> 0 bytes
 .../{0.11.0.meta => 0.12.0.meta}                |   0
 .../{0.11.0 => 0.12.0}/analyzers.meta           |   0
 .../{0.11.0 => 0.12.0}/analyzers/dotnet.meta    |   0
 .../{0.11.0 => 0.12.0}/analyzers/dotnet/cs.meta |   0
 .../dotnet/cs/SpacetimeDB.BSATN.Codegen.dll     | Bin 0 -> 57856 bytes
 .../cs/SpacetimeDB.BSATN.Codegen.dll.meta       |   0
 .../{0.11.0 => 0.12.0}/lib.meta                 |   0
 .../{0.11.0 => 0.12.0}/lib/netstandard2.1.meta  |   0
 .../SpacetimeDB.BSATN.Runtime.dll               | Bin 0 -> 68096 bytes
 .../SpacetimeDB.BSATN.Runtime.dll.meta          |   0
 12 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 packages/spacetimedb.bsatn.runtime/0.11.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
 delete mode 100644 packages/spacetimedb.bsatn.runtime/0.11.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
 rename packages/spacetimedb.bsatn.runtime/{0.11.0.meta => 0.12.0.meta} (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.11.0 => 0.12.0}/analyzers.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.11.0 => 0.12.0}/analyzers/dotnet.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.11.0 => 0.12.0}/analyzers/dotnet/cs.meta (100%)
 create mode 100644 packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
 rename packages/spacetimedb.bsatn.runtime/{0.11.0 => 0.12.0}/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.11.0 => 0.12.0}/lib.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.11.0 => 0.12.0}/lib/netstandard2.1.meta (100%)
 create mode 100644 packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
 rename packages/spacetimedb.bsatn.runtime/{0.11.0 => 0.12.0}/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta (100%)

diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll b/packages/spacetimedb.bsatn.runtime/0.11.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
deleted file mode 100644
index d56f1f0f232ba24dd9c18f50389b15e95ce0f0f6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 47616
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

diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/0.11.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
deleted file mode 100644
index 0ef9930fd6d81bdeb798f061cb1c6288f05974c8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 52736
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

diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0.meta b/packages/spacetimedb.bsatn.runtime/0.12.0.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.11.0.meta
rename to packages/spacetimedb.bsatn.runtime/0.12.0.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0/analyzers.meta b/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.11.0/analyzers.meta
rename to packages/spacetimedb.bsatn.runtime/0.12.0/analyzers.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0/analyzers/dotnet.meta b/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.11.0/analyzers/dotnet.meta
rename to packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0/analyzers/dotnet/cs.meta b/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.11.0/analyzers/dotnet/cs.meta
rename to packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll b/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
new file mode 100644
index 0000000000000000000000000000000000000000..222b592781a64e8c004ffecde831368d31b1689e
GIT binary patch
literal 57856
zcmb?^3t&{$we~va%uHq`?_@H0lL-MFk`Ueqf|x)6qsS|us3?SFfN01GXC^=l&`?lo
z#nxASw*|rWVy(66wYH@Sg0}Xe^})4b)uQ;Qt@Y{^TfJBD|JK^)%uHTN|NoC>owe3p
zd+)W^UVH7e_n8UjU35JeMC8KnmtPV+iYNcn3jAu&gW`;`UuDq4zGuoG)#g4^zIaV*
zG}K|4tF5NBq2{Lcb~6@Q83|dP?V;B8Q2qSI&|0%4Qj?zUA7(ebU>4C_&7jG5tbf_*
z?HCOWrD|h{nB!I4%l?69h;fZUmf*V5n;ERX{M4cxeEu<L#g#0||0kX{$t?Wjq22j{
zY4mx#5n(70(kKnsUrrD$PGWy88j7nfqF&HvCsnG6MK;Djcf16EG8wC_Hz@fD5v{1P
zqE<5~r5ncP0r83y$3ZQotHz47nGj@M2|9}njxmw=sU@0`pcK}?cEu0trjwiQT7vob
zp>1U;`PaY@JzPNKuXLW5Dq7FKt_6(_4;puEhH|dTGi<)mm*hE3Dur*lD%Tsq(eCg8
z4Bl1k(~VV|F;T8c-B8b=4l*Pdg|~Prhvcc}4Be@wE5_^uW0m5p)VsN@;ApQxR#mEJ
zrTq+^bX8LB7=!X*1}L7biv4;x13guHJVyS~rG8K46-H+Y3|Jjd<wh4%()3BKGFUm?
zW;>iAie@XNvc`lyG#VmvfId{?DS9}M3-xe19{wB(7qVqpRwtmMj|HVV5)ws_2p6jf
z=ytP}&=p+91r?0V%+Ot%g+_gDXF8s+akkM3)9KX{jC=UWodwZpYL2E063zxy9RwSO
zP;5qojq$0rMx!lQGdok0I%uR<Ww5!9uzOWzJ!<T_ss?0E2HAvW3C5y3^^$nuC(xAi
zYtZ;X>XxFeg)zfEcE@%DTo8t}{gvbNupbRY;j^B~abX`Gx*}!>kyOfKG-x^cLX(&y
z+dgWp(u^EUrs+a|mDfgXz0-4yxQwA>(jcSIG_Nty<?&8(hYzA_kJocyw2bv~mQP}t
zz#1}{&J)w*s$|y}Bq4_(h@3pnkFPR}lBXWtCZ$ZWYY3gFjOZb3=LyGCod}Xx%d6E|
zzI!twYw~Ip63yDr-l4!5)2TiaYQgzLEqNx`IX2sQ<~rI6;&hXc57_eZ9AGe5ZOMZX
z5`&TF6>&>q-dzZ1$^@>vH^a4Dl?g*ju}g7LnMpRZNcC3<ekaB9OlXSLEo}R#?08vR
z1*~$H9=r~1YMZgxle?E9m*S#ZCb@f&a=JesUK8dfT$@MoBOGFvt9h;h3ocx)+^?Gj
z#J>bV6D%qWL2}2q=`^ebj)@k$2y5&DUOaj?7Nsj6F>x~^o*k<o6CTQqO1!B>9mJpP
zC_3}|Jr=yZ!yE>DgvV-#<GRPZ1aj3rPg%$uE~RCgZN%i&Tlr3S1RjR9FkZ({8ko?^
zKf<uEQ0<0Ma3LB~1^JaVx)Da9Cy2;APd94P^=hwfm@C0TB+G}^yw1;up8ONW@cp_8
z(qm%a{?N!JOYXTS3@N`ZHZrS#F73r;1NCB8i!|HA9L3U=lXRn#t*v_H{vxV7f<nuU
z>Wfs5hV&aoZ1h*pN$S&3JtN-wt4G^>?$nS;GKHTXPV{QXq?ltMFGC!nM_YKf_p7Pb
zReQ=OR2#}MR6Uu<%GtJk7s6lIoC|qA{q!;PPLX&RLhE{lYx7t<-R3yJPRyK^?whg=
zGCmVg+Mnync2#f4c9|1E`0<>GrxnFig(m^4Ugk4TXEArSyLv&k+nfxdVEpWCchH;y
zv=f8Way{9e>hakg^9<(jGE7aWuE=)hD-rmTmgcR_@jSN{n7DIzDkQ6e)>ibRGz(7y
zCweBp6`1;qF&tNlVe+sF^8<k}oVqG{7D_kQ0_a}1S%+sBsY#VNliBqEJbn+MJ5Euv
zqqD&BdocdlKy<_9_MG(00UA9UAlv{@>B#$7{v2>b{#+oo{9K>|$opCTJV$<BLLP~0
zviyyDx9Ho=Q(%}2Sg@N_HB2lMe|Ql9oDh0v&<8FeEZc1B3mC=nY19#2g5meT*IZi|
zSfjvu4%=_B*wC5}GTew3{DJ2db88Uy$FK;sg6ptGklI-na1EXiWp%6>|J}p$pW`qk
z97oXe972U(wY`*^g5g=x^V~)K`Ojf?k~#}7W7#mG1K_2A`Pac?(7WgEuz~s60&}}g
zdJbbO(G@6;HUactMcAYIch<4&Ul~=I{?(%@w1@9`4k5&^+K!Lvxn}SZrV{NF1_`&I
zR0fXa->>SbQ>a?tVT1Rpx~6~CL2L#$aBTJr+pHBeqn82nAX?Zq`xRRN%U8{!HO%;0
zPpE;&sd>UF+UN5A1A49vyyvj96o;|Wl`9Tt-+`UQof!DDJn(k35j6pNuzKu)|Cxt@
zP-PE%q3df0-VBki8hF0rEQ3skC!y6JSgQ`!Y8`8ZfNE<s!i_!<IBl&qg8Z6=xt(i#
z#lnnh^_+#S`nc;Lnx-T)eU3Fn5cfx8tSLOj*0jolei7JhO*er28cna`8mFS^AX<47
zT0PHNb+T6LSu0E<=Sjxq4WN+uY~)8c1c=NBd$<a7oGY<_BszkC!J@(tM4fdIXnW-`
z?i458=#$5Eq4HPcF?{wx*ynS5ww=<H#+$;Hdj+cRsD^q@UNbhiv>T;zRvN_;oEWKG
zN@Y2lK=;XVHiIQ8z)3r?*}`>30@xYMH-IV=m_0z9#0Fa@*gSsoo6MFBhOK5wiz;Wr
z79~H(VdfasGjx+1Hw3C2W^_2wydicrw?U*jKb&aaP`zvi-^o?3WPD3JSK(<<v#4Zc
zDl1pn#@fopLXN_w*~(@?lGlAYCf{(GSAl0<&8?lI^YN}~GZ)xi0MRins>cY@dB4TD
zJbuGtUIX#e*GtnpTPCxtH~MXE1Y2@dj&?E+URC@$rFf(V^I8-|cQCjPpi;|Xb9l&~
zMWu+Q+9cil4)_M2`Kz!I^FI7EBtT|cvoNpL5&+qUt#1J1n0xBG?~`2PRF=+j--QyY
z?WMqE_x%@kS$JyImIm13q~{1PvFp)B^ag+)Hc;gmnH0Vel$>v?kn_0cdu#^$WNP}B
zn@}`-RQ`x9Hv>88L6JXt3-fxogb&J9TW(`IA#*#++#xbt63&E-zU8joLf>bhABYf_
zgkk!sEjxS5>|&X_MTSfG@}jEJLP(gxGwa%ngwmzEH&5k9I0OkqhLOo<B9@atAP6D@
z*ARvvU~pYw2!b&e<D7H>o)}m*QcaGpuJEI<n^oaOG=%$mbXWM-c!c3tp4Z3v-CIVZ
z5yRz)?t!qG!=tr^Ls$>Pbv;%S*Biq6O9iSV<!AYnF`UM-pW&*<Fz=C`;E^7g1GGsn
zTz2$zaQq%U{3DcaUWlHo2pTkyt^OG$(I0cex#%;z7g*&JRx9_sWdQ_bO6CJO>3Pi&
z9p1wwNfkJr)uJzKWbreei6#a-<6RHAuZfL|&=&vLvGJyOQ&{eZ3-+nbuy!XGu$`QE
z`HSR&YvKheLc&q|o&({LUvUmZSQ_9Q$nMbVz=y?+aLG<F0GnMyu_cPKhndprfagH&
z(J&eIJ_mB2Mz{2gxlNn{xl==RE&P1@e8{~T;-7LpbYknRJlw=NklRzsLA9aQgsLYC
zL*gtOp3i}7=Y?)P%w}DP#WLNASG<kh%l^X`RDy6EIIPLtdv^3EDDrz;o9|;Yg+qWI
zee+N8h~5v7ii<)_j6XIDzMPf<>Ss(L)M}d_0OmD+4!EO^I}7kKe+Z;F=fglwdj1_S
z`UvxSxP&iJt5QySu;~2JUos=em43wn9As1_tU!NsAM<*+gf9%M(o?#*Kl3qWk8+I&
zRQb)vnNbR0y$HvWQ|lD$h@|Il-Vbh44f6nKzPYK&P03E_Wc72s+1~0vc8YlrMb)X<
zUh@!;Tz6Hmr<-lDWgN_(+(aR2`@%)s2A_I!Y_ahW!vVM${A~A**)T+URf--I4ZP-4
z+$JBi9dUFGlCM&$uz#g!<k|dN$mn)Y7Vyo#OE4rnZGM^=K7@te1Bw0zKp4ZW;>c4K
zeTK<r0T5ff^dlXMo#R`#G~3Npqa)BwnjZcG@Etgl6^F}EG2OT2c`%af{sPPXn0Y;1
zB9SE5rFXM2^J@#?G2U+EZ?59&R>OceWajy(14kykn>D_Bc!71AFbXA5WxFJ7-95a>
z>SA{IMF^?T<Fmd2j&&1*9|A-<^s?_&rK=t!4kjtApY;4EYDZrJ;Nz=`h^jH`PuvU#
z&TQ9~KSCgBL@#rtqs;5!62ALVRjuKEJ97IiS8AgEE4}OgDN&zGlIru2B=V<DhHt?z
z8(<h~44N`ug=8N?Z2=#Ka<oLqPSz6JfTJasBzj?!ekxT9ovPRvlB*s|ROOQ7s{PGw
zZBE1fAueJ45vb_zxBdn+)wX+iI(3x!<Ti77P>DkCB3~Fuln3fKtU?e)4pE$P_wW*j
zC{_Nl17TOcdpNE+6JGZnZX^5#^i(tFh0H*Elq-9XJ?c$V{hB=rL5p(W|MnhL9dF7|
zD?&2#Iu7$#LAD--H9c93o!Qy3mL(VPT5<|DCKv2S0bb9X<d-kK8{Uy5CYDIc(N6|>
z4JP%k_P^t3q|XWAEwE&BP&qv|9{I743vaVJBLVE=!aG3KAkBAyI>!a*1hx#Ssvld1
zl+6B%Nb`Wq_mZUlD(rii{WoUIZpmAWDLN|s?zHvOjj1;RHKu$UP&ZjmL!jC<H-r<K
z8WN_=_aRcf+}<5oRYNH(yQXv7%DNijy|QcKwl$%wAwkOgJGYY`PH1b$)@ObIzA_~H
z+e}B#a0q<dxN@jeVOaI6BCzU91z**^1a-)>9n@9||8>zCyFDx%J23tT(~fmxsM8{E
z(Y%yj5N@H(y;`_M)=R=I?j>7dy&_yJCbkCFk@XHUB!*&huZCUa8n1E$t}Da;1)0jB
zhKtWTco8?yn))lM5199Th`L{~rjRs*Swybte}?A!xF~jYm7-y#f5dWpozCi+QiAH{
ze>3|G97J)oAO4t$eB>liqy`?&Nx~<X#qTiw2X@TG+C`S}33ynl7JfUnT#C>tLH!aS
zCp{RgC;ATv4DaEREz5fsLt9VupHj>v;R?ijBRmYynvT}O!-0+H+r^6BZD1r$7hJNX
zsdq6(<cUICXuu^LYtY4M+(nGL2m{-)vUeQ}+!Os@slz4Vkt}^TOIJ#5WJ7pcZl86=
z>09a{WPT3$%Defjw$^Fwav&!?+1SyeUr1|Q62=m)!V6UEuiRiU*J4}ZUB>+yQGoLS
z^CY+h<12OZOCTm*7WvCUHN|?+)PQD@^&zV2x;p+~pY&Jio%6BH`#qyZ=#nv|ri>b;
zcP`-E2`S8!S!fxVjE>rAlXF3M<U|$z6|nTllflrX7tWSuA@8FYezy$rtK0kxJd5y)
zNh5d>O~mhX{LaBIdY1YZ;t3NHEJ0P9tZBK_k?Woe*C*>Th4(Oiv*1-5tj846Zv9mu
z5i1zrDpkv@8478%+7)t+b%#Rgtfv$*+4^sVjJAg4Nv#nn;r$pQ>X%pxz|z$)cPxZq
zc>lHEWn{b4t0sAso&7br)-4eAdK2cYa$B!}m0p!?<pj}6(rXYOCa)NAY6gY@!)53D
zU8Vsur&g7xm@c-rXB59CgHQWM1o2K}2eL~0QYyuCLtxY&U-zd}ds0jfh*x#A$LCU=
zd^Bnj`O&QS2FESr-`Th&KqBfd8h^fFdV%;o;P`-GvkLq145tF52Gh}hqQn<Y1J@J&
z4UFM4(}DZ)m!|s?0#bF{Gbxo|WuREjzR1Y<^BdX5s5HLKRaYumnqg)_f?tzW;SC?W
z+rQ&{lzPk@pj+TwD(MLTIqAs*j0Tz4!zJNSsI}!XSs=M10w+DJQ8Zu5najIQRd_T&
zDlAe2{yp4tnr;>Y&voUv!X-e`t0v=v0Hw@w8#(Uq5MX8*lW<^VVsJxXAl)y=Lq={6
z1%`SRc#L}7Te&4X3|P<{4v6=q$h`e!wdQGf^ze#?4N~Z0cstG_Sd)0W<u4hZZB6Ur
z0ji{Ue4}oTgvge585|BsYV~8(o@gZshWBtucnroiD%-O9v|_z3j7MRP#7zYPz~dYM
zN&!++rc`5{ri20g>Ate`3uk#SKWI*T53a`kNBsOLp1!i7Q?YB|IezMQ@SKcDOetk)
zVZ5G_Q%+e!&FE}b*^-*GCm-P=D<dD_XcBrF^^M6-2&Xd6>74w4aL$f%E>E#8ixcgW
zZ;;|0an9lt>;5=#K~-mpg||0$^9!n0rC7lNhis_2AjR4eCudZhZS4V-R%Kc*$aA%Y
zPwjwSZcUQs1y-9p=UaEkbB^^pd7fqcL!PHwV~SXQbc)pm#H_)HtFx_5z*8jN+AlEG
zb<+J{3pdRRZywFEZ60eMxYm9E-8=x3Y{Bxwwk96SQxwIgjxeFj4Uffy+ET3vsb43g
zm@87@aqQfC(Vm*(@n{5}ftq1G#l5`%5S;+l6_fPhm3mom%L;v|(NtMuWfY@iB9}OO
z4#xyt<{KwnoF8YSO~ahT?ct+Fr{fvlp3c#`&y`X{dB5DF#)~f1yXQ&K6fQagAUqx#
zR@U&b)zfn}^p498!Ci(lYjm$h9jpzV_bT21vJDfi&OL|tV-4YHEax}u|7)Tza$^mB
z8atDPYNFHe=s8OocD7T)>_%%l5GaZ(vG=>ewNh-DS8%_TD)$PUG*BC-H%|{XzJ!{u
z#Lv4WFdC<IrjyZ45JsWHD6*z8LuF}>T~C(SS)tyIEyBgez>QL^z~BpQWQK)y4p`*0
zQ*7OpXs0Gx#{+tpHFesYZJ0B_G-m?rXy#E>8fHBR&d!FYW-8w-b<)uXq`!QFlhDTm
zF9cp>C#1!|ORVP-JtiuCm{jreq>9T**bu5>8{=xo=NQ%lpbYB}V3=L8^1-<A-jq5@
zi4O%=N@SJB>pR24TLQ!zKaOno;b9`vNDLkR!G3~di;(BQPZ34nr?Vl$emVzF^K1Z|
z$HEBnRbiwM?0z5cyk3$#ua!n8TvOv|SNkC{L&C*OcJu^f{T^d8EbH=g3q0xh1kC6;
zXqf|ARpq33ZMM1Wr(7RlHJg)Dsox^?1)lUECG|wl<@%>{eazBa5b-IMak=Rmcn;xl
zZQ^d#-5YD^_sD|a9r-*ST~!$4n+Gi2XX4`k>XIp7Y(eZsa^~|y7l6s1*}$uj@Iv6D
z{*Y*)4JMOyH8#!If>`77@aHwEa@;5Lu&%XicU-GUdN-?YMDK<6a)Y=CZK1eZo=D#}
z3xe@$e5Xxitb4c-LOdIbSy<*Pt8bYRUc!ZolrZvft`i8K!M3?5jE^tiHj-I85D<&a
zr7Sx;nR8)34$=x0Lu%0%_ObY#cMu*n(Ag(^5!(2Qvk&{(0<;xETZT0u-U_a}?E#()
zigvu0stycmcCy&T=s+$8R>7?OPW;PI%FZ()lZ@~sJf2I9PDIG!>U7<>hY`gM!r4@p
zTe&+qD?JOn%Aps3o~Fugbk0Ht_^8bqkJr2uE%65(m*eT>&ml7<cN0nlbt|bZQQe}H
z>{VWK1uAelbTWwTMO{#E8s#yYq@|UBomfFymR9v0d@8INbhHIvGe+m){Ix38=v)B-
z`OHvx3O+OxL9rV5Dq#3z7ogL|i+YN=8gz6Gz-H_K_;|1QN-f5gJb#zQP1^f?F6XFU
z_0GZ{lv8Ueq~c~qBI>EUJKTyc^={VNybP#)gL1iWSrfAj=u)1KI^@kVAB=Dw%g5cP
zk{U2nGiy-+R}YCMWK(mQ?ck$EO*9Ktd$6e`HWt1+z-CD}G~ghGe9p54D^neHS@5JM
z2fV0>7KZn5N%&0IIE?d9l|NJSSeL;rGIf>(OlH6zUdR2NV}va{M|q91ni`{Qd8L8R
zZJSYUNbb(nw9DyQ(le+RLt#%RS9YQ>BGh`OFTx^Uhu-m4&f<rAa}*Db0nC-4AP5*-
zE(}4y5J`>_f?%w?ruxqB?+2S-WZz#kzueY&Xp?^o>-BgmSS$so>0H$<PyX~F(*JnD
ziR2nM0@wxWIu03r!fS?ss61)kPw`;oossP|@LKp1k9dF=OgwJ;1rwYJt5i7?BYaX|
zXM#-(LM|geNqrb%U+1nX(Tkz_!hwbzPVu=LL#!?GXqDf=vlaN=5D%K)4e=NkR=$Gi
zh(R9n*~t(2_~+*Jf^NWs^ZR^o1>MMKIE1cn>ol8{M$nP?&n?JQ3xcWUwuB)_F~*dF
zb52D(4(nl@cKGA!n|OhRH=?KD*ohu1IK+<5Ry8ms#rdFX$6AhnXR*uI0$5{M@CsBL
zVGHr{-GPNtyaj2TS~gukPI@Mzqi8oIhxc$v7)!S*JOjYo3})Ko-@(*ga|;V}e*-YR
zy9Y4W<r{T|e6Yf0Ze`kCm4g%CHyQQd45<1BXB#-9-hMp;`(+SjD^{m$k2T2|2~L#a
zfWu%b`$Mx}iR&e?M)*cm%Evog=619g99!bC&UTtm2L*YnAfq4QQO8t|>@!KW@XCSz
zj8R{H`Q__=Z#Ck-ocTTGm1uK>N0&D?YAM*f#6++G!&mY6QmV@FD(q@Ty&h|UqeYHa
zX)RWVfExm%UV1$(JEa=$(d^rWf#x;MV=aqMmq&I0yc-Y0f#{c1_A+I#v+Hy{y>gl6
zSNI;S<^?T{abDLq;t5*~bdN9nA-gyk<dB@Ss~T4Fb$yrvsuKgQa7Hu&NhQ0wQ*cXi
z0Xx1^@NjYgF9TJef&-3peJ?`CfrVw~d}et&4+KBzu0D(lfL`ya-+^c7-Mn-LxU1&{
z)GL&H3ud>~z6Pjsv;S>ji_+KjV~fhdmMd9VyP~7Yb?;Q_;WN(3clDyD!Pgb`8*b;W
zo;5X;zVAcz_+34#YRJ-8acWLDp{t<`y#uP@u0ElxeA>umUdQ}=o6p+HCx{eZ42e5p
z99`}E?3s?f5{z&M&l;&PrutX0O!cXPnd(PHGu1YKItd><LuBMow3Xcl(T)8CZ_J~o
z<JrRjB)$U<MdJG%sEHUmqwyS^xHQp%opk+#nlUxw$BZ9~#F@W^g6)}V5vwY2!+9T`
z)d+kQjWMgWeKle;zEZZ5=m-+~iY1M7-&Xa#w~9GS8tPHD5A^lOAuDFI@rTgm2cc8D
zpzQ8cAL`KmXyf^!j(h($e&^s9ag7k>2v=pYn4l)V_o5tB#JZ91NZ~9%b@)XQVO;Wb
z;aP~^T>Q?!Z#I63?g+39XI&3vPAT%x)!7VxlEbhm<L`yJbYT&fzMXM(u7_^S`6%e2
zSy>EU%VyXj_*0pT9~XE?_&YP0vp=0-dIq=lc+RFg4>gxEY{+03&L}SS&`W8If1oog
zD`R-B=&;nq_}X-amr329q;Cj7!wiPE7Ay_<>Hfm0Xkj5F{q&6><NvEa1Gp=fYt0KX
zt_i#?pEVg`EJfW_!kG%_r|0vg0uJ{x+!tUt(ZlVexVg>e!ST>H@;BvW(D?FCLmA{6
z%J2i=etJ#h4*_P-6!1NCnzVU?F|{~{9yQwi@6z`RuxRMn5Vt%Yd_U~~?t$a5hL7j1
zhgFa1DIO0+WE78x<Yz-!=IT7|_hspKyTA~7@lz<9+qo8F_tVM(maIwLly{tZFui_y
zc?fgbN<KzuP)6q#_(dA?n~fBYpLUip{=K0*#`oNezYF`kD=m1a-NpL+Q!Ms?%<uXB
zk0G<D@MDbBD>~ePv1HJ>qSc*%9@>ePuhv)x4;_`dPs^;mVDLy^6!@gf%VU1#yi>wn
zu>iF^^kE*))U#6S*F%|a!sdQTsbJkUix=H1wZ0=Vw+bGFwKM35^xh=62|S0k4{i7R
z>4sv~aBiu$z(W`K>k4w{;o`aiKfNw~vJx%$X|IoMxHOevehI^K1nvYM-YE0lBV+s(
zpr1Yvf0!>iKU=`o2!qe-=V>=Xi4(YRe<git@vJzt1*?fEUfEgHiPgZAA=FeU<L`WO
z*?4&VER=Z23u-CmX9>Q`mm*XHG+qKZ4hLDZD*Ni(StuzN%9q9Ud^AF+-wNd?Y`Tzq
zKb_0cs7k0T=`V|rL!#_Wk<6xX)B|c|*_5J75EsTvnOk&msM~DG2~t*NQxk>y)Rvqi
z)Y8mij6Iu97wU4Gnk>}TELAo|s9#|Hv*Z~<ofImEaGHcJ0jU?DT2;@c5YtdrCsZE4
z%>{LvP(i{z2WpN`1$2&3r`goGLj6FfLOwY_^2gcSdl7%{7}Vk%Md8#B>N(LRjPDw2
z_}cP_f*bNKfi;&1wa#FwidKou4i++1gI7{4xlPI@VozXdl$4!Ln`kTA>?~%<DYR9}
zejZfRHqsD)clvI~%hsmR?I_J6ue5R&DBdl0L2?8>5xZCFtxe~8_4J6ed7-pfkME0b
zLk~|N)?7lf=zvh4;6jV3Cwi3~Bm<HkqGc{SBouNxP_yYNp=Jv;hki#!c@`N6RhQs<
z$-hsc8t4U~o`pkS0!#mAQrUd^leB{S50ovW*OST?(J?7oEWKYu?+KMHtt_LzB}raF
zf0r`&Gg@h;6GDA1ZMM)q$d57n7z=0#zOnVGQ0uWZFTtFoXl#iiSWcJV?R=(|7{lc@
z^+)N?q=3e)SW<5t<!d^qCvdTN30_x@NUGOGle7_ZqUeE~5wtG%VZguS{UWEFM&~j-
z;r$ihJ`cmcdS1l6#D(4$edW}a!tl|Q$G|TXd?KJmXL_H=IlpIV>5IPed-jyD%r5Vf
zkooVFCjhUK7LG~_|0$erNog{!T2`D?pK9T0w0Y$aZu5Tyt{3>2z{>?*lh38~g0~E1
z{C&Zn7WjECa~=(FYdO-pA=*|H@)%z%JgSw`y5I&ty?BT|mZlawlQW5Sro908tD<)S
zW2K)17NmM|C(#+cEWqW(MY-j)$MdmKPN#W;?sB@PU|8;0I-{@#d~Uy-?iSdN9zC8{
z+`qsmMwP{&$+o<hZv?GRdlqn7+KYgiz(;&B)cTgU%sZC8H{>kro$G>Ab%r+y{JB1f
z9&y*B_eb0f0ylYrbQv`Ro~FMEnBgi;3DVuJt`wG;mm8#Y+DyNPUN3yn$DD)SAWfy8
z1AbzR^9AWTn&}VHSl4#ICk0M&Gk!jxhq8+!UhK8GD*&zZO<r!H5p7~m0X(Ly0z7Ik
zewC{mu*iKqbp9Z;(}v|#;aibePV0;AflX?Peg+wT+Ajcqlh5$}vL|E|e*nHhKLYqu
zdJXVu{jb75m=>fPv|pr^)AR5g$Ey2e2Cq$d7Mw+}@Cf>_^po5Xw6*9nz?#y}q^=eS
z(h>3m7KE_K=&FKU_?VwYOM6i(;?x-Ai5uh8L{L}9DK5JuPPx&_Jxpob=2Vm&l(Ma$
z+}PU=3w4Y4A7ym`7ag&w^L<Rc%9M5sQD`=(zuQ#IH#^{_FGcby@3T2CV1Fzqha_F)
zZTH>k!}tG~(ypSqvbo6b=1AF7w5ZrfO`%mny`wEEUKsGwdb`Z;e*ydD7NKtOo?kXQ
z;G=KZWe?@<!wfzw)K<FG$J9}wu7cJV1pM@dO`Y#!>ODnae9J(6E|ls$jm{p*dUEeA
zfplahOg)7w@)wZ1@3$%LFN3}m>K2+f<g!2prQsAobPJ6Jl}Uw)@?IBM7s!$m29NfS
zx$8mQDrIW^a_EO~DhsEA`xWJ#=--FD{}G#-na9*)Hg#@Z7O3AQ)eF!|c3DZ<KD-xv
zJzmxm$fFZ>nJ@jjT0VVlQ+reQ;pE}s1Bm!i7N}fBc@LtjfQoIZI&iD6fGTWiYT)WX
z0aYi}E2R23H5&VKqb+$y>5f1#T^ujd@D`}K7j=0rD%y+c?nQ0uMP1vAx~Ug+XPmkk
zz2B=S?}?mSeI@i@yetcEj}F*nwVr)=7xc7E-93b<=WXhNA@~vsy%Mj-e{JH;ICXVk
z2z_KrzKkBq=(BiP7T&L94|l9PnnDy(ly^tTjzBr_hntk;ZvZtXPTd-)pi68?ZgV(A
zlIjhowQ)&}h7*5R*qOiKwB43uFBm~P;$>F{M$nyh8Mk>F?T(ject7`(IF$wJsW|n6
zK$u>&>y?)8!*?d$vZ*^t?+H}W`*BGP`PGRyl?TetsQ?}F`OChmjiR7XS9xb*<&2^s
zHg#_9y@645noV5+udAWaHnlDF-arjaRuo-|IT}rELOn&i{zlWILLJf`FA2Fv(|-$f
zi}%>jp9jX!Nt-$XY8(YlV_noLo<Qquilfa0+O8<9_g@Dl(kC{h(G!75^o3B{5hs2J
zY9!Kg*qSDm{ULBVO;Z%gR_Ie`+DIt_^~b=O)E1}eTy=C;oO;lhMTZqdk=*aN8|Z{k
zHx&H1Fi$&&KB#e8ae2-m7gB!5f^#WLsH?oKo<e;t71&hF^J!o%mD^Nf?gaOFG}5M)
z<x<`}njn<2*?j5|O4)2ay(|>l>}>Y}ddsGcfLcVK+Vwc{EvCtQK>-W0%@)(yih|89
zaxbA>Hl<NU-ubjwD7IO*`vQ7eD7INa-cmYlQw5=L-bM6Jp?H_kXc?uA<sNRKf96ig
zTSjehYF^%@v`Hvsr4_VroRWOIXjR?{T47UEv?XsPX*de0^>ABWgoX&Ed~gj_sxmM8
z*%}&WQ|xDJXsS(Z!pdo-nKpH0+P#5Rnrl<L^Y<Y$S!`1e<lh^(j8-TLWB6g-<#Z%Y
z-Iv!+ZwYk^<rF=V*Fj}Ci1GMdE_yQ0q6I>!S&7nJLaAAa(*Gz)%*yk5G4kNZhI-y3
zpw?4~P|A}x(iWTIS=mTC6opy&Q(hN+VN)8tnRf-banvK?S@{d7u|n~z{8wH#ohy{G
z(iXZvl_5%v_iv%)Hg#J`mj4^v1bz;=&nvh;qleb0GPL=b|C>~c10y^{+g_ZSxt&hn
zh{*oJD|I{7;>{=O$x7W$|05K8-EaI?k_X2}HNM~Yuci{A)cCHU`)rEGcMa`R6vp=l
zKi{qK&r>)GeU^7EwcvG|8lN|H2R$s*Rys#F{nrt{g+uRNjzr&~2}1Gi`<eecG+mX^
zc?CxBdOBMurS*+;vt7pV<wp9xP^@)k@Fv=8Q%693kA7p<<F#@tJ!w;{^{w=xQ14*n
z6b5gjS5+CtFg$oW{mquts5*EDeJm8u(dnQ*SM{_>xzmGpl3t4;*g4-_<QM7|%1oOT
zyo>T}s&L5M;P<K4rW*4u4*rl9*whpGD}p;IZ3f}z26`=Tb#NE8+0;X28-jc2m{7OS
z+l4*BAJd_kA}MicFTEwyO;n^^8{A9h&gQaPXlj0*b}ucnsq@or4BktZ*;EnA?xXcW
zsZ8fS>Je%i-K)*f@1tEwW%twGq_X>IUsBlvbSSCp0eV#^6$>7uza&XMNFUmg59zlB
zAEZxh>TTD3!H3jUEN!Fp?)|}sDKv-2u#JA~emeN?RAE!Ua=#FKghtrZbK0MRzo3yq
zss0|Ni9)FnJxXWVl6&;Gf{)UyB*|aW!X(LG(uKBUl&<vrl2+N&82!JnuXWf|zN;qX
zG1_QTKXGkK*-zVqQoSFb?+T@QKR~zIlHJ-o{{eb7sq6`Q$u4^YWls=)ivja4vw4t)
z3Z+^(NR>iu!`;GR??IYoQ(qcq`VP??o4S?e`JbfuHZ|3Co&PENmQDQu)Nkp4P1U-u
z^Z$;H*whM8Pm|Wby{rCyPd=fx(FxZ}zTZ=6QrUkH|Gf{Ml_&Io??32bp_JB#X?2q1
zVKQyWTsjdvOq*=#J$$d@S^B9>y=j~XK1cg(>btJY{1@o&HdWyc<sYF>gi@NlM0^Fs
zy<h3B&VPxn6-t%;k#4ffZgEe{|0C^+mwn`ZneJ7Tw|(fl?xXaeO>G=HJ^vNjXH$oB
zU%)-f%Qh9wyI=bgoe+vo8iz7pB_FQ5IAU@Pd5uCsy`ya|EKPfj#tHR?c4^@^QC4qD
za%_E#t`}-6ag=(E-WQ6a)PtF?)2B9d1k^D?+8{k}TzZp=gyKEm-2CGdRup2-1^I80
zOJ3EhIQTX#5K8s%HZ=;xJzSdq4lTE-BcT35t#&;g!(Zt}o8tcdO7{xIqg|8#H+oel
zHMj56UxZS&exE)RY8!6M%>4K19RAn^W~Ei{%Kv~av8n6zE&2aN{P{)4uRo-#g;K42
zNZ++3@6ZmXeMq;)%Wlj2i0)UE_b5(^C+HEIdfRtz-~>HxQ=BDyLcg^s&JsSM=WOb;
z(tWtodfBFYL+%aygWeKK+3cS*W<G1CZ1zvOMkuz~mHD62_iXA2sQ;lK3Z>@#bNaJQ
zvCTfGPlaNeeK-FLI&T5Dsdnv?v|3S^v0L&r?FT|_l|9bT?p0;pOVfUkZ)gwN)S9$C
zpnh#rA7Xqi?VwG4f$_Pt!$PSsxHWHMVhnEWM?&!!ewy#m9<-?=puF1egi>ShYfBe%
zJ(Vl^wKYQV7=DqTs%0+Wva4|8keZpM6$r%{;A8n|+G@LOV%d}V>Dp$Yl!s($*Qhc`
z;<Ibo4MJ_hUF9G0Gc{Z!(3sq;ES)y_6y6u&+XN!R@Ta(QWqF4F5Wm^}Zc;5(%6v`u
ztS#fJg*tztZcQ5Fh3VYFqp6I)C{VS0xQsdP;7y@MDbm+M596xzFL?c@(Z!<4;S$D~
zquU&XE57PQ$uAtrk_>fe+0ku2+SjR0^il0Ac#pJyE;PYs<3yiioIk$nSfe7K1D~I(
z$J?2Tx;jn4hz$B6#^}P09n1g!;$J3X*$A8Hv^qXJ&WQds{heBB6dOG}3f1O|h1|aC
z>s!ztc2IMTd35j(LJsb<a|AP@<Ia!A%U0F#PLu8MWIl6}Ev#^!M;*6`EYl`qIS0My
zHvWOkmzqrl|J8Y^OXCr(P1kK596eR<z50@|C>>6<7pJuf@rUo`@fej&`j6#Q+f4YC
z)0#%pq~#HKH|^NASvYJrEMf74voT)=Jr5a2tApabr;E%#-Mq$?yn;^~+#3HmQ%9cX
zdN5qGJwf@y4(a_FSv71!l;T~2l5twNU3#A`YbV(z$^37~x>j~muugnHLB*LZz4V8w
z-+zR-U;I%xj3v1*g%8GO3pny>rWE{Mk_D89Tq<i#MYgY-L5>65g3<@~!lxWVlzpBO
zOHLP?oOE+LYsJp*$%^3BWKjALX+OT|oi%l8eX)k``BbFh6`@+=w@D}wJ14KuQ)`p;
zQPE?)tTk@O@d13&4K1I{P2qRExL2;g&F=`@)Q-eWU==<OT8&$=Q8Zku#objct;KU3
zKFKi&`SclhLpL3F*1TtB1G@2P4#x2YsnAbj0kiOSkzt*{27wC&UMR3hV5`7&0=oe7
zkXLX!w*wZ_F2N4~j;5o6zXv#x>U5TQ9x#iJ>YI@{UL&O=4bB_K3Y=n`Ib=WmQgY5;
z%2}N`FX6<#tMKpOOAGW*|0guXFv`B5kA(9P?eO_DhM8J};R@slUa0M$EoG+x`u$_I
zn+3mF@Vf-ZsTKU^>B!JoC|y*1o_3eOJ@TIFLgUV%+q99|uYK2OO~$)v-v#6hY>IJY
z=*{5YQF;f?lkb<kK=%=6&kfqMIS-??V`z<adsJIz@JM&*MHP=}pFz*3wLS74>_S5;
zeNC&=-gN&(dzi9P3-vwnPHdlyWuLr{+9zkyL*QJ5QohkUETxC#J=I|;JtCYV;QU-a
zV$09>|3-h67`AG+r9Z3JX@!L!>aE6Y>7VIajpO*fa-H_8vQ*<O>Tv~(8;s}t1>n^C
zhJh1sk1@7te9vE}Ra8s>e_dHE;P(P^0pD~lGu{_{P5?e=d@k~PjfV=}L}^y&FW^X<
z8go9U!^X$PHL%G)4VT8FNCT{M-LCB@S?LOBY&X_ty{kk@he>I*;1d8JG@3NF_B7$t
z3umt2ivjCg%QSu~xJ=`>g3II<XPL(Lkjpf_aa^YHjo~t6cozZkElW&ePl#ze<C_HE
zBzO!m=Yhj;8CvdkZ`b%9bcYu4{Lp>CxTfG9_stsH^DdPBopxx~`rmc80sqK-AE3)~
zp|&ZQ<GD-Yu|EvXMfyI#75Y&v=wISFr16`>L)s(mO@MsXJ}fd%8xIV95FCD^cu3<@
z_YvX0r=1aUrySDw9pfR5&)=`w@*~RTgTrqf4{3Z7f6L}?NWU@VEuN8-z1pU<XHuRw
zx<f}(-j~v&#)z`Nrc5!8=cRd1X#CFebMW!^(KUYG__@aK9$m63k7`wU>w)td$dUSv
zlC9pO#<8^Tc>_AX$qeZHRx_aUiM#~z7wJc#|KA|b=i*_)3F!Q`GobT1z1o)9kUr1X
zrR`5^_wCY*{C3|7jo-fR(tcgq<$J^UcG-56K9F`RINvJ0({~h{`+OtyVWB4=$!~5?
zX#D2(gvM`fKiBwtK22IaV0?4vN4|RCAGuFxd=q#Ael^~I)F=zF&iuwTpz|F8M~@}o
zZ}(jc8NPj+YirBzV=+416)d(n{BAa&^X<Vhoo7Fw^LyHW&Nm1Fo!{05biO~})%_#1
z#^>7;@U-6m=NrHi;%O~9ds>Ump4KLKo8U3QV}iHn>~C!XV*=-520!!9l{52PJNog7
zYc3+vAHd&L=uLf3TVGI^x=FO%E^wi~Begd5Y2(kS>r;0K=VpOT+P>Vwsdow9r5y}@
zoZ1EZKa<j>eU|na@K=Igrf$_|q(76g2XVMG?LPfjS)u-hK0kD;?<3<|>4@a|O}^T+
z=V=k%(A}>8tY~)H!#dv>?9xB-T?CvX-Y$JaZgbl0x{7;4O7BcNYWPy`^X=82DV?3R
z)yOLSx3qmazgynN{sYJ--$SC+VSz^tSHZ`qb<@yL`p@<G{&DGh^?xg!oPGpaElqz_
zw0cY5Gqg~Do<bGf>2IO0Z>B%3H$khX(fieqVVzs`MMJJjZ`IFAy$R4$au?vZl6%s-
zw7Yzdq&I21iuR?yFFn3t+&A?3^eG09Ws335lD`4}DEGtkUD|ixhbL^A5oKSdABE?X
zXR!aAkx}mAJ&s`(eGWZ;qc4<I?=l!q6WFA^UEG@Smc+e)#`d{O;}{sgE}&7s;0Tbd
zkM>-b5kM~*jda}*yg6g6YfaG|8BN+y4|>=57JG`$@pGZp62e~Ndbs4b8N;v=U(KjS
zI~VB_1kNSC(+=P+W=!TZgXiuBEtoqq^K*#<(+svrz0RKtsMq-ps9wffZ?INx80Q4K
zGuP?I3hv5maQXdrXD%c5fqI?&xn5?uUg!IndU)oc%#r$0AM3Lg`i#`CE&6BXVuM%5
zh1!3XE%7WiI36y8Rv)=F?2n~cEmGPd{5Ijo42ivl#9qNS2_7>f_6poC<6>(s%fhF5
z{CV`e@nu0<)?R%|X}fO+N;TR68y-w6G=^jLmx&GAWL!s$>(lpSeMIM``Lvs*9gcgy
z%eu?paqSWN+-LAy+-Go<UIy<Pn*Ffw9~N6J(|JGQ7RF~UlUn<v^pI$KNVGjH_+h~h
ziOz=w-iIFlj(p5V_vd8LWLlq{fzO{^3)n&T0><cRz>V|{;3hI4(?bP-+i4Www`daJ
z4q6C!JuL&gnYsXPqgw#)qVMN;aUZk?@Kf5GlY{lQC+9TebK6U6C>5L<ymy~mP=oi_
zb$}JL0<el&0mswN0jJWFfHUa@z;o$Uz(%^bu!b(CR={TZ0pR8IGr%Z4TR0x?$}@^4
z02T&jQa9S4iTrYJP9r#Ffo9<}3nwC+sK9N)-zNNRxEFh@=t|+^b{?(W3|JW0B{I8h
z$ZhV1<l9B}h~z^ec|b}J+K^=qLME;FNs)O`WZsa{<H&aR<{YPM0pFs_^uoZ~BBN=n
zv!QXRp>b)h#+sK4ze1~oJ{7{L(6-U|;tG)&t_`K(f$_qx6Umv7gaw2%6Os+ZGexpd
zI87qcEHcf)X@*QkakI$8z$pxD6`5@!vrS~SLFTIBZ6dQ>W1V-2%x;m{Ei${MuiYYZ
zk8mCW%qTht{!fb!3jayrzbNpywwsO=9~b_|!Xcf<sOe${eH*=2Z0KwUmwpqSRhp}_
zH3EQzfpU?lfXv6m6(Un7oSEPhmCV$+<(a~7fP6+#qrfH`a{JAY98=OPGEwl$0zK#*
zW0!Wep>%f1HYwdH{9VG|E&ScW-!Gg40uO@!TJb^Q9}~_S0*`}VRB~MSnjzydxEI6V
z9u0%%(J*+7A@DPb%0;FE{ADE-!mks~OmHwR;nW*<LcYNmN`ay#8_I~J<z{KQ8S++1
zv&gqf3q4Z0&4%3jHj&vTGP|Y6-GUz!nS;{KLGW)cIVk+6!6^(pEv+2~ALA0f;o3&~
zOAMFHl#6xqx!5Nw@TJB=K<=voGVhjDh|EYAYdaI1jMACHSs|Qek#83H9^q^g&Nks}
zmzH-5f4A^=3xBV04uS(u6VB7p`!V4k7s=zoe@{4?n|n9hsjR1)^$ZE8TwsM;bau1O
z!`wWUVUP(F)k<l-;0-7(3^a>mvq<(x=~k4M6>Ss#HfedM@OQg^f_C-`eo#seO09#U
z!_&fl!+jG~6}^F4Gm13NO|$@z@sLMsC9qlGHi5eY?iP3elEVWB1V1S7xIiuCCh9EG
zQijqsMMes@Q!cPVV4c930#^uZ64)$oo51a;TUNAF@ZAFUr?8#(3w}`GG2t8&{J22F
zTgkrdl{n^oh$fa+2&Y0gwO$#Kz$Pzi-XwUlz-<C|3fv{7yHU3=u-nTsvRhg>0RAmS
z2Zeu7_-_d3xYQyax3BqFJ|uX#;7z`vbazn;;P60?@b?J5U+_bMzaf&EpX<8(L+Sj|
za>0iQUhC(U>x5G;oE5@p5>AV7whF#W;2z=Z7nuXXIRs8q=`rEFA)L2_L#d*3s^~0u
zx!}W6S=(CS)Cs3aV2^ON3cgeD{i!l9f*+7t$AoiCIFu&sr*UhcG?okrr&jP<!Rw`T
zh2Sl~Zz<{#e5b%&Qo2j<Hw4$xS=(}fbpo3NZWXvQoo8)lI`_LvIQs=ZAowxC-w>QK
zM7InXyWr&lYcsfoTEXiCt`N=&!J7p32;3@gr@&nT_X|8GkTSXbkihax?xj}ny3CvC
zfucI$tPswjOt#Nk0z+Bcdnk*eM6JM{EN*9~z&%;)8~X)6B=|AG-x8d%S<;owG9kfh
z1=b6v1+b}fyTD_@ryS8RN9INFTES}tUm>tZI6Z>z6nv-P`vo2oNV(E)?oetg4GCT=
zaD~7<;13TR6PyClqrh5$D+Ko7GiVt_J%Vo!@V>cI@cjah38Xw;-GtA%V2pVz6B4{f
z;CA8c6nsA<5i0~gB>ZE-IVKzmN((`00pA2hJHn|ISdY(yR29_+hth`96;irF_$}Zs
zC~6UYk8pMhbmeobbLF$&hVpsVh5>IX?Gb#xKq`<?7yMq^o3lb-PZ9U)DrU<J6Id^B
zyTF~rJknzVYfBhkA+V){<$DC*DR95QV*;s^C2Ixt2s{P|Um7ASLf|ohp)%H|R$xyV
zmmU*HA(0PBslXKidj#$jxL@EgNMhlX%eVyA3S1$uN8nC@`vtyL&ORR+Dq|72Um#UT
z3j%8et`OKGaHqii6<lk-;Ku|%CO8d~x&mtjt{5im3*IAer@&(ZX}HJ>tQELI;7)=2
zhl|e$eoXLVg3}18HA4JE@LIuZ1z#bsN8nC@bQ<gMFg=R*rqAH5zDrx8jnud5Kh*!E
zk8nTYzAxp)l(4td|5JZ%>Yr1+X`|Cx)9z27k#R-FFEifF_$(tkvo-U_nSaPUH>)eF
zE;|MH*<O6}$R{_}eoDoEY54o>>G-=J`S^xP0q&!VaF!{?OTZF*UU&$&W#HnQ4>;8n
z<9>Sx?zhWvwi%B5?bC3t9maij74EZZa4qf%y^c3wJwApbbB_aBzIOp#p}z^A;SGTg
z0jKys0i2)5FqFnHJ^eGlpQbYYTY+Z<xbCZ^CjmdrVZ7eMr4J8b_^NOYm2hb?u3A%^
zbB2m!seyMD8D-r5{9NYLNso%N(c?ww>fH3Wj4EB5&XP~&GgOj?N($mK-y1p<_;DHI
zhP-Ov@A(ofr;CQF*7~$@DAmv-pG^&%Q2nsK4vVJ%W`L*Tdtj-6`QYiWb|zp2=0V4I
zKyxu)!vXnk<>Ud5gp`i=3Wb2xm=7Iq7)l{i1E}N8K^fpw%#TiIq7DAn=!T>8EI|HC
zbf*E%LK`~11ylvtfZF`8C5#4~huS(V!g*E4*>ob{`S{+Kj=!}&1uZNE)agRBt<gn*
zc<YEBbZST28kvCjCr$9SLZfwnI!@Iy0k1@F8s6#80)92V@v7mRJqP$T=vkw01L}BJ
zaW3E;_$HS|cLM78cGP^p&+v^S4S!8?A@Ki&Mml|tZw2X8pj`ldA)t;=om~jL7*MAY
z?PB1ifUuQz31C=T4$eqGSWIgIUIkc-mo}qep)f`<6Fr@eZwW=9^%c<VdYtt4;61`S
zRHmJ-P1j8A9?h?h*XQfk>U;G=xS6}!_<`}F5p<1mt#w`Ry36&D>v7jht~Xtux!mpy
z_gME??udJ>`zrS>?gQ?_?zh~ZyT^HEc`o+c;rYySX38}w$5QgWOTF#h9p1g(SG=XZ
zdfzX7ulv0IPXCSmANpVMANRlSFH5aXy(abk)E86p(oRcTnD(=@BWdrZHKeahUzh&d
z^iR^y&S=cIG~>#Qdoo_k_<P2e8E0fhGxe<0tUy*pR%O=Mth2J_XRXV6B<qW;)a=6S
z>g>tcbF$}WyLzxdvDOnm_u&1To*?Ps>}T*Uj^F6x<*EJCg72p?+MCBKMqbSFLw?p~
zx8p4(!IM&G3}VYz{EmbFj>qo={7!@iPJ;iP4!ci=2TsB78SufW_??E|GvSHT@p~42
z`F&X(erMo!CVuPjI}4oI_?-jDKWEdn5I^VA%XpVan8g?5*<$lo+0Qlhv)z`9*>dac
z=SKV4W0!x+etu@x`@*Kbw4a8i`g7aQF8jF|&&~9tb|szE9;bHWary$k-*i1r_u%(;
z`2CwJTYJF$DgDv?ITd&wr&7;JJV$H)={X(zv$VA-bF>1_r?f9+q2~5RwB24)OZ6?(
zM*6z7HNGpg8+@PAk9^kx|CIRmcPM+$ce`fzcWGz(_u_Y<wgta;_&?GjsV=P}^<(^g
zq<tUwzXAWZ)U&kT;Q3VQ>G&<z?@n8&{W)!{o}WHmuSvf^e>=TdFUpAM7=sqexJh5*
zE61;nHgweelo~QWrHe9us(&vtTl)yVPihOb3$otO*JOQ+IvYWMroRRJzq2@=8CXXK
zo+<eC0{7zS!_$YSA5VOr88I&if1HIFScI5Ygx#me-hF2Alun!3X0}JB52I<*rz~GS
zX89PJ*3jM>Yi(+4y&^JwrOle&ynK0mYqX=SscU9iQ#2}aTw&~3u2It*Gc6WYWM65U
z%i=7(DAHkCvHI4g)$L|9*4iAEnp`3+j$>@GIcsAq(jIL!+f}h}xqQ58Vs&dY7O@)5
zPOCXGzcbd+8521vm1ZWWX4KymkRF87SGNI~6S?l3NNjOeN2H;Bl{tO&^5se7Y}1<8
zv^LVh#hXO7Z>y8IfxgVKrwf<OFj;lb9<iEYk^0CgHAdmG@`5aAvZ9eXDG@quWYJAk
zoe^z{wa;#iw6%yFN@|*&xi}rO;mj(KzO%|@{bqFlCMM5rMvy@!4<Z9hnO$)_x3DNO
z=#<%F6Im?D%sgqrON?m}izG-4G1>Xlh{mqq_As=`KpJMXcdmt%SGGljTG!bWvx!+7
z@u%>k>|rRG(G-pFbk;|j+nO*bin}P%)H1)lt!t*)))r~DnGNmDR%C6YJ=WBAep6d#
zB)Y&d*SEGrET@CE));E6?P#)Wo>Boz1QN3>%e3kv(Ppc)LvduD7e%6-Z84NLMo<q<
z(bCw39yZQ}n{zEk?>ftB>f(;puI-e8IE*#m#Ug9R(vpVu*!XeI!~^L&@pc*J6<FM<
z6e%l*`GZWeQ+FK83^3v2Xm)3N^NMjKmRa1{0kh-d7|L|x=-fz`6f9_JwZLC9PIR^#
z9kYCVe`Uc^Isq9(Cr4x)*B?M9aFaboNIP7OSL%*WR(HJUWH&ly`Go#Dfh9VP<H7+t
zOq5R?upHcEg+TV6qJE4?y({3mPt);@r{p$3o@cgnwne5Rx0^P7KE5%uo_%xqa+=$;
zc4bQw)y41!R#tW*+F$`t6DUEVD<R%Yja`VQYikmI9<7-ZL5OK>rqz+y@`h+*3~Qp9
z`c8qACL(!53$?_<I*57r$HMWbYiSWd@$?poqD32puSX*-G%dM_>6b5GKBKAma{M_M
ziEK1Y3HRsEYH#V!gpX}7tpN(o!(wk*9qC_#V|jn>d6C!}vt{72*^#DLrxh8bu(Pdg
z;1Y}jU18fAxVW*|>=-~14om&jo6*_YhL|&O;i3rCYnP?gzh+#ELCP05t?plmC#XNS
zAv(W<qheEA|FR|408Ca_Hq?G|d|qVj%7_*1-%g#i8WFr5+k3w{Gm#v`tftlh3(-IJ
z>9tL<{`KI@)<A5Dxc$W?#P(yuOsgX;yuBzdUB$aFt>kGDXNPmrVpF9bvn_Ki(`qd_
z)GC|1z>0K4P+Hd^4;DJN)s|+13BgE<47jO17B5y#N^mOpDz!&q(O6S^OOvI#vX_D^
zI0v6;!FMqSEZ7|3rKxf#!p3`cQ*_Ntvn3*WE^e}*$vh_2RwQV<Q*5s$bS<lj7B#i6
zj!;AUdh>ET61y%naNcM}dD9&z%)~b`7%PD<>THj-u8oLg&&G&Q*Jh~^_vW!}Yz{^t
zmDt7!ma5d7$CZ*ejR-gBh4<}NJQK6q(B9VC9+9mqX`7%}YYbu+w8qxV!C#_kk`*8A
zXljl$#=20@*tK@0*=DEA14{5Ta~zP_5d`iUkJ8*Qv~Fraw3b2^SHlo;Z9F>3WF-Y8
zT9pV+qTgam1=Dylv+V#SJ;#Y@W2P@(uGC&^#%1HdLO31C0gM{gAdMG(JC8%T?_3y*
zt+<k(th7Wm=}KX2cZG2&Q&K1ha~h)d&Lf;9?a|H-J}#(i+g?F38}S-W?nW!^B+i~E
zZhHQzxR^@qFwJpJV@ISJ2c0;b6jRkgR`FFjjT=Iw5kR18yyC1jNeG3W6Nx30JR~HD
z9T6+mrK+-87p#d`5mNKX>XTX|@bbudL_t_kmMI~$MXV094NI10wX`B_nPHh5WHIrM
z45LS*2%K$Qj<3WWh-M+4wzNcA5**vNE!$ZZMb>q;S_28l1aJ<Ts5@(8b6aPNEEtXu
zGfk+8%`_np$CmIW8>gr~va)maYF_;b-aI&9Z%&`FB}AR^E#~ExVAq?G=sYu~_PK^t
zi30cw@1iY>B1udY%4YNCi`3xqgfxx-$Z=FIpWvR?)U`6gIwn}?ix~~8Y$Q>l_N{*G
zy0$iRL+>^)#ZCRW@y_59?SnMiyC{AzPDndenvKwPKKut;a{of!cX>aQ{kosjOz0M|
zoXs|IHcGT(`%84L*({ADN}TSoJ*{e8-KmaG{fnJbPcQ9y&19mE<DAO82|musO*km^
zWhW9>dkrUQ;5g(gp%%3pt9>C6Ye}Wfi6lI!$X*Ibkr_*LRb$htNUUoS^6hA%BMD0O
z(&wm{ROFZrJN^3B$Od}>CJCseDP~<1X=~ajSW<Z-cJ|&TNh);Ak1*5H*&It~<P^*_
zJG!ja)oYT98ZU3{;E8OD@~{(C2Dg@-h9yLuRg77WA<s_~C@ZU^A;FaZDydY0*MLE(
z6Lx}^P#P!b_O3*ModB?@V4jt&e9TUi&geok<X|gVtzb!6Fj<L=xOX^L;_;0wQJat4
zZBa$T{0dpVo=;UsbDSG8`~fZQ6zPK6#qeaB(`8`@ve=YI3o~c80occ_#cL4dTd*TJ
z410(*_UhykmBY$WU)eRDR06T{3%h_jo*QXj9b3c6-27FmaL}r2Z?Rczszh?%D5n>+
z#A+pT<z+Mrd#n{{>|C{~wYe3U_N<MO=1vY1kZr!4Ot?-fQhXU$BIB3gC6SHTP9jJt
z#cs}k66-QrGk@h}xI@8Oi?k(**LL9cvEAnK01!BdV-YoSGQ~+?{fwF!jdhFX;dI&(
zSsiJwX+i1IwQba(vK4BOjL#u>lXY-jhH^`n%#bW?zMPyKwzy?-MaJVhzAeStshz}T
zL?y=)v*55H_TcAvO_xU&ZHTu(F{dpOFH>g3Y1=jeHFmDW6aYjRBoEsja4%jjQ@~QN
zI5tzBt;NW^+tDar8!236WapTz?PPnDeH)Mn?{*Ht7VpL6!&nj{Zi^(Ia~Mft&5LXh
zQzo&Nv^QB@Np#F~_78T_INoM&Dr)s4F5!snm~<%zeOa|+4$q4di|X3jO}?ox+a>iK
zfNd{51abRDPkNkh`#83jR$kkvkHu+XH0tn)8|L||<cNbrC?aQGB_Ls;ztr-1kx0ut
zvwdD<^}Noti8?qR;bOgIKGF`+GEs6)6n%;#^FD1)i=g6nu!0bLcfuwSV%k`w?66{-
zp^PJC@fj0J=E}n6U|Oow&Pav0sI`O6Yi+j7sJSX8tE>*oy(`)pt(n=lrpfB)duchx
zGCMnHwLsgRNc-0z?QdU?JXdLflOfNP?T}(8=b}_ht{gSaQVFlUdy|T24z*I<b&wfD
z+N{=33xY=Ls#cIPPiIHkU{ahrIcO(czp9>MJaVKZZT*THq7CtuV6oUt47aHn2?NFL
zN3A$^<2VW)M{#un#(gmhc9IKSEdCDEgn8p<U&aTxR!ce><BBb2AC#qH(#3K-?I5|J
z1>~s{1=KqeCzk@V&y6y*#4nd=eJd{RWGwt9!BK~YVZV9lccB->s_ge_!M<OJ5})%V
ze8$^yb}Z*?(HODTw>C$jcHWO2j01jD=HdJ%tCiFKsDwm014iQ)?@C1ZDc|VeHB)C4
zqOehXlXsfoOLqyGyp18Yv|-;;8+24%dnQJ~?^bv&qY;+nkw?ji3cM9ZX)VIF+GMee
zqqq&7uzY!JO>2CFN!IGMHU?QTa#i0Jr6sXeKwg>RNoveC%1y?zcnBrE>w;VLe!Ji-
zkR<u|HHjT-o%dwU{PJ3?NrYTwH7C->$Cb1-^DU5CwCXyKWs<HhdKa;5YgBff_K4YO
z-vIWlGN43!9ZC*owIbx%(~f1QFx6L7Hd6=hllZbrI7JKaN5kX9S_wGOq$}vNO}-<I
zI(J7ZN<@k8xg2~o0;)_4-^+@-^`?>{Cwy)rt{d4Mm9lZily{;q8gIR`5kJr)4hb^c
zXyWEwB@fDT7n|mJ$Zlmx;QCV5NAdx}?!dYGlyb>toV~`b0{`mGNzyk_&=hY6#c&t9
z!^CP+22Z93d|ih{hdTj8XM{>TA&;XV))U^awKl6oB%1Q2QrAKb#R$<YcEOy^RtK%e
z<-%gV-;)EWT)LUj)|f*p?@MYgewXVcS#}vmPaEatkUO>8WG@F!65+RbHpxmPk?aVG
z{h=Kb-5ev8v*M*3CktdBun^mt<>nc?3Ol39w5ct!Dn@e5BC}(8!&()Vs3FQrmv;(2
zHQ<$qN|A)%KJ61N_I@iGn~%&!4!Ah5@C!i+An|Konl=s_K3)}?ZR>FbBX_tl5?yd9
zOwKIJ6u^ry&w|eEv=TUPWx|z7B)$PvSd=H#*~0C80r_QANyh^jFB5(#35ovib8(Vh
zAK{liPAFQ;IFB-pNFpE<EGN&!7)gxfl0sj6|BIirBwcbO)s?k99Z1$3e!N<IWvVsl
zlsDTwtsf+K+xbq7s-?^%i<)@t*<5iFbud($l+EvDBJ>zluO@oQB%-oii7)>o>r2XL
zlZv=o*>L+8JG*KB66Zd&e+jRbfw?N6_Al$(i)jrsT6PGVA652hXm5#Z#PuaZcnV;1
zY@--dHZ57l3QM~7cNpr)ZZpGd>5^J_eL;2YUG_@k(AocF%#qi$x_I?D3t3iTd&JHP
zIUlkw4)9JISxTHrZ1RnK0gDV0_op3za8kIL+}`3(CtQkug`ftXlOlX7dJJu*Zo*$@
z#wVvH0H=|&$ijane(UjBw<x}EX5nuccHld4%$p-+ouDZtgqk6I7;`Z-(Q064GL>5m
zI1e101RY-bOw@{i7Xzg3S@>pM2e4+LTOieh&jyCjOS^C^l$!Wk>Pnu=k#~p|?b1&Z
zXs#0ynYH+*fm?)HiCQhx1^!CvM2!%nO?j$uV#KL4@ae!hyjRAbS*mD6KTXgg0-09P
zw_ZL+mLyZY1Ug00T8HRlK{A3qLU?w8gVCh$C^q8HhbL<BNY<jX4drYF9u<!T_Y^YD
zRd`xxLutj*Jf3!2S1#=Y)q*);nXx=8trtV@fwf(1YjO#sxvx(2$?Y|x&-Qq$Ye20>
zIm@v1+t6z>e%VUvQPzffJloWByJIZXbqIgt(lIzs(pObyb;m*75N$v$?qCh@-oxXr
z+AzcoXo(HUlO7smaLEJ0<o#b5p-CK%9fhZahwDtAiC)LyqlT04WCO61v%z9)1fOF_
z>iL;7OO6>Fv-GVr(4g1KOtaNvVn!Y+W6bGmh{2Qz;c`y-%fKGc$4KkcYFup()EP+s
zL55(EP7IbkV5Ml(0@w^wDWmb^Y!H*FNo*G*wu@v8HI;wESlKI4BMQFbiPUqzF<J{$
zXSYhYcft`JLnx0*4hL$$Ytbw#H}J4)&>e>zHPBg@Id=SM_{ivDe84k#KF6Ys^;kw6
zm^kd!2-a6>o=DBZM@^@5Xk3`wda{WJUs&wPY)<wf4k|oxt$4P<&taz21VugfI0jOS
zBN6`wYk-wcUQ~`_J5hsUk!8EM<K#-AR&>wG3~WaB$AlS^2MQyc>&$3KVvhw$j%VDy
zC6n4$i!LeUc-=Q*68;9QikJ&za=0ZJWy9C?;Ml2ePyKuNx=`ZuALZ%IS6Z;wF2XOj
z)`oFWZi3JLpV-mrB|OA;xy(km8SfSi*hv;+*BscoH7IxXw04ZUjc8V1&fqiCjK#xq
z$1biyud_4LC3V8#8CJ8QTIcz5WJ0LjjQ=`?qrzT`P+W^g(z|`N+i*UB55G?xY&?lw
zj>pEfYl4m!pbr&X@yB%y{K;7ZAMkcp<CD8oaUNuNk7ms{qi`ZjVn?LRKKX*=5DCwa
zSt#Ze;PBXn93<=+svAt(<VBna5xv7h6bqiRJ7feL)7hTLV-|)H3V1^c!6JVAH;}DW
z&<WvF=uVtvE3Sm6b1Qz-#=qKR|3_{=+ctMOEsskp{U|k2|I{p>7)zoiM$yo}?V9);
zg)u@kTRamywx}K7)i&Kr*PhoBiZ6%gnJ|*tx;Qo50Gu}hel}vT9JF|nmAkVMdB1JJ
z7ba9#N=!AUejFP)omA;i7=QeVr!!H@2}#L`2~R%n7b;w;AgLxQ3N9y19A%x2jMFDI
zSRPsvCWKS58uT<06M{*o>OJ&uQVOIdJu!MZZ!qWTy%ZXup9MWQ9poj)Ht4@RsH+2|
ztPf{LJVH|}6^hHw2JP$_;eOVgk5SBk1TS|BmUnvKDGlMb_XPKz(rr9+_T<4-NUY+2
zO^HN3R$>FxP_aOHSuZ6n{Qqgpgl{A2<W9%d-`fB*Q8^W7wlzsHs`u!6>x(}szU__P
z267tZ<h>0xcQ!-zV4h{?c%tS$g!yrf7$HgFPi@G~OeTyu4dH{s@pMdCcdt;QQc#{s
zC%E+1*vZ13HveD!NUi>Ed_iY3zJxP)zX@+njN<G2PRRCkA71s{ax6`b1!{#RyOm>w
zZshaq;tsvpc6f*GZKYG0mpaTZZ@(+yT1}Ym=J*yA!cmx0p}{41<O3hs5+1@4)7jK`
zwpODLj&9tWv!Z+Rc=S9UiBUSEV?XUJs}_jE;~3%e#lAI3d@GFY$cgWXnEv&84?gZ1
zw0%0-4r9GId&H@<$GN;3gW7~=!S;y*^u_q<9ecw-^X^!n8($Yoo_~kWelQaMvF|cY
zr_F$UlaDNeBqrI7m~m5fF+0^LWuI)6J%=v?`Xnxrq|BDxsI70ABsJ$^e)(u`w^qol
zB_~LHQj&D1s<*GQt{iJr8pl>*y)0=7|CBruE~G4}%Vk^V6od=}vNC732N~V?!Ti&y
zSBDX*ix+jFg6ocnUstDw5-GHkrqHN=r54TkdTCyJ>|MN0I1k{wf}eZ>Q+Wjr7x?E#
zF2EsXu-1}SA+NnvlCL;<i4%QQ4B|@|Bv^xvBe|^^m>Isl8vIa@EZqQ~JvGTCELn9b
zqiMit7yqipDakJR7i1f-1K{6DImLEQUA6(*PB`UuPhEEQzo74IrNh`$v9HSYcqOmK
zfo`xX!l=XzzGUN-%lWH10CN=MeLaK-sdn;_L^DsN-#Yj^dwdt}IaC|Hyz}%^X=4Uz
z^GZpyMI#3rL0^q&;!Jq9lWRLy4;+o6;_>Q&v0tsroj8yf`B&Ww@x|_`U3c=@?-QR!
zpNb6}eULU5_dmbHup-9sS}W~cw!}Wn+ok1$^~9@B>VJiVy6mGtC3sbSbsI}i&bOB|
ztGAXsLwv)k?$exDSR>hrikO_m)Zoj|D$|&ToB)w+_5WQfd@aH!9@URJlW>dYqW`X>
zdp32wjDCjq?q{C8S2|}jTbomgvvE70l62gngYICxqq4F;uXKDJ<}3ES<XTQ2@mi;(
zS%Wi^rz9Pp_fwK~W|^i8=B>&44>X&nb|G=T#5g`^@tNQ82f{U3^6dbP9W2sBljM>k
zC8hIu*Evs-ffb8uCC+scM?0E24?f?HKL)`5y;?GYR-CN)8b@8wsLLmHK3)fpYef|0
zOsa;obY3YO$N6@F@>RylnX9_$G?5h`yGj`;zD!fqI{NCYpWAkFZk5M#?nxEuoX9at
zo&8ykFV7O^O3GE)pQ8n5tdyR(;=#pbHcRkbjFN#R$`Z%mz6W5|no{{i5a*AOU9N6A
z_+-Jm7q`KO^fQu969Zi#B~EDJUdMZ$iC)@esvO(NyJ=?fvAciWWF0s+ck1zJi*0i`
zkKeXQ!V6#p{2|Rnw)OgsnJv~!7WVln{mCs>E}exx>(Plm`8r(P7bWeG*$Ldv&+~cg
zbD@LdJ2pQxablnp{$riULoXPOKXnnpp525V_%-S%_y^Za<ga`p7%iu|3h;S{<<~Gu
zkC4bZ6raA;-mm34d3sWxc`EX5KriZaAg76P)|Ph$^@f7Il5NlLx@^7i56vl$kH*ie
ze2Rdr-Mnk_1t~{&_Fa|D@atbWX{2%{qee)j3A}%MB&Q>#h04|cPkZMd8^>|o@!h@S
z{UW)%Tapgt-kmRrlPFE3BlRPYf;hGzyN(LWs%_bcff|NHQ8ppjQbjv0Q@Gw0sy~cM
zsr^Tg8gLC5V1PIY3#x$r=pRJmphhD!0z#lft0D^8q6QM6c2gh@YM_q$`M%k`+aqPm
z{i}b}N8ax2%$qlF-n{qb&D_jvu6!F;Z5);LsJlt@J0D-P-wqw>_j~EzdFkt0#(sL+
z{=fL?FR#A#<3G7e!y&)e@%_pWm&T-m;ZP^=L#{;ZFHJ@d`HiN#brjcfDZf`%N)(?P
z)_pRH|I8ov3@p91y%b_8gZLg06(GMywxu+21+GPjkR?9J4z$55z{g$oMp87$Ml#`Y
zBvXa5U*TJY^pG=u!Z0kAgGQ&(ES8~^Sl%^UAU3R&i<L%`|I%b*E~r$>)N9-u_c^X9
znr|d88(34>qD5*JEvjbGVu6ENd<!*2)++#Wf{TU5X=J}*6(l~Sy4)%pITS?m(LDGA
z@bfzBax@=C@$*sqjVOMB8vi*pemRQ21-|$>Rg;`?0&o<c6$9dz?fOEI@H};*QoIu<
z%P5{11`3CR)UavwZkFnt&C}*L1V0?>RB5v?Y$U5>ZiR(X^mHG^)ycXafaO`gt-_4i
zQG9i{riK$8t!8M+y+<e+_i7oLt!A|>&>y;Hv3su$jrf%^e2dSLA<b{q3jF3&r&A>5
z+yL?@KHmp(cz=}Q)xC!|ikDsLkJD7$bEy|fu!E>-kLVFjAdW9aPg8uWIYhI@SHsCh
z{8z+Yh~m{KezoESMAAAII3Ko}6@(#qwUNALG2d!N^M%s5&&g3ya;cGAMocWcrUpzd
zkrwoy;};aBo#$I5kE!%;2rhm>&y4||6LWPc<@X>>@Z$!n!p7(e<3vB_4@O^)qZhIo
zzZS)pqWCg`MFZ7TpDUtG)sv};l8xk~88(vBi(VceCyl-yIm;5lM*J_d#idFXFb<06
zaCbE238Ydo`j0$Xcv)iq9QiKyL1={@2;mDE$XXv{JqJR#2eRG=fe$?_gnI>Dk$TFE
zRWTTtAY=)R3!=pu!k<Q<D^??yOpRQCbH$`z%ADS6<V=Ikii~@sW-hWU0Ayy<nFS1{
z)aar!l0Q$22V)I22i4C}-l3YJYh@(uMXB<uPUGyUCM$>N6FUM^dk;a|t6C$xE?g?L
z5i96w+xAAyEM{bxAv#;EQP@OJTr<2dE`pLI=wqkAF`^`<8I++|7W$unWlBcm?E)8Z
zrxCxCTAzy*CH#cAi4L5?{8O_&)JOWc+WA}`tHbF={GWbX_24Gfyj|$SwEdBq<GdJj
zafDKmp`ejed8krV7edf_v6It&&`0K?$-9y6aWCx9{CyG|8%S(>t@k0W?GN|pqD6#V
zmN$@yxh79&sbGt&Mq066{Vc@{+N;%00hVF+g1Q<xZ`_RUs|NOOCC{fX7<IOh?l!zp
zq>0P$&2FlQ@V5O@4Y64Yu@NDL8jw(JXT7ykgmJH17N&ovWNyFU7A2Dg8pZ2Td<8mQ
zr}+r-kDXl;0znr`h^95P&?#1#jnE59TXV{^hz)*9%4C7jx->(iQq1EL`DBZ-{*0^*
z$2VeJ@kz_DD`~Xjaz#mt<T@F!Bz?G>-iraQD8B+1k}YJeNDJ2qq{awz@w%ldkoJj$
z0{R~qx1RBM-L+lDT%+HJpjAz8*R9@b#Zn{wwlj-j+Uf|^MT*73RKZv2;)6cKy5(L=
z;T(S1Qe(N{ykZbnz?>9=QivUqYq6dghjm!5Hs(&JB&ktRDT`5cwT$z*MmqjYUjV=y
zu*vdJ7)HsI<8-`a_t0#KrCXs(J%%iWFa)<}X$aYCh2z%!rChKZwF4lNb<}C7hUACV
zfC;jP^BJ1x*+Y#O8ap|QpC!p`HOI;Y>Id^u`ck7S$%4<irAAjlx(0kR;L||-?GcMf
z^O_}y-#|JkHE5>BSQ*iuM)GOc%9SkG7P<(`R-o?h?Ls4d!)zGVtdVTHdD<_)PMIP3
zI6c@LXqy+FI71ISEaMt&((!N;@+e-(@)0yvuVh86KmqL{nT%HmC^eZf?kBtZmMxhY
z#}iF%LCp{|TJm;G!kt#Lx9obSiTY|Id26IxkagHkJ<M;n_EJkL&J@?u>g6JiZgQ_l
zP$N0Or~x*;lZmQgdP(v)?v3UF!4a&?h?0j|O$mDPuq5no05t~;Jol7FN6B2N<Dth7
zS=}CT59hH0NgWzfFEC2ZQ-Fk|E+Wxeh&!K3z0xH0x=WL3y5vAK-~4#JKxd>1ruHyZ
z1htX+kv0jHS_&*vgoo|m<!Cn%;byB@Pdn5e<?^~-?^nwy$-_`ZLcYG$UJjazS|aoq
zbK?<CJ@#(5+9cWCIOAu5p)61>OCiHbL0msGnsGf!9!O14@<1T1Q~%)<+zh-KpX34L
zyik#_hnc}z9q1GW@}!-@YB;q?i&I{dy`sh&q0|Nc66UEl%LUPzEEYGcM=S##`7meA
zr*eLwY`gpbI6?|OmlvJc;xgbjVvwni1#0SlF=J@$C_}#Z6{{%NhcW%4pJ13-#tXG+
zxlJa?)+hc~YR}^rrHC3G{C6)#Dkh(Js$Hg6x=bU@kbcP(EI*omywz>4U1uPcVjPU}
z#jo`{<J2*>T3$vtMHeomTu2LHYVE$I9-wmyn<wKM?94}bqCeI!QsQvt6SP>RSt~n8
ziZ!E`+Glq&qvwJjEu#!Lij0=+j?Pm8Y_g8^=_pAci$r6ti&H(+>pm@C+Hxw!6O=W?
zryWL2v0}rV4-15B%`1|6QW%n_#=B4`@+!8%FuLRX2^*poik=@7oCc43zgezEi&$q6
z><0nEbI|DvvS;ZAES^XGtIHbbRh{Fd3|Y?KxK`&bZLYNa(Hh<#cwHGXs%cPlQE%uH
z^pqndi*_ykti;oihQdaR>Qwd{kJMXeiUK}Fizz>>)2jUF569oVyzT0}m6^ZZ^WgI5
z?%7>gx%H7}8tb*sPiRi=nCE^SbE{z%ytX3qldgk5cegbkq{Z?lnay#_hJMTDuH5S1
z<{eD;XtL-a(^Xo0bIrs<<kZ5{eBwm*BhNtOUCga%Wm-P6^4k=xsj(aNYlQG<0n_XN
zOii`Wq}?BQ&8)O*l9VO7>2~%)=PFZrz%ZA-LLn!-qQ|G`bMd`GsWlXo_^%X7%=MHa
zUWgSC$$UqvDTnghgyePOpm{Jd)lhT6ZGhPet@T3dz0eg4*>J3$;m$@nl$h*Rv45}2
zKkD+&y8LofkUej}ir?ruY>vbTjb-`LE?&Ok8xW9cB<gLt*7LbmLyd2GeH&#bBdI@C
zDCCAd$yAnwJ_5Ea%23F)QjTUi)X6K<kPo*#u6$~~7wFCd*2o{C3-nuD1HTf`I1M^3
zCf?MyR5XnkFcU`y)zoxbqe-fwIt)l`jt=-vRpweVa+MM=%*F_9Kqk#C2J}#h4qA4@
z?^8mP&H>Lf<X~@{o^$*Yp^%whJz%fTsmOX*58r=Q0*i>R05%&lWd5!V59u&$m^vmz
z<6hm^P0HxBhKLd@IY=L|P7y$jFwYXrKttp4f%xTX#?zer_>E&dQiQV+zg1$CN9Q`i
zjXurBR4>Y9b)8>`Kg{5c7F4a5hOxd`*zsqHSjV3w<BuK$sllW8Q#UW(`OL!|h$q83
zRdBgi5JY-Z4WezT)?r#vr_qlA-HNb^Sjtz=>!qV;x=~^=_c-vDv^rMz3(+DItVSkQ
z*$bNHjWM;s5EKt4ns=aU%xoeT;~Ilqpzq4f-C5jn8kg#@Ik3z0*cO0MYgu4DOS&>9
zTxTV4+?X7JkA&pX*ER9r9C_!~XA#uRMTj}cls&!!Liz5DXN3?Zy_k)btUrfiKJsE=
zV|VhD*r^dqQWOih*{Fk=h-3<hFBFWicy9)#uFio?nC2u!lmYL$NO8!ha!dB1#$0`c
zTrpF^S|`08GC`5`TT<p?1vO;RQ-yC(+{%MuIy{9uMe|%*3ZY_KHQl>a&bdeBE>_bZ
zj*CK8siCcMdxk&*O?u&hK5f~FL%|JSK7IHU2VnFLxUgdy7JT5$ba;1hy8QNg?mWci
zQ#-Kmv*`&Xw|sTScKozM;Y9DeuJn`}?S*V8ODD_I0d(B=LXNPWJ+70zI(HvF!p}w{
zyz`x7l;(7>npgF`;*RMZtdjX7-&;KN*j$Hg!r93(9Xn2?lOD9vnP=0ko#eLA;i!qu
zeJ2-AEI!eh?{CTPJnBwIIC*-ZbL`~lH2VTO26bMx?NRM=+(G`C?45ld=jR~aGg+D5
zJ_F6$r#)|%?{(eNXLd}_9oe~Sc4m6-?6J8$hxhE=vukee?2)-+Gc$V*@7%F>dV2TH
z!@K5YJdb(5;T-kG?Jc>8!Gm%<?^fR%)qxf4t!85+yQn|=*ppA5TKIgo`zWU&JauII
z?8(Qwvl;g|lWn1!!)E55)=JI2PjHwXSB78V8(g^Lw%r$>WGlK4zp3VsKmekDxY+>>
z+ZIf>X|^`UE>ySQw5T9IR63!kWQV{A4Q)tQVrY8Bg0hF-((Fm{<j)7}Y4<+qdw+af
z$L${qMmb36<nJF~5A{54N<?-46PzBxCi9~LyL;jTfeH8Zuub~jyS%+ZQa@ORG~xqf
z9-*F_Gr#-HwKDq~%g~z!u2%*+XWh03rMHP$n<za;`t`7oSryulnb<e&W#a>c5gYRp
z*=E?7pYu1w(iq=QE0JU0#s>5Oi??2j%1tckq}Z+_0V42vbrx+Opb=$abojREghZy~
zjsz&BM{i{sq@+xl`oRFkrqb?ohV~jJx%av4liz*T^AG%vvi~LDFTBO~A9~3!6cyt8
zDZX!#_GT_kP<35$pZo5=<Nk;LZsnFQR{!+icb|Fw2c7c2{*7>SA3OQ@To<!>v@2uU
zHw@dPm?s`Pnl}!dyzx~IQ0Sg|>IlcLbZ0sIW^SR&sh>K}Y+>8%f({Pqnt9C*?&@;b
zSU0uH-P~EVSj0T$K_j;P)X^i}{a?C$$L`O0DbZucQ=-L~8^8Xw=bqp9&7b}1#NU4N
zmS6R2`DKMW{pWmWe-4hN9s4+t{ltj_oI2w@&gqe-=jQB)u{6iKp8(B97Ur>i82&%!
zfNu>n<$3WSDbDcG+ir>%+?V)%1?_oB9ZmXqsfeTCJ;+e}5w3T#Smu5fFCJt``Xk)$
zVN`n1AXkh3@oSkf*<XFK`>pQL`Y!2f{&NQpK3KIJL_2A;fNDRZ=VOd?^|{${9U@h`
zS{G~~i<XUOgzY{n#b0YJLOM~Pg(w^lxCzrg8O$_GW!>K{mczgUjLg@_>!uAfSWmZX
zv*^(6tG@O^w@z*unOh2z-&whNzrL21WE+(4gLc(pk+R&vDV>SX-<seS#0)O!(efMN
z5LdL^s=p*j%fQ?egYwPuE+MxhO#JCGHKE0{@0FhIaoxxJn()QEFY+#wj2Bv<^8_?z
zTN1?UeUzYGpvPIZB|45n$=$#mp$vU~m$#_+J>F}ZK>oakew$sJr}?FMdizd(x2ngY
z#%d1tgI1?(alXo)rUqJMx!po)S<%xbkEBU+KBu{hNBtW8@9EeMN41#Bqa4Qbwq#37
z1Ua4&dQZVGP4+yB>^up~4rtk-rRaQ)8Z8IYbV;dlWpb(~NuP%lUw?DUAaD9K?Lp&w
zHcV(!rS|4(DQ&;D?}gjrjak#1@@?dBp1+^5nrR!;PHHy`-=}%2(k#+B$3o}BeE0I*
z#gk&ST=Ez&GnS@h{Ck0)X1VcBU<HK}&*Cq&@9jv8<W)O--R8LWqeE@|;U~v|UpSk4
Of_2;<e*XV);C}#@e7AuB

literal 0
HcmV?d00001

diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta b/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.11.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
rename to packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0/lib.meta b/packages/spacetimedb.bsatn.runtime/0.12.0/lib.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.11.0/lib.meta
rename to packages/spacetimedb.bsatn.runtime/0.12.0/lib.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0/lib/netstandard2.1.meta b/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.11.0/lib/netstandard2.1.meta
rename to packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
new file mode 100644
index 0000000000000000000000000000000000000000..2f56513350acc70730d652af65dce9fa658f1928
GIT binary patch
literal 68096
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

literal 0
HcmV?d00001

diff --git a/packages/spacetimedb.bsatn.runtime/0.11.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta b/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.11.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta
rename to packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta

From cff42fb934bb35526c514a2fa7a5668ed5ced31f Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Fri, 4 Oct 2024 01:25:05 +0100
Subject: [PATCH 23/55] Accept multiple queries in Subscribe (#153)

## Description of Changes

Turns out, we're not ready for single Subscribe per query, so bringing
back this ability.

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
---
 src/Event.cs             | 6 +++---
 src/SpacetimeDBClient.cs | 6 +++---
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/Event.cs b/src/Event.cs
index ff687c0f..b637e698 100644
--- a/src/Event.cs
+++ b/src/Event.cs
@@ -61,7 +61,7 @@ public SubscriptionBuilder<EventContext> OnError(Action<EventContext> callback)
             return this;
         }
 
-        public SubscriptionHandle<EventContext> Subscribe(string querySql) => new(conn, Applied, Error, querySql);
+        public SubscriptionHandle<EventContext> Subscribe(params string[] querySqls) => new(conn, Applied, Error, querySqls);
     }
 
     public interface ISubscriptionHandle
@@ -80,10 +80,10 @@ void ISubscriptionHandle.OnApplied(IEventContext ctx)
             onApplied?.Invoke((EventContext)ctx);
         }
 
-        internal SubscriptionHandle(IDbConnection conn, Action<EventContext>? onApplied, Action<EventContext>? onError, string querySql)
+        internal SubscriptionHandle(IDbConnection conn, Action<EventContext>? onApplied, Action<EventContext>? onError, string[] querySqls)
         {
             this.onApplied = onApplied;
-            conn.Subscribe(this, querySql);
+            conn.Subscribe(this, querySqls);
         }
 
         public void Unsubscribe() => throw new NotImplementedException();
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 11237718..6aa22f9d 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -76,7 +76,7 @@ public DbConnectionBuilder<DbConnection, Reducer> OnDisconnect(Action<DbConnecti
 
     public interface IDbConnection
     {
-        void Subscribe(ISubscriptionHandle handle, string query);
+        void Subscribe(ISubscriptionHandle handle, string[] querySqls);
     }
 
     public abstract class DbConnectionBase<DbConnection, Reducer> : IDbConnection
@@ -803,7 +803,7 @@ public void InternalCallReducer<T>(T args)
             ));
         }
 
-        void IDbConnection.Subscribe(ISubscriptionHandle handle, string query)
+        void IDbConnection.Subscribe(ISubscriptionHandle handle, string[] querySqls)
         {
             if (!webSocket.IsConnected)
             {
@@ -817,7 +817,7 @@ void IDbConnection.Subscribe(ISubscriptionHandle handle, string query)
                 new Subscribe
                 {
                     RequestId = id,
-                    QueryStrings = { query }
+                    QueryStrings = querySqls.ToList()
                 }
             ));
         }

From b79d90c486bc56c55837a4c879585579ea01c374 Mon Sep 17 00:00:00 2001
From: Ingvar Stepanyan <me@rreverser.com>
Date: Fri, 4 Oct 2024 01:35:51 +0100
Subject: [PATCH 24/55] Fix UnityNetworkManager (#141)

This got broken when we switched to a new DbConnection API.

Keep track of all the active connections and update/destroy them from a
singleton game object. Fixes #134.

Marked as a draft for now, because it's untested and because we're not
yet sure that singleton for all connections as requested is the right
approach.

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

---------

Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
Co-authored-by: John Detter <no-reply@boppygames.gg>
---
 .../_Globals/UnityNetworkManager.cs           | 21 ---------
 .../ClientApi/BsatnRowList.cs.meta            | 11 +++++
 .../ClientApi/CompressableQueryUpdate.cs.meta | 11 +++++
 src/SpacetimeDB/ClientApi/QueryUpdate.cs.meta | 11 +++++
 src/SpacetimeDB/ClientApi/RowSizeHint.cs.meta | 11 +++++
 src/SpacetimeDBClient.cs                      | 10 ++++-
 src/SpacetimeDBNetworkManager.cs              | 43 +++++++++++++++++++
 src/SpacetimeDBNetworkManager.cs.meta         | 11 +++++
 8 files changed, 107 insertions(+), 22 deletions(-)
 delete mode 100644 examples~/quickstart/client/module_bindings/_Globals/UnityNetworkManager.cs
 create mode 100644 src/SpacetimeDB/ClientApi/BsatnRowList.cs.meta
 create mode 100644 src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs.meta
 create mode 100644 src/SpacetimeDB/ClientApi/QueryUpdate.cs.meta
 create mode 100644 src/SpacetimeDB/ClientApi/RowSizeHint.cs.meta
 create mode 100644 src/SpacetimeDBNetworkManager.cs
 create mode 100644 src/SpacetimeDBNetworkManager.cs.meta

diff --git a/examples~/quickstart/client/module_bindings/_Globals/UnityNetworkManager.cs b/examples~/quickstart/client/module_bindings/_Globals/UnityNetworkManager.cs
deleted file mode 100644
index 21ab1ef4..00000000
--- a/examples~/quickstart/client/module_bindings/_Globals/UnityNetworkManager.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
-// WILL NOT BE SAVED. MODIFY TABLES IN RUST INSTEAD.
-// <auto-generated />
-
-#nullable enable
-
-using System;
-using SpacetimeDB;
-
-namespace SpacetimeDB.Types
-{
-	// This class is only used in Unity projects.
-	// Attach this to a gameobject in your scene to use SpacetimeDB.
-	#if UNITY_5_3_OR_NEWER
-	public class UnityNetworkManager : UnityEngine.MonoBehaviour
-	{
-		private void OnDestroy() => SpacetimeDBClient.instance.Close();
-		private void Update() => SpacetimeDBClient.instance.Update();
-	}
-	#endif
-}
diff --git a/src/SpacetimeDB/ClientApi/BsatnRowList.cs.meta b/src/SpacetimeDB/ClientApi/BsatnRowList.cs.meta
new file mode 100644
index 00000000..95ec13f6
--- /dev/null
+++ b/src/SpacetimeDB/ClientApi/BsatnRowList.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3736538171ef3574f914e9e880b67a03
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs.meta b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs.meta
new file mode 100644
index 00000000..486b1dd8
--- /dev/null
+++ b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fa7fc0d9632450b47a0d88960f28e66a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/SpacetimeDB/ClientApi/QueryUpdate.cs.meta b/src/SpacetimeDB/ClientApi/QueryUpdate.cs.meta
new file mode 100644
index 00000000..ee9369dd
--- /dev/null
+++ b/src/SpacetimeDB/ClientApi/QueryUpdate.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d989a072d0ab7664ea89ce118d38d8a5
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/SpacetimeDB/ClientApi/RowSizeHint.cs.meta b/src/SpacetimeDB/ClientApi/RowSizeHint.cs.meta
new file mode 100644
index 00000000..7b775411
--- /dev/null
+++ b/src/SpacetimeDB/ClientApi/RowSizeHint.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a21b01e7a4f857a469aa9181dececc57
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 6aa22f9d..0df4c7b3 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -34,6 +34,9 @@ public DbConnection Build()
                 throw new InvalidOperationException("Building DbConnection with a null nameOrAddress. Call WithModuleName() first.");
             }
             conn.Connect(token, uri, nameOrAddress);
+#if UNITY_5_3_OR_NEWER
+            UnityNetworkManager.ActiveConnections.Add(conn);
+#endif
             return conn;
         }
 
@@ -76,7 +79,9 @@ public DbConnectionBuilder<DbConnection, Reducer> OnDisconnect(Action<DbConnecti
 
     public interface IDbConnection
     {
-        void Subscribe(ISubscriptionHandle handle, string[] querySqls);
+        internal void Subscribe(ISubscriptionHandle handle, string[] querySqls);
+        void FrameTick();
+        void Disconnect();
     }
 
     public abstract class DbConnectionBase<DbConnection, Reducer> : IDbConnection
@@ -146,6 +151,9 @@ protected DbConnectionBase()
             webSocket = new WebSocket(options);
             webSocket.OnMessage += OnMessageReceived;
             webSocket.OnSendError += a => onSendError?.Invoke(a);
+#if UNITY_5_3_OR_NEWER
+            webSocket.OnClose += (a, b) => UnityNetworkManager.ActiveConnections.Remove(this);
+#endif
 
             networkMessageProcessThread = new Thread(PreProcessMessages);
             networkMessageProcessThread.Start();
diff --git a/src/SpacetimeDBNetworkManager.cs b/src/SpacetimeDBNetworkManager.cs
new file mode 100644
index 00000000..129d87c3
--- /dev/null
+++ b/src/SpacetimeDBNetworkManager.cs
@@ -0,0 +1,43 @@
+#if UNITY_5_3_OR_NEWER
+using System;
+using System.Collections.Generic;
+using SpacetimeDB;
+using UnityEngine;
+
+namespace SpacetimeDB
+{
+	// This class is only used in Unity projects.
+	// Attach this to a gameobject in your scene to use SpacetimeDB.
+	public class SpacetimeDBNetworkManager : MonoBehaviour
+	{
+		private static bool _alreadyInitialized;
+
+		public void Awake()
+		{
+			// Ensure that users don't create several UnityNetworkManager instances.
+			// We're using a global (static) list of active connections and we don't want several instances to walk over it several times.
+			if (_alreadyInitialized)
+			{
+				throw new InvalidOperationException("UnityNetworkManager is a singleton and should only be attached once.");
+			}
+			else
+			{
+				_alreadyInitialized = true;
+			}
+		}
+
+		internal static HashSet<IDbConnection> ActiveConnections = new();
+
+		private void ForEachConnection(Action<IDbConnection> action)
+		{
+			foreach (var conn in ActiveConnections)
+			{
+				action(conn);
+			}
+		}
+
+		private void Update() => ForEachConnection(conn => conn.FrameTick());
+		private void OnDestroy() => ForEachConnection(conn => conn.Disconnect());
+	}
+}
+#endif
diff --git a/src/SpacetimeDBNetworkManager.cs.meta b/src/SpacetimeDBNetworkManager.cs.meta
new file mode 100644
index 00000000..e8f74142
--- /dev/null
+++ b/src/SpacetimeDBNetworkManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e016ef92e52934343857fd26e55140c1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

From 8916c18fe1084fe249a2b69b781bb8f73f9511b5 Mon Sep 17 00:00:00 2001
From: John Detter <4099508+jdetter@users.noreply.github.com>
Date: Thu, 3 Oct 2024 19:39:13 -0500
Subject: [PATCH 25/55] Upgrade SDK Version to 0.12 (#156)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

- Upgrade version to 0.12.

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

Co-authored-by: John Detter <no-reply@boppygames.gg>
---
 SpacetimeDB.ClientSDK.csproj | 2 +-
 package.json                 | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/SpacetimeDB.ClientSDK.csproj b/SpacetimeDB.ClientSDK.csproj
index 006a68bf..eb7773db 100644
--- a/SpacetimeDB.ClientSDK.csproj
+++ b/SpacetimeDB.ClientSDK.csproj
@@ -15,7 +15,7 @@
     <PackageProjectUrl>https://spacetimedb.com</PackageProjectUrl>
     <PackageIcon>logo.png</PackageIcon>
     <PackageReadmeFile>README.md</PackageReadmeFile>
-    <RepositoryUrl>https://github.com/clockworklabs/spacetimedb-csharp-sdk</RepositoryUrl>
+    <RepositoryUrl>https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk</RepositoryUrl>
     <AssemblyVersion>0.12.0</AssemblyVersion>
     <Version>$(AssemblyVersion)</Version>
     <DefaultItemExcludes>$(DefaultItemExcludes);*~/**</DefaultItemExcludes>
diff --git a/package.json b/package.json
index 86f04059..2bf0c6f8 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "com.clockworklabs.spacetimedbsdk",
   "displayName": "SpacetimeDB SDK",
-  "version": "0.11.0",
+  "version": "0.12.0",
   "description": "The SpacetimeDB Client SDK is a software development kit (SDK) designed to interact with and manipulate SpacetimeDB modules..",
   "keywords": [],
   "author": {

From a7c720f3a4a1d777ba571155ddbe37a4cef125eb Mon Sep 17 00:00:00 2001
From: John Detter <4099508+jdetter@users.noreply.github.com>
Date: Thu, 3 Oct 2024 20:15:37 -0500
Subject: [PATCH 26/55] Use SpacetimeDBNetworkManager everywhere (#157)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

Co-authored-by: John Detter <no-reply@boppygames.gg>
---
 README.md                        | 4 ++--
 src/SpacetimeDBClient.cs         | 4 ++--
 src/SpacetimeDBNetworkManager.cs | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/README.md b/README.md
index 18cb6f04..75c5fba0 100644
--- a/README.md
+++ b/README.md
@@ -26,9 +26,9 @@ Download the [.unitypackage release](https://github.com/clockworklabs/SpacetimeD
 
 ## Usage
 
-### UnityNetworkManager
+### SpacetimeDBNetworkManager
 
-The Unity SDK for SpacetimeDB requires that there is a `UnityNetworkManager` component attached to a GameObject in the scene. The `UnityNetworkManager` component is responsible for connecting to SpacetimeDB and managing the connection. The `UnityNetworkManager` component is a singleton and there can only be one instance of it in the scene.
+The Unity SDK for SpacetimeDB requires that there is a `SpacetimeDBNetworkManager` component attached to a GameObject in the scene. The `UnityNetworkManager` component is responsible for connecting to SpacetimeDB and managing the connection. The `UnityNetworkManager` component is a singleton and there can only be one instance of it in the scene.
 
 ### Connecting to SpacetimeDB
 
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 0df4c7b3..5ba858f9 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -35,7 +35,7 @@ public DbConnection Build()
             }
             conn.Connect(token, uri, nameOrAddress);
 #if UNITY_5_3_OR_NEWER
-            UnityNetworkManager.ActiveConnections.Add(conn);
+            SpacetimeDBNetworkManager.ActiveConnections.Add(conn);
 #endif
             return conn;
         }
@@ -152,7 +152,7 @@ protected DbConnectionBase()
             webSocket.OnMessage += OnMessageReceived;
             webSocket.OnSendError += a => onSendError?.Invoke(a);
 #if UNITY_5_3_OR_NEWER
-            webSocket.OnClose += (a, b) => UnityNetworkManager.ActiveConnections.Remove(this);
+            webSocket.OnClose += (a, b) => SpacetimeDBNetworkManager.ActiveConnections.Remove(this);
 #endif
 
             networkMessageProcessThread = new Thread(PreProcessMessages);
diff --git a/src/SpacetimeDBNetworkManager.cs b/src/SpacetimeDBNetworkManager.cs
index 129d87c3..ae5e2d4f 100644
--- a/src/SpacetimeDBNetworkManager.cs
+++ b/src/SpacetimeDBNetworkManager.cs
@@ -14,11 +14,11 @@ public class SpacetimeDBNetworkManager : MonoBehaviour
 
 		public void Awake()
 		{
-			// Ensure that users don't create several UnityNetworkManager instances.
+			// Ensure that users don't create several SpacetimeDBNetworkManager instances.
 			// We're using a global (static) list of active connections and we don't want several instances to walk over it several times.
 			if (_alreadyInitialized)
 			{
-				throw new InvalidOperationException("UnityNetworkManager is a singleton and should only be attached once.");
+				throw new InvalidOperationException("SpacetimeDBNetworkManager is a singleton and should only be attached once.");
 			}
 			else
 			{

From 704640813a0e916d1d1692bc31a6c548a772a38f Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Fri, 4 Oct 2024 00:12:43 -0400
Subject: [PATCH 27/55] Update to tests/examples follow codegen changes (#160)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*
---
 examples~/quickstart/client/Program.cs        |  20 +--
 .../client/module_bindings/Message.cs         |   2 +-
 .../module_bindings/SendMessageReducer.cs     |   2 +-
 .../client/module_bindings/SetNameReducer.cs  |   2 +-
 .../quickstart/client/module_bindings/User.cs |   2 +-
 .../_Globals/SpacetimeDBClient.cs             | 166 +++++++++---------
 examples~/quickstart/server/src/lib.rs        |  34 ++--
 src/SpacetimeDB/ClientApi/DatabaseUpdate.cs   |   1 -
 src/SpacetimeDB/ClientApi/EnergyQuanta.cs     |   1 -
 src/SpacetimeDB/ClientApi/IdentityToken.cs    |   1 -
 .../ClientApi/InitialSubscription.cs          |   1 -
 src/SpacetimeDB/ClientApi/OneOffTable.cs      |   1 -
 src/SpacetimeDB/ClientApi/Subscribe.cs        |   1 -
 src/SpacetimeDB/ClientApi/TableUpdate.cs      |   1 -
 src/SpacetimeDB/ClientApi/Timestamp.cs        |   1 -
 .../ClientApi/TransactionUpdate.cs            |   1 -
 ...otTests.VerifyAllTablesParsed.verified.txt |  32 ++--
 tests~/SnapshotTests.cs                       |  36 ++--
 18 files changed, 150 insertions(+), 155 deletions(-)

diff --git a/examples~/quickstart/client/Program.cs b/examples~/quickstart/client/Program.cs
index 29ad6c95..8327d976 100644
--- a/examples~/quickstart/client/Program.cs
+++ b/examples~/quickstart/client/Program.cs
@@ -31,13 +31,13 @@ void Main()
         .OnDisconnect(OnDisconnect)
         .Build();
 
-    conn.RemoteTables.User.OnInsert += User_OnInsert;
-    conn.RemoteTables.User.OnUpdate += User_OnUpdate;
+    conn.Db.User.OnInsert += User_OnInsert;
+    conn.Db.User.OnUpdate += User_OnUpdate;
 
-    conn.RemoteTables.Message.OnInsert += Message_OnInsert;
+    conn.Db.Message.OnInsert += Message_OnInsert;
 
-    conn.RemoteReducers.OnSetName += Reducer_OnSetNameEvent;
-    conn.RemoteReducers.OnSendMessage += Reducer_OnSendMessageEvent;
+    conn.Reducers.OnSetName += Reducer_OnSetNameEvent;
+    conn.Reducers.OnSendMessage += Reducer_OnSendMessageEvent;
 
 #pragma warning disable CS0612 // Using obsolete API
     conn.onUnhandledReducerError += onUnhandledReducerError;
@@ -88,7 +88,7 @@ void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
 
 void PrintMessage(RemoteTables tables, Message message)
 {
-    var sender = tables.User.FindByIdentity(message.Sender);
+    var sender = tables.User.Identity.Find(message.Sender);
     var senderName = "unknown";
     if (sender != null)
     {
@@ -100,7 +100,7 @@ void PrintMessage(RemoteTables tables, Message message)
 
 void Message_OnInsert(EventContext ctx, Message insertedValue)
 {
-    if (ctx.Reducer is not Event<Reducer>.SubscribeApplied)
+    if (ctx.Event is not Event<Reducer>.SubscribeApplied)
     {
         PrintMessage(ctx.Db, insertedValue);
     }
@@ -108,7 +108,7 @@ void Message_OnInsert(EventContext ctx, Message insertedValue)
 
 void Reducer_OnSetNameEvent(EventContext ctx, string name)
 {
-    if (ctx.Reducer is Event<Reducer>.Reducer reducer)
+    if (ctx.Event is Event<Reducer>.Reducer reducer)
     {
         var e = reducer.ReducerEvent;
         if (e.CallerIdentity == local_identity && e.Status is Status.Failed(var error))
@@ -120,7 +120,7 @@ void Reducer_OnSetNameEvent(EventContext ctx, string name)
 
 void Reducer_OnSendMessageEvent(EventContext ctx, string text)
 {
-    if (ctx.Reducer is Event<Reducer>.Reducer reducer)
+    if (ctx.Event is Event<Reducer>.Reducer reducer)
     {
         var e = reducer.ReducerEvent;
         if (e.CallerIdentity == local_identity && e.Status is Status.Failed(var error))
@@ -182,7 +182,7 @@ void ProcessThread(DbConnection conn, CancellationToken ct)
         {
             conn.FrameTick();
 
-            ProcessCommands(conn.RemoteReducers);
+            ProcessCommands(conn.Reducers);
 
             Thread.Sleep(100);
         }
diff --git a/examples~/quickstart/client/module_bindings/Message.cs b/examples~/quickstart/client/module_bindings/Message.cs
index c0e52cf0..c63d4bfa 100644
--- a/examples~/quickstart/client/module_bindings/Message.cs
+++ b/examples~/quickstart/client/module_bindings/Message.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.Types
@@ -39,5 +38,6 @@ public Message()
 			this.Sender = new();
 			this.Text = "";
 		}
+
 	}
 }
diff --git a/examples~/quickstart/client/module_bindings/SendMessageReducer.cs b/examples~/quickstart/client/module_bindings/SendMessageReducer.cs
index 45dd29f3..15106671 100644
--- a/examples~/quickstart/client/module_bindings/SendMessageReducer.cs
+++ b/examples~/quickstart/client/module_bindings/SendMessageReducer.cs
@@ -10,7 +10,7 @@
 namespace SpacetimeDB.Types
 {
 	[SpacetimeDB.Type]
-	public partial class SendMessageArgsStruct : IReducerArgs
+	public partial class SendMessage : IReducerArgs
 	{
 		string IReducerArgs.ReducerName => "send_message";
 
diff --git a/examples~/quickstart/client/module_bindings/SetNameReducer.cs b/examples~/quickstart/client/module_bindings/SetNameReducer.cs
index 0f96ad9e..83a0b728 100644
--- a/examples~/quickstart/client/module_bindings/SetNameReducer.cs
+++ b/examples~/quickstart/client/module_bindings/SetNameReducer.cs
@@ -10,7 +10,7 @@
 namespace SpacetimeDB.Types
 {
 	[SpacetimeDB.Type]
-	public partial class SetNameArgsStruct : IReducerArgs
+	public partial class SetName : IReducerArgs
 	{
 		string IReducerArgs.ReducerName => "set_name";
 
diff --git a/examples~/quickstart/client/module_bindings/User.cs b/examples~/quickstart/client/module_bindings/User.cs
index a6d6d1b9..2d4c79b0 100644
--- a/examples~/quickstart/client/module_bindings/User.cs
+++ b/examples~/quickstart/client/module_bindings/User.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.Types
@@ -38,5 +37,6 @@ public User()
 		{
 			this.Identity = new();
 		}
+
 	}
 }
diff --git a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
index cf4f4e95..c0fb266b 100644
--- a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
+++ b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
@@ -5,75 +5,74 @@
 #nullable enable
 
 using System;
-using System.Collections.Generic;
-
+using SpacetimeDB;
 using SpacetimeDB.ClientApi;
+using System.Collections.Generic;
 
 namespace SpacetimeDB.Types
 {
 	public sealed class RemoteTables
 	{
-		public class MessageHandle : RemoteTableHandle<EventContext, Message> {
-            public IEnumerable<Message> FilterBySender(SpacetimeDB.Identity value) {
-                return Query(x => x.Sender == value);
-            }
-
-            public IEnumerable<Message> FilterBySent(ulong value) {
-                return Query(x => x.Sent == value);
-            }
-
-            public IEnumerable<Message> FilterByText(string value) {
-                return Query(x => x.Text == value);
-            }
-        }
-
-        public class UserHandle : RemoteTableHandle<EventContext, User> {
-			public override object? GetPrimaryKey(IDatabaseRow row) => ((User)row).Identity;
-
-            private Dictionary<SpacetimeDB.Identity, User> Identity_Index = new(16);
-
-            public override void InternalInvokeValueInserted(IDatabaseRow row) {
-                var value = (User)row;
-                Identity_Index[value.Identity] = value;
-            }
-
-            public override void InternalInvokeValueDeleted(IDatabaseRow row) {
-                Identity_Index.Remove(((User)row).Identity);
-            }
-
-            public User? FindByIdentity(SpacetimeDB.Identity value) {
-                Identity_Index.TryGetValue(value, out var r);
-                return r;
-            }
-
-            public IEnumerable<User> FilterByIdentity(SpacetimeDB.Identity value) {
-                if (FindByIdentity(value) is { } found) {
-                    yield return found;
-                }
-            }
-
-            public IEnumerable<User> FilterByOnline(bool value) {
-                return Query(x => x.Online == value);
-            }
-        }
-
-        public readonly MessageHandle Message = new();
+		public class MessageHandle : RemoteTableHandle<EventContext, Message>
+		{
+			internal MessageHandle()
+			{
+			}
+
+		}
+
+		public readonly MessageHandle Message = new();
+
+		public class UserHandle : RemoteTableHandle<EventContext, User>
+		{
+			private static Dictionary<SpacetimeDB.Identity, User> Identity_Index = new(16);
+
+			public override void InternalInvokeValueInserted(IDatabaseRow row)
+			{
+				var value = (User)row;
+				Identity_Index[value.Identity] = value;
+			}
+
+			public override void InternalInvokeValueDeleted(IDatabaseRow row)
+			{
+				Identity_Index.Remove(((User)row).Identity);
+			}
+
+			public readonly ref struct IdentityUniqueIndex
+			{
+				public User? Find(SpacetimeDB.Identity value)
+				{
+					Identity_Index.TryGetValue(value, out var r);
+					return r;
+				}
+
+			}
+
+			public IdentityUniqueIndex Identity => new();
+
+			internal UserHandle()
+			{
+			}
+			public override object GetPrimaryKey(IDatabaseRow row) => ((User)row).Identity;
+
+		}
+
 		public readonly UserHandle User = new();
+
 	}
 
 	public sealed class RemoteReducers : RemoteBase<DbConnection>
 	{
 		internal RemoteReducers(DbConnection conn) : base(conn) {}
-
 		public delegate void SendMessageHandler(EventContext ctx, string text);
 		public event SendMessageHandler? OnSendMessage;
 
 		public void SendMessage(string text)
 		{
-			conn.InternalCallReducer(new SendMessageArgsStruct { Text = text });
+			conn.InternalCallReducer(new SendMessage { Text = text });
 		}
 
-		public bool InvokeSendMessage(EventContext ctx, SendMessageArgsStruct args)
+		public bool InvokeSendMessage(EventContext ctx, SendMessage args)
 		{
 			if (OnSendMessage == null) return false;
 			OnSendMessage(
@@ -87,10 +86,10 @@ public bool InvokeSendMessage(EventContext ctx, SendMessageArgsStruct args)
 
 		public void SetName(string name)
 		{
-			conn.InternalCallReducer(new SetNameArgsStruct { Name = name });
+			conn.InternalCallReducer(new SetName { Name = name });
 		}
 
-		public bool InvokeSetName(EventContext ctx, SetNameArgsStruct args)
+		public bool InvokeSetName(EventContext ctx, SetName args)
 		{
 			if (OnSetName == null) return false;
 			OnSetName(
@@ -101,64 +100,69 @@ public bool InvokeSetName(EventContext ctx, SetNameArgsStruct args)
 		}
 	}
 
-	public partial record EventContext : DbContext<RemoteTables>, IEventContext {
+	public partial record EventContext : DbContext<RemoteTables>, IEventContext
+	{
 		public readonly RemoteReducers Reducers;
-		public readonly Event<Reducer> Reducer;
+		public readonly Event<Reducer> Event;
 
-		internal EventContext(DbConnection conn, Event<Reducer> reducer) : base(conn.RemoteTables) {
-			Reducers = conn.RemoteReducers;
-			Reducer = reducer;
+		internal EventContext(DbConnection conn, Event<Reducer> reducerEvent) : base(conn.Db)
+		{
+			Reducers = conn.Reducers;
+			Event = reducerEvent;
 		}
 	}
 
 	[Type]
 	public partial record Reducer : TaggedEnum<(
-		SendMessageArgsStruct SendMessage,
-		SetNameArgsStruct SetName,
-		Unit IdentityConnected,
-		Unit IdentityDisconnected
-    )>;
-
+		SendMessage SendMessage,
+		SetName SetName,
+		Unit StdbNone,
+		Unit StdbIdentityConnected,
+		Unit StdbIdentityDisconnected
+	)>;
 	public class DbConnection : DbConnectionBase<DbConnection, Reducer>
 	{
-		public readonly RemoteTables RemoteTables = new();
-		public readonly RemoteReducers RemoteReducers;
+		public readonly RemoteTables Db = new();
+		public readonly RemoteReducers Reducers;
 
 		public DbConnection()
 		{
-			RemoteReducers = new(this);
+			Reducers = new(this);
 
-			clientDB.AddTable<Message>("Message", RemoteTables.Message);
-			clientDB.AddTable<User>("User", RemoteTables.User);
+			clientDB.AddTable<Message>("message", Db.Message);
+			clientDB.AddTable<User>("user", Db.User);
 		}
 
 		protected override Reducer ToReducer(TransactionUpdate update)
 		{
 			var encodedArgs = update.ReducerCall.Args;
 			return update.ReducerCall.ReducerName switch {
-				"send_message" => new Reducer.SendMessage(BSATNHelpers.Decode<SendMessageArgsStruct>(encodedArgs)),
-				"set_name" => new Reducer.SetName(BSATNHelpers.Decode<SetNameArgsStruct>(encodedArgs)),
-				"__identity_connected__" => new Reducer.IdentityConnected(default),
-				"__identity_disconnected__" => new Reducer.IdentityDisconnected(default),
+				"send_message" => new Reducer.SendMessage(BSATNHelpers.Decode<SendMessage>(encodedArgs)),
+				"set_name" => new Reducer.SetName(BSATNHelpers.Decode<SetName>(encodedArgs)),
+				"<none>" => new Reducer.StdbNone(default),
+				"__identity_connected__" => new Reducer.StdbIdentityConnected(default),
+				"__identity_disconnected__" => new Reducer.StdbIdentityDisconnected(default),
+				"" => new Reducer.StdbNone(default),
 				var reducer => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}")
 			};
 		}
 
-		protected override IEventContext ToEventContext(Event<Reducer> reducerEvent) {
-			return new EventContext(this, reducerEvent);
-		}
+		protected override IEventContext ToEventContext(Event<Reducer> reducerEvent) =>
+		new EventContext(this, reducerEvent);
 
-		protected override bool Dispatch(IEventContext context, Reducer reducer) {
+		protected override bool Dispatch(IEventContext context, Reducer reducer)
+		{
 			var eventContext = (EventContext)context;
 			return reducer switch {
-				Reducer.SendMessage(var args) => RemoteReducers.InvokeSendMessage(eventContext, args),
-				Reducer.SetName(var args) => RemoteReducers.InvokeSetName(eventContext, args),
-				Reducer.IdentityConnected => true,
-				Reducer.IdentityDisconnected => true,
+				Reducer.SendMessage(var args) => Reducers.InvokeSendMessage(eventContext, args),
+				Reducer.SetName(var args) => Reducers.InvokeSetName(eventContext, args),
+				Reducer.StdbNone or
+				Reducer.StdbIdentityConnected or
+				Reducer.StdbIdentityDisconnected => true,
 				_ => throw new ArgumentOutOfRangeException("Reducer", $"Unknown reducer {reducer}")
 			};
 		}
 
-        public SubscriptionBuilder<EventContext> SubscriptionBuilder() => new(this);
+		public SubscriptionBuilder<EventContext> SubscriptionBuilder() => new(this);
 	}
 }
diff --git a/examples~/quickstart/server/src/lib.rs b/examples~/quickstart/server/src/lib.rs
index 0c6572e1..015aaefe 100644
--- a/examples~/quickstart/server/src/lib.rs
+++ b/examples~/quickstart/server/src/lib.rs
@@ -1,7 +1,7 @@
-use spacetimedb::{ReducerContext, Identity, Timestamp};
+use spacetimedb::{ReducerContext, Identity, Table, Timestamp};
 use anyhow::{Result, anyhow};
 
-#[spacetimedb::table(name = User, public)]
+#[spacetimedb::table(name = user, public)]
 pub struct User {
     #[primary_key]
     identity: Identity,
@@ -9,7 +9,7 @@ pub struct User {
     online: bool,
 }
 
-#[spacetimedb::table(name = Message, public)]
+#[spacetimedb::table(name = message, public)]
 pub struct Message {
     sender: Identity,
     sent: Timestamp,
@@ -17,20 +17,20 @@ pub struct Message {
 }
 
 #[spacetimedb::reducer(init)]
-pub fn init() {
-    // Called when the module is initially published
+pub fn init(_ctx: &ReducerContext) {
+	
 }
 
 #[spacetimedb::reducer(client_connected)]
-pub fn identity_connected(ctx: ReducerContext) {
-    if let Some(user) = User::filter_by_identity(&ctx.sender) {
+pub fn identity_connected(ctx: &ReducerContext) {
+    if let Some(user) = ctx.db.user().identity().find(&ctx.sender) {
         // If this is a returning user, i.e. we already have a `User` with this `Identity`,
         // set `online: true`, but leave `name` and `identity` unchanged.
-        User::update_by_identity(&ctx.sender, User { online: true, ..user });
+        ctx.db.user().identity().update(User { online: true, ..user });
     } else {
         // If this is a new user, create a `User` row for the `Identity`,
         // which is online, but hasn't set a name.
-        User::insert(User {
+        ctx.db.user().try_insert(User {
             name: None,
             identity: ctx.sender,
             online: true,
@@ -39,9 +39,9 @@ pub fn identity_connected(ctx: ReducerContext) {
 }
 
 #[spacetimedb::reducer(client_disconnected)]
-pub fn identity_disconnected(ctx: ReducerContext) {
-    if let Some(user) = User::filter_by_identity(&ctx.sender) {
-        User::update_by_identity(&ctx.sender, User { online: false, ..user });
+pub fn identity_disconnected(ctx: &ReducerContext) {
+    if let Some(user) = ctx.db.user().identity().find(&ctx.sender) {
+        ctx.db.user().identity().update(User { online: false, ..user });
     } else {
         // This branch should be unreachable,
         // as it doesn't make sense for a client to disconnect without connecting first.
@@ -58,10 +58,10 @@ fn validate_name(name: String) -> Result<String> {
 }
 
 #[spacetimedb::reducer]
-pub fn set_name(ctx: ReducerContext, name: String) -> Result<()> {
+pub fn set_name(ctx: &ReducerContext, name: String) -> Result<()> {
     let name = validate_name(name)?;
-    if let Some(user) = User::filter_by_identity(&ctx.sender) {
-        User::update_by_identity(&ctx.sender, User { name: Some(name), ..user });
+    if let Some(user) = ctx.db.user().identity().find(&ctx.sender) {
+        ctx.db.user().identity().update(User { name: Some(name), ..user });
         Ok(())
     } else {
         Err(anyhow!("Cannot set name for unknown user"))
@@ -77,12 +77,12 @@ fn validate_message(text: String) -> Result<String> {
 }
 
 #[spacetimedb::reducer]
-pub fn send_message(ctx: ReducerContext, text: String) -> Result<()> {
+pub fn send_message(ctx: &ReducerContext, text: String) -> Result<()> {
     // Things to consider:
     // - Rate-limit messages per-user.
     // - Reject messages from unnamed users.
     let text = validate_message(text)?;
-    Message::insert(Message {
+    ctx.db.message().insert(Message {
         sender: ctx.sender,
         text,
         sent: ctx.timestamp,
diff --git a/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs b/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs
index 3294c6b7..98460753 100644
--- a/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/DatabaseUpdate.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/EnergyQuanta.cs b/src/SpacetimeDB/ClientApi/EnergyQuanta.cs
index 476712e9..e571a9e1 100644
--- a/src/SpacetimeDB/ClientApi/EnergyQuanta.cs
+++ b/src/SpacetimeDB/ClientApi/EnergyQuanta.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/IdentityToken.cs b/src/SpacetimeDB/ClientApi/IdentityToken.cs
index 4a53ad2f..751fcd75 100644
--- a/src/SpacetimeDB/ClientApi/IdentityToken.cs
+++ b/src/SpacetimeDB/ClientApi/IdentityToken.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/InitialSubscription.cs b/src/SpacetimeDB/ClientApi/InitialSubscription.cs
index cdbc73de..c6144101 100644
--- a/src/SpacetimeDB/ClientApi/InitialSubscription.cs
+++ b/src/SpacetimeDB/ClientApi/InitialSubscription.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/OneOffTable.cs b/src/SpacetimeDB/ClientApi/OneOffTable.cs
index d1f48f3f..fe667b18 100644
--- a/src/SpacetimeDB/ClientApi/OneOffTable.cs
+++ b/src/SpacetimeDB/ClientApi/OneOffTable.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/Subscribe.cs b/src/SpacetimeDB/ClientApi/Subscribe.cs
index 0adad9b2..c58f1a46 100644
--- a/src/SpacetimeDB/ClientApi/Subscribe.cs
+++ b/src/SpacetimeDB/ClientApi/Subscribe.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/TableUpdate.cs b/src/SpacetimeDB/ClientApi/TableUpdate.cs
index cc2586d3..d3265065 100644
--- a/src/SpacetimeDB/ClientApi/TableUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/TableUpdate.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/Timestamp.cs b/src/SpacetimeDB/ClientApi/Timestamp.cs
index c0f53ba1..92bd242d 100644
--- a/src/SpacetimeDB/ClientApi/Timestamp.cs
+++ b/src/SpacetimeDB/ClientApi/Timestamp.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/TransactionUpdate.cs b/src/SpacetimeDB/ClientApi/TransactionUpdate.cs
index e4925bf4..d2c349ce 100644
--- a/src/SpacetimeDB/ClientApi/TransactionUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/TransactionUpdate.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
index 53528975..ea57bb0e 100644
--- a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
+++ b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
@@ -8,7 +8,7 @@
     OnInsertUser: {
       eventContext: {
         Reducers: {Scrubbed},
-        Reducer: {},
+        Event: {},
         Db: {Scrubbed}
       },
       user: {
@@ -20,7 +20,7 @@
     OnInsertUser: {
       eventContext: {
         Reducers: {Scrubbed},
-        Reducer: {
+        Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_1,
             Status: {},
@@ -40,7 +40,7 @@
     OnUpdateUser: {
       eventContext: {
         Reducers: {Scrubbed},
-        Reducer: {
+        Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_2,
             Status: {},
@@ -68,7 +68,7 @@
     },
     OnSetName: {
       Reducers: {Scrubbed},
-      Reducer: {
+      Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_2,
           Status: {},
@@ -87,7 +87,7 @@
     OnInsertMessage: {
       eventContext: {
         Reducers: {Scrubbed},
-        Reducer: {
+        Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_3,
             Status: {},
@@ -111,7 +111,7 @@
     },
     OnSendMessage: {
       Reducers: {Scrubbed},
-      Reducer: {
+      Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_3,
           Status: {},
@@ -130,7 +130,7 @@
     OnUpdateUser: {
       eventContext: {
         Reducers: {Scrubbed},
-        Reducer: {
+        Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_4,
             Status: {},
@@ -158,7 +158,7 @@
     },
     OnSetName: {
       Reducers: {Scrubbed},
-      Reducer: {
+      Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_4,
           Status: {},
@@ -177,7 +177,7 @@
     OnInsertMessage: {
       eventContext: {
         Reducers: {Scrubbed},
-        Reducer: {
+        Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_5,
             Status: {},
@@ -201,7 +201,7 @@
     },
     OnSendMessage: {
       Reducers: {Scrubbed},
-      Reducer: {
+      Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_5,
           Status: {},
@@ -220,7 +220,7 @@
     OnInsertMessage: {
       eventContext: {
         Reducers: {Scrubbed},
-        Reducer: {
+        Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_6,
             Status: {},
@@ -244,7 +244,7 @@
     },
     OnSendMessage: {
       Reducers: {Scrubbed},
-      Reducer: {
+      Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_6,
           Status: {},
@@ -263,7 +263,7 @@
     OnUpdateUser: {
       eventContext: {
         Reducers: {Scrubbed},
-        Reducer: {
+        Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_7,
             Status: {},
@@ -289,7 +289,7 @@
     OnInsertMessage: {
       eventContext: {
         Reducers: {Scrubbed},
-        Reducer: {
+        Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_8,
             Status: {},
@@ -313,7 +313,7 @@
     },
     OnSendMessage: {
       Reducers: {Scrubbed},
-      Reducer: {
+      Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_8,
           Status: {},
@@ -390,4 +390,4 @@
       Max: type=InitialSubscription
     }
   }
-}
+}
\ No newline at end of file
diff --git a/tests~/SnapshotTests.cs b/tests~/SnapshotTests.cs
index 8e99242e..d293c126 100644
--- a/tests~/SnapshotTests.cs
+++ b/tests~/SnapshotTests.cs
@@ -190,7 +190,7 @@ private static byte[] Encode<T>(in T value) where T : IStructuralReadWrite
     }
 
     private static TableUpdate SampleUserInsert(string identity, string? name, bool online) =>
-        SampleUpdate(4097, "User", [new User
+        SampleUpdate(4097, "user", [new User
         {
             Identity = Identity.From(Convert.FromBase64String(identity)),
             Name = name,
@@ -198,7 +198,7 @@ private static TableUpdate SampleUserInsert(string identity, string? name, bool
         }], []);
 
     private static TableUpdate SampleUserUpdate(string identity, string? oldName, string? newName, bool oldOnline, bool newOnline) =>
-        SampleUpdate(4097, "User", [new User
+        SampleUpdate(4097, "user", [new User
         {
             Identity = Identity.From(Convert.FromBase64String(identity)),
             Name = newName,
@@ -211,7 +211,7 @@ private static TableUpdate SampleUserUpdate(string identity, string? oldName, st
         }]);
 
     private static TableUpdate SampleMessage(string identity, ulong sent, string text) =>
-        SampleUpdate(4098, "Message", [new Message
+        SampleUpdate(4098, "message", [new Message
         {
             Sender = Identity.From(Convert.FromBase64String(identity)),
             Sent = sent,
@@ -238,27 +238,27 @@ private static ServerMessage[] SampleDump() => [
         SampleTransactionUpdate(
             1718487768057579, "j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", "Vd4dFzcEzhLHJ6uNL8VXFg==",
             1, "set_name", 4345615, 70, [SampleUserUpdate("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", null, "A", true, true)],
-            Encode(new SetNameArgsStruct { Name = "A" })
+            Encode(new SetName { Name = "A" })
         ),
         SampleTransactionUpdate(
             1718487775346381, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==",
             1, "send_message", 2779615, 57, [SampleMessage("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", 1718487775346381, "Hello, A!")],
-            Encode(new SendMessageArgsStruct { Text = "Hello, A!" })
+            Encode(new SendMessage { Text = "Hello, A!" })
         ),
         SampleTransactionUpdate(
             1718487777307855, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==",
             2, "set_name", 4268615, 98, [SampleUserUpdate("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", null, "B", true, true)],
-            Encode(new SetNameArgsStruct { Name = "B" })
+            Encode(new SetName { Name = "B" })
         ),
         SampleTransactionUpdate(
             1718487783175083, "j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", "Vd4dFzcEzhLHJ6uNL8VXFg==",
             2, "send_message", 2677615, 40, [SampleMessage("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", 1718487783175083, "Hello, B!")],
-            Encode(new SendMessageArgsStruct { Text = "Hello, B!" })
+            Encode(new SendMessage { Text = "Hello, B!" })
         ),
         SampleTransactionUpdate(
             1718487787645364, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==",
             3, "send_message", 2636615, 28, [SampleMessage("l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", 1718487787645364, "Goodbye!")],
-            Encode(new SendMessageArgsStruct { Text = "Goodbye!" })
+            Encode(new SendMessage { Text = "Goodbye!" })
         ),
         SampleTransactionUpdate(
             1718487791901504, "l0qzG1GPRtC1mwr+54q98tv0325gozLc6cNzq4vrzqY=", "Kwmeu5riP20rvCTNbBipLA==",
@@ -268,7 +268,7 @@ private static ServerMessage[] SampleDump() => [
         SampleTransactionUpdate(
             1718487794937841, "j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", "Vd4dFzcEzhLHJ6uNL8VXFg==",
             3, "send_message", 2636615, 34, [SampleMessage("j5DMlKmWjfbSl7qmZQOok7HDSwsAJopRSJjdlUsNogs=", 1718487794937841, "Goodbye!")],
-            Encode(new SendMessageArgsStruct { Text = "Goodbye!" })
+            Encode(new SendMessage { Text = "Goodbye!" })
         ),
     ];
 
@@ -319,15 +319,15 @@ public async Task VerifyAllTablesParsed()
         client.onUnhandledReducerError += (exception) =>
             events.Add("OnUnhandledReducerError", exception);
 #pragma warning restore CS0612 // Using obsolete API
-        client.RemoteReducers.OnSendMessage += (eventContext, _text) =>
+        client.Reducers.OnSendMessage += (eventContext, _text) =>
             events.Add("OnSendMessage", eventContext);
-        client.RemoteReducers.OnSetName += (eventContext, _name) => events.Add("OnSetName", eventContext);
+        client.Reducers.OnSetName += (eventContext, _name) => events.Add("OnSetName", eventContext);
 
-        client.RemoteTables.User.OnDelete += (eventContext, user) =>
+        client.Db.User.OnDelete += (eventContext, user) =>
             events.Add("OnDeleteUser", new { eventContext, user });
-        client.RemoteTables.User.OnInsert += (eventContext, user) =>
+        client.Db.User.OnInsert += (eventContext, user) =>
             events.Add("OnInsertUser", new { eventContext, user });
-        client.RemoteTables.User.OnUpdate += (eventContext, oldUser, newUser) =>
+        client.Db.User.OnUpdate += (eventContext, oldUser, newUser) =>
             events.Add(
                 "OnUpdateUser",
                 new
@@ -338,9 +338,9 @@ public async Task VerifyAllTablesParsed()
                 }
             );
 
-        client.RemoteTables.Message.OnDelete += (eventContext, message) =>
+        client.Db.Message.OnDelete += (eventContext, message) =>
             events.Add("OnDeleteMessage", new { eventContext, message });
-        client.RemoteTables.Message.OnInsert += (eventContext, message) =>
+        client.Db.Message.OnInsert += (eventContext, message) =>
             events.Add("OnInsertMessage", new { eventContext, message });
 
         // Simulate receiving WebSocket messages.
@@ -362,8 +362,8 @@ await Verify(
                     Events = events,
                     FinalSnapshot = new
                     {
-                        User = client.RemoteTables.User.Iter().ToList(),
-                        Message = client.RemoteTables.Message.Iter().ToList()
+                        User = client.Db.User.Iter().ToList(),
+                        Message = client.Db.Message.Iter().ToList()
                     },
                     Stats = client.stats
                 }

From 2783385a435c8fae4d6cd02f1ecba3e7279449f3 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <196249+bfops@users.noreply.github.com>
Date: Thu, 3 Oct 2024 21:43:39 -0700
Subject: [PATCH 28/55] 0.12.0 DLLs (again) (#161)

## Description of Changes
Update with the latest DLLs from the current 0.12.0 branch.

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*

## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 .../dotnet/cs/SpacetimeDB.BSATN.Codegen.dll   | Bin 57856 -> 57856 bytes
 .../SpacetimeDB.BSATN.Runtime.dll             | Bin 68096 -> 68096 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll b/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
index 222b592781a64e8c004ffecde831368d31b1689e..a17cd51fa7ba5288355b2a1cbfa19eab65a012bf 100644
GIT binary patch
delta 238
zcmZoT!rX9#c|r$^yk6ArjXisI2;_z8-cKk^_nB>z7uuimqIz@0&JszDWP>F0M3a<M
zqhvEnBV%(@lOzlCw3HN60|OHa3$qmCG*bgJQzHwD&0jA4U}lN%lG`@<!?gf`3#QQx
z_jUGqZDulx=Q<=+JUQU{QU$1>)n}+6NcGizDP8sBzgsu*7}jqVy%EahpUhyuki=ll
zkjP-dkiwA4V8oEjV8&nxq>X{1ra;jo1`8l74Jexe<Qo8?2~flWs44}hCJiiR1|*F@
LqMLW#b7uwsMR7_9

delta 238
zcmZoT!rX9#c|r$^#jLU$8+-Qb5Lh*@Pm=$hgXg+?U+x~g(CxlCVrPk@hLJ&PlCep$
zp@C&`TB=2&g{6f_s%3IgYMP;;MWV5hrGbH|aiU48;pQ)welW8*sIBgt{NY-FK<w!a
zwsxHT{;TUJ9#UX`bYybC^`#0>LH=y0AV{@TU)6+(&eLCf%Q-%Mv*?XbHh&`q1BO(F
zBnD#!6NY34Lm<x*NT&hCEEp1j*b<0MfIN_B5|B;<sxbu188a9GMGb(^6sS89tjcin
I&U^060J#oO6951J

diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
index 2f56513350acc70730d652af65dce9fa658f1928..4197c459741c228f3cd90f0f7ec497c9f29e1e59 100644
GIT binary patch
delta 240
zcmZpe!qPB>WkLr_TB_}pjXgb21*VIaFn#JW^_)<pWO<C?ht6h=XSYQ)k`0o~6HQW5
zjgrkQjf~ArO_D6k(^67Q4Gc^yEX-1j(@YJ_OpPooHf#TR$jl;<6tH8e0Aql_@=Lxa
zmF|D^Sai{&{=D?5im3&ROBJAk7D`Y-uxbfrZzJxO$9zWD?{7C{Wc<tGpUhyuki=ll
zkjP-dkiwA4V8oEjV8&nxq>X{1ra;jo1`8l74Jexe<Qo8?2~flWs44}hCJiiR1|*F@
LqT3tU80(n<N@z(2

delta 240
zcmZpe!qPB>WkLswq?Jkk#-5(10&KkP6G}b>xlYyIqOj^;r_pAOXSYQ)j0{qfj7^da
z4J?z>QY{iKEG<k@Et8W{(+mwQ5{->44Gc_;6HQVLH*5cS$jmbDM%Kou0*nCyrx$P0
zJHoZrbLqB8lebUhUOKgaaj61SkP{{dRBgB}?#rcoHkPL<fA@B6H)Uk}%i?duV8D>d
zki=ljV8W2hU<l+{0_ilMm<2;35L*JV36KX8O#;$sKsAP7Ib#MRpr`>5ngVqvf>jxA
KZ)9VvX9fVXn@pMj


From c74b1fd6d26f1b36aa47ad994d6fe9c68d140b6d Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Sat, 12 Oct 2024 10:40:26 -0400
Subject: [PATCH 29/55] Jeremie/one off query decoupled from table (#163)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

---------

Co-authored-by: John Detter <no-reply@boppygames.gg>
---
 src/ClientCache.cs       |  6 ++++++
 src/SpacetimeDBClient.cs | 25 +++++++++++++++----------
 src/Table.cs             | 15 +++++++++++++++
 3 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/src/ClientCache.cs b/src/ClientCache.cs
index 0ec8ad91..9e01e327 100644
--- a/src/ClientCache.cs
+++ b/src/ClientCache.cs
@@ -10,8 +10,12 @@ namespace SpacetimeDB
     // It should just provide auto-generated `GetTable` and `GetTables` methods.
     public class ClientCache
     {
+        private readonly IDbConnection conn;
+
         private readonly Dictionary<string, IRemoteTableHandle> tables = new();
 
+        public ClientCache(IDbConnection conn) => this.conn = conn;
+
         public void AddTable<Row>(string name, IRemoteTableHandle table)
             where Row : IDatabaseRow, new()
         {
@@ -19,6 +23,8 @@ public void AddTable<Row>(string name, IRemoteTableHandle table)
             {
                 Log.Error($"Table with name already exists: {name}");
             }
+
+            table.Initialize(name, conn);
         }
 
         internal IRemoteTableHandle? GetTable(string name)
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 5ba858f9..dc627f2f 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -82,6 +82,8 @@ public interface IDbConnection
         internal void Subscribe(ISubscriptionHandle handle, string[] querySqls);
         void FrameTick();
         void Disconnect();
+
+        internal Task<T[]> RemoteQuery<T>(string query) where T : IDatabaseRow, new();
     }
 
     public abstract class DbConnectionBase<DbConnection, Reducer> : IDbConnection
@@ -129,7 +131,7 @@ struct DbOp
 
         internal WebSocket webSocket;
         private bool connectionClosed;
-        protected readonly ClientCache clientDB = new();
+        protected readonly ClientCache clientDB;
 
         protected abstract Reducer ToReducer(TransactionUpdate update);
         protected abstract IEventContext ToEventContext(Event<Reducer> reducerEvent);
@@ -142,6 +144,8 @@ struct DbOp
 
         protected DbConnectionBase()
         {
+            clientDB = new(this);
+
             var options = new WebSocket.ConnectOptions
             {
                 //v1.bin.spacetimedb
@@ -830,24 +834,25 @@ void IDbConnection.Subscribe(ISubscriptionHandle handle, string[] querySqls)
             ));
         }
 
-        /// Usage: SpacetimeDBClientBase.instance.OneOffQuery<Message>("WHERE sender = \"bob\"");
-        public async Task<T[]> OneOffQuery<T>(string query)
-            where T : IDatabaseRow, new()
+        /// Usage: SpacetimeDBClientBase.instance.OneOffQuery<Message>("SELECT * FROM table WHERE sender = \"bob\"");
+        [Obsolete("This is replaced by ctx.Db.TableName.OneOffQuery(\"WHERE ...\")", false)]
+        public Task<T[]> OneOffQuery<T>(string query) where T : IDatabaseRow, new() =>
+            ((IDbConnection)this).RemoteQuery<T>(query);
+
+        async Task<T[]> IDbConnection.RemoteQuery<T>(string query)
         {
             var messageId = Guid.NewGuid();
-            var type = typeof(T);
             var resultSource = new TaskCompletionSource<OneOffQueryResponse>();
             waitingOneOffQueries[messageId] = resultSource;
 
             // unsanitized here, but writes will be prevented serverside.
             // the best they can do is send multiple selects, which will just result in them getting no data back.
-            string queryString = $"SELECT * FROM {type.Name} {query}";
 
             var requestId = stats.OneOffRequestTracker.StartTrackingRequest();
             webSocket.Send(new ClientMessage.OneOffQuery(new OneOffQuery
             {
                 MessageId = messageId.ToByteArray(),
-                QueryString = queryString,
+                QueryString = query,
             }));
 
             // Suspend for an arbitrary amount of time
@@ -860,7 +865,7 @@ public async Task<T[]> OneOffQuery<T>(string query)
 
             T[] LogAndThrow(string error)
             {
-                error = $"While processing one-off-query `{queryString}`, ID {messageId}: {error}";
+                error = $"While processing one-off-query `{query}`, ID {messageId}: {error}";
                 Log.Error(error);
                 throw new Exception(error);
             }
@@ -879,9 +884,9 @@ T[] LogAndThrow(string error)
             var resultTable = result.Tables[0];
             var cacheTable = clientDB.GetTable(resultTable.TableName);
 
-            if (cacheTable?.ClientTableType != type)
+            if (cacheTable?.ClientTableType != typeof(T))
             {
-                return LogAndThrow($"Mismatched result type, expected {type} but got {resultTable.TableName}");
+                return LogAndThrow($"Mismatched result type, expected {typeof(T)} but got {resultTable.TableName}");
             }
 
             return BsatnRowListIter(resultTable.Rows)
diff --git a/src/Table.cs b/src/Table.cs
index 2f5f3c6e..d3ebf918 100644
--- a/src/Table.cs
+++ b/src/Table.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading.Tasks;
 
 using SpacetimeDB.BSATN;
 
@@ -36,12 +37,23 @@ public interface IRemoteTableHandle
         internal void InvokeDelete(IEventContext context, IDatabaseRow row);
         internal void InvokeBeforeDelete(IEventContext context, IDatabaseRow row);
         internal void InvokeUpdate(IEventContext context, IDatabaseRow oldRow, IDatabaseRow newRow);
+
+        internal void Initialize(string name, IDbConnection conn);
     }
 
     public abstract class RemoteTableHandle<EventContext, Row> : IRemoteTableHandle
         where EventContext : class, IEventContext
         where Row : IDatabaseRow, new()
     {
+        string? name;
+        IDbConnection? conn;
+
+        void IRemoteTableHandle.Initialize(string name, IDbConnection conn)
+        {
+            this.name = name;
+            this.conn = conn;
+        }
+
         // These methods need to be overridden by autogen.
         public virtual object? GetPrimaryKey(IDatabaseRow row) => null;
         public virtual void InternalInvokeValueInserted(IDatabaseRow row) { }
@@ -93,6 +105,9 @@ bool IRemoteTableHandle.DeleteEntry(byte[] rowBytes)
 
         protected IEnumerable<Row> Query(Func<Row, bool> filter) => Iter().Where(filter);
 
+        public Task<Row[]> RemoteQuery(string query) =>
+            conn!.RemoteQuery<Row>($"SELECT * FROM {name!} {query}");
+
         void IRemoteTableHandle.InvokeInsert(IEventContext context, IDatabaseRow row) =>
             OnInsert?.Invoke((EventContext)context, (Row)row);
 

From f1b8fa8dd034ec50cd60bc95991430d55d07b02d Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 15 Oct 2024 21:47:40 +0200
Subject: [PATCH 30/55]  Add gzip + none compression algos and let SDK pick
 compression (#155)

## Description of Changes

Companion to https://github.com/clockworklabs/SpacetimeDB/pull/1802.

## Requires SpacetimeDB PRs

https://github.com/clockworklabs/SpacetimeDB/pull/1802
---
 src/Compression.cs                            |  9 ++++
 .../ClientApi/CompressableQueryUpdate.cs      |  3 +-
 src/SpacetimeDBClient.cs                      | 48 ++++++++++++-------
 src/WebSocket.cs                              |  4 +-
 4 files changed, 43 insertions(+), 21 deletions(-)
 create mode 100644 src/Compression.cs

diff --git a/src/Compression.cs b/src/Compression.cs
new file mode 100644
index 00000000..8f630f99
--- /dev/null
+++ b/src/Compression.cs
@@ -0,0 +1,9 @@
+namespace SpacetimeDB
+{
+    public enum Compression
+    {
+        None,
+        Brotli,
+        Gzip,
+    }
+}
diff --git a/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
index af397a58..1af6fd27 100644
--- a/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
@@ -12,6 +12,7 @@ namespace SpacetimeDB.ClientApi
 	[SpacetimeDB.Type]
 	public partial record CompressableQueryUpdate : SpacetimeDB.TaggedEnum<(
 		SpacetimeDB.ClientApi.QueryUpdate Uncompressed,
-		byte[] Brotli
+		byte[] Brotli,
+		byte[] Gzip
 	)>;
 }
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index dc627f2f..e076fa49 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -22,6 +22,7 @@ public sealed class DbConnectionBuilder<DbConnection, Reducer>
         string? uri;
         string? nameOrAddress;
         string? token;
+        Compression? compression;
 
         public DbConnection Build()
         {
@@ -33,7 +34,7 @@ public DbConnection Build()
             {
                 throw new InvalidOperationException("Building DbConnection with a null nameOrAddress. Call WithModuleName() first.");
             }
-            conn.Connect(token, uri, nameOrAddress);
+            conn.Connect(token, uri, nameOrAddress, compression ?? Compression.Brotli);
 #if UNITY_5_3_OR_NEWER
             SpacetimeDBNetworkManager.ActiveConnections.Add(conn);
 #endif
@@ -58,6 +59,12 @@ public DbConnectionBuilder<DbConnection, Reducer> WithCredentials(in (Identity i
             return this;
         }
 
+        public DbConnectionBuilder<DbConnection, Reducer> WithCompression(Compression compression)
+        {
+            this.compression = compression;
+            return this;
+        }
+
         public DbConnectionBuilder<DbConnection, Reducer> OnConnect(Action<DbConnection, Identity, string> cb)
         {
             conn.onConnect += (identity, token) => cb.Invoke(conn, identity, token);
@@ -209,6 +216,17 @@ enum CompressionAlgos : byte
         {
             None = 0,
             Brotli = 1,
+            Gzip = 2,
+        }
+
+        private static BinaryReader BrotliReader(Stream stream)
+        {
+            return new BinaryReader(new BrotliStream(stream, CompressionMode.Decompress));
+        }
+
+        private static BinaryReader GzipReader(Stream stream)
+        {
+            return new BinaryReader(new GZipStream(stream, CompressionMode.Decompress));
         }
 
         private static ServerMessage DecompressDecodeMessage(byte[] bytes)
@@ -221,16 +239,11 @@ private static ServerMessage DecompressDecodeMessage(byte[] bytes)
             switch (compression)
             {
                 case CompressionAlgos.None:
-                    {
-                        using var binaryReader = new BinaryReader(stream);
-                        return new ServerMessage.BSATN().Read(binaryReader);
-                    }
+                    return new ServerMessage.BSATN().Read(new BinaryReader(stream));
                 case CompressionAlgos.Brotli:
-                    {
-                        using var decompressedStream = new BrotliStream(stream, CompressionMode.Decompress);
-                        using var binaryReader = new BinaryReader(decompressedStream);
-                        return new ServerMessage.BSATN().Read(binaryReader);
-                    }
+                    return new ServerMessage.BSATN().Read(BrotliReader(stream));
+                case CompressionAlgos.Gzip:
+                    return new ServerMessage.BSATN().Read(GzipReader(stream));
                 default:
                     throw new InvalidOperationException("Unknown compression type");
             }
@@ -244,12 +257,11 @@ private static QueryUpdate DecompressDecodeQueryUpdate(CompressableQueryUpdate u
                     return qu;
 
                 case CompressableQueryUpdate.Brotli(var bytes):
-                    {
-                        using var stream = new MemoryStream(bytes);
-                        using var decompressedStream = new BrotliStream(stream, CompressionMode.Decompress);
-                        using var binaryReader = new BinaryReader(decompressedStream);
-                        return new QueryUpdate.BSATN().Read(binaryReader);
-                    }
+                    return new QueryUpdate.BSATN().Read(BrotliReader(new MemoryStream(bytes)));
+
+                case CompressableQueryUpdate.Gzip(var bytes):
+                    return new QueryUpdate.BSATN().Read(GzipReader(new MemoryStream(bytes)));
+
                 default:
                     throw new InvalidOperationException();
             }
@@ -579,7 +591,7 @@ public void Disconnect()
         /// </summary>
         /// <param name="uri"> URI of the SpacetimeDB server (ex: https://testnet.spacetimedb.com)
         /// <param name="addressOrName">The name or address of the database to connect to</param>
-        internal void Connect(string? token, string uri, string addressOrName)
+        internal void Connect(string? token, string uri, string addressOrName, Compression compression)
         {
             isClosing = false;
 
@@ -597,7 +609,7 @@ internal void Connect(string? token, string uri, string addressOrName)
                 {
                     try
                     {
-                        await webSocket.Connect(token, uri, addressOrName, Address);
+                        await webSocket.Connect(token, uri, addressOrName, Address, compression);
                     }
                     catch (Exception e)
                     {
diff --git a/src/WebSocket.cs b/src/WebSocket.cs
index cd22c26f..dd0dae75 100644
--- a/src/WebSocket.cs
+++ b/src/WebSocket.cs
@@ -50,9 +50,9 @@ public WebSocket(ConnectOptions options)
 
         public bool IsConnected { get { return Ws != null && Ws.State == WebSocketState.Open; } }
 
-        public async Task Connect(string? auth, string host, string nameOrAddress, Address clientAddress)
+        public async Task Connect(string? auth, string host, string nameOrAddress, Address clientAddress, Compression compression)
         {
-            var url = new Uri($"{host}/database/subscribe/{nameOrAddress}?client_address={clientAddress}");
+            var url = new Uri($"{host}/database/subscribe/{nameOrAddress}?client_address={clientAddress}&compression={nameof(compression)}");
             Ws.Options.AddSubProtocol(_options.Protocol);
 
             var source = new CancellationTokenSource(10000);

From 17e0c271d62ae330d6b276a64bceae6e37b203aa Mon Sep 17 00:00:00 2001
From: John Detter <4099508+jdetter@users.noreply.github.com>
Date: Wed, 16 Oct 2024 00:05:17 -0500
Subject: [PATCH 31/55] Revert PR 155 (#173)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

PR 155 introduced a build issue in Unity:


![image](https://github.com/user-attachments/assets/7e88a813-93bd-4b74-ad87-a4c821a7fb98)

This PR reverts back to a known working commit. I have tested after
reverting the commit and the branch is back to working properly.

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*

Not breaking

## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

## Testing
*Write instructions for a test that you performed for this PR*

- [x] Tested circle game against this commit and it builds + works

Co-authored-by: John Detter <no-reply@boppygames.gg>
---
 src/Compression.cs                            |  9 ----
 .../ClientApi/CompressableQueryUpdate.cs      |  3 +-
 src/SpacetimeDBClient.cs                      | 48 +++++++------------
 src/WebSocket.cs                              |  4 +-
 4 files changed, 21 insertions(+), 43 deletions(-)
 delete mode 100644 src/Compression.cs

diff --git a/src/Compression.cs b/src/Compression.cs
deleted file mode 100644
index 8f630f99..00000000
--- a/src/Compression.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace SpacetimeDB
-{
-    public enum Compression
-    {
-        None,
-        Brotli,
-        Gzip,
-    }
-}
diff --git a/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
index 1af6fd27..af397a58 100644
--- a/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
@@ -12,7 +12,6 @@ namespace SpacetimeDB.ClientApi
 	[SpacetimeDB.Type]
 	public partial record CompressableQueryUpdate : SpacetimeDB.TaggedEnum<(
 		SpacetimeDB.ClientApi.QueryUpdate Uncompressed,
-		byte[] Brotli,
-		byte[] Gzip
+		byte[] Brotli
 	)>;
 }
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index e076fa49..dc627f2f 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -22,7 +22,6 @@ public sealed class DbConnectionBuilder<DbConnection, Reducer>
         string? uri;
         string? nameOrAddress;
         string? token;
-        Compression? compression;
 
         public DbConnection Build()
         {
@@ -34,7 +33,7 @@ public DbConnection Build()
             {
                 throw new InvalidOperationException("Building DbConnection with a null nameOrAddress. Call WithModuleName() first.");
             }
-            conn.Connect(token, uri, nameOrAddress, compression ?? Compression.Brotli);
+            conn.Connect(token, uri, nameOrAddress);
 #if UNITY_5_3_OR_NEWER
             SpacetimeDBNetworkManager.ActiveConnections.Add(conn);
 #endif
@@ -59,12 +58,6 @@ public DbConnectionBuilder<DbConnection, Reducer> WithCredentials(in (Identity i
             return this;
         }
 
-        public DbConnectionBuilder<DbConnection, Reducer> WithCompression(Compression compression)
-        {
-            this.compression = compression;
-            return this;
-        }
-
         public DbConnectionBuilder<DbConnection, Reducer> OnConnect(Action<DbConnection, Identity, string> cb)
         {
             conn.onConnect += (identity, token) => cb.Invoke(conn, identity, token);
@@ -216,17 +209,6 @@ enum CompressionAlgos : byte
         {
             None = 0,
             Brotli = 1,
-            Gzip = 2,
-        }
-
-        private static BinaryReader BrotliReader(Stream stream)
-        {
-            return new BinaryReader(new BrotliStream(stream, CompressionMode.Decompress));
-        }
-
-        private static BinaryReader GzipReader(Stream stream)
-        {
-            return new BinaryReader(new GZipStream(stream, CompressionMode.Decompress));
         }
 
         private static ServerMessage DecompressDecodeMessage(byte[] bytes)
@@ -239,11 +221,16 @@ private static ServerMessage DecompressDecodeMessage(byte[] bytes)
             switch (compression)
             {
                 case CompressionAlgos.None:
-                    return new ServerMessage.BSATN().Read(new BinaryReader(stream));
+                    {
+                        using var binaryReader = new BinaryReader(stream);
+                        return new ServerMessage.BSATN().Read(binaryReader);
+                    }
                 case CompressionAlgos.Brotli:
-                    return new ServerMessage.BSATN().Read(BrotliReader(stream));
-                case CompressionAlgos.Gzip:
-                    return new ServerMessage.BSATN().Read(GzipReader(stream));
+                    {
+                        using var decompressedStream = new BrotliStream(stream, CompressionMode.Decompress);
+                        using var binaryReader = new BinaryReader(decompressedStream);
+                        return new ServerMessage.BSATN().Read(binaryReader);
+                    }
                 default:
                     throw new InvalidOperationException("Unknown compression type");
             }
@@ -257,11 +244,12 @@ private static QueryUpdate DecompressDecodeQueryUpdate(CompressableQueryUpdate u
                     return qu;
 
                 case CompressableQueryUpdate.Brotli(var bytes):
-                    return new QueryUpdate.BSATN().Read(BrotliReader(new MemoryStream(bytes)));
-
-                case CompressableQueryUpdate.Gzip(var bytes):
-                    return new QueryUpdate.BSATN().Read(GzipReader(new MemoryStream(bytes)));
-
+                    {
+                        using var stream = new MemoryStream(bytes);
+                        using var decompressedStream = new BrotliStream(stream, CompressionMode.Decompress);
+                        using var binaryReader = new BinaryReader(decompressedStream);
+                        return new QueryUpdate.BSATN().Read(binaryReader);
+                    }
                 default:
                     throw new InvalidOperationException();
             }
@@ -591,7 +579,7 @@ public void Disconnect()
         /// </summary>
         /// <param name="uri"> URI of the SpacetimeDB server (ex: https://testnet.spacetimedb.com)
         /// <param name="addressOrName">The name or address of the database to connect to</param>
-        internal void Connect(string? token, string uri, string addressOrName, Compression compression)
+        internal void Connect(string? token, string uri, string addressOrName)
         {
             isClosing = false;
 
@@ -609,7 +597,7 @@ internal void Connect(string? token, string uri, string addressOrName, Compressi
                 {
                     try
                     {
-                        await webSocket.Connect(token, uri, addressOrName, Address, compression);
+                        await webSocket.Connect(token, uri, addressOrName, Address);
                     }
                     catch (Exception e)
                     {
diff --git a/src/WebSocket.cs b/src/WebSocket.cs
index dd0dae75..cd22c26f 100644
--- a/src/WebSocket.cs
+++ b/src/WebSocket.cs
@@ -50,9 +50,9 @@ public WebSocket(ConnectOptions options)
 
         public bool IsConnected { get { return Ws != null && Ws.State == WebSocketState.Open; } }
 
-        public async Task Connect(string? auth, string host, string nameOrAddress, Address clientAddress, Compression compression)
+        public async Task Connect(string? auth, string host, string nameOrAddress, Address clientAddress)
         {
-            var url = new Uri($"{host}/database/subscribe/{nameOrAddress}?client_address={clientAddress}&compression={nameof(compression)}");
+            var url = new Uri($"{host}/database/subscribe/{nameOrAddress}?client_address={clientAddress}");
             Ws.Options.AddSubProtocol(_options.Protocol);
 
             var source = new CancellationTokenSource(10000);

From d938d6d50fec20cb8d1dd563530d6df7a97f3c3d Mon Sep 17 00:00:00 2001
From: Zeke Foppa <196249+bfops@users.noreply.github.com>
Date: Tue, 29 Oct 2024 11:33:15 -0700
Subject: [PATCH 32/55] Update DLLs and bump package versions to `1.0.0-rc1`
 (#180)

## Description of Changes
Update the SpacetimeDB C# DLLs to be up to date with `master` in
SpacetimeDB (now that C# bindings have been bumped to `v1.0.0-rc1`).

We will need a followup PR

## API

Not a breaking change.

## Requires SpacetimeDB PRs
`master`

## Testing
Only automated tests

---------

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 SpacetimeDB.ClientSDK.csproj                  |   6 +++---
 package.json                                  |   2 +-
 .../SpacetimeDB.BSATN.Runtime.dll             | Bin 68096 -> 0 bytes
 .../{0.12.0.meta => 1.0.0.meta}               |   0
 .../{0.12.0 => 1.0.0}/analyzers.meta          |   0
 .../{0.12.0 => 1.0.0}/analyzers/dotnet.meta   |   0
 .../analyzers/dotnet/cs.meta                  |   0
 .../dotnet/cs/SpacetimeDB.BSATN.Codegen.dll   | Bin 57856 -> 57344 bytes
 .../cs/SpacetimeDB.BSATN.Codegen.dll.meta     |   0
 .../{0.12.0 => 1.0.0}/lib.meta                |   0
 .../{0.12.0 => 1.0.0}/lib/netstandard2.1.meta |   0
 .../SpacetimeDB.BSATN.Runtime.dll             | Bin 0 -> 64512 bytes
 .../SpacetimeDB.BSATN.Runtime.dll.meta        |   0
 13 files changed, 4 insertions(+), 4 deletions(-)
 delete mode 100644 packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
 rename packages/spacetimedb.bsatn.runtime/{0.12.0.meta => 1.0.0.meta} (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.12.0 => 1.0.0}/analyzers.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.12.0 => 1.0.0}/analyzers/dotnet.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.12.0 => 1.0.0}/analyzers/dotnet/cs.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.12.0 => 1.0.0}/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll (83%)
 rename packages/spacetimedb.bsatn.runtime/{0.12.0 => 1.0.0}/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.12.0 => 1.0.0}/lib.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{0.12.0 => 1.0.0}/lib/netstandard2.1.meta (100%)
 create mode 100644 packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
 rename packages/spacetimedb.bsatn.runtime/{0.12.0 => 1.0.0}/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta (100%)

diff --git a/SpacetimeDB.ClientSDK.csproj b/SpacetimeDB.ClientSDK.csproj
index eb7773db..6bf4edcf 100644
--- a/SpacetimeDB.ClientSDK.csproj
+++ b/SpacetimeDB.ClientSDK.csproj
@@ -16,15 +16,15 @@
     <PackageIcon>logo.png</PackageIcon>
     <PackageReadmeFile>README.md</PackageReadmeFile>
     <RepositoryUrl>https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk</RepositoryUrl>
-    <AssemblyVersion>0.12.0</AssemblyVersion>
-    <Version>$(AssemblyVersion)</Version>
+    <AssemblyVersion>1.0.0</AssemblyVersion>
+    <Version>1.0.0-rc1</Version>
     <DefaultItemExcludes>$(DefaultItemExcludes);*~/**</DefaultItemExcludes>
     <!-- We want to save DLLs for Unity which doesn't support NuGet. -->
     <RestorePackagesPath>packages</RestorePackagesPath>
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="SpacetimeDB.BSATN.Runtime" Version="0.12.*" />
+    <PackageReference Include="SpacetimeDB.BSATN.Runtime" Version="1.0.0-rc1" />
 
     <InternalsVisibleTo Include="SpacetimeDB.Tests" />
   </ItemGroup>
diff --git a/package.json b/package.json
index 2bf0c6f8..015b4e0a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "com.clockworklabs.spacetimedbsdk",
   "displayName": "SpacetimeDB SDK",
-  "version": "0.12.0",
+  "version": "1.0.0",
   "description": "The SpacetimeDB Client SDK is a software development kit (SDK) designed to interact with and manipulate SpacetimeDB modules..",
   "keywords": [],
   "author": {
diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
deleted file mode 100644
index 4197c459741c228f3cd90f0f7ec497c9f29e1e59..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 68096
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

diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0.meta b/packages/spacetimedb.bsatn.runtime/1.0.0.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.12.0.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers.meta b/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.12.0/analyzers.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0/analyzers.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet.meta b/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs.meta b/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll b/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
similarity index 83%
rename from packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
rename to packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
index a17cd51fa7ba5288355b2a1cbfa19eab65a012bf..bcbcf0ef5a8048fa49abe3ed5f29c7e968896c71 100644
GIT binary patch
delta 4417
zcmYkA4^&ij7RT@Jy%`3E0YPA%^G}8uQ2q#lfZ&n|3$Bu-rkUE7fdk@y?CGwi)o6sL
z)im|DM>%yW46T;TTE;bWISGQ6#<pfGnhK67wPt6vLamO~-rs#sV&?qryPxm9zu&$0
z%`h;m?~vEG%G;jzSk{z&1^Och9(Op)1n5Q~R1@F0xxMk>$Omr%Oe2B89mDp77>k>M
z1%<?ZfQNX3G>Xq<BhCB%gOVFpH{Zn4*jav%jby#Nmw9Zpc!GFL#wCFf*31If_bLG6
zPn^vQOqc4sY%IT;wApWB0H)+o49pQ>@ey+;hTw)ITzR-I;xg;kZFmif_hdYkFN&Jt
zEy?M)C&mzMh%e0;jdoVX#Qeh|q(&;RB6%!sO<$J(7AdI%iZ6dBDU)@@Z%&_UQWp=z
zA5B|pQePOri6(Xb08CDsXHriMU{TsMlWHAyx7P2{3e|g%ENNBhV!A%A*3osg`Uzd9
zsRo;fPg2Lwb%I)En<|7nbt?&@P3lQ>sxxr1QPJu-^i9bQ9AxEqG;5{gW`GdYV#ks~
zwS=0b>d_*1X^3h^RUOXzMlKwaDBMgmD|0ZocC6%>FU315%A`4Rd1{8bR77$`WVn><
z#&c33@JzCoC9cK5>q&}SU5jO2Pa3A~Ai;K5u&XcG`LUElsoT!4rMRV^>^vg%et)Dx
z+a`86$+yX`C)w50(L#5i?^H8{p8T08_JwOp6}}IWtm@Q38y^|8@i6(?#*@EoyiZmm
zov=byJ!q4&ae&k&$CfIbKpa+xqG(=pF_nC+i{;M152<C6w93inxvhLfdWN*a$?MaT
zq&?2Shv^S8sf8j9nWLHIBXP30wdyG+zbCUrN_Nq%sH_Zj51){g#byMa$f{*&t6cap
zC5psN=t;@R3_{l7ScVst0XUK;0Hh@sqEWZHctZAT(qCQtXm(Nf8w1;h^T-^Rgwgbz
zN2UEPzB#8@I_%=7ayCn6UHq|J#om86cZ4jhTa8CokHmT-WOZm@YwirmmNOi{J8LFb
zHULE7d)hl`R%r=doq-?o<T(F`KcEjgp+JdajgY6)!<HS^MwqCR9b^08L86VrcH0>2
zgGY&Kppi|I_QBJGV*8<XP;5Wc4T`-7^@C#XL9?H5`>;1{ajXeC2BkJZr=A*+>a0!B
zrBk0_pEUp%bo#Tg)p`K#==7%Xg!Lcrt4@cFr>zG;nj{9Sfm7_f^?fiBY4w^RdXirR
zwV9g1rl;<au2`EPVNmKJNGH-V4?(V;xe{ta4#Dqr%9O5$w7~s3DTWNw2k?+iZyRb%
zt?)RJR=y3EOaf6~JG2c}>Z$A4RC60N5^1rc(4@x>V(ch<H|Usl_+?OLJA{ajQk-`p
zbcVLWFr9vt$A@)*SEpSt)qD)nkg$FY6d1Ock3)qX{5R5v@QO}_#x3TL;60tnkWN4k
zk=EKt=+k5UhVHPF@Z+G^$6zScnmH=PhJ6fqMB4P7P%Ox=Pu~es^wb#Ww|2rDovyN9
zte?PNboxT>x1NGJonAByQBK1NoxDc3(gmLqX{~j`1wB@49Hn$a)qSEFEp`T~iTpLN
z)0nHAfu{$8-x|-tMvX$3d%iM$4qJ6v<GEKk2X#7i#+-)pa6qS(ar@bMI7Rd&o8jmf
zasm2?j)U2J8hYT49(&s6vh+aY6w%BjKbvQJ7K3iW;}D2xL0U?*0ggD`#vb^HXlH29
z(=?<Px^(J73PP{GZ-zq-{{n6iZG_zTDavIq+<$l8*~%3N5@{9sVAKO5wgLR2L?4VM
z6eZ><UqXRST}c0hiA35IU&C^pM8U6NBaxVQp>hqHiL}@E8|Wa?Zud9PNmK&|p<4L{
zMobmuYhaOIdQ$lxjMH(O^o(*HW)o@0+yEbucFYY}qG!IuIxRO~<v^@1?pxTTQRwGk
zEzl1;bm|LhjO~Y)by^$V0ym*Sr<!noW9&`Xr{j;V7PtimbP5~Z7<&s^iL~2x8!YtK
zj`qUbhDsuF*J_m?;0c|&kbZ)7MA}`u1OL=X+_gK<MI`Rpi+<&2NSQ8fhIrMk$Nd7u
z8sW$6PKB|xL>ofQ@h>u&ZPa3+^DM6_GTW-tLdzbcT{_*s2@UKuoqi5)j5V;gh_oS$
z?8*#LPaDE-WY5kND5iKv31M4x>Ou--dx*3t%q-_2k$D`%6lPXJB&K*@31`=cHUfk2
zAr{t8v;l|sK(Vl5{G(1A@R$<8<`QWy?~o`~sRilR$`H0J;GbC?#WwQmz9QQ~TL$=`
z9_<qNJKB|S%9agwh~lLcMG>v`TJ+;%IVrm;ToGT{_mUDIrL97Vh;$qy<ug+Ha95Pw
z%fv1(tASjeU75nB@W(2>OywKUKF{}7dTmo24Qw;~ZRlRg44{p&w`2ah{8FXj?{-|K
z==T%_DHWqkT8H_vR09_svLyBzBo0Nc7)jKMMQe*qpd2se+;n&;r-+ndRGiLYsR6nj
z#iW;Few2MC*>c^A^L>~(hOb`WvQ2i@P-Z<=x5e(Ja~d!@nZL6@v0ZeuQ#45WC9;=A
z72dPJRh;XPWznHq7M&-^;$*K}1M{3-(u+tbMg_Yfr9^%ib4q0oSncJ)^6^y)Tg7Kp
zd6QN-Ybd9IPG}&%9Z$B!w##DncGO?yuT&`!PUmHc%7z*^%G;{EF;|^lgXkp1AbKc9
zJ&ND1dVodoi3{gOSnY*Ip_dp%#kUu_SOPz>uplPgehHNlI}71311<VoSyW_NZD%GA
zZ03(IDo9GO*PF!N2C}UtF=;FL?PP;O;YSv^SRU_LG&82o-X2Olhl-vrg?gZl7ccg*
zJ-ll1=&Cuc1hdc+%^sNJDm06ei%2OUrHqtvQYuK<K>lvBdq`=eoHkNAQ1Q8fq+BB9
zict8^iziLPKEuWNZQ&kBiVcQ~&V!_YMd-{Tbhkz5Zc+-#FC@Q&qGjY)pkK%NlFO`#
zuU=Z<pW|wc5+`&-i7A5QUm+i&g>Hxzx|{q$vL&Qcp!K<)BO4?ghKhXmQ0jsFLh=jA
zFC)92l=bA-3!i5#bFt-o+Oh)t8C)MLPIxX>{4DQU=Jn$&aY9*7_PIFm{;wy$HBMA%
zCBK98ASppoz)GE4MZVig{g6^fw#3RI-Ckn#z>}^rik6XHf%*)41?lUBGJI$~1q=#@
z)pmn|H_q->!m*)5^nHBxaxcCq*DXJSwgA6MHSs0YyVJ0(BvC$?Bnk(~hY><?kDyk_
zFBE<tZ$+g+#;>q}*H&E{ANa0m4dXF;k^(0V_zgqxi)?=1+bPBGmNfNVC{O(U`F{oG
z9QvcJ*uub+m60i)_&t}w7=m=wmz7pNwtTEFXF+EEf{OfcnU$IIEAxHjV|=;g<Hq@X
z^YbdR%X7-}vwUL%{ikoqSqWE1oCNm3bO}F&n{ch^$0feZ>ksS;VsMSbm3k8wcb)M@
zZ4Vz+xg#&TsHHmRyQz(jMDpop_KwlTPoL67Jo-N4?QJQ?o7em)kTB)5Cvp4T2N%A3
zdxBM}y~!t><vjA-y%F_>yJ3KOKKI<{aQt4TON{e#l@b{EPv<=BLcn$Y2$M4*lwZ8y
zipYWt$h^A(5j|;4-UQjapf_R3Z=rNh@fSuGq(M21rR9ShSb!Vz(N>@xhkhll`DpVo
zw;aZx&Bg0DeERS?AOEFL3E8OR;L69-e0Y|4<YOyGdXtP)FL13lmWAB_`gg}$xq;~5
Jb+$dz^ndfJ5mNvF

delta 4533
zcmZvgd0bOh7RS$h30nw@67onwAQDkDf|1>#EhrUnskCmjS_N69D9)pH(@tQbUB)`p
z-VW__u_8MClu^f$j@22eAXIDXr{jlG#T~cSwzkrbNS&^8?s-p!KPG;1-ueE{x#ynq
zZo)%q+jO;^x)+~|i%ojyC(vHK5a$SHZh#&X0#&hcU~}_=(8vLRIV3RnS-*Kigwesk
zh{CmgfO&j`G>$J~qYbN1pya@J5C0=`vD17n8_jz8c@}5M#|q*#9p4i8!5i}dX1xW#
z_`4@Fd<D|0PPUkT6~ECljsXNDpf!X9#fB`p*B=*POE3lBdW=PC*IjrGijB*9maZvT
zf5L0#4Kx9<#)L#%9-$wmkIhdSk9L02^vrG%QbJ`|osbS-Nc3bLB4zBLvL<s6fCrPN
z4@!>&D3yb-DswZfcwtbP7ohAOgoUm(0m|_~EO3<tDCVd;+vU3!1}MKD#3`=n%6259
zt6J%zYq<gz<SDLYO1f}d3zaIm&QV^YYo78EUGGr_=$fIpts-xHfKr7{brQ}zZkV#p
z%Iil*M(;)`!G?nx0}WF3coD1eS6We3+IZXO3jf2x?czxZmf@i`SY4BbDNn^n2@YH{
z*7s0?lZ}i<eOtV&tKI<Mzb!sWNhQH@N3bfBY`k&INa+b1KQhK4y<y{DjhW@yqb(CF
z4rnX3#aorGVWON(w=F(eIWF{s&%|Dr?3>E*a}aM<`i3n0dC0;g(f?amC46<^44twE
zNvCw8O-RB1$F|rumE!=S*d<yd<8Dz(ANdyatxCAv*FCmSlFW9#)M4hc5|gA<J71R=
zFHN)iniB74(o%{v8OJkYrCqy=iel$c?pEnzb=7ru5<Aar6DF{J-|Pt+n9&@AComGn
zQO3pa^T~F}9m9V~eoIP^;agI2f~OCL+xXWh6b(vUA{E5&^3<u)k{G@-bz{m?calcw
zq_vOXr@eYK796Eh8iocQ9};-aSDE&JWa*9paL%6#JL>?#@gwTYo1dSH*H+)>8M;W%
z%xUOD17yjOtQnSQw7~e1xfv=ovSMr}JVx|PRHKE#PN*gFLNm*gc0%Kj*lu`dNNhK>
z4vFo7&LOcqaMnY(IqGdoBx`|dLsDCyPfPVlubNxnwnkU=JIy|TJkhon9`kE6zXuMD
z-u63c{s&H|#{TKoW!?*;G&;`CnBRvnMCyL~AT7@$Qq`IE!DKCUyL8385AGe3x*zT*
zQZx6%A}zB9Hu&#{GL78Q4gXeHt&yxx3OE2yX!JL|H=qr?MC$hKP@jiCQSNNt4zFmb
zYuSB<cKDP?-S7~c&|-Trb_mSk2PLRwIv|cn&Fp}&L|(WTjs<qWB#nO4O%CdWJdIv~
z`wSn#93<S|3t9S2hQsij7W_BT5op&a+i#QMBk0zs5a}qee6hW{;l~g}<b{6yiJ*_c
zJ|y-DBxtcik}2pDSWKk0eGJM4d9*Uepju0ffPV8aSf|lf>{s)ruuG#$x_<L<Xw|4*
zA0~Ifw;DP99CA0@B2rt!=gkb!s24W)jgwEnMj|zK5;&2^3k`m0@=0hM41Vv|1I;Q0
zu8RB8?-aCX^hDg<@@Z(*=vYJ-oPi#VY9e>DGtf`;1$)5O8Fm(eW{T|(gTc@R=fFYq
z1$)|JH=cuJqKh83)ba-m=4z?Fh*qQ*iR$2Bw8QTlTqkM>?2T&)I}f)t>PG4XX_mUh
z12$doC9o1b18K1{<;#$u5`JM9%2z-?Tg?<ZT!jLnI`D`suEJbGvBgsP3s|O6H_|m&
zp)C|sd<`#YBsTmSnu)}`74kQ5mPkF{>u`-oz1`QLkH`yqp<2EUGwu`3cwvP{dQ$!l
z9@g+h>G$#tSWBdq>4Rs9)G~cguVuc*jv4#lmBHAnk>A5^l>$!%wL(Aa)#z$av#B2r
zYV=faE8K!38hL{~&8Ay$T*Lp^TVVitGzyAoHVwcPqQf9=+YjKT-*eQ1`2n6M5_fHb
zd>j6(Q8&_$@D`DJ_CLb~jl^C18EzAayH@X!e}UNr;%10byAk;-l&gfN)*v&sg{Usj
z5L?f5tXYi(E;VkEb*x3B3gdR9e`(Z*6Y5!qM!y6%oAm4$kvfDQ3!E$VQ-|>QvA+_E
zDR#;JtVN@4q(Jr&kvfHeJvdJ+JPcwA1FIksQ@k$+voQRXO$@;xILyeRi0W{N1G15o
zYq7N059JW{G?99|Vd3m~HAs(@Ft*vZcy4t#ThBi!&atepBtbE3LHh{&9c>MKYDobr
zg!1^3oQwn34d}<3xKOMwqqUeCVJ*Bfyh*bL^1X1?x`Q%(B9p&aB8M1lACmGJDeWaW
zA)!_$6V;r|3n@ITbPUVq6HA?JHGdfGGrX?UY00-Wv5i=B2W9%uhFUu?e;5CtRCaaS
zE>rX-ML`;iQ6`Cgbdnd&*>sXvtCu+3!+$H47vHowNy(v{shDGpo+>p#w{0rv`I4wV
zmu!({MYUqgbVnCcP7Ug@rdr&~VydG$UW`uTzblh1)1sRwr;YS>vK^um-dH9xE8kyc
zUz}po=|oo!o#=LiPSkhmys#wNNqP<`Q&GX*NXgZ`jyd_dI51g@G)rA!1&gUzC;BPI
ze1%UacZMj@URu>8YVx9TIsPxv9i$w^OpEC#)xS*jFO#m*d!dcLS?-MZGTNyZy^Ya}
z`cqL4<)4+$W}$pU#i9_CHQP_<xqjFQf40KTV)>4WtO%F&A}Uj?%%4L6TJ-tNikyHo
zRu&Kk&-1JmS@E&ftpQ?f6WO)^F?$>N9b|ij!e3uuXK8%@in$RD){a0iT}Pmp?qXmZ
zH1OC;C)>uSR*o-UU>{)+`ba|@EU;%AMCBY(a!Dy9rHGUgQtHTWB)grIHp*!yr4yAR
zdoL*$Nx32veyTEW4)z%=>bD2SLA<FqSajY?3K)gXj6!!9h3+6FoBV9@b17O#ehK;w
zy!w&LY!9DXmE~DrZwnU{I>W^jz2sjZABG8CKTPNj^0Ue2l2U@U$iALzFX=E`<U58_
z59DW)pG|%t*;-O+$=@n`9<tKTs<>-q7Jd_JO`^hjllZpQtaN&CmPn!0l3gDuz871`
zZ;KSWw2|LQdM_!xq=1<^H;a6Snff6mn{2L`gUgz0j)TYTg%m9$y#)0FYYFMKLWvo^
zl>&O1!y2nz#v5mK$idjqNc4+%$|@&*C>O3eh*rk`P3_@%)r~G}D_(5h8!tBQB_Bo!
z#W9LnAwOIAzKGSOdL4k#xAxI*CbM!rq9r{s7gpd8zemwl!zw5O1)hXSFb`%zDSG3;
zf&K#2t6&Y3`j)q>V{9U?+cDDo{}w`)2>EpHdGz6{<|ke#TvI;l^+~Jd*H>Lz>w9_M
zVoOd4gFtuEgybZ5k{ckE!FZKi#qQ-9MX4pF$;IgtlT$L%QkQ3Dl$DgEx!tLmndv1d
zWohp8wB*c8Uvk%gE(+km88Lf-%`TAeanOSANw@HQlHYy8?DrkI-|<B!oZ-jQ7S~=F
z_rVOGl)TJv$Xdf+II$y16YsjIiK5cy_147EM}FGyu5p5Avi4U3@t|2az?Yr0O8EnP
z?Md!)oS(#aXwTgtTl6BRzP9j1J>!GL-yy^cublUkO26v(k3Dhhw9kI(Ak!s75WjHR
zKFkeCFaeU$3J-69FX)Vm>DGgrXPh1385(xsskmV|WZ=C|g%UiCWK_~&B3@HaO+$4#
zWTIDw(Gp}g{!2wA6SGP%r;N08w8^9b+yz1S;LO1XTn*M+iR-KIj2(EsrFiZ&{KDCw
c0Idh#w`WZ(7@&_vf~s`iu=6+AW_Q4U0UJawa{vGU

diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta b/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.12.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/lib.meta b/packages/spacetimedb.bsatn.runtime/1.0.0/lib.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.12.0/lib.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0/lib.meta
diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1.meta b/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
new file mode 100644
index 0000000000000000000000000000000000000000..329765a8ece422bbc4ae14cf2818ae5e07beb858
GIT binary patch
literal 64512
zcmeFa3wTu3)jq!WK9k90CM208lW-FP0UQztcjP7p5<u{Ra#2Ji2_b4QFqi}tLtqfZ
zYVm@1tJOik%2#c@(AuiCQP6s+)_SX=t%G2#)z)gQH~QiKUGF}b86e@a-=E*}fBw(&
z<6+*j-nG`gthM*q=Q8I^PMLq5a+FdYe7^lwsb63#|H_F+hA7Ngy&ug|J2GDE^9z0Q
zi+$#tU*A-;yfJcKW6jc{+L~p{BF#mM>WUgyEGw#CR#Z82cG1$v;<~afUHtvrs!yAu
z)XCaWi~9cIruNq2s&7$14^`?jXna;XI;fQ@f?R~HQaO~3?YAhT|NK`CJM{9;QPr1=
ztNc%HT`DU4+moZ!Oc7A;u0$oGaQ~HSl?ic2wpMf6b>C%Ml;}FWec&gilq+klyQCR>
z!lwY(7^~ZFF#ao2s=BPPsj(J}eM29W7vyuA6Ht!fDr>B3h`>?$s?cZV;G2XCg>t1P
zAFNR-BzeU@>6=k$>beG{`fX9lYH9k9pqB~vQp#Vl&~8oP)yJW-{sqn*t*FvdGS1aI
zhf*2K6f5SWr=-2IWFd@@s9V~%X~O#&r<Fp|4_Trgw`U~UOo!TdS}~_+6)LrnCktn|
z>h`T)xHLi`8QB;c+1;&O#35Op6xF(0n~?TcI@>0TXSvO{Z?oH*r_e$3nBJ+)lcITU
zFHOWAgcpXxcG`1yYp#?^riNyZ)uOOaNe#W)`@AGkS)No@aCKK?pf&&CifHm!Eh-Qy
z7167`qV{ds%cm;UBivhNj8b_+jVi}%!$b)-6+!3sHbPz==>vIyx3MrG8*ij9bb~Uy
zy^A8nwDxXwg-Ac}5`RHSnQ_AXAr~CbC8rvvtcw}sGfrfHm<vh@OQwd8g=ivSU}T_Z
zM;m8_bjbQ#gffNBpj_+W&@YT`+R_N2ROI&UM9dHLM5Y(I#*o{$qDDE!HwasU_?#8p
zAPmZOw#n9Syy4@qZ<jcOO<_qR^0B-TtJ3l&xce`?%3LT;PIw|*2ANPvJ3oQE5Ye#i
zO4Kd?Ot>5dhd5%0X_59F;&HuG*@$e@B7Jm-2hx}oTew8V;(xAh)RF3QSfA|%27?_a
zSaQIFx;<(%d#Y4n{6J3$?yUpa{cTulg%&mqM&x0Perb3Jq=MB$1rO+^Vb~&>c|)}d
zp$-SRG~r2z*Pp8n6cl0h*a-le#DJYhjtxPx#P98WLan!HEL_`X$5hBNI|gJcCp=vY
zcZY|gew&ua2#7@k=g!?W-_=SYshwA{&>g@o#*UyZUQqH(N(DBrk&&ooP+>|Hb}Xnz
zie%zoPRhi=Y~{ph--?>C8YS}vYaHfHcce$=jcjG!V8XV~o3js_H{#@kF_qkTWBF<1
ziFtE6>Xv^d3<>i_aKr@DBF#I*a1~U8k3C3LCza%y7U`@*q?bF1qz-hQWAGj7ul`Q;
zi<dj8SpU>)wMse}UH}897TP;_Zb`s)Zi%#3ps;BaMkI{A@H@?|S*ZJvx#hQu%Nf#Y
z`}8?W`gV61^BU7fauUITuYLMht#p-IP9N#YAelZQgjrmsPqG4=)Cd-AnLf!X?2u6J
zP9H2@GJUX+ar(4xMcqCIGJm|BKRu*f%pcjx{8=a+x9iUL51T*Y<ZxW=x?{PF!yqhF
z1tm|I7HP#H%IcD2vbso59HP6r9ON&nN2mUF^*C%ir2}?6MOrIRDEqWOjFsR!jb{xy
z-|=|Lj82T_`I46Q<v`*%d^wQ5Czk{13dd7~FpDRbgJdEOUJjDsr!EH=EE!K6UpSua
zTT!QuCr)3m9`uxUF`lxO@mwk$x8wQPVdE)IPIwty?08xpA(!#|%(O@=4l%LUr>NTZ
zdg+tXBADFk4=&ukOCPy#VwcAJJapfc&e^dRX{|tE(>NJxtmxlqtd}FOj>ozgmc&?J
z43gM)C8opoU5O&O?@CuV)*^&iJh|^CQ*-dXn@mLezU#(}<w!1bf`wO~iIb211!k*k
zo5o9|X^0dN$k~Bkj{p9~k7Q6k0Yq^4_w&3I$IABO1P(ST19j!1U*%E;JAG+*B?9#3
z>H{I1S(x<j8qmS%-loY?L9RIvnveE;Jm%wkK>1O=sRG;HIXrv!dm}g%@O#6TqFf+X
zho?xn;ig5}4PzFTwjWTX;zU+21Hnm_UAV-R`I953^n&RVAxyu5l7%Ur4y(3lk`wPT
z32+8xE<-}DO0BAwX<9F>pfBPQM&yaUT$$RJjkYgS(Q)e<nI<uyFGcNr5g|-J=}Xen
zVbzfn#eas$)^eox_x3MY(25fioI$UdVYz7$K0kbtbzCz6%nAPm4O_<<R%6}5A4-Q<
z-O26M;S9%9G8r|S77^!%PjPF)*tge2pBZbYv2M1evX^mgV(f`Dk}_DMc5Elemd9Wu
z?x6GPPh|pibY6|qi6fm?V>IN9!_Twp+uanWoL%1~amm>=&WmS?pPW-m-y*c2c;qxu
zkHg6|&c@|j!w+w%76)3MPS1Ajt#cr_XW3;hFTfOSkFP~6ocR=nn=qzqY4{A$BF>Jk
zBhqyz@nTmyQoJ{Z=fS~g?2#z%@L=uVcn&%g!H(k}P{?GQ4N>NPN;1%Ad$Dl0d#Qmk
z_EN(=t;Dex^HG9`Q~~BOTM}u6Mc+V@hB$*tOhgJgL|%d5d>~oWu@zLqg_%Fq=FC_<
zvsg0P?e$veb;+fUX9N!4&Y*y2kk7fM-g8ZTnJFl7JmH6B`0|E2syp%+z&cRiFU>OE
zO^$bycz6rv`Mu_v`r#iJBGHoPBKT#(uXoVz1PU@sv(tT>x_Eo{o}V$#?<<^_=}U+A
zN8S=I&vS7`EeE!dGSjayYjE0*iH!rYzm=9XSdgGtW3bOyAM0XT#2j7(N9$r*#2k*o
zv83$faANAe()DUw)0zGSjmKiVOw%I>XDc;@jl-Z>jiuI;)HW@$`$@P~a@XO!8J`&U
zL#{s;qsS4iKV?FT3#Ufg;rq$1l>G$9RJ)%@AQ4&)+fU9FAK9y#o{^GL{duCA9L6Y>
zHeHB7q7q#D{4c<`biufUF*tGnF$W6dpb~i&rRBuD2gVo&7`Z+QHr1mhzqe@#Hi2xF
z?zp}efO{hiz|248rw{U`M^LN(9q%Bo*Gj$;rF){!XsK&|Ic$jRRRf1uxd-OQxK7$|
zn|MyT^FK6^Xrr)SvW;+=mF1iPhbsPiStd8v2*bToPKEq~OL!&Sc&1DUs*`S!WpD^b
z08PsQmzt8xl13+Tp;#LM+gNcEBpfk3VG(Qt&5$B1ME?V4^+nkBA6z(K^~DelcrO7q
z;lS(f9~Dakqfu(-7$&63M&6wW4ygXYq17$eV2qG=Oqm{$RiGtuw3cSmrHrEnqfCyJ
z@v!Cm13J<QH_HYktMIsWtd=@ZM)pzJm!<5X?W}=M_%WGIWns*N(x~(Ug`~_NlnEyL
z*nM>rwnO^Zv{wA3qnMrOsPt3LW!TSb9@u3?WJg^(s7InAXx5?pk@|Z`n}_vR>?OTy
z8cX^*9=0U;(vn}5i~i%LK&Tg{rMKx$?(23`>CAEK*!OYQcfB+q6<;nw$G*E=-wo})
zS9I?CmFxSxcHb*I_brgcjbo9ISn@a)QVz!f*?61g%g8NrkjJwjMWiYrIC5ChNq<Ks
z>McUOsGB*$0&6e>!yln^pj}9pmBAhlWX^^T_C;G*F}&fA0Vn~A1;f(L#$cATjRCt#
z!j`;#UxbeHdcT{ijqScyckcUw>w8VR@3o!#e(3sM*Y3NibKmqtt~wb5TzR@<Fb+~;
z492&UPGakysP{XJ!3=3b_N|V`;3Sw+#^B_3+SwRXxMOgAd;B+a9)FGNdt<xrO`ZEL
z7vE*Q4>a8jAKc43A8SJEEh0Ouw@NV{bEaY*;V6Q2ER0>WG$I4#iSz*aOM7}FT_FTk
z{{WboYn=3y#lagXgm&;dfAS}fKUk|Y78`@TBRszSc#yK*Nj)iRmaHF5Q5k-By%T%M
z)HSzb<Am=3hEZE-$!M$bgzpslaMym95HHT8oQO=bNKE)t2j@-<0+V^OXb_*wXPGYt
zuRpS;*w(!z^TT(;cMawYPIvGPj5o4H$}V&@V)R6|0>in|UANA|*R*TJI(5x9c)9^#
z&6WVDNd#c+ZUDA_{zLnR(8`kM5}0p>_gC#c-~T{J76`jM$U)8RlOtp4t_$rx9(!3R
zs{%TnH#AL^x@{G<pPX&Mu{gOf%Yu}0P9~=^cHKkU3WJXI33ZQT`+rBRO*m{E)c(Of
z9(yVH$r0Lr?4b5#Q988!UQQUJSBg8s2pTIzqP_m;6DDb}=~|TXd!1ISN*-?u@qqU_
zsY;Id5v<pxNGa;UOmOSLUUX1B-K3sPZatV&sE2sKdwrrF<Us1d<x=ZJco>;Da?U#q
z=}24-iG`O#6nM-iM?baHUxeP^dz9BZJC8jT_9L9f$~-`=at;whDsDsTgEF1QcN5h)
zjqfLA6CQ%m!!CEA0Ex19;_X$Yy+#@d>mk=jV`RAHf)U?TVHfneS4KZVw@iz~6S)_n
zy)t6ZERZ-qz8jZFax#p`?Zs75vY2BFZ%1MGdbDYrG&Kv(*ipT>Jd)a(RbC!R&(}(?
znd}o%lYL@pvc<w=Q;_@|n(HqU2|47N;XCFUt6^uk&M@tlvACd{h#oW713Joe1+0hU
zdYUBQ@Lc~Fb1mUSew@fPV`hQQa-A&Zw6O4fDY>35O{L^o99o$%xfGS2ua#bNovFtB
z>WP@wAdy%PpTy+vlCc7(9wyHd^b86FJ-I6KAhe~087r2EIxUzsXkaicS4Y}JosAo0
z*mJzR?~z#=!YwKs-Mqa0ky+|(x*r|8RPJv%stRo#gSH&MXN63sL<>5COFgvUSs{_L
zg=5iziOdjnR(cb5ac|QW>04>OuL&m&-lm7h-1^yjZ$|hjC}sUhQ!~((90L*;rLq$y
z*F8DGORhWp3mawLbY`}fs$5X8<hl#WFVTq-Sz{d~>ryYY)pQqXm30XRR;(w)1KyZ4
z#dQg5W&3(E4<07`xYSYhGEN(k>xo!6#VK^So)jl0;vsV!S1{jYJqe(%*b|>X>xZr<
zrHQIBQ|2Q3oa0F5;p@qKSPz-w3!!SC<4>Y?cRl$Dx@B4<p2$xj+VzA%v%q0<e3x{r
zFq|yr*uoE>aQk{vEltTBe+JH2Po(x%rfh)Q^Eq5g&Pq-6DXEDT3lmMDqqSswA{qZ#
zo}cO@xj6fC@B5*PixEKTEv)*()48<cbUw&*O0OdiCDO^zSfI0XCW|>OEc|dvIwOaq
zQyf~E7)ht}^>n6lerh_gq$cOBSeQ-<9nRa?iTICBK5G;8p^r`IV`@Gx0Y7AVu96_#
zB{*ez+Qdk=Q}W5!Sm4O{lwwW`3#aCDwKSD7J;k9_phWU1eYN>K8>+-QFf%ouVqrch
zbePYUMEpl5pI0R6Lmw|gA5-&r1^6NP{JsQvcs_S<eoD6^KTFI{#>N7j<uh5#X<^}?
zr_9f*rKyyBibE?iBl(oR+I%iZ&F5*U`4kKDNuk4h-kym6Kg(zPd72z=I@$HNC#ptw
zH=(;+S8>oVd}1Q?Jnd#!4@vY7B>KY>{Rk5+@kD-+NHl|HfzA@0EatSZ@GnymeTOua
zl4x;gWy<8-L3+Mcdd<b)oYZ8Wo|<g2FxeD3T3dgeNXSvo^>c};(c>6;+<C6I!Foup
zw@U&#%e91)l557y0!PlZ6mwcwI5pQlmZnm2Ee@>$JSUc(Cv&|J>cm1ZD>c_*VXi53
zl<T(>2|4Py-jk>rx&A47+<C5dz<Nloe<2CzEY}iFO0F3*3miGuQp{;#;nZ9|Dov&2
zS{zyhm}}{IGS@gyP3C%bYOck?TvO;M*PkR3a@2GEuSC_z^%LlE=egbq>mj-RjU=G6
zTuV49xn|5PaO7M|F{g!vQ*-^CG?kKTacC7_uBGS6TvtP#nAdYsb1fF;nnFjpcAWO}
zsiU6jK%#2o`bG4(^IX3I>mj**LlV$gt|gq5Tr*}CIC8F~nA5_-skwerno7yFIJ62d
z*V6N3u4|x9<a%yuuEoM!Q|KtyJrW5y>bWjXRE=D}gC2LD>pid@l55-n={(mGPD-vB
zGYcF!*HX-BVd2zVe;`ez<XRkB1(<8;c{10FpiboajMQ9<g}J8CQLaZM5^~gYJw8!2
za{Uo{+<C750qY^T{#+8!*}Rr;QgY3hS>VXImSRo|3#aD#3u!7P*W%DBz+6kulew;i
zI+5!$Q*$jA=9)rBxjre8kfWaK*@>!=>u=EG&U5`OtcT><ky{y^<yyi?$u(nUfg|Ty
zia9MToSN%2X(}bx;?OF<TuaZBxyCJqWUg_&oxA`P3v*4Oqg>Y}5^~gYeL<pX<Qg~X
zj*#mtSP#i{?vZjW;iTl6F|)vtb1lW378Xv;b^al_7Kc^==3085%yk{qiFtiiYOck?
zTvO;M*DZ;J9Q9nUOH_?qcSVmopV!C0dPuJONCG;W*Ah-jt{F26968rg%xPia)La)!
zQz`RW99jjKYw3A1*XKf=$Tcq1lk-|E%r%9Ma(zQ0AxAyeKTK4OTpx=bcb@A(upW|Y
z+#l~e*Ah-jt{F26968rg%xPia)Lajjrc!b(4y^*rwe&oh>+_&a<Qf<8$y|$txu(!j
zu78?H$WhPrFB4TG*Q3$n&U1}BgNNq&1W7<=^IF15$u(nUfg|Tyia9MToSN%N(o{;W
z#i3Pzxt5+MbA3M4iCp74KACH=FxM11%JmD0gdFu;zn-WXxt@X^cb@ARupTn6Pn868
zmTL(oCD)9Z1&*9+Ddx1WaB8kklcrK~Ee@>$%(e79nQMG&lFT)(<CD1-3v*4Oqg;QG
zNXSvo^{0udk?T3=ap$={3)Vw&eU2ocvs_C!DY<6MEO6vpOEIT~g;R4~B~7K|S{zyh
zm}}{IGS~PjDw%6s$0u_w7Ur5lN4a)9|L3k76ICPExIcY_T%Ql?A-Qgl1ay{b2`44j
zjF|<FoNFoOw6Jh$u9rzuDY+JhRsrT(dY;Vn1yCo}5M0M6b1fF;nnFjp?vY5yQJ>ev
ziK>z7M)bJzd3`aghvXVJ&pXexgp-nM#>@go&b1VCT39$W*R9f2O0LDBRe-scp4(hY
z{tAs!y>TCTO@q`GeiXN61L;%p72iNpJ+K{y&oq3nv#BP0uEggqd~mN_y@1aie7?k|
zi&m-_pV9bC$7caP_?k!IX1TfvpD}n6M6FrMX5jB_nk|<oV{R4gGHM?~<NWT^KSm0z
zi6pi1poo7=gJ_piy9QD42^;^IGemnKwLRh1bS-_$McbIv-brnVXb}ZMrSJXJ=8LvD
zsePQ<0|;u(ilp`hYX2hIi;~*i)V?Cxi<8<9seN3umn5}cQG1VQS0=Uc;F*8Sb)vmA
zsg-Yx{iUsIT9PVxlFVPaWX-CiN}i|jm!7$%HL0qgs&dWhq-qvb!`7@xs%og}wI-TW
zEvG8bI0Ey$30?PJ%I~)Ee7HxcBFqub3i%Q>FF%++C@Ywc@9Aq0&zMh<JkJXGJ}@s7
z48el0<Ri<)f-8Dh<eRO$f?xqG1^9}6jaWXRMZTlSD-0IGQkaV;t;F(oTI5TGysp8n
zuyoD!M1CliztJMM!1KBVyTQ^eH!X5s(jqr(^STGS!_qz18^Low?PcWlVqTA64_JES
zrbnJnTI6O}Ue91pSbFCAB5x%va_c7VnBXz69Fv<7`AgCwHyZMK1$)8LE7u>v7y0eI
zmdoP2-of6m^v(@LyvU~;sa(Y66$Oi6Day@^gv4UAbCy{81pC0!C$~$apIB^0<pepe
zZ?G>ceRH!SBgFC<b8xm;ii5?l6z66~CX3~tw8+UvUcX>JSo-DWL{1kA?ulR&<WQN{
zKiD6Z{<*<OwOIZ|i!AJU1A+r!8IYSBiHHSvLr_MRp}b>*$BylZMIv}?ZeC<{dxdtn
zC<y-w)5Px6-tbr0sY|S(&>FZ~r^^@re%H{|8n|csQVrd#fjf7Gec0bt)!iDne+NC`
zV~}pQt{&FHeLR?!YUyb$+|PsFRLe2e!hJoMo@(i3E!^LOzEn%^3~S;}AIvz&<hLg7
z`9c3drhqkZ_YVdRGG$s5*MMN=L8dO&#DyT(<seg*HE}@*W*ub8wk9qN!R&)fIo8Al
zBA9cKDQHbxD1yO*Ou5#?1tXYykSWiaxNrpXtSR|iN*~OWrp=fp@>~kmG(49=Jm9?>
zO8Z<&SNmK_S<|mEF`~#_^3D2hlF#Ia+hADzBp~HM`=>ygc8V@4mT)&z748nO&&&*W
zl5c&KoZJ3xOzYEdHS*+!zx6i&JY$FNV;zMMRA2Phw1@+rH7zVVsi4G!YzfoyEcAQ=
zwDmbirl9qCY)Vfsd}<YM$61e*NBLWEMD&|NmM=_H)FQ<)4c?Jq1%}+TNS(tUF2IW(
zEmEwcd(&^RxfCzB3FWi@d}gWw{VY!Ov-g1!T}_L`!H7l#&@Be&FHJAt1G#u@r{xyd
zTVDh~zExxiMcxw&zXU<HrLz5b;yKM9V%6tcYlaUvhW{#u=tls2r-m<`bWrLADRn%C
z+3<134oj82jC&x7bGY#Dq}>j`4}U*#f_2Eb+si0&gy$A<k`xvfzJGHorr9B<UUxvn
z(_BRTd-0R^)TB=lS`z12?eD4KVD7$ubElM)>R%OAd(!fTdKHdp{Fiv%%Sl5fCNUG&
z0>iJNL^6MP;!EBxS~EH6uvYemP7*BplULn`Wmo?7&ToI17I&DIbGbF#tHNI&G)U5j
zILNZ=I=p^xFS<6$Gci1|>e!)MBThS)^Bl`{IJleryEoo04ze7(4!y7<C*$bfqw&|`
zAggl64m}&+76)0JJ9apxQNGmV`B=vey&C14IG&ny?9e--QNBOoX<8>9{zm!MgQskr
zcmx{dUOi9WI`PPClsn8kmFvW#OQYNu<!N0f9$AfYH;-p|op@w7$~`Ea^mXEq(<paN
zcn;W!N3c<@_jyX#iAQduT&401u@jHHM!B})31f#Ib_JG)mv5Az4c{pHPT9-2o=)uh
zEn?yI8-<Rp-{i4L`*g~GwgyOD6S1%KlXcPw-;Bl&eb(@xXP39Zf!A+1U>*KU%zwdp
z$RhF+3CF!wz74Ybtl=Bj!3^Vy`~jkU){rr?Kw@pV+kJLfRvbKQm@MYl!f&FmyGAuV
zAWg~jn=C(g)=-kgr1JVrdcIbA&1Yh6O3gK{r<1uB3v*4Oqg;3T?DGGx-nQquf9JWz
z7YoTp4|kx)%ry?Shv)j2upW}@UqRJDuHRy=C7j6aM6MY#3v`z2WHG0Oh2KueH5RLb
zaxD(6%$PiXBt2g%z2<TFM9i-Nh<VM;aB{-$pqhZZDp^<-Djl!}M_efT%WAj<#r&nc
z*5JSk)j&}_MAg9;S8@)5vwV5i2iI0IX)=9-{J!=Fpz}R^0J=-Ypz#^)Pd|6FZ5M?9
zh{kP`-tYjP6SGr=*1(3-!?@Z_eP%d}cAB1+j^NzvHuTNgLOkGo21<Kw*2A8gwIAwu
z96Ib+Cp#${H>@ChtVEbNl(|ngGkVvd^dJYjQs4*5X3v<cl|}~aZ<$>*vTSJCh@m5f
zjTKFr!Yv8a6*mluafZ4c+sv+zXE!(2FFOxM52dcV9Pb~dK{t1{ie1Hb5moWDxzj6Q
zdjPyy{3ka=7Kt<d;c%+YyzA~jMlX<W^ay#OMOw$TE89Xc6f&W3mBZhELyi@4rWWJ+
zx34SXtckxNcLBEP_*{gK)FB_S72<;&%KMb~w<yO(=T$%J@<5(fy_F@{KQKQpTfLlz
zgSUD-a8b5bwPh6sy=q6MV1V+glt&R~5kKo9*2MwA^?t$M`=z$OW!;nGRbS@|b_oc6
z>>rcwRek&--%9ID|1`)a1q9y;(MJhR%8(lVnIUo@_trw3bFhbR`b6_Gefs3ifKQ$l
z&1b<4#;eZG6?~f3q5{$XcaGpn#&|0|e??7SeZ2?0rKZw|PcPzaIa0%)lvrB=(udLX
z+|PEe&b<Ns-{%uFne$<-q%|{JYPf@#%RU!V|AV0Dd$5&{vNyp$k}I0~*#}Ra$bZO}
zR(2PPd>31PEGRjg!Lm{6-}gNO&C+bi!?{86Z)BZO`drUQM?#j7or^glqmJ>#YiW1-
z=jBgIu(60p7+hehM@A<>#v}r(L5?Qjm#i>t!EWqwQT8NQykwVTiVY({=A&o2yx9%U
z2Qb!?@M|Av9Bd-%>>_WTffds;3v(|DHnre^yc)dgjma;}wORHLwveT|(e?wE;ra=l
z16XI4%wDk917i?Tmb|M0_7Pc*DkAHiDYl?olZa;*VR^EOfnAnm8TK2nAF*5?ykV@t
zZVN0llT;tP-@F!ac=bY416HOoU@J8X%~G(jWcg(M@K%M`hLRnNwNh9&vJzF#XwS)!
zS_Z32Xq#IgwG37($^M+5%DyQSR;Jd`c3hsYA?j+f9%Mt+Cibi}w9rh&eb1Z7PGUcY
zsV(%Jo?Dc&R1H@Tsm+MtmEaN#@(A^F+SV2<L7gMiBN+P}^-{(Xb1B}Dew3aO{L}~T
zjjCtKzE+mK$a0xl%8kbUCh<M&ve(GAksYVrBwL>&o@3NIWRr|#?~?7O=NR=KS(VG)
zC;OAj{z7)S$CmquteacQ-^nJr>{GHY-EyCko$azO$#%Q!8?seyo&Qai@7AKUM0BR>
z>5#qQGOzZ*_I;OS(Dn@3SlmmNaxWE1KgX#c*&W%!#;Xw7ujx5nb=7`&Mv>d4YJ%!{
z5bJ#q>w6IEpTdq;1GPad_hl%x5oeKu$wpyU+o(=Z6H+|O)k!IAlA5X0umC&-&u#c+
zg4rxLKU=Aon&+}#!WL6!sYSGX5E3?DT}ZYY2aA|G8}nFNzk}r#sB6jAv)noAPO^!J
zFQyi%`^hGeRjJ3xa25w!wR(YUKUt01O?EcfBK09z6<MwNiVQcdQEstHH`4l_$m&!9
z8D7hQ?OfHL45!v$=c$oo`DEv-3bJlw^=cN`nXF}rsv&!W>;n82LvoB7)EeXT$x+u}
zIjq6{waz$b{ZXu?HEO-Of^0I`)#}<5c8%I(9PCwL95v^wYt;?3ok`DY)m>zMvg_1l
zlN^;zY76@!V|$~%(Pc8WH|m?zLn%GGSv|>G<gBAc-KL&415}UvOZ)@W`Pr+0-r#@v
z`lu=CYy9|?Sl=3dA9V}lKI-S`mjM@2zLeH~r0;Ofi2gl)jsJ}3L%=?2oNoj0SX$?@
zY#(Y~g=ZgS<>l0m^Ie5f3qw-&Vd6~URm4i-eL=B~ru=N7$XhAjMBJ4vnrO}%|Lo}8
zZ0Ylc+-uPKWMERWiJDC*n$CUtsLE{dugt#5?^Ro}uK}*l6aT#Q_dTQ4PkpyRb9crX
z;7b{I`bVp|1$X*~sUMin(%SJp%Kz})=@tJiu!=kawcYC<f!gjxZL__Pc>1W@y!XSp
z$~*-9-5HMnU&?sO@AdxNS%tXfXa5HH%N)TELV~*s1@EAKJ@pffXeJTA)FSUEo=vPG
z?k4_;SW3^K#C&2m;+eF*0qmoecqNlBcz+9d4{^WuPRLR3E5IGZfy9Z#&1s^4ggAmY
zow$Pded2y%F8yDmypMPcu?jdsEzEucI6pfM{AJGjzz;%#y9=KJ-jV$oaD9&8L?bwf
z_@x$kKk;m06>&H5PsCDs4khLjyAjW%^$p-?b-MXgT7kM%HTVitk$M2T)nfmD`LtSE
z_`XN0KYK*><ZkzR)we;xviv)N1A$syqQ&|W(5v<Yzr@@)4BaukFXP`Bqft5kM#g4)
zbwK8THz2VGfcIsDfTMD{2W$<e6=4Te8@guU{7kEP3AP2jTb^Ls(7!baCbnx5OwQVV
zm|#-Nwgk%o+hLh+mv4w;)Z;F@GDp}hmu<?)!8zTFDdimXj%&LjV+d}h>`U0@1w85-
z*Y@8TRSwQ-`zZX|;5!|jUWKrQAtIa=scx?A0@%`3AD5Y&M@+gJ=(1qWfwXirJf)mZ
z%}B7VI8Qvw^~?)Z1^lWeVMA-G{vdYYL2TtgZ0$kp$^^?nEw@_cyWca!38<LMmW71f
z>#|j$9GuNQm{KlNJ(plxac=vj>v>OpRUk{n6Sl=*-zM0SK#mIawK?mN{Rn=&<QSJp
zIs9gTWt<baYH)((;GNtP6YRo3o?7UZd!TTL6H@28EH89PAf%QhJiWLyyyzgdnrv6b
zQ=uxSKy4&@MqQUZ1nf;~(@*6WgS}05v+v`=5l*4{z-4i;Zfd_<?iar2Jv~$xoIvA>
zQ*F$D39N@@dSiZtgR^e_dj|8iHE@g?OWS(H_o}Ctnv`H(e0M*cOlHr9KyP&x**f2<
z+^OC^s>Wqw$QsE0tRD<+#6Gq)!8Qf@s%Ob=_Pv*LOQ2YF?I+FO?0XfgzdGMCH6#13
zz_F^CY^}PaU|S%penDn45mxWG<;E5K7`885Psz(b^|fpJxbT)hiAw8lTZn@VQrTqB
zD9KBi8sjp_OPM;2?9a%{gMlIHGBSzwk-$)OJ()!N>%egJ1DA~<+v=8+XostJ5^NV%
z6S<8e@x7Pxd|;%icG;_7qt&l0L$t31#;BLcY_wxlJ}z=(#AMvZs!?QXmBcqzjUkh9
ze?BlyRk|z=HbI^0mXr7<s*7DF@l90Ml1Y4T22M~<lG)KLSHCB-qd8f<<uVz~$!ecl
zPU4%addiIoC1d-iK!rMiOyb)Ys8sT6)^;@a1*WPPnT_Z~wU5k3bfQWdD4sT=6P1rl
zBH9<2uJT<L2RljiBC{iQikjv!iRctnMJ5q_95_{NBC{hlQ*9=*BX+vl?lKv%)71{Q
zoJ4fG`Z&Qp3(Qj4B{qila=r@8RwujcRj|2gBbklpO!YFEjp$7EscVxlI#Ye_mixHy
ztH3;a!v?b;4mKa(>q!eXq6KP%%Os)&>LfCWNM)X*qGUI#rwYB93)Pck>o6m`WLB%+
zy0#rTd6_jTa}axtI}yDz7pZY%wr7jfG%}m(MQVoiM6UZ~)~YjH76+?S)owYNJ?E)L
zmr2jgQ&*8m&jw|lukI$3z6{T-S3f3`%y087QBRQFtajv#$-F>4LuUKZpk5`jeQ8i{
zSWon&Jaegf&t-A2i2B$qCw;k49dMcS<w8|3SfZ7_%*bq1Wn|L&>6uMxl4a_4-@MFb
zb*AgNG;bl;5|>?)SC_d$wI<3nWL~7MOO$KMyjX2cDR;5jky7pw^&7HXK3Snxs#nQw
z_Kho8nYmKEonV(`UaIzy+1Oju&@$=uF7CxGYAl(|`R`}0Qd3+O2V1SqBC|6js%l&&
zu}4*e?9W)sZ_30>v^Heo-ptFSdi;9^XCyz(T&J#}P1f=!GuNx@63nYESGOkE4W7%@
zkI3vXXM=i}Y=du^XQ$bq9&_0W&$F2u)Go_Vr&nE}UL&*dU7?DGNb9?Jbh<)KC6oAc
z+V|8fm&L)ZQs<J{_%^C*T_*8uR6n!~5#^;_EfwOQ9GzayyhgoBn?$rb^IG)**#`AV
z=>5#=)W68M7G!Qx`9o1mZ&LoW&oggO6NF*D{KEI|%$wBtWShF?=Y8(My=?w_Cas&_
zbh%kAp-tveewSO+rEWQyJ-4YlT_&^V2kI#@I}2`CFOl7#1_pa}xm`KKq|&v_(j6+3
z%x38hHIK~Bf;&_VnPjPdmmjL7E{lWRrPjLTWDnS^u5_7XX|uY8OlHB5E_bV#wIOGX
zUACy7x}F;MNw=y;$RuZvb=juc$ZYKQ*wB$(i7&|{z8|UA=y|i+?|G`rz3MBMeU|q^
zm+fl7a4CAT`YiADE<aAxvfncy?Y;zC?XOI`KfzweaJ)ZNZ7jD*P4(ZB_JGR9;Za6K
z$~~xtx=hMFq)v31l-r?}r+EHMZB6lfM8#7)f2q79rA`~)qbi?FTKHp^N7czLTkZdA
zm&ep~E|V61rGB1L?g{l&qTE+qo>0#x%6;4A*Xp&Da!;yH5}xT<PpK~xo>^Ht6@Ru6
z@kt9$s~)4;qb<mKMiskkwf~r`->5+@6VK<=w1j8>tmoCtgy*2F7u38I&li>a=Df||
z$gG!COTu$}*6-B%6wlwQSi-X+>lM|O@H{E&RrOAa=j-aLgy)>BH&nmTwuROH1zCSk
z^IRtVd`mUCY`>>2Yqx4ics69ct=6Y_{!!hP@NCZdlloD@vnA_Y^+1Z}9`!=Pb6wVZ
z>eYnjRatx0J1L&;t1lCt*Ju4%eVg#SE$aj2JI?l6`uU;i=d%5t%~^j{l`dQD-=6i6
zs!s9zn_89dd?@Sh>fVIsqgkJ*cTzk*RbM7NcV>O2zD;;OpY>1W8<TAPU#i$;`#rB@
zeW6NSw%Y$z)|YBzis#pAX42F9jcQ1E{>{5zy`19t-|7o8JIfC!!*8)<mcN~TK;^q^
zwST7XTh-TPk_oMcklAuZ+i$<5+@36>Pe_#eFw4<%Qp%<2=9F??eUWS1@A)jttFKO!
z`#LLK-<wh{L+?y@>TJJ$J>i*^9ngDIJiF+BklCJP>CY48dS+*7|G4%!*e^R<XSz%x
z3hJ&d+wU2iovSA#JV#~c>FN~EkiIqHIWfCHKc4WMmR+dhDW2VQ;dtBLe$VOI-F0u5
zt@h8)?x6>{Oj<uipF?JQ-Ah*`$}P_BrO!*0TbkWlH>Z^Aqqn7$>#Ki6X3t;x>YtO@
z<4Uo9%G!KSIP)@#_46)!*10&lSieSQk1PFj(FEzWJ+AcAOUUH763y<fFLGHN>{xvj
znLYXr)Z1Mq$CZKl5i&Wh+?!dV+bqLz<*Mvb{h{kAXBUI?r(|-B+mt<6dykja<yd@c
zcA3t%47P^MA-b5%Ml@6pu{Phoou<s8`Z$;QJ+bVex}3~LG)!-_<#@g{Ous=U5pB;N
zuHSQ69Bici!YwC9%F#L`k7u}7yQ6h6nT_Z;J;*Xd^l<hVJ=gV=h{o!3$Rwgiv&ZR1
zGKuKP?D0D4mfP=nE_;Ih*k!BzuVf#u=ba$!*>(N|{Sz`fC(88$u5G{Po$PY`3zx0-
zzn?ux?@B3Gq5qXqu2O$VCUZjLJ4tW3v|uwhMdy-j@V(+Z@0p^zyX<Y}lk6$FADPYI
zRK1+c&WWk|Q8LNk7unPFGcJpRP1n2Ka+1N5^w%zvIdPIspQP|lGT7MVWSwIfGN^J+
z(PPP;!M&`NT~5`L$Rva5IWzScWRk(GoYQo*Ww7PvoUS8eHlkU&#oBy>JUw$}>2)p}
z<tYZ+NM<9Nt>3ieI45T7jLFh7iD+=n936659PA7|kj&2VdHO_`NksGX8Duu1vvieZ
zi0HVS`TBdVr$ltNzK%>HnwYadZzGe4rsSNXe`*;cTBx5Ovk_J4=dH~*5fN4CS6p@y
zBC68wklBc;b+|%euwzuM&mxnEPR*&&buNp8)#{aGHljLxtIH&!I(-kBjp$tcQ_B$1
zyqxp&o35usbiR(0NkmmS_4;3AHlii^Tgza3tjh&DtCBtAbxwosPPV}}&vR~0gYN6H
zT2BMmATk@#QhkXn$1z%}x06XkD{_|UpSdg!wp>5wmXlf6sQ=<JiKtP3L1rUr(%)K!
zh}PsZ^KV7S9xf5B&_kz4KP93KITz_EWD?QUIT!1hmce#Y&Lw&wnH{5*dWp69_Bprb
ztkjJz`-c+)TSaCgx>P@F%Q2!$b?#JYPa?WEr$zU2SsbiY4=1x@v__xqGKpx7t|GG$
zMfLfXA)<$J*6K~Jr$ls_zKu*G`en{K{Sz{Ys4Zu`e%vxfbh&<k%to|9|H0aPT|Kww
zY|!tztgj~q_7^f6(G_~+G>O5^x-0Z*GKuInIp5P)xhxKLmA;eAMzm4?%4HJKM*RYr
zjp%Cqnq`RS_c_<-|8_kkqHA^9iPD}#^k&X=x;vSTXp;_G#)z)h$C25HZqOCh=DQhV
zbb~(0Wp`qXZqRecY(zKem@UUKx>5g?Od@(W=O+Dy%i>_SX#aHSi;d_uJ<w$m(QW!T
zG8@qkbh%}S=);`bb-n8;5#6CLB$J5#k@G{nfy_p9r@qlLMs%0nLS`e1>7QDg?;b=H
z(~r39Cx|Gf+sJH0n|0<4>8Bl|&H4;7iRjCmyY(WM#lg1fi^yz5_vo8kCK27Ew~*P0
zex&cS3=!$zz4~?6QzF`~|41eg`GWtYKO?gd{aCA$q%U$jx+&*AolRyVx?lIOHeX*v
zbiXckSt%mAUk@U)5&cA8V#{%iexjculZdi|Kh-a}EDrXde$Oo@E5pNDpDe9EgCo#O
zVA*6gq8+-cWr(O-@Mn6G>nRcaTu&#Hh>C)b=!Il9qF?9+%NWrwbqkq|=uv%zwfROO
zqDS?$E;}9(J*sadvk^U}_t|oc=rLV(iu6+=IyU&Y9_O++*c19xGCM|Xda27KqBh+^
zW+Qr1ueS^l4GTV{?{_^VqMiC@WD?Ps;4b|<nT_aa{ibD%=o$S1nT_Z-`k&V3d)C~Z
z^BcY2WxqEuFwdzryK=AjS$!IropsOZACO5zCj_6<_qZ$$_JV%YEhl62qJGO|648tL
z12P-YOZp#{A)@KQ-|22MZF>^Y%eoJlM08s4_j)v$jp!9!X&EDWRnI1~5xu6Xtj)I@
z5xu6*bJ<=*^qO8yX2<At{kSd1F?wBlPir5eGlOsFT$jZQ&kVk)2awq@+O4O!Od{H?
zXOr28-qs5&Lqs*fcl711r$qEeeKnaxbbjzp`ff5C(YyKq%NS8y|C-E3v`4>SZN3AD
zXper?W$Bo8d-OYGHlp{m{DGVHmEk?zNG4+x3GUUaT^0v>UtdpVBl<u;=rW1u1O00<
z8_{3%vz8&EmBA17r>>_&^jG~gnM4!~ex$QzN$WPEk9AMW7}4K!DVdGv@A^1v^W|Va
z`nx{CW!(_b-}Q-PHlk1TjkX-e=o9@XGKuJl;6L<VT^0xXOdoK|$*lWaA2VC}@(fpo
z&vhx8jp$!`q-BU`Q}7FYj_WBAeW~lnB%)h`U+GK9Y(!t{?^(u(zR|ak*@*V*E!O5+
zhKTm-AG_=lM6_S;AhQwu+x^47c0c;Jo-s%IDG}Wj{BM1R%i>_)>Lp}$jI_DZWim$E
z+(Kp}GA3pjBHA8w%yX`%MC38QCzFUC2&S1oli7&8=5xy!QMz&FN?&Y5K9fzh!FL%V
z@|i-HZA3&qQ$%JX$}kPK9LFfb{G3c8dL-yKPq{1(mTBH_%gGpJnSZ%VBFZw(8Pd9q
zDBEOOhKQaF=9p1r_Pj1=jwh3do(<-jS!6b%JX38MBg!`sG8<9Iv{;*ODk2J*buK#%
z5rxb~G8<8WdDE6-L<OernbI?f=y$<FQ|7WbST{47%#KkHQ{ys;sE3J=*@$|YODsb~
zZv~Grn_W*Cqh4k^nM4#1_BKzD*@%kFZ!Kd)eazcrHln`f18eimM?`(iCoWrzi29nZ
z$ZSN#rgEOdU}s&ixrR(4`XJcP{J>>#umR>LWHzF(dC_GOQP{jqW+NJC_F0CAJ`I+b
zE@w##c8p3*h)g2-DmciLklBa^n=zI#qB1j$%tkcC%(gb)&#~4GF=xB%*I2!Wn8jo^
zqM_yiTaIHi)O<rG5q%pRX1w#IFY>+Gx4{vnJDH7Wlo{(XiD;CWMrI=#ZBDZc5oP2a
zXI8qNGDc&}S~7_!CwHv5naoBs&TO@e5sfzwli7$Sm|t6)?_)$X!TiQ$|3X9)%*$jp
zqT@}^v!&N|jE*<wl1W5`xf4yJ%i>_=W&@dxXtLSnGKpxid6>*bRAC;s3=#Fotu*hu
zo)Xa%^EWbyD4aXhm<7_hjcA(5A(MN6Lvl|vBNvM8&w90gOzw2EV3B2Vuj?dpHJQDy
zak9DgAa*;MoE>`A$z}`LIyDgAESzlKbJ=EfvF{Y~Ny1aBQ%y##w6I5);+dV9246>#
zU0e8wnQ3mdEW=y46D;Q1_J_ptN3Lyh;j^&qaBa8czGhA{&SG23A9DX>PB#HE+p}3F
zk8B;jcYY>qmYI}dn{B42*k+rH$?Vw9G3&@AgI+bqY$UUzImf(dJvl$;m_1}Nnv-+q
zn!mX$4tA!|b<#6CnrE2|m&s_JWeUk;G*8Z*Z;Gr9qgj=Ewi)7jYISbz0&^Uhe4lek
z?m4EM%*MCSoJeNlTWIc1u~nJ-QfyUb@%hphDYquK+BA{bXlu+GYr{Rq4Y@Vu3YR_W
zYy`WG%*MXRykpBT_C;nuz0@hO-;`TxhPx~dR%fP?+1SrBbuN?G&olD(fb0>WD))S|
z$}+@$S8l!8=6Xu(OU(UbG7k6TUSOUglbL*fZiA8czidQ5%Ux>TC9@GNGap$S?m0f5
zyUhI4Wq!|7VE-nw5k<_2OQaUNZ$`}ZWD?N}xy#L+E{lUTnuo}2M9t>+E|Z9w&AVhW
znpL?g%wH@+M6c&wWP%q+3$lKmn|rb8MkW!xlY5CNBa?{s=B_jo$YkIADECrxoy%7H
zKhJG3U%5>7%~mt8LF%;o=4w+)X6M9eGm^~C33=ZH-=z8kE3*Y}%Mk41mv>gGDYp=<
z_09sZ_6Z3-;Ssd@kAfoqE?=+|^%!L}R<`=b3dJgDScCLXG~IFqhoEMoMza1?`C0aA
z5Pa-Et-hwF0ve;PU|HJ-i>YN(<y4>V+M-tfyH@_s)&Ku}&F!O5kt3tFm17#>xc>)z
zV_943KP~$VXCwYp2U<U$n8mr5s<A#3*~)kC)!}n&Wy%cyuJyF%=j&{P9@-jG=V7XB
z=k@^XYg+vXaT)c_VbT4Sn(x}WR)<HCni(tK&wVg;k4X9$caPq~tXiLrt?iL^Y?Y^T
z+sEkOI{&ZU=Jx;Q;ppb!w~ov=J7fR1`-|+eww|p2#lC;&-Y2!$dj8X~e)lNFV(S@u
zlwz^<%sfi9*?P`9O10T~K0iu%v-J!(N`15S+<lb#X6t$ADAi``8FG|rv-M0mO10T~
zUgtUL|NH&g*7Lzps?F9DI7*S)dX70twb^=B9i`fAJ=Yzj+H5^@j#6#5p7W1VZML4B
zM`?!GdcHnNwb^<)JB~DPrIK?<c~8oonH`K;Ss#o4+vB6upIXoVACI{Wp04t)6W$~0
zhPSo5;Z5`Icvq)8<nDO)rU$SG<R17tcRlgj3q2wC#7i5!@&0xZ-jv4ME6{Gm8|X9e
zi!aOY7x5bL{`pq?TElAm3d3%^Z@ya%#_tQ1srT@X_n*~J^;b1a{T=UZe}?z7zfdF9
zH)@nRfSQax4sW85QGPvEW$AG$SC3Z(dV=b%k5|3)L{*|sP-VJY4cC+K8wHb9iK;*?
zm3S+83f>f+swU&NF;7(|s#$8fIs?7ANS&-M!!Jr~fc7f<Qp7dtG<Cf?9Z%)XQa@0$
z)t&fdiM!QYbq~D%OP#5Hf;WX9QfH~3<E_?5@h<QaYJqwRzqR=c-u8VSf5Gr2Rjpo8
zi_`$UNc|q$zSzEq?Q^OQ9`%rx;62?7fEh}jN(urcuUUD1-071y%7zgU9b~-G51dXs
zop=@zzZU>~J@G<d2>F(JHUWF!U09K~6MqTpqdufOR%hjHRcnC{noW8l?iSvr<t|~R
zslnaB+jRE=(bV8>;K}9-+y&gMzrfwU?eO>FUZ3D*)h{E**+Y4c`kwC?r`gDx8X^yL
zp5%Kr%|_mxYBus-)G9N-V6OP!8UI!07rw>LW)&}70#B*!Ez}%R>kaOnIUnk8@-{dd
z&A5Us&ZqkCIXfH;>m$yMtl>tMy%BZ3=G;O5t<-O&ek=9&QNM$@3s~lnI!AeaYu+rJ
z<@r=!mp#w(q~7dX2+g>HMp*ZI)_7in=MA2(8ROSFkiQL@a|?EwcUb>Btp6R>KTt>V
zAI7tNk7hptT$%s4XBaiZ^kw-w@x;C4VI$v&dXnFxZ3I?8BkzC-;ukWEynn0BcHf7d
zeQb9hvzK9hoBcU7@}_`fazA8w!havy%>zpIK4*VEXMa9tfBtRciSK_KdD8oH*8e&C
z@HzYNIa?R~s~-HoQrA<`E@X_|fJ@Tu!@cQBXx=QmFm1Y4X&0sSF(=~v#V7S+q1Lp4
z=vxSH@$2mMu>K+Ry)=&_&zcW2{_H!`x}ofrv`k0dFU@r1jnhm=?osDES$S`#1@&+6
z=3`Gs-X-3F3{Rl{0m#zg4nD;_h}Mztzri!oIS%g!j&y?AJ55l3t4DgJ{xRO5uGPm=
zo&@<lJ(cnd$X{mFP_BdQH%lllgS<>X?~$_Dr}W?S!<3t#ADwXteO5tE&sa<Oa_<DR
zuGIub-hG|m$lI`E&83Bpdn+Az^Z8^)-gd5Z@U$`XZx+4_dA0v<K>NJxU-I^|o^75<
zW|YCBedf08bfC%al0JuJ$C~dI9+SSnk@>&Ck(s~1k=eVLn#I&Cre->_?NtrbH&EX|
zeKR%9)HGAGikel_tfFQ;HS4KaPt8X3c|zKaz_-)SLd`j9BYIv5jXcSmiKxB!wcmI1
z>LAN|!kO43FZSKRu^VgRq3`)7IP%VLjd{UyKV*4lc!DGE3{P<64dDrnydgZnkvEF#
z+4BjGyhS|0k?#$5a31d9Jlw%~xP$Xh^sjpUZ6td)GKX8)^R4XpR`&cpYVM=vK5BL_
zmL2SW7LE~JGqP}G7z~`FP6p0X7XTNi?*XgTHsE6QDDZssJ79x)6Sy3|mXoEL)dAoo
zs)s*Itx{uvQFVgfhhH$53cOC81iXXty^zyXjy?^TuV(?f>N&uk`V3%^o(Jrw=L5rf
z0dSCB2pp=bfg|-I;26CaI6<EaEZ64)EA<lKiMj!JvR(!}O)m$|(T%`)x*51YUj#hS
zNV_MSS^oYwx(>zLn<Z*V*D}15J2$TkzuB@7*h94fi`52Tsd@=GLcIqZuRZ}*sIP%1
zsk8ITaP&GKc(#fGYt@6m3)IW`BUp0<ej7R`RDt7pPN<f0tt+>vxuGWbghI{0-hs8W
zu5(fR*Qpk@DzurJEiQ_F3-nt;Pg1iJ$NNxdC)?Ty{qvC5!RJ+K_Rwc9e0m4=QnMF6
z@z7rSe2%k;{sE<>hnnbU@pQE0#L+D(y};2@TM?~&h{g0NrcW_^jwvXnPe1*Ac#eQR
z6e_3ZBw_{qE9hSV|9Gf^{?q9>oBCSlD+_9=Z=${#*gFtq4eRs`>VkrGwBA7f&D3u}
zspf($)Nf_$53_6=txpnn!sn`jo%DH?W#iQEq30gTd*Sn7!Ctnqm!2Q$?rKIz8_A4g
zTGVd}93y#1!yDE^0~yrkK@NqADEA>28_8ZVeTq@)`A{)S^)r&0{?v~kmeYR{v4W*4
zsINe&KNeK5)D&v)Z5PVc5NqjKOMNXpYw1}>O%pH_T5F`|Yw5oZKAysL^jXh7tf%#I
z;OM{&EVYGoZgJ%nRa&@({#)s}jrxa)ZLD)A>YRnM7|F)d)V~T0h4w<fvTz?tozV54
z)H@F6k|P=OIHFGjP6`w|x1(%7Y6d#oJE*CoW(xhMQ(sGc9X0DHucy!D)LaSd9k`O7
zG2&KO`v<nsx}DbT)VHB0p->y;ovddUJ)fp$oYpw4due^2`VU#dhtxYB>2n$`aE1no
zJsf3MUZOFwlm`NP2L^g1qH<ydJu7If@QCLW%C(*?DppuaYb`Z(#Cn!mNBuf#E+@vQ
z-$MNsYPPUH+bD0RwT-xwK2KA>m-1d$me${={2@J^v@Pn9LMKf!<D_+0L%KR?;**xf
z7@_YS=nwtLfq~E<t~AC)te|xYt<}`jrb&M4pcx&gr++>5>*%?Tb*`h&<@DJ?c^hlk
zPXF!nZzJwxshupflb%mgj?=oA*1gp1rS*Nv9|C&^KBNzRb`Sk=yqtkviOBJC1SuEM
z+J{(7pJM8Z>C>O`Kp>)~PdTxIo)xrK&~pmqYFcX`heEaVsinS_K6RAqfxQFu^o+tM
z6pB(_NB?#7Sx5iNDaUBt%u-wEvxWLC^x5W>Ja4CUJ3ZToJL$QTo;&IJH03z0d+5KH
zK6|O(OP}{Ce@N?x^mNjhw{+$$oq40&Ctc=4F|Eba6w}(D@<1Rmmd-tzJ{8ng&}Rze
z8rD!tYb`akwAN9s2O>+XAqt;RXdOM*(YlVFms8$C{T5f29&V$&9oRdtoi#j3+)2-!
zwC-dLPgCAQ>t0&-QnQ!V_bGn}#9X3}<6|~_%!ZHIpxnnNqfkt1F*U`s_NP1$h-~<{
z*U+cJMX9HPo>S;qOMR^?OZ|0}>sdoRYlsrp(Q_TG>sZ6(lw-7Rp}d9qZIrhIkquhg
zh&!p@NuQ@F$En|onz4pc^FHxIATmI!%HZCV!L=eo`kzKDqQ01NafbA~KjjJ+MKgtR
zEy@lJ)MapefCi(?vg>HQoOmVmS5hBiTU&s=16yd_M%+owPRdUcp9A&|JjYUdY28cx
z`$PvnuZrFhi;4Y-6~rmTYQMBnOSz61^-H|#C|~ZEKF6rpLQNaxos{F0_fl2?DW!=H
zetTtTponrGVlg$7C|6Lfp<GLOE#-BTWBApPP-rtXTc~-G@=nUTfV~5IsM$-6#;*uq
zt;>`QJDHO6KGYNw%c1Wbm_)gPSWT=U))J${wZwJA7;!UkOQsyHwxFI+XiKKVwIx%I
z6m7IVN!&?{6Za7J5>*%Ggy?jU9`>PJ+(qh{M7e@;4dq(+U@WMq#hd9lp(r$12WTzI
z5^H&u)LBi85@W<RVw_l>EuK+gEL;5Bh;gFI5ls=XUyelAFGtQ#%BiV=d~#qh^@}0*
z4@7gMHaxuuY$L|$xhF@Wz;DN*HXRh%6O?+2sOdvZKWfUUnM6$`HPzHCrW~cbnbxh;
zv;`&hC#l&5P5;0i%KIpn=ZbZ0uCyB?ZYDmND}C4p424u4V<h&;6McD}WU`!^YRc7=
zqr@0BG0JVkI5ly~Dxb9xEA!>dp)w!mnO&pQtfyu@H1oU0sM(6Yf`VL8R=CPRwu$A$
zYGRZa!_OCmLNUs1#5hqEuoSUhfz(!BAfA<!w*o^UPoZFWA!kLQ_*X*HJ5Wu{V#+bf
zF<RRww^5E0Radq`EGJeIqr@1o&FZ_el^%jceSWNZgx2?$nX|sXjLz2njJH2$NPnp_
zPE-R}{{WVvTu!;1ay2nZj1k+2aiThwWr_Wc<t#l`+A61}@>oVnId-hnAEVqxj1yH@
z^eW7HC>K#KCsq@q#2B%S7$>TMEJZ9Q?iwiLzH6Y2^1gx6dbC99kCupMjMzquQy-_S
zO4)}})<!HRRudPON}Y>KrOqfdF=87rPE><fmRL=U5@W<RVw@;HaD|yaSo}SMrDo4y
zskw;yBI?VD)znl|j#7?Nj!}+LZX?Ets!ZxECsq@q#29gFnY6XFOxkLrCSE2ziBncX
z*sCFof>=&XIpu1~)s&-@qm*OBHe#GuG?aZHRt}XGD~C#p)zmB=$`PR)Beo5dcH1b&
zDaR?RVeH8;u@+G-r(90CnsPPeC^1HCBkmg}?d}^U?W*A%+2K-~XSlRpM7f+;O=~sf
zDCH>S7_p5QC#n(b53!tBO^g!PkB}DEkB}B))NCCgZN*1O>v3w-NY+3sA1V5B%GH#s
zDMyJhVjD3|RHImy*l(1y)o+xvRZdOiC~2#ja+KIMO6qT;94D&LtYNh1izt^<E~i{g
zj1ptSHsY?)($=og(pH?BeWRr<bsTFWmJ_RqvE!uv809u%oT$c#UX5WX%0-mRiPgl#
zW2CLcW2CJpHS5PnTQSOQ#5hrnWj(}lVsxz3AEg{4wh`mh$0@6E?87)I>lr6)dB#aw
zMbz{gCvBBet|mr_F=87rPE_OBI<b1Z)LBhAN{kV=j+gqkj+gq|=+j31uJO`JoSHZ_
zY65E`mJ_RqQDThPMvN2H@#0^8ytG?Rx$<~vtMYhhtD2g{$4e_w$}xJzD7R5=qZ}uy
ziEN!%POK(Ii7{duF;3h!QQF!!QQGpHAgvUgAU!EMfxRMD6Qk5eDaR<sD7O*gL{-k#
ziRHv<VwAYPT-sV+E^WoA*;+0wwoz7-IGU4K1F@V~O?@@xDCH>S7_p5QC#uOTOYApU
z+Uhr1+A61}a<a5lO*u-85#y7k-8f}c!5WC=6&w-D)s(9#M~N|F8*x{Kw6&{3+KN-N
zuR_{Vm8^|ePOK(IiEWiqe;egEQB9%$6wwz^E~i{hxth3minO(OinJA_X8jatD@M7E
z7$>T!tc_SstR}{$O8qg)ZNxZHO%uJECZ#;nq!rIJX{CtzBI^51leWq!R}-Ve7_p5Q
zC#n<KI<cG>JyGh9QjQU~o+zzsJyBX|qh{BMQh%JDacb0b_G&t7BbF1ZiBV#V*hY*K
z_f6*+@(ji@L*ydL{U}$@kUFcWi4tSPHtO3b$0^4ttCQF|v7A_WlAIS+o+M}8)zn0Z
z>#1K4eg8m=nyn{EL~WGgM0K*%R(`Vdp`3CxF-nY4AEVqxxs7t1s7_%|h~>n}Q`nPJ
zq{V7#7M~(5Mk&XLZNxaS=u~O9=v4NBSWS#lAEg|l9HZPuj1%{rDsAmMRoYTBr3TMT
zX{(5GIkB1;CB}$t#Q02(<7sT27$e3{`v~=@(*?_k)x;<<Mr^bCSyHxomb4qA9HZPu
zxs7t1sAe-u#ByRaF-nXP+lb|Jq|T^|ta*-L8!=9OoU)qB{?BF2#ByRaF-nXP+lX<Z
zI)nbi>ND7X%28sB*hYOD<v8UyWpyUY63dCz#3(UFY$L{rYM%JZvnUErY1nOlcU$Ui
z2f5q9?zYU`4so|b-R&@UJKWulaJM7f?I?FU+T9-KZpXOWvF>)9yB+Ut<;QTOfAT{#
zvXvi*k*)lUi)_o??Id?Q+1*yS+e&vk#ofw}HAuPX?skT|t#-E;sIE?<v(tIbdB^#}
z@p-y?7JF{<3`i?Uo1a#dwkPfDw4is0ccyo?_iXP^yhGB*r%y{iC4E8q1?kcBo6>)k
zzAybO--Eti;FpJA^}Xl&+~;I?(O$Z8ln;L;A_Gs%_#p)$<>EWMJe8?J{7Vn`s|e6`
zho%QKJ@J<yilONTO&DyNItEXu^v07Zeeh&TF`i86k0(=(#gi!m@nlM=nuTX&X5%@T
zIe1oNt{Q<SQ%2#*l;iMy=vX|NGG5I`{?10u7U21jbMTGeLOlCYg<2OO4|Vu%upTup
z;a^01)^`BUo8Ocp`27q)e5Ia;zm`EcLJZ}kLsJ+E03Y;-Pc$U>n|#sq&K9eccNB`g
zFq8w$Ga;!bni~R6AVzb$Q5Nh>Z%bKR>FEW}RLyUl;)Ev4GcX~)>kLWAV?84h^2`+Z
zJkPj<{&S~1ArJ5*<-1e#52eUMQshY~^6Ms9_Jb5Tkm7Spio7aCzAi<clOms=BJWJ8
z^J~gKDv+GKTQDWjf197*I@1%HEYHk5gIVV&gL#*R`RE54%)NAA7Ia2sV>TMhz%IaC
zFpZg*4Y>e1gV~n{?1h=BF$+VG`(lO~%))L!{K`JC1YQPnu{W>`^VHx8t771Icp1#G
zV}U1Qz8cKLQs4s2S%X<O1b6}Ft-)XG7y;ahxohy(7>+|*_W+H06tft0>hZuKc&ba|
z+x6oiACD)y@HfNoT$ffS01duBuK>=~Q=mBmXjHA923)MCLsJJd_=_+n0h{zG&@=-L
zo`0GNyiA`C%{rh_*Xh~7O?oag*8`2ZOP>jh>9e5O3^eK|`fT7&^*PWy05s}Xx(fJ&
zu7T#)K%;)EYk@D~1x5KC^*YFJ>+^u`=z3`W2sG-i`U2obdMPv?1C9DxM}Xhx3!&K$
z#Mqf8V1`)%jUOm~_4#68SF;kDZa|EJX#pN<TA>L8jT&Xv07sj(&>RQE`y==^)Tk-u
za%iRkjhbz)0M0R2LNga=)FOQUioBVtp;-(x>OylZu+eOSrU_`&RptiZMspMJ26GE=
ztGNxh&D;*3dw@ngY<>vbVeW$FXTU}HOHYG=xoJay`S`m6i&R0{2w>N=QNZqL#{qk$
zjm1nEju9{Cb9r+yPiiqs8u2{aTKwhe>(%Xe>h4kX6rQbnMZK*)QvX!@m7_CtS6!qB
z>Uw>lUa8mWEA=LQo8GLq>j(8O^^^KJ{d@hE-lOpg4Ek%WO@;}Y?xwFPF~^ySW(uBf
zn{DQsMfj^H7n)1V8neM%V{SG-G+WJM=C@{_`J4Hd`M1e%PH`@F?r>go_Belc_B&lX
z#hwA4lRV$|{MhqH&sUyaX~Wa5O}jVkcWHk~`y%Za@3G#iyf=EE_2#9|PG6LMd-~n!
z_oe?V{h9RNrLXoq?|aMlk<Syg$0Hnm+<y<^=~H>*q5WTW#<h5_5Pxe6`(Fk2u1Zye
z)w>U#T<nVs72~*2j8$BoqdXRSSs43R7{`b(R`W295n&u7!Z=2Raf}G#7!k%XB8+21
z7{`b(juBxTBf>aFgmH`rW6umD-(egh!Z=2Raf}G#IhwGl!5+H^$B<gIycjLlp~Z92
z;(4&14_1%Q5_~ServZq+`i19m{5ZGBNB{1@ds6cExUMszKZ9Ej+8v%Ne`RN$x}N&^
zE}u`X)TMYDLhP5SyJ1&&O2_h5F2Bs>myvhHjF9@}9aHPK%hiAC>X&M<=io1yTfbZM
z!$z`vi_34r_8fJKbB_8DAIEc!3VBwlsh)L^|AEgs@PFX*WA%yW_i9esk6~-jpMYn2
zM_@Z1pHuL;QIAS*z~@Fi3EN57&Pi+Fr^<Jw-r^fiIU_?OYxp}1I4jtO&r+Nj?8bV$
z6zlYEtk1i#I`78Xyc?_VHhh+19o~(Vc_}iw6)W%?Sbw)lxHy<rG(?uwP3)&8OsuV{
zs;qBX-cYl$qM@d#Y50h$q0o-4s-iHhu6a_!d3B2#YwBy~tXy6<agl2{w45z=NM$2g
z*CEPLqU@;NM7zT}wvVWSVOCwu;)#o^AfCFSp`m6`LtXVSHN7ITba_o<JDaj>#nQSY
zyKqHKbGu23pV?U7ET!huoOfQ`VsQo$!^~w3D`zjSStd13L8*rN=9RYQx<=}3z0DC}
zC)YPMV^g`PBC@Qx?h=uwju@_{<1-f@sc-J|WzDW=r3tl>70a3@j;g8}uBNV7R$Dz>
zrSx^UI-{mxMcteg%Mp}IW-f28k1PY5Rd;SeX4Avfq{haYl`u`Hml{W?siQ}#>G;gW
zr@eVsMDt=ChCkARPrK0-VT3e&_$XKfQhEXPu;F7+2yk9qbJg5AQ^%<3P>f0S8Y2@%
zO*kd8ctu0qM1>UA)-~5Jt*e}zDwj>3J!#IVXnc92m1eJOYOY&aHhm`c^Xbc$)iusK
zQ`NiMDGhZ?>y|Y`Q<spW14wa|YHAlmgM?cR1$MGsgK?;0w~-mQln5-<u0g`A23fN{
z6zDT-v|F<Xthrr-EV}g|VXhM;dL?v{PS+0^Y_CitTU)zM^6UDwd$s$xd@i;Z$?T}I
zeshpsTc4GrK1>m-q97XkXA`ZmT^2n?ysi<|xjjlSu}zLdT)mZ8&x)mPB_fFCv_=ee
zZL`%Th*&r)t=<(yTe*m%hK)?9+0Ba=aZ*vh8l>F0P!VZpsH>GJ-&8iO4pXAOmd#bx
z*POR3($rjEi=T#AoJyqfiWQBGm@KE%EUUo|J?H#J?0fK=FtMSks(x90bA3%iLMd}!
zO>e5KJGXvW-D1VvylL*Ti_mJMvHnu1CdeF{ctKUw<eJ(G@K-0N*4H&aE7R+6txU1Q
zwKCrh*UD5oTr1P<a4mM#4zx1uI`EZQcDS08?{Kx`za#IC)zdrl?MTUaczAO%7Z2CE
zlkspvVrCw0;&eP*JsVT<aBcgPJltX@<>C6uMIGo;X4>J_Q|g+UFyT5fG@l<?d}__o
z4s28FYMNIx)^%(=4acyhb=WsMHcwtr->|r@k;mb~=I5+B)Vqvp_u)O7-eeCRH4TT`
z<~DYqJf&{wqPoVW!@Vapo`-|$vgQs<sAy`WacNES;iYD;T-N;mw0Cx~aUItkpS#>I
zlF~}MvYI$0)h&`1Dq@k8tT=R`IHpC(VybUaw%Qt?mb;hSwN|_9-K9h|3c3p@fKoU>
z0?0rVxPS^cs0uhhQnU|EYalNH@{j;U--5P}eQ+Ndq$to26m@_9nYnu}Dalrwr=nSj
z_spDg=IhLvbI!dpcek?j5PqT430pPO3j4i&rB$nRYi6a5O^}ml;zZ1GmU2H_YKctt
z<*<LM(yJeD*FtL+{0x|DZYGj(03Li41(+~SE-Bb)_Y@CUKe*W5v`PFjCRL(6MNc5o
zmU1V%?Q0$*)3J;}fVgCxwC#hY%6BH3b^0?(%04CL+^om*Z%b{Pa-$$-qyVO+s<o~j
zcB3;FU5C}pZ2_98B*Qh+Yr8>tcg=uos|igqYq3@#kqyEcr(&ir?#M~UVw-WvP*pZ+
zOpiHHYhXNI>b7rKxi0sGJoduj)m7$=<PysrXR+C>G$lhDf0>0|4;^dXJQMaS)KXdK
z^Bccwo2m}gtJT6<j8PEQXog)c$cy0{n~m<H7_85r$wb)`Th-=f&Ca9r=6L%$q2Wdt
zS3XKz(rO;%%wo8<xv?QdiE&ZP8Dn;gJtjosTWR!@H7p_B3evJdI#a3EaYJz-X<VGU
z)aq5+ov?-tjgc#rE;@BmdUB)Py&4lvY<2LLTAP(-jCBk7Y`d?n$7naWuzRY3q+2n5
z8~dyEBq<uuNoL{|Yy(a@E*BA(TI<#XK&&($;yPZzy>}xMLWjF7+->#vsqLL^S1Sqw
z9&Ukfd%dxNE<KvO81|~&hK-uzvXR2L(Z%>U-0%w`CRs<+X*Z=z&RaPv(2ZGKyu0KA
z3_^zli5Xk2tcU%Z7m0{_aS>}ad~7Sjksw7QKi>_nH^LiU)e{VE5!hj044aiLn@Z4^
zv7*}tnjl8=<NadXqlj?4-MQIqY}ETPY58iSqj_ldG{zYJc+q&@5VJ<>#or^v1SeAG
z7GkV5hSovHxFrVVZp~s`+-Yw6S~p{Yw~F?rt>0K{=ngJHl>vY0CMHHz+QdrR0$FM6
zI<0j~xKh)N-KwSGe;ng=MdL)0XTuF<;yRWR6`<mEv$`sO!`-Dh+2nGfRc+UB8<8pX
zeVp;DLlikZ{lK}bxlf&GRJ-k7SZ%jzJ)BN8Jke=a>*i9cvE@_UhH0<8PW3(FiRI1p
z^+vV9;y<w!RyVaaurSrD29<AjZ=R`id-Y1w5aMn$SebSxaZq4m^F%gr2RCD9TScPK
zjC(Y9_Ye(8(&lLb0XX)xX)g5}&Br^enOd`HE?;XJg>$wWgblWRLDySE5LT}F>di&`
zar>H)BQ^wk_Kw+lbT^As6INQL-C2E^Qu1AOmpzSbvFWAW=|&$Te4@pjL(9ma>Mq~-
z2{1KpOrr5HhyEtSoT*$5UF2jiq05_{PP>aiz^8=P#BdMp!l84U{d4Q|bR&#u%QqVR
zYCX1cF=eTR_B3keFxYk#$CRkP81sc*yJf6Gcf*yoBt&2)GaGgHbffhK0STVNdGBte
zi`L4ID|OBCo0pjN?oFwE*u^zJySj?7ly>Uo&0iD?z`mjB-hiRquXDBc=We=)*}7&G
zQ2?}f?0WSb1Y;YrF1~AS=t+xkeGI_$5YcsQ9jDtjR7cZ-C{V*GMnj72^5`~jCSt=M
zAM+OU1@001KFoVe=|rg=%nRIRUY92}GrINTYC)tOdQ4%KtMyRNG#2_cyNG&;er|o8
zM-Yy~J;OMw2TqM@FB(96zuL1}YVRR?#)`$KlM6g57MTXS)Y_e8Zqggoa8zqVmar8L
zjp)vsV?eY5d$J<dxs1$Q4-2EI;uqO^4#MIRXL)qxQfrnWve+_RJ*O$hUO2kC+OIc8
z{YZ>%Mlsa_=HX@!x*Jn_y}up3fpuMJRIk!}t>zM1%`WBcz#|DHX5MOwQ+El`g?v%|
zJm#_=Wt@(~<YMAeVH4f7jVZpM>^fRb017G!GF=qaBZlo_6QHP%(c<fwN_3Z#Pyrq|
z+DUfzIOgTeM$IQ9z3^FU4|{07&#UUuy-{T9JWbl`lab~nvU(utvuY!eRh?FH_7P=^
zrC#kb$>-Ky=Rt;9=AjwDJ9{Eo+z93X5j;Z9qm{)fn7J6D*(Ms0Q*_e|*Zal>2Qsru
z*E&sHO&{NPVv7~c<SRaqYwBAu@@%ED+3ZUVt*boOjWB4RH7sUfV*?Y#ko-!<s9$e%
z+bu<}BjG=)ul}J>vd^(K@XvuBRW7mv8smqseQ5QP`G=HEHj!jK_QH|X)v9|$g&{{r
zxms(;gy~VPIm11P)?w7~6{WB9X!#WaLDRiqrRriO)3bNdlspw~q1hW;wS27+2J0ZR
z6e)+Du@<YxKFu~uMEiYohMTMoSAF)cuvfFezmR>J6MV16COZZuS2kZ{*T~E+u#dK3
zaUrxmxNGEkHnm2XGNsGx?Ho2o3@0-tuaj@W!B?C<aoHp6-*U?13HdKYZ9Or+uYc^2
z2?Dc!nLR1(K-K7F6S%-w%)Ui-tB#wt9b?E_-r)EZ)iuWUIsWvPP@9o6s&Rr1xJdo-
z0_7#QHDpv_Z>GwV?3=tT4(+#I8OcGCoHJjdmIiVwQ+m@%ug!i~*_LeCT0{{>a@HKE
z++oU@kFBz+R-wN&xI^mbkzY0DX<Zv&-OMzo^`@hYuYk9`%{)UrrWoZ{$=UG~m;6Y(
zXqslsJiQY$;>}&8g>_^0I2hxXZ9mN(2S@ll=jmtL%C{;xer$Vw#5XD3lH^dteQ|n3
z-@Q!fE+dhAG;eWk#54X9Ew$DEVw4)uGE36P-MYrOOBSc=2$z%gqJMiFjPcSm;T??e
zOPo45V)+GQyw1@G?_i8yq83gyQNLh}zvS@_j_~87)x<2hbrsV_+Fy)PF>Q&~?MkAY
zOU1NHBU+Ri(Q+q!za32CUB6Fm?>9fb((+m(?JF}cvLI!T)7qET^;u<3<7F)>{K;DM
zz-k3FZAoWAHmOgVU9l^(!g|uW<lNYyGt^Lp)}~xYN-M8Mdf94472FBdTicd1Pd|>^
zOh0PPOPf2?ZN|^ivRy5h!;jzj-B0Zq7G8QU?Ec5~^RM1B>2eU{$I2$ikSG?FEo926
zpuiQx348tRiT$N8*k8I5>@!&<i#5QP93WSBIRSD_mlGh@ak)-ze`)X_C~i6IEuR&H
zX)wq;a-6swVeY64(}g{1et&WBN2%iAt>WOGEm#`7>ELk6!?G&|Az9#dad5{o-1YDs
z4<Gmf!@HB}3f=e`ql7s4lVCa%b>i*M`{uu!&rcTzZ|ko#xL@4TKYI1uyh}z`P=B6{
zGJ>wP!F}KAoQFp}ocHjUhc9}#=;0|3PkVUY!xaxNd-$4%S3InFSog5$p{64YO2fW~
zzJJ48k@(b6=IcP<Am{RIo^gHMDFMV3a|y^ekaJ+%fk{`cs0KCfQUhSxfvf|02PQm^
zIxAl35pb6SyM4>0!F#kUWhh-hVN+uM0hn}|vsfUc0hVRFY&<DbHl@Lj-H@i;q&{F$
zUA=`-y+3gyl6L0|wHF8fkj@3AH)yN$hSovKr^jffu*alQZYj9yICPg%2i~VV=T&UV
z_N{b*3i7Hsl`35*U7+S711%1Irscy*+Y{vX?hT~cKMOMUdcdS7?Ao%Zy+*Vz(>Y7r
zXHwbJWO>XXGpSUD3J1fnTri<=y&p{G$|(*O(l`X>-L_O$jZy*_icL|N7)xo2Vln81
z#dL(}<a1FA2aE_`4i1>CR^mS6yZdF^UEwJJ(K2O_IV>3y6sAe13WdV%+*t8e@fPH-
z2gO^vM#F(^l7VxGPPJ#$h!`}(P;#khNh88cL${spFb5OqEJlFdaOEqy0QV+9=doU?
zDdxkQDwWV;9?R09y#dFC=qOnZ7$G1#yHiCwo0iRUPuTe!S%LReA{XRyxpW?TkQt{_
z-$@mULxM<1rNLM7Ok!#9RZJsoOdl{A#5Z^w86Pkcxv|pVFCe0HQrzKgw3W2gg{iC=
zD-@=t=(#XcXo_U;F10cyJA;_zDVbyqes~+4T@&9<m4<UzA1xn?&7-J;`yer4gNQ0C
zKK1czF13$xuGiEVAPhzy&^<0xo$`eT-;i+79*9=%uF#)Jl`sNs-Ai${=x<IXb0o%<
z7$-5Q#3X{6%;m7qKPon@Uj7JDTBJ0ItP=L3+1jPtE)vKj2zHM%mOHjF_4QwD3XP7E
z=`4~)lNg{Dy*ef3(b|3wL95Ka*)qGzvf(lnDgX;J;+b~4iSlITU-M~9Y51$8t-69K
zP}MMPt14<)mIgnOin?a(nEu*M@NLqi;hQ#n$ELq#sc)%EEV98{HhVA1-g_#C(#jFx
zn@YpGrQtiJ;RBFphx2F_IaL~#ZEfFht2vKcs80UI)x<>mm9Ul1rR0N#&*T~Xy8($w
zD+YLr!-LE#D-0pLo;&!k&r15H?P=-O@Mvi`Um6}O4PPt`7fZuarQzw)@O){wQW{<^
z4PPq_uat(h(y(3{HcP_}exx+qDh+RqI|<7GNIGvL9eRj1PZvrTtbO`6OK0%5UAk{0
zYN@LbpV%v-s;P9dXC?ma)B(P*Fgsy6QrSEUH=oUo<@W{oNvu<(FILVrT#(o`F9<mj
z`yB~sc(*vb9|`GxA(!?OVW+_M^gHV5@NWJ`U)=Y>j}QI*g{R!jfD6hu3BdY<We0?O
zgXped<GC8A3PU0*MR{G3b%S-y25dc86cC;S!&6Ed9!@R#DDfOoUX#0mM-ro3nI!S4
z=)QFu@@3l*9X^cP$bW%;D2n{VS$p%Mjw!@U@=RzHy06<ZQ&DS=>{3KrW=Iw4OjeS;
zWNXe|W^hfD<{R<lhjnr@z@!9YK|06;*#Ns4j0Y3JB*#&A2L*iH-k=zif_?m^aVC}J
ze_<?(JI_u7r>9a`zU-yg<gX(Oe^-nCzEc0G%MW$A$7T4gH4M%QD?iZXnM_uzgu+|I
zAbvrp$lqZ!WgXnI5Nlo)e?uu-`)zUE85I(4_>?Xm&oCat7in_-)SXHN!N(&KG%-vD
zaxL(|BgbC4P>{8^;dH7XOlsPK!Zb$ROi$$%s3_`?sh*St%}-&8^27%?h+?f+%iyWF
zmJJ@Bbg`C)4h9#G)5dK>Y1$%nTclpB+ah(#rfVKYugYMyILF<wxK6QSaUC32P{46v
zhl@?VRSa>-?@njZ+<4xyyf|>nYu$5^@+`8!bY@(24+i{aNh>8cC)=kk%R{sNzv94G
z9qFDW-OCeb4c>$&O7Qz21W1@h{#y@xMcs&^eaebhbQ0T6P(}FSUzwAiv$3C?K5ks5
zL`gNw3m1xurZWT*G$hD)@aV-k`Q<rliJV)Na0@7&?b&@2u4hWU6!+|Zdn4dRa(`ho
zlAog@8P_~>cR*%-91}X7k;Tk`QcAAS`E9vEMun^K2-l0RXs94lWHa#itYVd1oXwFP
zkF(=sC*v&PCQ3uzhe7BYh)x30p+Gt=kR~f<?i<UJ&Bxh1*@-wip~`CHquNn@0@(zj
zPJvx<fn8*G$JyPmPitttyp6+{+^F?}3m0?;05X!1e7^LBU?(ohJsgNz3B)a2EGiGi
z`#mxibvuc=ZBcmrnClKG)D`Wwsx`#vPtk82l>q8EMN`3Etq#xVR>!bRbl?~TU@Uva
zdobF?6E#A{w#!{=gmQkDcJr=P-29xYOhAi324HVqRmzfPu~7ixY0B7?R;WUQqpp|$
z#g5WYus3EPaF}-t0x-<8<fW;$qG&xSxH#t61YkR6#{%8jp)J`qiClu(ay=#(dC?US
zpoj%~BQk-?q9Y4HUUbEXUQRi@0Qgf5Pe^mx;RV2-c6j2P^A0Zn{=CBz{H!><0QeP$
zCnCD+@B-j3J3L|1YYr~}{xyducDmy50^qMWJONeB;RV3g9G)mkT8``mz}Fp~(5vb2
z0^pktPdwIfcmePohbKtuJG=n+zQYr_Z8^LEcrWf-M05@>0A32u{KP6Xn#{WjUSs1Z
zv#n6qmA<>(Y<mLr-Bq;;+2k#>PVAz%?RxbN5wa^U0QWmy*KfO0JQt$WXer%sr5+Ge
zyHWy_df-cmQJowu2Qp&^`5BFah5+QCNs*XVZhDH`BnjN>L2fiMq;P1u-h-0Q!osou
z!RW=d1$N5PZ`<pge84*k`W#UBu#)<vSG$$Y*>-ER?ag^zPLmNE*|@@(mw9Dr=In_T
z4mH?wg3tKP`_ElJGIN+33QvtrMESQFv;$gHk#ba~3@cyPTj1S?>Q$YcDxa>b^^DoY
z%a)v|2`jyjXMy~B&XKtzJguz+=Czf2SWX;<DBFYUWxvl@Zm<((kE!>{3+I=5<@I*g
zbM)8^X2a$8?C$<7d$P%VxzQ>g|0GX0)$rk&IsG%{vw=BcGl#m>!=J7^S9z{_bbW4q
zy*B^+TsXHD&Q~i(s-LMm|9rK&_Sx{+%F)XF;VKWOxuc#;bkU0R=>)<ZyC0nw<gGWe
zo2~0M8<ZRjVPEo@dcWW4{pRfKMx$TfT$`!3ugz8?5%GpaZ#GdIL9F6Cf;_^xnZW!;
zg63QD8}jVaUpeyW#QPdiOc+q|*8_8#SAO&s+3tlV=K#*IVc0;LAjX$koH$_nv?jLG
zPdyPEb$(=R`vdcV{n4zQZAceCsw))Ul~#niv+xJM|ER*jPPSc7&_T4_2G54ZUWEVQ
z#@>Yf1U=P&b`++{f66|DMZn+p9ZQIP=cEL%l|9=>OxM7^iMF$XhlKY1Cy+RePJMLW
z3@?0X^3&Qr&)b6&oUJkDM!>sm#*DG~KgOw{oZk!2*bUOGJN1&*8Kl(GeCpEt7zggh
zI9@--G5;|R^^b8_e~hE~X&skO>-~(hUXV%aQ2iJ$2#j&W|AU7=?D6Q$ZGE`Q6Yw`e
z>Y^v{qMjr9yuBe5E7LzI=sy2A{qKKif-~n;@=y6AiZ%Iv_C$bc=XG5>%I`t@UV<hr
z-Eby97nc{8|MsW9b2$I6@4o!agAe}dxvSs$iRzfGb3}L+>sOnVO^lcRA#6aUS+6CR
zKgTXOGZW5sI5gd;&Q>|T6!vD<8l0?ZZS)RRIb_!D%vviMS)5r8sm*%xI-5A@jWJHv
zyxmOAba+8z`P2f^Hont;{0ZM_3FZ&K_02c_;PWrG?<|e~V7zDrZO8garOU}-$LakE
zK4Vsox4VnY=9x;PWv+3|wi|}_XqxB$;Mb^TrwHS^{?DfLcBI~@G=uF!aFz!*^blTr
zr}(>E=2!o)fYGO(#z&f0%rg6#udoYuk<=1zkDevJ#PuX;ecns|^uL_8M$_b=zKua2
zRVf`$eiq5_Ha5>xy42IKyMfwsT<6J+KA*CsR-o#sOAoqs7da0}&V9a<{-GXX)2DdP
z_~Dw~u{?9^&bxm{c~XT8%-`@fE5ATVeb@NscGn3M*xlE;fikt~d5?A<)v7oadDphg
z-!i8ORv3L5d1zNNqHFJ855Bao8P`~b`#jRpsQ`_wyQ2>6dFt_$_U9YC)f$g-mR(St
z1b7@>?X{@wIB)st`#1D07<xlLdH^T6-K3xKzUOh;&_3!_bHn!JDy2_D=fy2s{x!Z=
zf;YgaS7TVTt!rnt!Kjk5f3$3760(`uAsd6td6F=y`xQGXJs^zc^DtwW8~qvHH$DKr
zG(wLMyFf`O9?k!}4>QQK$v=V`?aVN8Jpoj$l2`{>X`~y>e;=MB^yY|m^!e0mU(R{D
zq^?qtoRrgio5$$Phsh=G(>!nX253t1R7E`6$JK54Et+Q^Dz{U*v1|`ff0gqFpQg{x
z*}p1dTxYEFTx(pPCmr&q=ehInR**u~d<OVD|Em03<J%WPTCGsB0?%P^1gU)H?Hn(l
rP10ID6V?;nGOJuO7|(XxAI<qMK0mhvhz%5c&g<)Te)0K#CxQP4h~9;d

literal 0
HcmV?d00001

diff --git a/packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta b/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/0.12.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta

From 8ee021e0bae8ff19b85c6122c0e459ebcd240ac0 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Tue, 29 Oct 2024 13:32:22 -0700
Subject: [PATCH 33/55] Update DLLs to release/v1.0.0-rc1

---
 .../dotnet/cs/SpacetimeDB.BSATN.Codegen.dll   | Bin 57344 -> 57344 bytes
 .../SpacetimeDB.BSATN.Runtime.dll             | Bin 64512 -> 64512 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll b/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
index bcbcf0ef5a8048fa49abe3ed5f29c7e968896c71..d25daddb24b51168c1c9b0f330b3047d0d54c689 100644
GIT binary patch
delta 238
zcmZoTz}#?vc|r%v<jo<+H}?G4E^zYiGRr%8&%F9J%-box|4aSmDLcv}HH^{>(kv5A
zjgpO%63r}(Eld;5lMRdwEG<(^Qj<)~%uSNb(~=U?j5Zrx`o_#sAG&(;WSwgP0&3C*
zeKk_;p51@cnhl-5l~3-uwp0Ns_|h9H2vVJXNB-ElHRjQ46=(Ww4!kbS>Tkr5#$W)%
zmJEpurVK_5$qdE}NkFz4g9VUf0TfGQFb9en0C@&LRhA4X3?>YzKs6>nHReDv8Azsq
O^`tQvZQgyyl^Fo%@=vt@

delta 238
zcmZoTz}#?vc|r#ZPlf06jXgiM3#eK=U9IW7-euFhJBccvJI-#NvZG8=Bhf6;EZHQ@
zz#=Wh!qOnsASu-%IngNDG||#BIXTHZ)i}{4(ZVp<Y_rj&Z_F%;FV#*>*0~lSFp*m)
zb&|QU<DPtzPkyVS_$K#UTdDvRyjTMj1giF8{XRkS*p7<Q&5GWaHwRvqX7x{GFk=AW
zWCjz4GzJ3(3m};SBrSpLR3J_Qk`_SOL<S=uX$qt*fiM{elNii_a>hUr6Ck!=Fa(O3
KZQgyyl^FmRmrb1j

diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
index 329765a8ece422bbc4ae14cf2818ae5e07beb858..96670361095fbd462e5d19ef78c05f770ee2ac24 100644
GIT binary patch
delta 238
zcmZqp!QAkJc|r%v`a{<@Z|qreLts0{I;%B3O3qF7P79s~<#26wxLGEmVU%W&W|?Se
zlx&=oXl7w-VVY>3Y+!6)X_;b@nq*>TZjx-CmXw%gwE5oKTg)ux`QMLB-t#d)V6yJo
ztxOYpyypM7c4w{Bt6!64J}p&%3QEaC1%awvV&41_{=d@hu6FY;-pvm`1+)4aF{CjV
z0I?-QB7-S|5koSAF+&oNZN^{$WLW^k5*f^aq6R>o0Z^4CLkfclLn=^>2~dqWkW2=W
QX<$8R3`U!qf7CJq0H@wn6aWAK

delta 238
zcmZqp!QAkJc|r$ElG6358+(@A5RmAIR^e~tbK09)^s6i&eCB3{n`I&ziDrpr$tGzA
z7HKIKmIkQ?NvRgeiAKq$iI$eh$w}s^#)&407KX`YoA157#mw?b_UG=&dp-sT+<qTr
z$nkxR`z(zWd(5(z-kdD+X{iEKaJdvz5TttU(piOF_73?So}5QFKl~KT>YvD9#sI>}
z3?>X|3<eAqKr#hLS_0XrK%4|5Er7C#3`RiG6i8bFVKNXVF_;78jDaF1Ky1Na2oy8h
J-29`K830%(Q)2)C


From d687f5620df12cb0b562ebfe9ded22a55993b39e Mon Sep 17 00:00:00 2001
From: SteveGibson <100594800+SteveBoytsun@users.noreply.github.com>
Date: Wed, 30 Oct 2024 12:33:54 -0400
Subject: [PATCH 34/55] Fixed subscription updates not clearing tables with no
 subscribed values (#182)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

Context:
https://discord.com/channels/568217153853980682/669989878955638785/1301132060878049332
Currently, when we receive subscription updates, a table will only be
diffed if subscription has any rows for that table. If, however, there
are no subscribed values, that table will NOT be diffed, and therefore
will not get cleared. Values from previous subscription will still be
there, so the table is in incorrect state.

This PR fixes that by making sure that ALL tables are checked in state
diff

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*


## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

## Testing
*Write instructions for a test that you performed for this PR*

- [ ] Create a table A with an `val: i32` field
- [ ] Generate rows for table A with field values in the range (0..100)
- [ ] Connect client and subscribe to `SELECT * FROM A WHERE val > 0`
(will have all rows from table A)
- [ ] Change your subscription to `SELECT * FROM A WHERE val > 1000`
(should have no rows)
- [ ] Note that after subscription is applied, table A will have no
values

Co-authored-by: Steve Boytsun <steve@clockwokrlabs.io>
---
 src/SpacetimeDBClient.cs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index dc627f2f..ae9476ab 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -547,7 +547,10 @@ ProcessedMessage CalculateStateDiff(PreProcessedMessage preProcessedMessage)
                 {
                     if (!subscriptionInserts.TryGetValue(table.ClientTableType, out var hashSet))
                     {
-                        continue;
+                        // We still need to process tables that weren't included in subscription.
+                        // Otherwise we won't delete no-longer-available values
+                        hashSet = new HashSet<byte[]>();
+                        subscriptionInserts.Add(table.ClientTableType, hashSet);
                     }
 
                     foreach (var (rowBytes, oldValue) in table.IterEntries().Where(kv => !hashSet.Contains(kv.Key)))

From b533b1d9a28b215a6e15753d6b1480e18b2f6764 Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Wed, 30 Oct 2024 14:45:05 -0400
Subject: [PATCH 35/55] Quickstart client fix

---
 examples~/quickstart/client/Program.cs | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/examples~/quickstart/client/Program.cs b/examples~/quickstart/client/Program.cs
index 8327d976..9f478f3c 100644
--- a/examples~/quickstart/client/Program.cs
+++ b/examples~/quickstart/client/Program.cs
@@ -137,11 +137,7 @@ void OnConnect(DbConnection conn, Identity identity, string authToken)
 
     conn.SubscriptionBuilder()
         .OnApplied(OnSubscriptionApplied)
-        .Subscribe("SELECT * FROM User");
-
-    conn.SubscriptionBuilder()
-        .OnApplied(OnSubscriptionApplied)
-        .Subscribe("SELECT * FROM Message");
+        .Subscribe("SELECT * FROM user", "SELECT * FROM message");
 }
 
 void OnConnectError(WebSocketError? error, string message)

From 53d8a926df5a76af533d3e61544f1f5278107ff5 Mon Sep 17 00:00:00 2001
From: John Detter <4099508+jdetter@users.noreply.github.com>
Date: Wed, 30 Oct 2024 22:08:36 +0000
Subject: [PATCH 36/55] Fix Connection Error: Success (#166)

## Description of Changes
This PR edits the handling of errors related to websocket connections
and disconnections. In particular, clients and users would often run
into the dreaded `Connection Error: Success` message which was confusing
and frustrating. This PR better addresses the error by providing more
guidance and debug info for the user. It is unfortunately still
suboptimal because the `HttpStatusCode` is not available in the .NET
core version that Unity supports. We try to be as helpful as possible in
this scenario.

## API

- [x] This is an API breaking change to the SDK, because it changes the
returned values from the `OnDisconnect` and `OnConnectError` callbacks
to implement the API specification:
https://github.com/clockworklabs/SpacetimeDBPrivate/pull/866/files#diff-be533cc04817c33605a68d717c6ec320c4449904266ee8e1096971e9e17e8d31R424

## Requires SpacetimeDB PRs
No changes to SpacetimeDB required.

## Testing

I, Tyler, have tested this and confirmed it to be working with
CircleGame. Here is a sample of the output in the case of `Connection
Error: Success`:

<img width="1324" alt="image"
src="https://github.com/user-attachments/assets/2b98c69f-07e2-4d0b-a61f-0ae4f84d62f6">

---------

Co-authored-by: John Detter <no-reply@boppygames.gg>
Co-authored-by: Tyler Cloutier <cloutiertyler@aol.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 examples~/quickstart/client/Program.cs |   4 +-
 src/SpacetimeDBClient.cs               |  10 +-
 src/WebSocket.cs                       | 132 ++++++++++++++++++++++---
 3 files changed, 123 insertions(+), 23 deletions(-)

diff --git a/examples~/quickstart/client/Program.cs b/examples~/quickstart/client/Program.cs
index 8327d976..f6978ff6 100644
--- a/examples~/quickstart/client/Program.cs
+++ b/examples~/quickstart/client/Program.cs
@@ -144,12 +144,12 @@ void OnConnect(DbConnection conn, Identity identity, string authToken)
         .Subscribe("SELECT * FROM Message");
 }
 
-void OnConnectError(WebSocketError? error, string message)
+void OnConnectError(Exception e)
 {
 
 }
 
-void OnDisconnect(DbConnection conn, WebSocketCloseStatus? status, WebSocketError? error)
+void OnDisconnect(DbConnection conn, Exception? e)
 {
 
 }
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index ae9476ab..40f8d0cc 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -64,15 +64,15 @@ public DbConnectionBuilder<DbConnection, Reducer> OnConnect(Action<DbConnection,
             return this;
         }
 
-        public DbConnectionBuilder<DbConnection, Reducer> OnConnectError(Action<WebSocketError?, string> cb)
+        public DbConnectionBuilder<DbConnection, Reducer> OnConnectError(Action<Exception> cb)
         {
-            conn.webSocket.OnConnectError += (a, b) => cb.Invoke(a, b);
+            conn.webSocket.OnConnectError += (e) => cb.Invoke(e);
             return this;
         }
 
-        public DbConnectionBuilder<DbConnection, Reducer> OnDisconnect(Action<DbConnection, WebSocketCloseStatus?, WebSocketError?> cb)
+        public DbConnectionBuilder<DbConnection, Reducer> OnDisconnect(Action<DbConnection, Exception?> cb)
         {
-            conn.webSocket.OnClose += (code, error) => cb.Invoke(conn, code, error);
+            conn.webSocket.OnClose += (e) => cb.Invoke(conn, e);
             return this;
         }
     }
@@ -156,7 +156,7 @@ protected DbConnectionBase()
             webSocket.OnMessage += OnMessageReceived;
             webSocket.OnSendError += a => onSendError?.Invoke(a);
 #if UNITY_5_3_OR_NEWER
-            webSocket.OnClose += (a, b) => SpacetimeDBNetworkManager.ActiveConnections.Remove(this);
+            webSocket.OnClose += (e) => SpacetimeDBNetworkManager.ActiveConnections.Remove(this);
 #endif
 
             networkMessageProcessThread = new Thread(PreProcessMessages);
diff --git a/src/WebSocket.cs b/src/WebSocket.cs
index cd22c26f..78247b44 100644
--- a/src/WebSocket.cs
+++ b/src/WebSocket.cs
@@ -4,6 +4,7 @@
 using System;
 using System.Collections.Concurrent;
 using System.Linq;
+using System.Net.Sockets;
 using System.Net.WebSockets;
 using System.Text;
 using System.Threading;
@@ -17,9 +18,9 @@ internal class WebSocket
 
         public delegate void MessageEventHandler(byte[] message, DateTime timestamp);
 
-        public delegate void CloseEventHandler(WebSocketCloseStatus? code, WebSocketError? error);
+        public delegate void CloseEventHandler(Exception? e);
 
-        public delegate void ConnectErrorEventHandler(WebSocketError? error, string message);
+        public delegate void ConnectErrorEventHandler(Exception e);
         public delegate void SendErrorEventHandler(Exception e);
 
         public struct ConnectOptions
@@ -70,23 +71,81 @@ public async Task Connect(string? auth, string host, string nameOrAddress, Addre
             try
             {
                 await Ws.ConnectAsync(url, source.Token);
-                if (OnConnect != null) dispatchQueue.Enqueue(() => OnConnect());
+                if (Ws.State == WebSocketState.Open)
+                {
+                    if (OnConnect != null)
+                    {
+                        dispatchQueue.Enqueue(() => OnConnect());
+                    }
+                }
+                else
+                {
+                    if (OnConnectError != null)
+                    {
+                        dispatchQueue.Enqueue(() => OnConnectError(
+                            new Exception($"WebSocket connection failed. Current state: {Ws.State}")));
+                    }
+                    return;
+                }
+            }
+            catch (WebSocketException ex) when (ex.WebSocketErrorCode == WebSocketError.Success)
+            {
+                // How can we get here:
+                // - When you go to connect and the server isn't running (port closed) - target machine actively refused
+                // - 404 - No module with at that module address instead of 101 upgrade
+                // - 401? - When the identity received by SpacetimeDB wasn't signed by its signing key
+                // - 400 - When the auth is malformed
+                if (OnConnectError != null)
+                {
+                    // .net 6,7,8 has support for Ws.HttpStatusCode as long as you set
+                    // ClientWebSocketOptions.CollectHttpResponseDetails = true
+                    var message = "A WebSocketException occurred, even though the WebSocketErrorCode is \"Success\".\n"
+                    + "This indicates that there was no native error information for the exception.\n"
+                    + "Due to limitations in the .NET core version we do not have access to the HTTP status code returned by the request which would provide more info on the nature of the error.\n\n"
+                    + "This error could arise for a number of reasons:\n"
+                    + "1. The target machine actively refused the connection.\n"
+                    + "2. The module you are trying to connect to does not exist (404 NOT FOUND).\n"
+                    + "3. The auth token you sent to SpacetimeDB was not signed by the correct signing key (400 BAD REQUEST).\n"
+                    + "4. The auth token is malformed (400 BAD REQUEST).\n"
+                    + "5. You are not authorized (401 UNAUTHORIZED).\n\n"
+                    + "Did you forget to start the server or publish your module?\n\n"
+                    + "Here are some values that might help you debug:\n"
+                    + $"Message: {ex.Message}\n"
+                    + $"WebSocketErrorCode: {ex.WebSocketErrorCode}\n"
+                    + $"ErrorCode: {ex.ErrorCode}\n"
+                    + $"NativeErrorCode: {ex.NativeErrorCode}\n"
+                    + $"InnerException Message: {ex.InnerException?.Message}\n"
+                    + $"WebSocket CloseStatus: {Ws.CloseStatus}\n"
+                    + $"WebSocket State: {Ws.State}\n"
+                    + $"InnerException: {ex.InnerException}\n"
+                    + $"Exception: {ex}"
+                    ;
+                    dispatchQueue.Enqueue(() => OnConnectError(new Exception(message)));
+                }
+            }
+            catch (WebSocketException ex)
+            {
+                if (OnConnectError != null)
+                {
+                    var message = $"WebSocket connection failed: {ex.WebSocketErrorCode}\n"
+                    + $"Exception message: {ex.Message}\n";
+                    dispatchQueue.Enqueue(() => OnConnectError(new Exception(message)));
+                }
+            }
+            catch (SocketException ex)
+            {
+                // This might occur if the server is unreachable or the DNS lookup fails.
+                if (OnConnectError != null)
+                {
+                    dispatchQueue.Enqueue(() => OnConnectError(ex));
+                }
             }
             catch (Exception ex)
             {
-                Log.Exception(ex);
                 if (OnConnectError != null)
                 {
-                    var message = ex.Message;
-                    var code = (ex as WebSocketException)?.WebSocketErrorCode;
-                    if (code == WebSocketError.NotAWebSocket)
-                    {
-                        // not a websocket happens when there is no module published under the address specified
-                        message += " Did you forget to publish your module?";
-                    }
-                    dispatchQueue.Enqueue(() => OnConnectError(code, message));
+                    dispatchQueue.Enqueue(() => OnConnectError(ex));
                 }
-                return;
             }
 
             while (Ws.State == WebSocketState.Open)
@@ -102,7 +161,45 @@ public async Task Connect(string? auth, string host, string nameOrAddress, Addre
                             await Ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty,
                             CancellationToken.None);
                         }
-                        if (OnClose != null) dispatchQueue.Enqueue(() => OnClose(receiveResult.CloseStatus, null));
+                        if (OnClose != null)
+                        {
+                            switch (receiveResult.CloseStatus)
+                            {
+                                case WebSocketCloseStatus.NormalClosure:
+                                    dispatchQueue.Enqueue(() => OnClose(null));
+                                    break;
+                                case WebSocketCloseStatus.EndpointUnavailable:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("(1000) The connection has closed after the request was fulfilled.")));
+                                    break;
+                                case WebSocketCloseStatus.ProtocolError:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("(1002) The client or server is terminating the connection because of a protocol error.")));
+                                    break;
+                                case WebSocketCloseStatus.InvalidMessageType:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("(1003) The client or server is terminating the connection because it cannot accept the data type it received.")));
+                                    break;
+                                case WebSocketCloseStatus.Empty:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("(1005) No error specified.")));
+                                    break;
+                                case WebSocketCloseStatus.InvalidPayloadData:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("(1007) The client or server is terminating the connection because it has received data inconsistent with the message type.")));
+                                    break;
+                                case WebSocketCloseStatus.PolicyViolation:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("(1008) The connection will be closed because an endpoint has received a message that violates its policy.")));
+                                    break;
+                                case WebSocketCloseStatus.MessageTooBig:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("(1009) Message too big")));
+                                    break;
+                                case WebSocketCloseStatus.MandatoryExtension:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("(1010) The client is terminating the connection because it expected the server to negotiate an extension.")));
+                                    break;
+                                case WebSocketCloseStatus.InternalServerError:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("(1011) The connection will be closed by the server because of an error on the server.")));
+                                    break;
+                                default:
+                                    dispatchQueue.Enqueue(() => OnClose(new Exception("Unknown error")));
+                                    break;
+                            }
+                        }
                         return;
                     }
 
@@ -116,7 +213,10 @@ await Ws.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty,
                             var closeMessage = $"Maximum message size: {MAXMessageSize} bytes.";
                             await Ws.CloseAsync(WebSocketCloseStatus.MessageTooBig, closeMessage,
                                 CancellationToken.None);
-                            if (OnClose != null) dispatchQueue.Enqueue(() => OnClose(WebSocketCloseStatus.MessageTooBig, null));
+                            if (OnClose != null)
+                            {
+                                dispatchQueue.Enqueue(() => OnClose(new Exception("(1009) Message too big")));
+                            }
                             return;
                         }
 
@@ -134,7 +234,7 @@ await Ws.CloseAsync(WebSocketCloseStatus.MessageTooBig, closeMessage,
                 }
                 catch (WebSocketException ex)
                 {
-                    if (OnClose != null) dispatchQueue.Enqueue(() => OnClose(null, ex.WebSocketErrorCode));
+                    if (OnClose != null) dispatchQueue.Enqueue(() => OnClose(ex));
                     return;
                 }
             }

From bac557c446b89211683d7922b14a910476c54a47 Mon Sep 17 00:00:00 2001
From: John Detter <4099508+jdetter@users.noreply.github.com>
Date: Thu, 31 Oct 2024 17:25:28 +0000
Subject: [PATCH 37/55] Unity testsuite as a git submodule (#186)

**Please do not rebase this PR**

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

This is very similar to
https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk/pull/176
except it imports the circle game as a submodule instead of copying the
code over into this repo. This is the SpacetimeDBCircleGame PR that
we're dependent on right now:
https://github.com/clockworklabs/SpacetimeDBCircleGame/pull/3

- This PR introduces a testsuite which runs in Unity. Right now it just
spawns in a circle, eats some food and verifies the decay logic is
working correctly. I've also written some reconnection tests but they
don't work because reconnections are currently broken. There are also
one-off tests but those don't work either because they also require
reconnections to be working.

Update: reconnections have been fixed via
https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk/pull/168.

I've used the built-in unity testsuite framework to achieve this, along
with the UnityCI tool from GameCI. The documentation for this docker
container can be found here:
https://game.ci/docs/github/getting-started/

## API

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*

Not breaking

## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

None

## Testsuite

SpacetimeDB branch name: 0935b7346b825b8cbb9f36d9ed256136b73b5f0b

## Testing
*Write instructions for a test that you performed for this PR*

- [x] The testsuite is passing:
https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk/actions/runs/11604456943/job/32313229775

You can follow test instructions here to double check my work:
https://github.com/clockworklabs/SpacetimeDBCircleGame/pull/3

## Follow-up Actions

- [ ] Rebase the reconnection logic PR onto this PR and re-enable the
reconnection tests

---------

Co-authored-by: John Detter <no-reply@boppygames.gg>
---
 .github/pull_request_template.md              |  11 +-
 .github/workflows/unity-test.yml              | 149 ++++++++++++++++++
 .../workflows/unity-testsuite-bindings.yml    | 120 ++++++++++++++
 .gitmodules                                   |   3 +
 unity-tests~                                  |   1 +
 5 files changed, 283 insertions(+), 1 deletion(-)
 create mode 100644 .github/workflows/unity-test.yml
 create mode 100644 .github/workflows/unity-testsuite-bindings.yml
 create mode 100644 .gitmodules
 create mode 160000 unity-tests~

diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 88fcaef9..71d6531a 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -7,6 +7,15 @@
 
 *If the API is breaking, please state below what will break*
 
-
 ## Requires SpacetimeDB PRs
 *List any PRs here that are required for this SDK change to work*
+
+## Testsuite
+*If you would like to run against a specific SpacetimeDB branch in the testsuite, specify that here. This can be a branch name or a link to a PR.*
+
+SpacetimeDB branch name: master
+
+## Testing
+*Write instructions for a test that you performed for this PR*
+
+- [ ] Describe a test for this PR that you have completed
diff --git a/.github/workflows/unity-test.yml b/.github/workflows/unity-test.yml
new file mode 100644
index 00000000..774fd847
--- /dev/null
+++ b/.github/workflows/unity-test.yml
@@ -0,0 +1,149 @@
+name: Unity Test Suite
+
+on:
+  push:
+    branches:
+      - staging
+  pull_request:
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v3
+
+      - name: Checkout submodule
+        run: |
+          git submodule init
+          git submodule update
+          cd unity-tests~
+          git checkout jdetter/circle-game-testsuite
+      # Grab the branch name from the PR description. If it's not found, master will be used instead.
+      - name: Extract SpacetimeDB branch name or PR link from PR description
+        id: extract-branch
+        if: github.event_name == 'pull_request'
+        run: |
+          description=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
+          ${{ github.event.pull_request.url }} | jq -r '.body')
+
+          # Check if description contains a branch name or a PR link
+          branch_or_pr=$(echo "$description" | grep -oP '(?<=SpacetimeDB branch name:\s).+')
+          echo "Branch or PR found: $branch_or_pr"
+
+          if [[ -z "$branch_or_pr" ]]; then
+            branch="master"
+          elif [[ "$branch_or_pr" =~ ^https://github.com/.*/pull/[0-9]+$ ]]; then
+            # If it's a PR link, extract the branch name from the PR
+            pr_number=$(echo "$branch_or_pr" | grep -oP '[0-9]+$')
+            branch=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
+            https://api.github.com/repos/clockworklabs/SpacetimeDB/pulls/$pr_number | jq -r '.head.ref')
+          else
+            # It's already a branch name
+            branch="$branch_or_pr"
+          fi
+
+          echo "branch=$branch" >> $GITHUB_OUTPUT
+          echo "Final branch name: $branch"
+
+      - name: Replace com.clockworklabs.spacetimedbsdk in manifest.json
+        run: |
+          # Get the branch name from the environment variable
+          branch_name="${{ github.head_ref }}"
+          # Replace any reference to com.clockworklabs.spacetimedbsdk with the correct GitHub URL using the current branch
+          sed -i "s|\"com.clockworklabs.spacetimedbsdk\":.*|\"com.clockworklabs.spacetimedbsdk\": \"https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk.git#$branch_name\",|" unity-tests~/client/Packages/manifest.json
+
+          cat unity-tests~/client/Packages/manifest.json
+      - name: Replace spacetimedb dependency in Cargo.toml
+        run: |
+          # Get the branch name from the environment variable
+          branch_name="${{ github.head_ref }}"
+          # Make sure we're using the correct bindings when building the module TODO
+          sed -i "s|spacetimedb.*=.*|spacetimedb = \{ path = \"../SpacetimeDB/crates/bindings\" \}|" unity-tests~/server/Cargo.toml
+          cat unity-tests~/server/Cargo.toml
+      - name: Install Rust toolchain
+        run: |
+          curl https://sh.rustup.rs -sSf | sh -s -- -y
+          source $HOME/.cargo/env
+          rustup install stable
+          rustup default stable
+
+      - name: Cache Cargo target directory
+        uses: actions/cache@v3
+        with:
+          path: unity-tests~/server/target
+          key: server-target-SpacetimeDBUnityTestsuite-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('unity-tests~/server/Cargo.lock') }}
+          restore-keys: |
+            server-target-SpacetimeDBUnityTestsuite-${{ runner.os }}-${{ runner.arch }}-
+            server-target-SpacetimeDBUnityTestsuite-
+
+      - name: Cache Cargo registry
+        uses: actions/cache@v3
+        with:
+          path: ~/.cargo/registry
+          key: cargo-registry-${{ runner.os }}-${{ hashFiles('unity-tests~/server/Cargo.lock') }}
+          restore-keys: |
+            cargo-registry-${{ runner.os }}-
+            cargo-registry-
+
+      - name: Cache Cargo index
+        uses: actions/cache@v3
+        with:
+          path: ~/.cargo/git
+          key: cargo-index-${{ runner.os }}-${{ hashFiles('unity-tests~/server/Cargo.lock') }}
+          restore-keys: |
+            cargo-index-${{ runner.os }}-
+            cargo-index-
+
+      - name: Install SpacetimeDB CLI from specific branch
+        run: |
+          cd unity-tests~
+          git clone https://github.com/clockworklabs/SpacetimeDB.git
+          cd SpacetimeDB
+          # Sanitize the branch name by trimming any newlines or spaces
+          branch_name=$(echo "${{ steps.extract-branch.outputs.branch }}" | tr -d '[:space:]')
+          # If the branch name is not found, default to master
+          if [ -z "$branch_name" ]; then
+            branch_name="master"
+          fi
+          git checkout "$branch_name"
+          echo "Checked out branch: $branch_name"
+          cargo build --release -p spacetimedb-cli
+          sudo mv target/release/spacetime /usr/bin/spacetime
+
+      - name: Generate client bindings
+        run: |
+          cd unity-tests~/server
+          bash ./generate.sh -y
+
+      - name: Start SpacetimeDB
+        run: |
+          spacetime start &
+          disown
+
+      - name: Publish module to SpacetimeDB
+        run: |
+          cd unity-tests~/server
+          bash ./publish.sh
+
+      - uses: actions/cache@v3
+        with:
+          path: unity-tests~/client/Library
+          key: Library-SpacetimeDBUnityTestsuite-Linux-x86
+          restore-keys: |
+            Library-SpacetimeDBUnityTestsuite-
+            Library-
+
+      - name: Set up Unity
+        uses: game-ci/unity-test-runner@v4
+        with:
+          unityVersion: 2022.3.32f1  # Adjust Unity version to a valid tag
+          projectPath: unity-tests~/client  # Path to the Unity project subdirectory
+          githubToken: ${{ secrets.GITHUB_TOKEN }}
+          testMode: playmode
+          useHostNetwork: true
+        env:
+          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
+          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
+          UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
+
diff --git a/.github/workflows/unity-testsuite-bindings.yml b/.github/workflows/unity-testsuite-bindings.yml
new file mode 100644
index 00000000..1bfee47d
--- /dev/null
+++ b/.github/workflows/unity-testsuite-bindings.yml
@@ -0,0 +1,120 @@
+name: Check Unity Testsuite Bindings
+
+on:
+  push:
+    branches:
+      - staging
+  pull_request:
+
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v3
+
+      - name: Checkout submodule
+        run: |
+          git submodule init
+          git submodule update
+          cd unity-tests~
+          git checkout jdetter/circle-game-testsuite
+      # Grab the branch name from the PR description. If it's not found, master will be used instead.
+      - name: Extract SpacetimeDB branch name or PR link from PR description
+        id: extract-branch
+        if: github.event_name == 'pull_request'
+        run: |
+          description=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
+          ${{ github.event.pull_request.url }} | jq -r '.body')
+
+          # Check if description contains a branch name or a PR link
+          branch_or_pr=$(echo "$description" | grep -oP '(?<=SpacetimeDB branch name:\s).+')
+          echo "Branch or PR found: $branch_or_pr"
+
+          if [[ -z "$branch_or_pr" ]]; then
+            branch="master"
+          elif [[ "$branch_or_pr" =~ ^https://github.com/.*/pull/[0-9]+$ ]]; then
+            # If it's a PR link, extract the branch name from the PR
+            pr_number=$(echo "$branch_or_pr" | grep -oP '[0-9]+$')
+            branch=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
+            https://api.github.com/repos/clockworklabs/SpacetimeDB/pulls/$pr_number | jq -r '.head.ref')
+          else
+            # It's already a branch name
+            branch="$branch_or_pr"
+          fi
+
+          echo "branch=$branch" >> $GITHUB_OUTPUT
+          echo "Final branch name: $branch"
+
+      - name: Replace spacetimedb dependency in Cargo.toml
+        run: |
+          # Get the branch name from the environment variable
+          branch_name="${{ github.head_ref }}"
+          # Make sure we're using the correct bindings when building the module TODO
+          sed -i "s|spacetimedb.*=.*|spacetimedb = \{ path = \"../SpacetimeDB/crates/bindings\" \}|" unity-tests~/server/Cargo.toml
+          cat unity-tests~/server/Cargo.toml
+      - name: Install Rust toolchain
+        run: |
+          curl https://sh.rustup.rs -sSf | sh -s -- -y
+          source $HOME/.cargo/env
+          rustup install stable
+          rustup default stable
+
+      - name: Cache Cargo target directory
+        uses: actions/cache@v3
+        with:
+          path: unity-tests~/server/target
+          key: server-target-SpacetimeDBUnityTestsuite-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('unity-tests~/server/Cargo.lock') }}
+          restore-keys: |
+            server-target-SpacetimeDBUnityTestsuite-${{ runner.os }}-${{ runner.arch }}-
+            server-target-SpacetimeDBUnityTestsuite-
+
+      - name: Cache Cargo registry
+        uses: actions/cache@v3
+        with:
+          path: ~/.cargo/registry
+          key: cargo-registry-${{ runner.os }}-${{ hashFiles('unity-tests~/server/Cargo.lock') }}
+          restore-keys: |
+            cargo-registry-${{ runner.os }}-
+            cargo-registry-
+
+      - name: Cache Cargo index
+        uses: actions/cache@v3
+        with:
+          path: ~/.cargo/git
+          key: cargo-index-${{ runner.os }}-${{ hashFiles('unity-tests~/server/Cargo.lock') }}
+          restore-keys: |
+            cargo-index-${{ runner.os }}-
+            cargo-index-
+
+      - name: Install SpacetimeDB CLI from specific branch
+        run: |
+          cd unity-tests~
+          git clone https://github.com/clockworklabs/SpacetimeDB.git
+          cd SpacetimeDB
+          # Sanitize the branch name by trimming any newlines or spaces
+          branch_name=$(echo "${{ steps.extract-branch.outputs.branch }}" | tr -d '[:space:]')
+          # If the branch name is not found, default to master
+          if [ -z "$branch_name" ]; then
+            branch_name="master"
+          fi
+          git checkout "$branch_name"
+          echo "Checked out branch: $branch_name"
+          cargo build --release -p spacetimedb-cli
+          sudo mv target/release/spacetime /usr/bin/spacetime
+
+      - name: Generate client bindings
+        run: |
+          cd unity-tests~/server
+          bash ./generate.sh -y
+
+      - name: Check for changes
+        run: |
+          git diff --exit-code
+        continue-on-error: true
+
+      - name: Fail if there are changes
+        if: ${{ steps.check-for-changes.outcome == 'failure' }}
+        run: |
+          echo "Error: Bindings are dirty. Please generate bindings again and commit them to this branch."
+          exit 1
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..50c54dcb
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "SpacetimeDBCircleGame"]
+	path = unity-tests~
+	url = https://github.com/clockworklabs/SpacetimeDBCircleGame
diff --git a/unity-tests~ b/unity-tests~
new file mode 160000
index 00000000..75047b5e
--- /dev/null
+++ b/unity-tests~
@@ -0,0 +1 @@
+Subproject commit 75047b5e58a67ba8e3b652dab17ddde61b661989

From 9a5670431b1efab8648c69f440e316ac81ea9478 Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Thu, 31 Oct 2024 19:08:52 +0100
Subject: [PATCH 38/55] Add gzip + none compression algos and let SDK pick
 compression (take 2) (#174)

## Description of Changes

Companion to https://github.com/clockworklabs/SpacetimeDB/pull/1802.

## Requires SpacetimeDB PRs

None

## Test suite

SpacetimeDB branch name: 0935b7346b825b8cbb9f36d9ed256136b73b5f0b

---------

Co-authored-by: Jeremie Pelletier <jeremiep@gmail.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 src/Compression.cs                            |  9 ++++
 src/Compression.cs.meta                       | 11 +++++
 .../ClientApi/CompressableQueryUpdate.cs      |  3 +-
 src/SpacetimeDBClient.cs                      | 48 ++++++++++++-------
 src/WebSocket.cs                              |  4 +-
 5 files changed, 54 insertions(+), 21 deletions(-)
 create mode 100644 src/Compression.cs
 create mode 100644 src/Compression.cs.meta

diff --git a/src/Compression.cs b/src/Compression.cs
new file mode 100644
index 00000000..8f630f99
--- /dev/null
+++ b/src/Compression.cs
@@ -0,0 +1,9 @@
+namespace SpacetimeDB
+{
+    public enum Compression
+    {
+        None,
+        Brotli,
+        Gzip,
+    }
+}
diff --git a/src/Compression.cs.meta b/src/Compression.cs.meta
new file mode 100644
index 00000000..eef0325c
--- /dev/null
+++ b/src/Compression.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 03fdc211a87474eeba9f03495eab491e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
index af397a58..1af6fd27 100644
--- a/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/CompressableQueryUpdate.cs
@@ -12,6 +12,7 @@ namespace SpacetimeDB.ClientApi
 	[SpacetimeDB.Type]
 	public partial record CompressableQueryUpdate : SpacetimeDB.TaggedEnum<(
 		SpacetimeDB.ClientApi.QueryUpdate Uncompressed,
-		byte[] Brotli
+		byte[] Brotli,
+		byte[] Gzip
 	)>;
 }
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 40f8d0cc..7fa8dd6f 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -22,6 +22,7 @@ public sealed class DbConnectionBuilder<DbConnection, Reducer>
         string? uri;
         string? nameOrAddress;
         string? token;
+        Compression? compression;
 
         public DbConnection Build()
         {
@@ -33,7 +34,7 @@ public DbConnection Build()
             {
                 throw new InvalidOperationException("Building DbConnection with a null nameOrAddress. Call WithModuleName() first.");
             }
-            conn.Connect(token, uri, nameOrAddress);
+            conn.Connect(token, uri, nameOrAddress, compression ?? Compression.Brotli);
 #if UNITY_5_3_OR_NEWER
             SpacetimeDBNetworkManager.ActiveConnections.Add(conn);
 #endif
@@ -58,6 +59,12 @@ public DbConnectionBuilder<DbConnection, Reducer> WithCredentials(in (Identity i
             return this;
         }
 
+        public DbConnectionBuilder<DbConnection, Reducer> WithCompression(Compression compression)
+        {
+            this.compression = compression;
+            return this;
+        }
+
         public DbConnectionBuilder<DbConnection, Reducer> OnConnect(Action<DbConnection, Identity, string> cb)
         {
             conn.onConnect += (identity, token) => cb.Invoke(conn, identity, token);
@@ -209,6 +216,17 @@ enum CompressionAlgos : byte
         {
             None = 0,
             Brotli = 1,
+            Gzip = 2,
+        }
+
+        private static BinaryReader BrotliReader(Stream stream)
+        {
+            return new BinaryReader(new BrotliStream(stream, CompressionMode.Decompress));
+        }
+
+        private static BinaryReader GzipReader(Stream stream)
+        {
+            return new BinaryReader(new GZipStream(stream, CompressionMode.Decompress));
         }
 
         private static ServerMessage DecompressDecodeMessage(byte[] bytes)
@@ -221,16 +239,11 @@ private static ServerMessage DecompressDecodeMessage(byte[] bytes)
             switch (compression)
             {
                 case CompressionAlgos.None:
-                    {
-                        using var binaryReader = new BinaryReader(stream);
-                        return new ServerMessage.BSATN().Read(binaryReader);
-                    }
+                    return new ServerMessage.BSATN().Read(new BinaryReader(stream));
                 case CompressionAlgos.Brotli:
-                    {
-                        using var decompressedStream = new BrotliStream(stream, CompressionMode.Decompress);
-                        using var binaryReader = new BinaryReader(decompressedStream);
-                        return new ServerMessage.BSATN().Read(binaryReader);
-                    }
+                    return new ServerMessage.BSATN().Read(BrotliReader(stream));
+                case CompressionAlgos.Gzip:
+                    return new ServerMessage.BSATN().Read(GzipReader(stream));
                 default:
                     throw new InvalidOperationException("Unknown compression type");
             }
@@ -244,12 +257,11 @@ private static QueryUpdate DecompressDecodeQueryUpdate(CompressableQueryUpdate u
                     return qu;
 
                 case CompressableQueryUpdate.Brotli(var bytes):
-                    {
-                        using var stream = new MemoryStream(bytes);
-                        using var decompressedStream = new BrotliStream(stream, CompressionMode.Decompress);
-                        using var binaryReader = new BinaryReader(decompressedStream);
-                        return new QueryUpdate.BSATN().Read(binaryReader);
-                    }
+                    return new QueryUpdate.BSATN().Read(BrotliReader(new MemoryStream(bytes)));
+
+                case CompressableQueryUpdate.Gzip(var bytes):
+                    return new QueryUpdate.BSATN().Read(GzipReader(new MemoryStream(bytes)));
+
                 default:
                     throw new InvalidOperationException();
             }
@@ -582,7 +594,7 @@ public void Disconnect()
         /// </summary>
         /// <param name="uri"> URI of the SpacetimeDB server (ex: https://testnet.spacetimedb.com)
         /// <param name="addressOrName">The name or address of the database to connect to</param>
-        internal void Connect(string? token, string uri, string addressOrName)
+        internal void Connect(string? token, string uri, string addressOrName, Compression compression)
         {
             isClosing = false;
 
@@ -600,7 +612,7 @@ internal void Connect(string? token, string uri, string addressOrName)
                 {
                     try
                     {
-                        await webSocket.Connect(token, uri, addressOrName, Address);
+                        await webSocket.Connect(token, uri, addressOrName, Address, compression);
                     }
                     catch (Exception e)
                     {
diff --git a/src/WebSocket.cs b/src/WebSocket.cs
index 78247b44..86f47c70 100644
--- a/src/WebSocket.cs
+++ b/src/WebSocket.cs
@@ -51,9 +51,9 @@ public WebSocket(ConnectOptions options)
 
         public bool IsConnected { get { return Ws != null && Ws.State == WebSocketState.Open; } }
 
-        public async Task Connect(string? auth, string host, string nameOrAddress, Address clientAddress)
+        public async Task Connect(string? auth, string host, string nameOrAddress, Address clientAddress, Compression compression)
         {
-            var url = new Uri($"{host}/database/subscribe/{nameOrAddress}?client_address={clientAddress}");
+            var url = new Uri($"{host}/database/subscribe/{nameOrAddress}?client_address={clientAddress}&compression={compression}");
             Ws.Options.AddSubProtocol(_options.Protocol);
 
             var source = new CancellationTokenSource(10000);

From 0c590a8db34deba68079c6cb9981a3611081c3ab Mon Sep 17 00:00:00 2001
From: Mazdak Farrokhzad <twingoow@gmail.com>
Date: Tue, 15 Oct 2024 11:43:49 +0200
Subject: [PATCH 39/55] execute gen-client-api.sh against
 centril/websocket-light

support TransactionUpdateLight
support SetReducerFlags
---
 .../_Globals/SpacetimeDBClient.cs             |  28 +-
 src/CallReducerFlags.cs                       |   9 +
 src/SpacetimeDB/ClientApi/BsatnRowList.cs     |   1 -
 src/SpacetimeDB/ClientApi/CallReducer.cs      |   7 +-
 src/SpacetimeDB/ClientApi/OneOffQuery.cs      |   1 -
 .../ClientApi/OneOffQueryResponse.cs          |   1 -
 src/SpacetimeDB/ClientApi/QueryUpdate.cs      |   1 -
 src/SpacetimeDB/ClientApi/ReducerCallInfo.cs  |   1 -
 src/SpacetimeDB/ClientApi/ServerMessage.cs    |   1 +
 .../ClientApi/TransactionUpdateLight.cs       |  38 ++
 src/SpacetimeDBClient.cs                      | 330 ++++++++++--------
 src/WebSocket.cs                              |   9 +-
 ...otTests.VerifyAllTablesParsed.verified.txt |  17 +-
 tools~/gen-client-api.sh                      |   0
 14 files changed, 285 insertions(+), 159 deletions(-)
 create mode 100644 src/CallReducerFlags.cs
 create mode 100644 src/SpacetimeDB/ClientApi/TransactionUpdateLight.cs
 mode change 100644 => 100755 tools~/gen-client-api.sh

diff --git a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
index c0fb266b..726f56d0 100644
--- a/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
+++ b/examples~/quickstart/client/module_bindings/_Globals/SpacetimeDBClient.cs
@@ -63,13 +63,14 @@ internal UserHandle()
 
 	public sealed class RemoteReducers : RemoteBase<DbConnection>
 	{
-		internal RemoteReducers(DbConnection conn) : base(conn) {}
+		internal RemoteReducers(DbConnection conn, SetReducerFlags SetReducerFlags) : base(conn) { this.SetCallReducerFlags = SetReducerFlags; }
+		internal readonly SetReducerFlags SetCallReducerFlags;
 		public delegate void SendMessageHandler(EventContext ctx, string text);
 		public event SendMessageHandler? OnSendMessage;
 
 		public void SendMessage(string text)
 		{
-			conn.InternalCallReducer(new SendMessage { Text = text });
+			conn.InternalCallReducer(new SendMessage { Text = text }, this.SetCallReducerFlags.SendMessageFlags);
 		}
 
 		public bool InvokeSendMessage(EventContext ctx, SendMessage args)
@@ -86,7 +87,7 @@ public bool InvokeSendMessage(EventContext ctx, SendMessage args)
 
 		public void SetName(string name)
 		{
-			conn.InternalCallReducer(new SetName { Name = name });
+			conn.InternalCallReducer(new SetName { Name = name }, this.SetCallReducerFlags.SetNameFlags);
 		}
 
 		public bool InvokeSetName(EventContext ctx, SetName args)
@@ -100,14 +101,25 @@ public bool InvokeSetName(EventContext ctx, SetName args)
 		}
 	}
 
+	public sealed class SetReducerFlags
+	{
+		internal SetReducerFlags() { }
+		internal CallReducerFlags SendMessageFlags;
+		public void SendMessage(CallReducerFlags flags) { this.SendMessageFlags = flags; }
+		internal CallReducerFlags SetNameFlags;
+		public void SetName(CallReducerFlags flags) { this.SetNameFlags = flags; }
+	}
+
 	public partial record EventContext : DbContext<RemoteTables>, IEventContext
 	{
 		public readonly RemoteReducers Reducers;
+		public readonly SetReducerFlags SetReducerFlags;
 		public readonly Event<Reducer> Event;
 
 		internal EventContext(DbConnection conn, Event<Reducer> reducerEvent) : base(conn.Db)
 		{
 			Reducers = conn.Reducers;
+			SetReducerFlags = conn.SetReducerFlags;
 			Event = reducerEvent;
 		}
 	}
@@ -124,10 +136,12 @@ public class DbConnection : DbConnectionBase<DbConnection, Reducer>
 	{
 		public readonly RemoteTables Db = new();
 		public readonly RemoteReducers Reducers;
+		public readonly SetReducerFlags SetReducerFlags;
 
 		public DbConnection()
 		{
-			Reducers = new(this);
+			SetReducerFlags = new();
+			Reducers = new(this, this.SetReducerFlags);
 
 			clientDB.AddTable<Message>("message", Db.Message);
 			clientDB.AddTable<User>("user", Db.User);
@@ -136,7 +150,8 @@ public DbConnection()
 		protected override Reducer ToReducer(TransactionUpdate update)
 		{
 			var encodedArgs = update.ReducerCall.Args;
-			return update.ReducerCall.ReducerName switch {
+			return update.ReducerCall.ReducerName switch
+			{
 				"send_message" => new Reducer.SendMessage(BSATNHelpers.Decode<SendMessage>(encodedArgs)),
 				"set_name" => new Reducer.SetName(BSATNHelpers.Decode<SetName>(encodedArgs)),
 				"<none>" => new Reducer.StdbNone(default),
@@ -153,7 +168,8 @@ protected override IEventContext ToEventContext(Event<Reducer> reducerEvent) =>
 		protected override bool Dispatch(IEventContext context, Reducer reducer)
 		{
 			var eventContext = (EventContext)context;
-			return reducer switch {
+			return reducer switch
+			{
 				Reducer.SendMessage(var args) => Reducers.InvokeSendMessage(eventContext, args),
 				Reducer.SetName(var args) => Reducers.InvokeSetName(eventContext, args),
 				Reducer.StdbNone or
diff --git a/src/CallReducerFlags.cs b/src/CallReducerFlags.cs
new file mode 100644
index 00000000..0a3ea363
--- /dev/null
+++ b/src/CallReducerFlags.cs
@@ -0,0 +1,9 @@
+namespace SpacetimeDB
+{
+    public enum CallReducerFlags : byte
+    {
+        // This is the default.
+        FullUpdate = 0,
+        NoSuccessNotify = 1,
+    }
+}
diff --git a/src/SpacetimeDB/ClientApi/BsatnRowList.cs b/src/SpacetimeDB/ClientApi/BsatnRowList.cs
index 5df43d6b..1f17c790 100644
--- a/src/SpacetimeDB/ClientApi/BsatnRowList.cs
+++ b/src/SpacetimeDB/ClientApi/BsatnRowList.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/CallReducer.cs b/src/SpacetimeDB/ClientApi/CallReducer.cs
index 7c3ce90e..212d9bb3 100644
--- a/src/SpacetimeDB/ClientApi/CallReducer.cs
+++ b/src/SpacetimeDB/ClientApi/CallReducer.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
@@ -22,16 +21,20 @@ public partial class CallReducer
 		public byte[] Args;
 		[DataMember(Name = "request_id")]
 		public uint RequestId;
+		[DataMember(Name = "flags")]
+		public byte Flags;
 
 		public CallReducer(
 			string Reducer,
 			byte[] Args,
-			uint RequestId
+			uint RequestId,
+			byte Flags
 		)
 		{
 			this.Reducer = Reducer;
 			this.Args = Args;
 			this.RequestId = RequestId;
+			this.Flags = Flags;
 		}
 
 		public CallReducer()
diff --git a/src/SpacetimeDB/ClientApi/OneOffQuery.cs b/src/SpacetimeDB/ClientApi/OneOffQuery.cs
index 5ee2c66d..11370a54 100644
--- a/src/SpacetimeDB/ClientApi/OneOffQuery.cs
+++ b/src/SpacetimeDB/ClientApi/OneOffQuery.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs b/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs
index f539516f..2bdb8e1a 100644
--- a/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs
+++ b/src/SpacetimeDB/ClientApi/OneOffQueryResponse.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/QueryUpdate.cs b/src/SpacetimeDB/ClientApi/QueryUpdate.cs
index 858dea65..25acc28e 100644
--- a/src/SpacetimeDB/ClientApi/QueryUpdate.cs
+++ b/src/SpacetimeDB/ClientApi/QueryUpdate.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs b/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs
index 0ca52252..f8acaffd 100644
--- a/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs
+++ b/src/SpacetimeDB/ClientApi/ReducerCallInfo.cs
@@ -7,7 +7,6 @@
 using System;
 using SpacetimeDB;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.Serialization;
 
 namespace SpacetimeDB.ClientApi
diff --git a/src/SpacetimeDB/ClientApi/ServerMessage.cs b/src/SpacetimeDB/ClientApi/ServerMessage.cs
index 46b5be3a..f66fdd98 100644
--- a/src/SpacetimeDB/ClientApi/ServerMessage.cs
+++ b/src/SpacetimeDB/ClientApi/ServerMessage.cs
@@ -13,6 +13,7 @@ namespace SpacetimeDB.ClientApi
 	public partial record ServerMessage : SpacetimeDB.TaggedEnum<(
 		SpacetimeDB.ClientApi.InitialSubscription InitialSubscription,
 		SpacetimeDB.ClientApi.TransactionUpdate TransactionUpdate,
+		SpacetimeDB.ClientApi.TransactionUpdateLight TransactionUpdateLight,
 		SpacetimeDB.ClientApi.IdentityToken IdentityToken,
 		SpacetimeDB.ClientApi.OneOffQueryResponse OneOffQueryResponse
 	)>;
diff --git a/src/SpacetimeDB/ClientApi/TransactionUpdateLight.cs b/src/SpacetimeDB/ClientApi/TransactionUpdateLight.cs
new file mode 100644
index 00000000..3a3ea6b5
--- /dev/null
+++ b/src/SpacetimeDB/ClientApi/TransactionUpdateLight.cs
@@ -0,0 +1,38 @@
+// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
+// WILL NOT BE SAVED. MODIFY TABLES IN RUST INSTEAD.
+// <auto-generated />
+
+#nullable enable
+
+using System;
+using SpacetimeDB;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+
+namespace SpacetimeDB.ClientApi
+{
+	[SpacetimeDB.Type]
+	[DataContract]
+	public partial class TransactionUpdateLight
+	{
+		[DataMember(Name = "request_id")]
+		public uint RequestId;
+		[DataMember(Name = "update")]
+		public SpacetimeDB.ClientApi.DatabaseUpdate Update;
+
+		public TransactionUpdateLight(
+			uint RequestId,
+			SpacetimeDB.ClientApi.DatabaseUpdate Update
+		)
+		{
+			this.RequestId = RequestId;
+			this.Update = Update;
+		}
+
+		public TransactionUpdateLight()
+		{
+			this.Update = new();
+		}
+
+	}
+}
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 7fa8dd6f..859a3d54 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -23,6 +23,7 @@ public sealed class DbConnectionBuilder<DbConnection, Reducer>
         string? nameOrAddress;
         string? token;
         Compression? compression;
+        bool light;
 
         public DbConnection Build()
         {
@@ -34,7 +35,7 @@ public DbConnection Build()
             {
                 throw new InvalidOperationException("Building DbConnection with a null nameOrAddress. Call WithModuleName() first.");
             }
-            conn.Connect(token, uri, nameOrAddress, compression ?? Compression.Brotli);
+            conn.Connect(token, uri, nameOrAddress, compression ?? Compression.Brotli, light);
 #if UNITY_5_3_OR_NEWER
             SpacetimeDBNetworkManager.ActiveConnections.Add(conn);
 #endif
@@ -65,6 +66,12 @@ public DbConnectionBuilder<DbConnection, Reducer> WithCompression(Compression co
             return this;
         }
 
+        public DbConnectionBuilder<DbConnection, Reducer> WithLightMode(bool light)
+        {
+            this.light = light;
+            return this;
+        }
+
         public DbConnectionBuilder<DbConnection, Reducer> OnConnect(Action<DbConnection, Identity, string> cb)
         {
             conn.onConnect += (identity, token) => cb.Invoke(conn, identity, token);
@@ -331,18 +338,28 @@ void PreProcessMessages()
                 }
             }
 
-            PreProcessedMessage PreProcessMessage(UnprocessedMessage unprocessed)
+            IEnumerable<(IRemoteTableHandle, TableUpdate)> GetTables(DatabaseUpdate updates)
             {
-                var dbOps = new List<DbOp>();
+                foreach (var update in updates.Tables)
+                {
+                    var tableName = update.TableName;
+                    var table = clientDB.GetTable(tableName);
+                    if (table == null)
+                    {
+                        Log.Error($"Unknown table name: {tableName}");
+                        continue;
+                    }
 
-                var message = DecompressDecodeMessage(unprocessed.bytes);
+                    yield return (table, update);
+                }
+            }
 
-                ReducerEvent<Reducer>? reducerEvent = default;
+            (List<DbOp>, Dictionary<System.Type, HashSet<byte[]>>?) PreProcessInitialSubscription(InitialSubscription initSub)
+            {
+                var dbOps = new List<DbOp>();
 
                 // This is all of the inserts
                 Dictionary<System.Type, HashSet<byte[]>>? subscriptionInserts = null;
-                // All row updates that have a primary key, this contains inserts, deletes and updates
-                var primaryKeyChanges = new Dictionary<(System.Type tableType, object primaryKeyValue), DbOp>();
 
                 HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                 {
@@ -355,54 +372,168 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
                     return hashSet;
                 }
 
-                switch (message)
+                int cap = initSub.DatabaseUpdate.Tables.Sum(a => (int)a.NumRows);
+                subscriptionInserts = new(capacity: cap);
+
+                // First apply all of the state
+                foreach (var (table, update) in GetTables(initSub.DatabaseUpdate))
                 {
-                    case ServerMessage.InitialSubscription(var initialSubscription):
-                        int cap = initialSubscription.DatabaseUpdate.Tables.Sum(a => (int)a.NumRows);
-                        subscriptionInserts = new(capacity: cap);
+                    var hashSet = GetInsertHashSet(table.ClientTableType, (int)update.NumRows);
+
+                    foreach (var cqu in update.Updates)
+                    {
+                        var qu = DecompressDecodeQueryUpdate(cqu);
+                        if (BsatnRowListCount(qu.Deletes) != 0)
+                        {
+                            Log.Warn("Non-insert during a subscription update!");
+                        }
 
-                        // First apply all of the state
-                        foreach (var update in initialSubscription.DatabaseUpdate.Tables)
+                        foreach (var bin in BsatnRowListIter(qu.Inserts))
                         {
-                            var tableName = update.TableName;
-                            var table = clientDB.GetTable(tableName);
-                            if (table == null)
+                            if (!hashSet.Add(bin))
                             {
-                                Log.Error($"Unknown table name: {tableName}");
+                                // Ignore duplicate inserts in the same subscription update.
                                 continue;
                             }
 
-                            var hashSet = GetInsertHashSet(table.ClientTableType, (int)update.NumRows);
+                            var obj = table.DecodeValue(bin);
+                            var op = new DbOp
+                            {
+                                table = table,
+                                insert = new(obj, bin),
+                            };
+
+                            dbOps.Add(op);
+                        }
+                    }
+                }
+
+                return (dbOps, subscriptionInserts);
+            }
+
+            List<DbOp> PreProcessDatabaseUpdate(DatabaseUpdate updates)
+            {
+                var dbOps = new List<DbOp>();
 
-                            foreach (var cqu in update.Updates)
+                // All row updates that have a primary key, this contains inserts, deletes and updates
+                var primaryKeyChanges = new Dictionary<(System.Type tableType, object primaryKeyValue), DbOp>();
+
+                // First apply all of the state
+                foreach (var (table, update) in GetTables(updates))
+                {
+                    foreach (var cqu in update.Updates)
+                    {
+                        var qu = DecompressDecodeQueryUpdate(cqu);
+                        foreach (var row in BsatnRowListIter(qu.Inserts))
+                        {
+                            var op = new DbOp { table = table, insert = Decode(table, row, out var pk) };
+                            if (pk != null)
                             {
-                                var qu = DecompressDecodeQueryUpdate(cqu);
-                                if (BsatnRowListCount(qu.Deletes) != 0)
+                                // Compound key that we use for lookup.
+                                // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
+                                var key = (table.ClientTableType, pk);
+
+                                if (primaryKeyChanges.TryGetValue(key, out var oldOp))
                                 {
-                                    Log.Warn("Non-insert during a subscription update!");
+                                    if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
+                                    {
+                                        Log.Warn($"Update with the same primary key was applied multiple times! tableName={update.TableName}");
+                                        // TODO(jdetter): Is this a correctable error? This would be a major error on the
+                                        // SpacetimeDB side.
+                                        continue;
+                                    }
+
+                                    var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
+                                    op = new DbOp
+                                    {
+                                        table = insertOp.table,
+                                        delete = deleteOp.delete,
+                                        insert = insertOp.insert,
+                                    };
                                 }
+                                primaryKeyChanges[key] = op;
+                            }
+                            else
+                            {
+                                dbOps.Add(op);
+                            }
+                        }
 
-                                foreach (var bin in BsatnRowListIter(qu.Inserts))
+                        foreach (var row in BsatnRowListIter(qu.Deletes))
+                        {
+                            var op = new DbOp { table = table, delete = Decode(table, row, out var pk) };
+                            if (pk != null)
+                            {
+                                // Compound key that we use for lookup.
+                                // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
+                                var key = (table.ClientTableType, pk);
+
+                                if (primaryKeyChanges.TryGetValue(key, out var oldOp))
                                 {
-                                    if (!hashSet.Add(bin))
+                                    if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
                                     {
-                                        // Ignore duplicate inserts in the same subscription update.
+                                        Log.Warn($"Update with the same primary key was applied multiple times! tableName={update.TableName}");
+                                        // TODO(jdetter): Is this a correctable error? This would be a major error on the
+                                        // SpacetimeDB side.
                                         continue;
                                     }
 
-                                    var obj = table.DecodeValue(bin);
-                                    var op = new DbOp
+                                    var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
+                                    op = new DbOp
                                     {
-                                        table = table,
-                                        insert = new(obj, bin),
+                                        table = insertOp.table,
+                                        delete = deleteOp.delete,
+                                        insert = insertOp.insert,
                                     };
-
-                                    dbOps.Add(op);
                                 }
+                                primaryKeyChanges[key] = op;
+                            }
+                            else
+                            {
+                                dbOps.Add(op);
                             }
                         }
-                        break;
+                    }
+                }
+
+                // Combine primary key updates and non-primary key updates
+                dbOps.AddRange(primaryKeyChanges.Values);
+
+                return dbOps;
+            }
+
+            void PreProcessOneOffQuery(OneOffQueryResponse resp)
+            {
+                /// This case does NOT produce a list of DBOps, because it should not modify the client cache state!
+                var messageId = new Guid(resp.MessageId);
 
+                if (!waitingOneOffQueries.Remove(messageId, out var resultSource))
+                {
+                    Log.Error($"Response to unknown one-off-query: {messageId}");
+                    return;
+                }
+
+                resultSource.SetResult(resp);
+            }
+
+            PreProcessedMessage PreProcessMessage(UnprocessedMessage unprocessed)
+            {
+                var dbOps = new List<DbOp>();
+
+                var message = DecompressDecodeMessage(unprocessed.bytes);
+
+                ReducerEvent<Reducer>? reducerEvent = default;
+
+                // This is all of the inserts
+                Dictionary<System.Type, HashSet<byte[]>>? subscriptionInserts = null;
+
+                switch (message)
+                {
+                    case ServerMessage.InitialSubscription(var initSub):
+                        var (ops, subIns) = PreProcessInitialSubscription(initSub);
+                        dbOps = ops;
+                        subscriptionInserts = subIns;
+                        break;
                     case ServerMessage.TransactionUpdate(var transactionUpdate):
                         // Convert the generic event arguments in to a domain specific event object
                         try
@@ -428,111 +559,16 @@ HashSet<byte[]> GetInsertHashSet(System.Type tableType, int tableSize)
 
                         if (transactionUpdate.Status is UpdateStatus.Committed(var committed))
                         {
-                            primaryKeyChanges = new();
-
-                            // First apply all of the state
-                            foreach (var update in committed.Tables)
-                            {
-                                var tableName = update.TableName;
-                                var table = clientDB.GetTable(tableName);
-                                if (table == null)
-                                {
-                                    Log.Error($"Unknown table name: {tableName}");
-                                    continue;
-                                }
-
-                                foreach (var cqu in update.Updates)
-                                {
-                                    var qu = DecompressDecodeQueryUpdate(cqu);
-                                    foreach (var row in BsatnRowListIter(qu.Inserts))
-                                    {
-                                        var op = new DbOp { table = table, insert = Decode(table, row, out var pk) };
-                                        if (pk != null)
-                                        {
-                                            // Compound key that we use for lookup.
-                                            // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
-                                            var key = (table.ClientTableType, pk);
-
-                                            if (primaryKeyChanges.TryGetValue(key, out var oldOp))
-                                            {
-                                                if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
-                                                {
-                                                    Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
-                                                    // TODO(jdetter): Is this a correctable error? This would be a major error on the
-                                                    // SpacetimeDB side.
-                                                    continue;
-                                                }
-
-                                                var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
-                                                op = new DbOp
-                                                {
-                                                    table = insertOp.table,
-                                                    delete = deleteOp.delete,
-                                                    insert = insertOp.insert,
-                                                };
-                                            }
-                                            primaryKeyChanges[key] = op;
-                                        }
-                                        else
-                                        {
-                                            dbOps.Add(op);
-                                        }
-                                    }
-
-                                    foreach (var row in BsatnRowListIter(qu.Deletes))
-                                    {
-                                        var op = new DbOp { table = table, delete = Decode(table, row, out var pk) };
-                                        if (pk != null)
-                                        {
-                                            // Compound key that we use for lookup.
-                                            // Consists of type of the table (for faster comparison that string names) + actual primary key of the row.
-                                            var key = (table.ClientTableType, pk);
-
-                                            if (primaryKeyChanges.TryGetValue(key, out var oldOp))
-                                            {
-                                                if ((op.insert is not null && oldOp.insert is not null) || (op.delete is not null && oldOp.delete is not null))
-                                                {
-                                                    Log.Warn($"Update with the same primary key was applied multiple times! tableName={tableName}");
-                                                    // TODO(jdetter): Is this a correctable error? This would be a major error on the
-                                                    // SpacetimeDB side.
-                                                    continue;
-                                                }
-
-                                                var (insertOp, deleteOp) = op.insert is not null ? (op, oldOp) : (oldOp, op);
-                                                op = new DbOp
-                                                {
-                                                    table = insertOp.table,
-                                                    delete = deleteOp.delete,
-                                                    insert = insertOp.insert,
-                                                };
-                                            }
-                                            primaryKeyChanges[key] = op;
-                                        }
-                                        else
-                                        {
-                                            dbOps.Add(op);
-                                        }
-                                    }
-                                }
-                            }
-
-                            // Combine primary key updates and non-primary key updates
-                            dbOps.AddRange(primaryKeyChanges.Values);
+                            dbOps = PreProcessDatabaseUpdate(committed);
                         }
                         break;
+                    case ServerMessage.TransactionUpdateLight(var update):
+                        dbOps = PreProcessDatabaseUpdate(update.Update);
+                        break;
                     case ServerMessage.IdentityToken(var identityToken):
                         break;
                     case ServerMessage.OneOffQueryResponse(var resp):
-                        /// This case does NOT produce a list of DBOps, because it should not modify the client cache state!
-                        var messageId = new Guid(resp.MessageId);
-
-                        if (!waitingOneOffQueries.Remove(messageId, out var resultSource))
-                        {
-                            Log.Error($"Response to unknown one-off-query: {messageId}");
-                            break;
-                        }
-
-                        resultSource.SetResult(resp);
+                        PreProcessOneOffQuery(resp);
                         break;
                     default:
                         throw new InvalidOperationException();
@@ -594,7 +630,7 @@ public void Disconnect()
         /// </summary>
         /// <param name="uri"> URI of the SpacetimeDB server (ex: https://testnet.spacetimedb.com)
         /// <param name="addressOrName">The name or address of the database to connect to</param>
-        internal void Connect(string? token, string uri, string addressOrName, Compression compression)
+        internal void Connect(string? token, string uri, string addressOrName, Compression compression, bool light)
         {
             isClosing = false;
 
@@ -612,7 +648,7 @@ internal void Connect(string? token, string uri, string addressOrName, Compressi
                 {
                     try
                     {
-                        await webSocket.Connect(token, uri, addressOrName, Address, compression);
+                        await webSocket.Connect(token, uri, addressOrName, Address, compression, light);
                     }
                     catch (Exception e)
                     {
@@ -736,6 +772,16 @@ private void OnMessageProcessComplete(PreProcessedMessage preProcessed)
                         }
                         break;
                     }
+                case ServerMessage.TransactionUpdateLight(var update):
+                    {
+                        stats.ParseMessageTracker.InsertRequest(timestamp, $"type={nameof(ServerMessage.TransactionUpdateLight)}");
+
+                        var eventContext = ToEventContext(new Event<Reducer>.UnknownTransaction());
+                        OnMessageProcessCompleteUpdate(eventContext, dbOps);
+
+                        break;
+                    }
+
                 case ServerMessage.TransactionUpdate(var transactionUpdate):
                     {
                         var reducer = transactionUpdate.ReducerCall.ReducerName;
@@ -811,7 +857,7 @@ internal void OnMessageReceived(byte[] bytes, DateTime timestamp) =>
             _messageQueue.Add(new UnprocessedMessage { bytes = bytes, timestamp = timestamp });
 
         // TODO: this should become [Obsolete] but for now is used by autogenerated code.
-        public void InternalCallReducer<T>(T args)
+        public void InternalCallReducer<T>(T args, CallReducerFlags flags)
             where T : IReducerArgs, new()
         {
             if (!webSocket.IsConnected)
@@ -820,14 +866,12 @@ public void InternalCallReducer<T>(T args)
                 return;
             }
 
-            webSocket.Send(new ClientMessage.CallReducer(
-                new CallReducer
-                {
-                    RequestId = stats.ReducerRequestTracker.StartTrackingRequest(args.ReducerName),
-                    Reducer = args.ReducerName,
-                    Args = IStructuralReadWrite.ToBytes(args)
-                }
-            ));
+            webSocket.Send(new ClientMessage.CallReducer(new CallReducer(
+                args.ReducerName,
+                IStructuralReadWrite.ToBytes(args),
+                stats.ReducerRequestTracker.StartTrackingRequest(args.ReducerName),
+                (byte)flags
+            )));
         }
 
         void IDbConnection.Subscribe(ISubscriptionHandle handle, string[] querySqls)
diff --git a/src/WebSocket.cs b/src/WebSocket.cs
index 86f47c70..bf65c84e 100644
--- a/src/WebSocket.cs
+++ b/src/WebSocket.cs
@@ -51,9 +51,14 @@ public WebSocket(ConnectOptions options)
 
         public bool IsConnected { get { return Ws != null && Ws.State == WebSocketState.Open; } }
 
-        public async Task Connect(string? auth, string host, string nameOrAddress, Address clientAddress, Compression compression)
+        public async Task Connect(string? auth, string host, string nameOrAddress, Address clientAddress, Compression compression, bool light)
         {
-            var url = new Uri($"{host}/database/subscribe/{nameOrAddress}?client_address={clientAddress}&compression={compression}");
+            var uri = $"{host}/database/subscribe/{nameOrAddress}?client_address={clientAddress}&compression={compression}";
+            if (light)
+            {
+                uri += "&light=true";
+            }
+            var url = new Uri(uri);
             Ws.Options.AddSubProtocol(_options.Protocol);
 
             var source = new CancellationTokenSource(10000);
diff --git a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
index ea57bb0e..e3ae0cdc 100644
--- a/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
+++ b/tests~/SnapshotTests.VerifyAllTablesParsed.verified.txt
@@ -8,6 +8,7 @@
     OnInsertUser: {
       eventContext: {
         Reducers: {Scrubbed},
+        SetReducerFlags: {},
         Event: {},
         Db: {Scrubbed}
       },
@@ -20,6 +21,7 @@
     OnInsertUser: {
       eventContext: {
         Reducers: {Scrubbed},
+        SetReducerFlags: {},
         Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_1,
@@ -40,6 +42,7 @@
     OnUpdateUser: {
       eventContext: {
         Reducers: {Scrubbed},
+        SetReducerFlags: {},
         Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_2,
@@ -68,6 +71,7 @@
     },
     OnSetName: {
       Reducers: {Scrubbed},
+      SetReducerFlags: {},
       Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_2,
@@ -87,6 +91,7 @@
     OnInsertMessage: {
       eventContext: {
         Reducers: {Scrubbed},
+        SetReducerFlags: {},
         Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_3,
@@ -111,6 +116,7 @@
     },
     OnSendMessage: {
       Reducers: {Scrubbed},
+      SetReducerFlags: {},
       Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_3,
@@ -130,6 +136,7 @@
     OnUpdateUser: {
       eventContext: {
         Reducers: {Scrubbed},
+        SetReducerFlags: {},
         Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_4,
@@ -158,6 +165,7 @@
     },
     OnSetName: {
       Reducers: {Scrubbed},
+      SetReducerFlags: {},
       Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_4,
@@ -177,6 +185,7 @@
     OnInsertMessage: {
       eventContext: {
         Reducers: {Scrubbed},
+        SetReducerFlags: {},
         Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_5,
@@ -201,6 +210,7 @@
     },
     OnSendMessage: {
       Reducers: {Scrubbed},
+      SetReducerFlags: {},
       Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_5,
@@ -220,6 +230,7 @@
     OnInsertMessage: {
       eventContext: {
         Reducers: {Scrubbed},
+        SetReducerFlags: {},
         Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_6,
@@ -244,6 +255,7 @@
     },
     OnSendMessage: {
       Reducers: {Scrubbed},
+      SetReducerFlags: {},
       Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_6,
@@ -263,6 +275,7 @@
     OnUpdateUser: {
       eventContext: {
         Reducers: {Scrubbed},
+        SetReducerFlags: {},
         Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_7,
@@ -289,6 +302,7 @@
     OnInsertMessage: {
       eventContext: {
         Reducers: {Scrubbed},
+        SetReducerFlags: {},
         Event: {
           ReducerEvent: {
             Timestamp: DateTimeOffset_8,
@@ -313,6 +327,7 @@
     },
     OnSendMessage: {
       Reducers: {Scrubbed},
+      SetReducerFlags: {},
       Event: {
         ReducerEvent: {
           Timestamp: DateTimeOffset_8,
@@ -390,4 +405,4 @@
       Max: type=InitialSubscription
     }
   }
-}
\ No newline at end of file
+}
diff --git a/tools~/gen-client-api.sh b/tools~/gen-client-api.sh
old mode 100644
new mode 100755

From befe0d1bf46d121276f781aeab850a85db56cfa0 Mon Sep 17 00:00:00 2001
From: Tyler Cloutier <cloutiertyler@aol.com>
Date: Tue, 29 Oct 2024 21:47:48 -0400
Subject: [PATCH 40/55] Added missing meta files

---
 src/CallReducerFlags.cs.meta                          | 11 +++++++++++
 src/Compression.cs.meta                               |  8 ++++----
 .../ClientApi/TransactionUpdateLight.cs.meta          | 11 +++++++++++
 3 files changed, 26 insertions(+), 4 deletions(-)
 create mode 100644 src/CallReducerFlags.cs.meta
 create mode 100644 src/SpacetimeDB/ClientApi/TransactionUpdateLight.cs.meta

diff --git a/src/CallReducerFlags.cs.meta b/src/CallReducerFlags.cs.meta
new file mode 100644
index 00000000..dbfee1f8
--- /dev/null
+++ b/src/CallReducerFlags.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c0567f0d188b749659b7291c277a2b17
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/src/Compression.cs.meta b/src/Compression.cs.meta
index eef0325c..31f1b190 100644
--- a/src/Compression.cs.meta
+++ b/src/Compression.cs.meta
@@ -1,11 +1,11 @@
 fileFormatVersion: 2
-guid: 03fdc211a87474eeba9f03495eab491e
+guid: 78dd2c1276a6e4e859d2c4fad671c2c7
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0
   icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
+  userData:
+  assetBundleName:
+  assetBundleVariant:
diff --git a/src/SpacetimeDB/ClientApi/TransactionUpdateLight.cs.meta b/src/SpacetimeDB/ClientApi/TransactionUpdateLight.cs.meta
new file mode 100644
index 00000000..50cff86d
--- /dev/null
+++ b/src/SpacetimeDB/ClientApi/TransactionUpdateLight.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: de607af1bdc1244f894fb952d4199473
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

From c1cfca3a33768f5996095d63fec671d3642986c5 Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Thu, 31 Oct 2024 15:42:52 -0400
Subject: [PATCH 41/55] Update quickstart chat server for 0.12 host

---
 examples~/quickstart/server/.gitignore |  6 +-
 examples~/quickstart/server/Cargo.lock | 95 +++++++++++++++++++-------
 examples~/quickstart/server/Cargo.toml |  5 +-
 examples~/quickstart/server/src/lib.rs | 91 ++++++++++++------------
 4 files changed, 124 insertions(+), 73 deletions(-)

diff --git a/examples~/quickstart/server/.gitignore b/examples~/quickstart/server/.gitignore
index 91ad2584..31b13f05 100644
--- a/examples~/quickstart/server/.gitignore
+++ b/examples~/quickstart/server/.gitignore
@@ -3,6 +3,10 @@
 debug/
 target/
 
+# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
+# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
+Cargo.lock
+
 # These are backup files generated by rustfmt
 **/*.rs.bk
 
@@ -10,4 +14,4 @@ target/
 *.pdb
 
 # Spacetime ignore
-/.spacetime
+/.spacetime
\ No newline at end of file
diff --git a/examples~/quickstart/server/Cargo.lock b/examples~/quickstart/server/Cargo.lock
index 372fb071..e0f96b7c 100644
--- a/examples~/quickstart/server/Cargo.lock
+++ b/examples~/quickstart/server/Cargo.lock
@@ -62,6 +62,18 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "bytemuck"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
+
+[[package]]
+name = "bytes"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
+
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -144,6 +156,15 @@ dependencies = [
  "syn 2.0.32",
 ]
 
+[[package]]
+name = "ethnum"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "generic-array"
 version = "0.14.7"
@@ -259,6 +280,14 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "quickstart-chat-module"
+version = "0.1.0"
+dependencies = [
+ "log",
+ "spacetimedb",
+]
+
 [[package]]
 name = "quote"
 version = "1.0.29"
@@ -325,6 +354,26 @@ version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 
+[[package]]
+name = "serde"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.32",
+]
+
 [[package]]
 name = "sha3"
 version = "0.10.8"
@@ -341,21 +390,13 @@ version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
-[[package]]
-name = "spacetime-module"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "log",
- "spacetimedb",
-]
-
 [[package]]
 name = "spacetimedb"
-version = "0.10.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec3fbc884bd532f1f9cddcde961686284091dfa3facd49b71c553df28d30a5f"
+checksum = "6b083dadcc676ec1f2bdbd862776ac2fb295c7cd1cd63a671f3e4660c22ce4c7"
 dependencies = [
+ "bytemuck",
  "derive_more",
  "getrandom",
  "log",
@@ -369,11 +410,12 @@ dependencies = [
 
 [[package]]
 name = "spacetimedb-bindings-macro"
-version = "0.10.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a5a6d8be2a892ae1d1175b228f12deffb685947cc30d60449dba98219cc3bc2"
+checksum = "f2216aa0e94ee5eff29322f7a80b847674a6415bdedca36267d4f9827838ef17"
 dependencies = [
  "bitflags",
+ "heck",
  "humantime",
  "proc-macro2",
  "quote",
@@ -383,29 +425,30 @@ dependencies = [
 
 [[package]]
 name = "spacetimedb-bindings-sys"
-version = "0.10.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a450cdc41a3d6a6a33ba113255c2a1d73dbf32bcf7aa2d272beb58cc6efe9655"
+checksum = "bd06c9176160de7138fdd579fcac3fb5735441bdf82896ce9bcadc7000892362"
 dependencies = [
  "spacetimedb-primitives",
 ]
 
 [[package]]
 name = "spacetimedb-data-structures"
-version = "0.10.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d866aa0c287936e13f03206f32c15ce46893076918b7d1d9e1a1421ddca2e6a"
+checksum = "0293e7ff788f4d36e85f4029e946145b3ca884d3702b046b1f05497931e2c117"
 dependencies = [
  "hashbrown",
  "nohash-hasher",
+ "smallvec",
  "thiserror",
 ]
 
 [[package]]
 name = "spacetimedb-lib"
-version = "0.10.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0c1d4c3106bdfe395c8f266df1daff9e6259322bd70d05e3f78c7fa67efd14f"
+checksum = "e9e92b11f138722de120c6bba2cdc46d0aed348fbeb673bd60d8758a5199e6ac"
 dependencies = [
  "anyhow",
  "bitflags",
@@ -414,6 +457,7 @@ dependencies = [
  "hex",
  "itertools",
  "spacetimedb-bindings-macro",
+ "spacetimedb-data-structures",
  "spacetimedb-primitives",
  "spacetimedb-sats",
  "thiserror",
@@ -421,33 +465,36 @@ dependencies = [
 
 [[package]]
 name = "spacetimedb-primitives"
-version = "0.10.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38f80f43ce78747ae4deb061130fcbedf9c57cbe9d3db8269e2ce403d6cf3a0c"
+checksum = "02c6c81cb1df7d6bd77923121d1663f8bbe8e28e669d29d25b335fc81a2a3ccd"
 dependencies = [
  "bitflags",
  "either",
+ "itertools",
  "nohash-hasher",
 ]
 
 [[package]]
 name = "spacetimedb-sats"
-version = "0.10.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ab8da7807277abaef5452d25c3cbc01978297a37d0f00071e52621e655b3a84"
+checksum = "b6e07d8e872575b4825eb62c1bbb6f0a50081858664bbe9ee135f977ee7263d2"
 dependencies = [
  "arrayvec",
  "bitflags",
+ "bytemuck",
+ "bytes",
  "decorum",
  "derive_more",
  "enum-as-inner",
+ "ethnum",
  "hex",
  "itertools",
  "second-stack",
  "sha3",
  "smallvec",
  "spacetimedb-bindings-macro",
- "spacetimedb-data-structures",
  "spacetimedb-primitives",
  "thiserror",
 ]
diff --git a/examples~/quickstart/server/Cargo.toml b/examples~/quickstart/server/Cargo.toml
index 735a5ad6..4775c4e1 100644
--- a/examples~/quickstart/server/Cargo.toml
+++ b/examples~/quickstart/server/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "spacetime-module"
+name = "quickstart-chat-module"
 version = "0.1.0"
 edition = "2021"
 
@@ -9,6 +9,5 @@ edition = "2021"
 crate-type = ["cdylib"]
 
 [dependencies]
-spacetimedb = "0.10"
+spacetimedb = "0.12.0"
 log = "0.4"
-anyhow = "1.0"
diff --git a/examples~/quickstart/server/src/lib.rs b/examples~/quickstart/server/src/lib.rs
index 015aaefe..cf986470 100644
--- a/examples~/quickstart/server/src/lib.rs
+++ b/examples~/quickstart/server/src/lib.rs
@@ -1,5 +1,4 @@
-use spacetimedb::{ReducerContext, Identity, Table, Timestamp};
-use anyhow::{Result, anyhow};
+use spacetimedb::{Identity, ReducerContext, Table, Timestamp};
 
 #[spacetimedb::table(name = user, public)]
 pub struct User {
@@ -16,71 +15,41 @@ pub struct Message {
     text: String,
 }
 
-#[spacetimedb::reducer(init)]
-pub fn init(_ctx: &ReducerContext) {
-	
-}
-
-#[spacetimedb::reducer(client_connected)]
-pub fn identity_connected(ctx: &ReducerContext) {
-    if let Some(user) = ctx.db.user().identity().find(&ctx.sender) {
-        // If this is a returning user, i.e. we already have a `User` with this `Identity`,
-        // set `online: true`, but leave `name` and `identity` unchanged.
-        ctx.db.user().identity().update(User { online: true, ..user });
-    } else {
-        // If this is a new user, create a `User` row for the `Identity`,
-        // which is online, but hasn't set a name.
-        ctx.db.user().try_insert(User {
-            name: None,
-            identity: ctx.sender,
-            online: true,
-        }).unwrap();
-    }
-}
-
-#[spacetimedb::reducer(client_disconnected)]
-pub fn identity_disconnected(ctx: &ReducerContext) {
-    if let Some(user) = ctx.db.user().identity().find(&ctx.sender) {
-        ctx.db.user().identity().update(User { online: false, ..user });
-    } else {
-        // This branch should be unreachable,
-        // as it doesn't make sense for a client to disconnect without connecting first.
-        log::warn!("Disconnect event for unknown user with identity {:?}", ctx.sender);
-    }
-}
-
-fn validate_name(name: String) -> Result<String> {
+fn validate_name(name: String) -> Result<String, String> {
     if name.is_empty() {
-        Err(anyhow!("Names must not be empty"))
+        Err("Names must not be empty".to_string())
     } else {
         Ok(name)
     }
 }
 
 #[spacetimedb::reducer]
-pub fn set_name(ctx: &ReducerContext, name: String) -> Result<()> {
+pub fn set_name(ctx: &ReducerContext, name: String) -> Result<(), String> {
     let name = validate_name(name)?;
-    if let Some(user) = ctx.db.user().identity().find(&ctx.sender) {
-        ctx.db.user().identity().update(User { name: Some(name), ..user });
+    if let Some(user) = ctx.db.user().identity().find(ctx.sender) {
+        ctx.db.user().identity().update(User {
+            name: Some(name),
+            ..user
+        });
         Ok(())
     } else {
-        Err(anyhow!("Cannot set name for unknown user"))
+        Err("Cannot set name for unknown user".to_string())
     }
 }
 
-fn validate_message(text: String) -> Result<String> {
+fn validate_message(text: String) -> Result<String, String> {
     if text.is_empty() {
-        Err(anyhow!("Messages must not be empty"))
+        Err("Messages must not be empty".to_string())
     } else {
         Ok(text)
     }
 }
 
 #[spacetimedb::reducer]
-pub fn send_message(ctx: &ReducerContext, text: String) -> Result<()> {
+pub fn send_message(ctx: &ReducerContext, text: String) -> Result<(), String> {
     // Things to consider:
     // - Rate-limit messages per-user.
-    // - Reject messages from unnamed users.
+    // - Reject messages from unnamed user.
     let text = validate_message(text)?;
     ctx.db.message().insert(Message {
         sender: ctx.sender,
@@ -89,3 +58,35 @@ pub fn send_message(ctx: &ReducerContext, text: String) -> Result<()> {
     });
     Ok(())
 }
+
+#[spacetimedb::reducer(init)]
+// Called when the module is initially published
+pub fn init(_ctx: &ReducerContext) {}
+
+#[spacetimedb::reducer(client_connected)]
+pub fn identity_connected(ctx: &ReducerContext) {
+    if let Some(user) = ctx.db.user().identity().find(ctx.sender) {
+        // If this is a returning user, i.e. we already have a `User` with this `Identity`,
+        // set `online: true`, but leave `name` and `identity` unchanged.
+        ctx.db.user().identity().update(User { online: true, ..user });
+    } else {
+        // If this is a new user, create a `User` row for the `Identity`,
+        // which is online, but hasn't set a name.
+        ctx.db.user().insert(User {
+            name: None,
+            identity: ctx.sender,
+            online: true,
+        });
+    }
+}
+
+#[spacetimedb::reducer(client_disconnected)]
+pub fn identity_disconnected(ctx: &ReducerContext) {
+    if let Some(user) = ctx.db.user().identity().find(ctx.sender) {
+        ctx.db.user().identity().update(User { online: false, ..user });
+    } else {
+        // This branch should be unreachable,
+        // as it doesn't make sense for a client to disconnect without connecting first.
+        log::warn!("Disconnect event for unknown user with identity {:?}", ctx.sender);
+    }
+}

From fb41046d62ab2aac7d62e8c2d1a865a794edfc13 Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Thu, 31 Oct 2024 17:31:39 -0400
Subject: [PATCH 42/55] Update example stdb version

---
 examples~/quickstart/server/Cargo.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples~/quickstart/server/Cargo.toml b/examples~/quickstart/server/Cargo.toml
index 4775c4e1..db1752dc 100644
--- a/examples~/quickstart/server/Cargo.toml
+++ b/examples~/quickstart/server/Cargo.toml
@@ -9,5 +9,5 @@ edition = "2021"
 crate-type = ["cdylib"]
 
 [dependencies]
-spacetimedb = "0.12.0"
+spacetimedb = "1.0.0-rc1"
 log = "0.4"

From 3581ed7484d3684f0d318387c487fd6b9f27fd23 Mon Sep 17 00:00:00 2001
From: John Detter <4099508+jdetter@users.noreply.github.com>
Date: Thu, 31 Oct 2024 22:34:26 +0000
Subject: [PATCH 43/55] Fix Reconnection Logic (#168)

## Description of Changes
*Describe what has been changed, any new features or bug fixes*

- switched our "already connected" logic to using a reference to a
`MonoBehaviour` instead of just a bool. `MonoBehaviour`s are typically
destroyed when a scene reload happens and in this case we'll want to
allow developers to spawn a new `SpacetimeDBNetworkManager` if the
previous one has been destroyed.

## API

This is *not* an API break.

 - [ ] This is an API breaking change to the SDK

*If the API is breaking, please state below what will break*

## Requires SpacetimeDB PRs
*List any PRs here that are required for this SDK change to work*

- https://github.com/clockworklabs/SpacetimeDB/pull/1869

## Testsuite

SpacetimeDB branch name: master

## Testing
*Write instructions for a test that you performed for this PR*

- [x] I have added in several new tests here, one of which is a
reconnection test. Also, the reason why we couldn't have more than 1
test before this is that it was required for reconnections to be working
in order to have multiple tests running in the testsuite. Now that we
have fixed reconnections I have enabled all of the tests.

Testsuite passes


![image](https://github.com/user-attachments/assets/09ef5835-f2c7-41f1-af6b-e612ac5e0497)

---------

Co-authored-by: John Detter <no-reply@boppygames.gg>
Co-authored-by: Mazdak Farrokhzad <twingoow@gmail.com>
Co-authored-by: Jeremie Pelletier <jeremiep@gmail.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 .github/workflows/unity-test.yml              |  2 +-
 .../workflows/unity-testsuite-bindings.yml    |  4 +-
 .gitignore                                    |  1 +
 src/SpacetimeDBClient.cs                      | 13 +++-
 src/SpacetimeDBNetworkManager.cs              | 76 ++++++++++++-------
 unity-tests~                                  |  2 +-
 6 files changed, 63 insertions(+), 35 deletions(-)

diff --git a/.github/workflows/unity-test.yml b/.github/workflows/unity-test.yml
index 774fd847..29e50886 100644
--- a/.github/workflows/unity-test.yml
+++ b/.github/workflows/unity-test.yml
@@ -7,7 +7,7 @@ on:
   pull_request:
 
 jobs:
-  test:
+  unity-testsuite:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout repository
diff --git a/.github/workflows/unity-testsuite-bindings.yml b/.github/workflows/unity-testsuite-bindings.yml
index 1bfee47d..442abcd1 100644
--- a/.github/workflows/unity-testsuite-bindings.yml
+++ b/.github/workflows/unity-testsuite-bindings.yml
@@ -7,7 +7,7 @@ on:
   pull_request:
 
 jobs:
-  test:
+  check-testsuite-bindings:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout repository
@@ -110,7 +110,7 @@ jobs:
 
       - name: Check for changes
         run: |
-          git diff --exit-code
+          git diff --exit-code unity-tests~/client/Assets/Scripts/autogen
         continue-on-error: true
 
       - name: Fail if there are changes
diff --git a/.gitignore b/.gitignore
index 825b31b1..42502a20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -75,3 +75,4 @@ obj~
 # This is used for local paths to SpacetimeDB packages.
 /nuget.config
 /nuget.config.meta
+.idea/
diff --git a/src/SpacetimeDBClient.cs b/src/SpacetimeDBClient.cs
index 7fa8dd6f..d908763c 100644
--- a/src/SpacetimeDBClient.cs
+++ b/src/SpacetimeDBClient.cs
@@ -36,7 +36,10 @@ public DbConnection Build()
             }
             conn.Connect(token, uri, nameOrAddress, compression ?? Compression.Brotli);
 #if UNITY_5_3_OR_NEWER
-            SpacetimeDBNetworkManager.ActiveConnections.Add(conn);
+            if (SpacetimeDBNetworkManager._instance != null)
+            {
+                SpacetimeDBNetworkManager._instance.AddConnection(conn);    
+            }
 #endif
             return conn;
         }
@@ -163,7 +166,13 @@ protected DbConnectionBase()
             webSocket.OnMessage += OnMessageReceived;
             webSocket.OnSendError += a => onSendError?.Invoke(a);
 #if UNITY_5_3_OR_NEWER
-            webSocket.OnClose += (e) => SpacetimeDBNetworkManager.ActiveConnections.Remove(this);
+            webSocket.OnClose += (e) =>
+            {
+                if (SpacetimeDBNetworkManager._instance != null)
+                {
+                    SpacetimeDBNetworkManager._instance.RemoveConnection(this); 
+                }  
+            };
 #endif
 
             networkMessageProcessThread = new Thread(PreProcessMessages);
diff --git a/src/SpacetimeDBNetworkManager.cs b/src/SpacetimeDBNetworkManager.cs
index ae5e2d4f..379bf63d 100644
--- a/src/SpacetimeDBNetworkManager.cs
+++ b/src/SpacetimeDBNetworkManager.cs
@@ -6,38 +6,56 @@
 
 namespace SpacetimeDB
 {
-	// This class is only used in Unity projects.
-	// Attach this to a gameobject in your scene to use SpacetimeDB.
-	public class SpacetimeDBNetworkManager : MonoBehaviour
-	{
-		private static bool _alreadyInitialized;
+    // This class is only used in Unity projects.
+    // Attach this to a GameObject in your scene to use SpacetimeDB.
+    public class SpacetimeDBNetworkManager : MonoBehaviour
+    {
+        internal static SpacetimeDBNetworkManager? _instance;
 
-		public void Awake()
-		{
-			// Ensure that users don't create several SpacetimeDBNetworkManager instances.
-			// We're using a global (static) list of active connections and we don't want several instances to walk over it several times.
-			if (_alreadyInitialized)
-			{
-				throw new InvalidOperationException("SpacetimeDBNetworkManager is a singleton and should only be attached once.");
-			}
-			else
-			{
-				_alreadyInitialized = true;
-			}
-		}
+        public void Awake()
+        {
+            // Ensure that users don't create several SpacetimeDBNetworkManager instances.
+            // We're using a global (static) list of active connections and we don't want several instances to walk over it several times.
+            if (_instance != null)
+            {
+                throw new InvalidOperationException("SpacetimeDBNetworkManager is a singleton and should only be attached once.");
+            }
+            else
+            {
+                _instance = this;
+            }
+        }
 
-		internal static HashSet<IDbConnection> ActiveConnections = new();
+        private readonly List<IDbConnection> activeConnections = new();
 
-		private void ForEachConnection(Action<IDbConnection> action)
-		{
-			foreach (var conn in ActiveConnections)
-			{
-				action(conn);
-			}
-		}
+        public bool AddConnection(IDbConnection conn)
+        {
+            if (activeConnections.Contains(conn))
+            {
+                return false;
+            }
+            activeConnections.Add(conn);
+            return true;
 
-		private void Update() => ForEachConnection(conn => conn.FrameTick());
-		private void OnDestroy() => ForEachConnection(conn => conn.Disconnect());
-	}
+        }
+
+        public bool RemoveConnection(IDbConnection conn)
+        {
+            return activeConnections.Remove(conn);
+        }
+        
+        private void ForEachConnection(Action<IDbConnection> action)
+        {
+            // It's common to call disconnect from Update, which will then modify the ActiveConnections collection,
+            // therefore we must reverse-iterate the list of connections.
+            for (var x = activeConnections.Count - 1; x >= 0; x--)
+            {
+                action(activeConnections[x]);
+            }
+        }
+
+        private void Update() => ForEachConnection(conn => conn.FrameTick());
+        private void OnDestroy() => ForEachConnection(conn => conn.Disconnect());
+    }
 }
 #endif
diff --git a/unity-tests~ b/unity-tests~
index 75047b5e..386db358 160000
--- a/unity-tests~
+++ b/unity-tests~
@@ -1 +1 @@
-Subproject commit 75047b5e58a67ba8e3b652dab17ddde61b661989
+Subproject commit 386db35877caa84a6d8842cde1e8d1a823c7fd78

From 662e3e2a35913e222ade5acb70c4ba0fd76ce5b0 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Fri, 1 Nov 2024 10:07:00 -0700
Subject: [PATCH 44/55] regenerate DLLs from latest
 SpacetimeDB#release/v1.0.0-rc1 (be63a47e)

---
 .../dotnet/cs/SpacetimeDB.BSATN.Codegen.dll   | Bin 57344 -> 57344 bytes
 .../SpacetimeDB.BSATN.Runtime.dll             | Bin 64512 -> 64512 bytes
 2 files changed, 0 insertions(+), 0 deletions(-)

diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll b/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
index d25daddb24b51168c1c9b0f330b3047d0d54c689..b4965fc4efc59cb8ac32d6af56fd4518b4091f0f 100644
GIT binary patch
delta 238
zcmZoTz}#?vc|r$^63?AU8+(3i7l`o6tvtxl=(T`zq0u9oKOZ+w*-<8`k(6p?oM>X6
zYGiDbYLc9qoMd5XkeHZeZfu-vnPQxnl9pm&W@wUZzS-!~H)fVsCodeGtaB|u;ErlA
z!|qr6edfPYl<YZs^6=!IYfBZNf;so0f<V=-58{_^-zHvhZb#Hy?#+SMrCI%x7*ZL`
z7>pSb8B7?=fovln+XzUTFeC%XWQHUL3kFLD1E72&LmE(pF%TvLMN+_eQh;J9Kow>T
OhF~4$n|I%FWd;Bj<5Y71

delta 238
zcmZoTz}#?vc|r%v<jo<+H}?G4E^zYiGRr%8&%F9J%-box|4aSmDLcv}HH^{>(kv5A
zjgpO%63r}(Eld;5lMRdwEG<(^Qj<)~%uSNb(~=U?j5Zrx`o_#sAG&(;WSwgP0&3C*
zeKk_;p51@cnhl-5l~3-uwp0Ns_|h9H2vVJXNB-ElHRjQ46=(Ww4!kbS>Tkr5#$W)%
zmJEpurVK_5$qdE}NkFz4g9VUf0TfGQFb9en0C@&LRhA4X3?>YzKs6>nHReDv8Azsq
O^`tQvZQgyyl^Fo%@=vt@

diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
index 96670361095fbd462e5d19ef78c05f770ee2ac24..36caaf3f63b08f275db0631e6bb1319617d76e91 100644
GIT binary patch
delta 7578
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

delta 7520
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
XD2JnEDB5x`o?=!&miE{Wb%y@~hqb_k


From faacb45ab0c1c4d1c70f97fd9e3d788377a7b2b6 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Fri, 1 Nov 2024 10:09:45 -0700
Subject: [PATCH 45/55] empty commit to bump CI


From be120394edfe6363b08f82f079e55e9abc0807c5 Mon Sep 17 00:00:00 2001
From: Jeremie Pelletier <jeremiep@gmail.com>
Date: Mon, 4 Nov 2024 14:17:05 -0500
Subject: [PATCH 46/55] Update the quickstart module (#185)

Fix the quickstart client program, also removes the rust server program (it lives in the stdb main repo under modules/quickstart-chat)

Second subscription resets the first one without the fix

SpacetimeDB branch name: master
---
 .../quickstart/server/.cargo/config.toml      |   2 -
 examples~/quickstart/server/.gitignore        |  17 -
 examples~/quickstart/server/Cargo.lock        | 586 ------------------
 examples~/quickstart/server/Cargo.toml        |  13 -
 examples~/quickstart/server/src/lib.rs        |  92 ---
 5 files changed, 710 deletions(-)
 delete mode 100644 examples~/quickstart/server/.cargo/config.toml
 delete mode 100644 examples~/quickstart/server/.gitignore
 delete mode 100644 examples~/quickstart/server/Cargo.lock
 delete mode 100644 examples~/quickstart/server/Cargo.toml
 delete mode 100644 examples~/quickstart/server/src/lib.rs

diff --git a/examples~/quickstart/server/.cargo/config.toml b/examples~/quickstart/server/.cargo/config.toml
deleted file mode 100644
index f4e8c002..00000000
--- a/examples~/quickstart/server/.cargo/config.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-[build]
-target = "wasm32-unknown-unknown"
diff --git a/examples~/quickstart/server/.gitignore b/examples~/quickstart/server/.gitignore
deleted file mode 100644
index 31b13f05..00000000
--- a/examples~/quickstart/server/.gitignore
+++ /dev/null
@@ -1,17 +0,0 @@
-# Generated by Cargo
-# will have compiled files and executables
-debug/
-target/
-
-# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
-# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
-Cargo.lock
-
-# These are backup files generated by rustfmt
-**/*.rs.bk
-
-# MSVC Windows builds of rustc generate these, which store debugging information
-*.pdb
-
-# Spacetime ignore
-/.spacetime
\ No newline at end of file
diff --git a/examples~/quickstart/server/Cargo.lock b/examples~/quickstart/server/Cargo.lock
deleted file mode 100644
index e0f96b7c..00000000
--- a/examples~/quickstart/server/Cargo.lock
+++ /dev/null
@@ -1,586 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "ahash"
-version = "0.8.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
-dependencies = [
- "cfg-if",
- "once_cell",
- "version_check",
- "zerocopy",
-]
-
-[[package]]
-name = "allocator-api2"
-version = "0.2.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
-
-[[package]]
-name = "anyhow"
-version = "1.0.71"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
-
-[[package]]
-name = "approx"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "arrayvec"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
-
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[package]]
-name = "bitflags"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
-
-[[package]]
-name = "block-buffer"
-version = "0.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "bytemuck"
-version = "1.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
-
-[[package]]
-name = "bytes"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "convert_case"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
-
-[[package]]
-name = "cpufeatures"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "crypto-common"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
-dependencies = [
- "generic-array",
- "typenum",
-]
-
-[[package]]
-name = "decorum"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "281759d3c8a14f5c3f0c49363be56810fcd7f910422f97f2db850c2920fde5cf"
-dependencies = [
- "approx",
- "num-traits",
-]
-
-[[package]]
-name = "derive_more"
-version = "0.99.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
-dependencies = [
- "convert_case",
- "proc-macro2",
- "quote",
- "rustc_version",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "digest"
-version = "0.10.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
-dependencies = [
- "block-buffer",
- "crypto-common",
-]
-
-[[package]]
-name = "either"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
-
-[[package]]
-name = "enum-as-inner"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "ethnum"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "generic-array"
-version = "0.14.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-dependencies = [
- "typenum",
- "version_check",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.14.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
-dependencies = [
- "ahash",
- "allocator-api2",
-]
-
-[[package]]
-name = "heck"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
-[[package]]
-name = "itertools"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
-dependencies = [
- "either",
-]
-
-[[package]]
-name = "keccak"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940"
-dependencies = [
- "cpufeatures",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.155"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
-
-[[package]]
-name = "log"
-version = "0.4.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
-
-[[package]]
-name = "nohash-hasher"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
-
-[[package]]
-name = "num-traits"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.64"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quickstart-chat-module"
-version = "0.1.0"
-dependencies = [
- "log",
- "spacetimedb",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.29"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "rustc_version"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
-dependencies = [
- "semver",
-]
-
-[[package]]
-name = "scoped-tls"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
-
-[[package]]
-name = "second-stack"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4904c83c6e51f1b9b08bfa5a86f35a51798e8307186e6f5513852210a219c0bb"
-
-[[package]]
-name = "semver"
-version = "1.0.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
-
-[[package]]
-name = "serde"
-version = "1.0.193"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.193"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "sha3"
-version = "0.10.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
-dependencies = [
- "digest",
- "keccak",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
-
-[[package]]
-name = "spacetimedb"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b083dadcc676ec1f2bdbd862776ac2fb295c7cd1cd63a671f3e4660c22ce4c7"
-dependencies = [
- "bytemuck",
- "derive_more",
- "getrandom",
- "log",
- "rand",
- "scoped-tls",
- "spacetimedb-bindings-macro",
- "spacetimedb-bindings-sys",
- "spacetimedb-lib",
- "spacetimedb-primitives",
-]
-
-[[package]]
-name = "spacetimedb-bindings-macro"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2216aa0e94ee5eff29322f7a80b847674a6415bdedca36267d4f9827838ef17"
-dependencies = [
- "bitflags",
- "heck",
- "humantime",
- "proc-macro2",
- "quote",
- "spacetimedb-primitives",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "spacetimedb-bindings-sys"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd06c9176160de7138fdd579fcac3fb5735441bdf82896ce9bcadc7000892362"
-dependencies = [
- "spacetimedb-primitives",
-]
-
-[[package]]
-name = "spacetimedb-data-structures"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0293e7ff788f4d36e85f4029e946145b3ca884d3702b046b1f05497931e2c117"
-dependencies = [
- "hashbrown",
- "nohash-hasher",
- "smallvec",
- "thiserror",
-]
-
-[[package]]
-name = "spacetimedb-lib"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e92b11f138722de120c6bba2cdc46d0aed348fbeb673bd60d8758a5199e6ac"
-dependencies = [
- "anyhow",
- "bitflags",
- "derive_more",
- "enum-as-inner",
- "hex",
- "itertools",
- "spacetimedb-bindings-macro",
- "spacetimedb-data-structures",
- "spacetimedb-primitives",
- "spacetimedb-sats",
- "thiserror",
-]
-
-[[package]]
-name = "spacetimedb-primitives"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02c6c81cb1df7d6bd77923121d1663f8bbe8e28e669d29d25b335fc81a2a3ccd"
-dependencies = [
- "bitflags",
- "either",
- "itertools",
- "nohash-hasher",
-]
-
-[[package]]
-name = "spacetimedb-sats"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6e07d8e872575b4825eb62c1bbb6f0a50081858664bbe9ee135f977ee7263d2"
-dependencies = [
- "arrayvec",
- "bitflags",
- "bytemuck",
- "bytes",
- "decorum",
- "derive_more",
- "enum-as-inner",
- "ethnum",
- "hex",
- "itertools",
- "second-stack",
- "sha3",
- "smallvec",
- "spacetimedb-bindings-macro",
- "spacetimedb-primitives",
- "thiserror",
-]
-
-[[package]]
-name = "syn"
-version = "1.0.109"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "thiserror"
-version = "1.0.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "typenum"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73"
-
-[[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "zerocopy"
-version = "0.7.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
-dependencies = [
- "zerocopy-derive",
-]
-
-[[package]]
-name = "zerocopy-derive"
-version = "0.7.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
diff --git a/examples~/quickstart/server/Cargo.toml b/examples~/quickstart/server/Cargo.toml
deleted file mode 100644
index db1752dc..00000000
--- a/examples~/quickstart/server/Cargo.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-[package]
-name = "quickstart-chat-module"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[lib]
-crate-type = ["cdylib"]
-
-[dependencies]
-spacetimedb = "1.0.0-rc1"
-log = "0.4"
diff --git a/examples~/quickstart/server/src/lib.rs b/examples~/quickstart/server/src/lib.rs
deleted file mode 100644
index cf986470..00000000
--- a/examples~/quickstart/server/src/lib.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-use spacetimedb::{Identity, ReducerContext, Table, Timestamp};
-
-#[spacetimedb::table(name = user, public)]
-pub struct User {
-    #[primary_key]
-    identity: Identity,
-    name: Option<String>,
-    online: bool,
-}
-
-#[spacetimedb::table(name = message, public)]
-pub struct Message {
-    sender: Identity,
-    sent: Timestamp,
-    text: String,
-}
-
-fn validate_name(name: String) -> Result<String, String> {
-    if name.is_empty() {
-        Err("Names must not be empty".to_string())
-    } else {
-        Ok(name)
-    }
-}
-
-#[spacetimedb::reducer]
-pub fn set_name(ctx: &ReducerContext, name: String) -> Result<(), String> {
-    let name = validate_name(name)?;
-    if let Some(user) = ctx.db.user().identity().find(ctx.sender) {
-        ctx.db.user().identity().update(User {
-            name: Some(name),
-            ..user
-        });
-        Ok(())
-    } else {
-        Err("Cannot set name for unknown user".to_string())
-    }
-}
-
-fn validate_message(text: String) -> Result<String, String> {
-    if text.is_empty() {
-        Err("Messages must not be empty".to_string())
-    } else {
-        Ok(text)
-    }
-}
-
-#[spacetimedb::reducer]
-pub fn send_message(ctx: &ReducerContext, text: String) -> Result<(), String> {
-    // Things to consider:
-    // - Rate-limit messages per-user.
-    // - Reject messages from unnamed user.
-    let text = validate_message(text)?;
-    ctx.db.message().insert(Message {
-        sender: ctx.sender,
-        text,
-        sent: ctx.timestamp,
-    });
-    Ok(())
-}
-
-#[spacetimedb::reducer(init)]
-// Called when the module is initially published
-pub fn init(_ctx: &ReducerContext) {}
-
-#[spacetimedb::reducer(client_connected)]
-pub fn identity_connected(ctx: &ReducerContext) {
-    if let Some(user) = ctx.db.user().identity().find(ctx.sender) {
-        // If this is a returning user, i.e. we already have a `User` with this `Identity`,
-        // set `online: true`, but leave `name` and `identity` unchanged.
-        ctx.db.user().identity().update(User { online: true, ..user });
-    } else {
-        // If this is a new user, create a `User` row for the `Identity`,
-        // which is online, but hasn't set a name.
-        ctx.db.user().insert(User {
-            name: None,
-            identity: ctx.sender,
-            online: true,
-        });
-    }
-}
-
-#[spacetimedb::reducer(client_disconnected)]
-pub fn identity_disconnected(ctx: &ReducerContext) {
-    if let Some(user) = ctx.db.user().identity().find(ctx.sender) {
-        ctx.db.user().identity().update(User { online: false, ..user });
-    } else {
-        // This branch should be unreachable,
-        // as it doesn't make sense for a client to disconnect without connecting first.
-        log::warn!("Disconnect event for unknown user with identity {:?}", ctx.sender);
-    }
-}

From 04d084ea2f6f83d53550067093dc524a013aca60 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <196249+bfops@users.noreply.github.com>
Date: Wed, 6 Nov 2024 11:29:48 -0800
Subject: [PATCH 47/55] Bump Unity SDK version to RC1 (#187)

## Description of Changes
Just bump `package.json` to `1.0.0-rc1` instead of `1.0.0`.

## API
No breaking changes

## Requires SpacetimeDB PRs
None

## Testing

Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 015b4e0a..7a1c5a6e 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "com.clockworklabs.spacetimedbsdk",
   "displayName": "SpacetimeDB SDK",
-  "version": "1.0.0",
+  "version": "1.0.0-rc1",
   "description": "The SpacetimeDB Client SDK is a software development kit (SDK) designed to interact with and manipulate SpacetimeDB modules..",
   "keywords": [],
   "author": {

From 87071668b9cec45a59d2d3caf7e65b9abe29cef0 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Wed, 6 Nov 2024 13:09:40 -0800
Subject: [PATCH 48/55] update

---
 .../{1.0.0.meta => 1.0.0-rc1.meta}            |   0
 .../{1.0.0 => 1.0.0-rc1}/analyzers.meta       |   0
 .../analyzers/dotnet.meta                     |   0
 .../analyzers/dotnet/cs.meta                  |   0
 .../dotnet/cs/SpacetimeDB.BSATN.Codegen.dll   | Bin 57344 -> 57344 bytes
 .../cs/SpacetimeDB.BSATN.Codegen.dll.meta     |   0
 .../{1.0.0 => 1.0.0-rc1}/lib.meta             |   0
 .../lib/netstandard2.1.meta                   |   0
 .../SpacetimeDB.BSATN.Runtime.dll             | Bin 64512 -> 64512 bytes
 .../SpacetimeDB.BSATN.Runtime.dll.meta        |   0
 10 files changed, 0 insertions(+), 0 deletions(-)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0.meta => 1.0.0-rc1.meta} (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0 => 1.0.0-rc1}/analyzers.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0 => 1.0.0-rc1}/analyzers/dotnet.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0 => 1.0.0-rc1}/analyzers/dotnet/cs.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0 => 1.0.0-rc1}/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll (98%)
 mode change 100644 => 100755
 rename packages/spacetimedb.bsatn.runtime/{1.0.0 => 1.0.0-rc1}/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0 => 1.0.0-rc1}/lib.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0 => 1.0.0-rc1}/lib/netstandard2.1.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0 => 1.0.0-rc1}/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll (99%)
 mode change 100644 => 100755
 rename packages/spacetimedb.bsatn.runtime/{1.0.0 => 1.0.0-rc1}/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta (100%)

diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0/analyzers.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
old mode 100644
new mode 100755
similarity index 98%
rename from packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
index b4965fc4efc59cb8ac32d6af56fd4518b4091f0f..5a2ceb283098edb4405a918b43bb8b7b3dcd675a
GIT binary patch
delta 238
zcmZoTz}#?vc|r%vx^0SwH}?G4F7RAxC;N+*MQ)9cQ)^#ErA*p9Wk;E$hLO3sfkA4T
zWr~S~nPHNNxq*>!nz3n;xv80frMa=Oahi!qidkYx(q^Me-<VlyCc3vw*0~lSQ1w72
z>)nP2Zkw)_COa)rd^5S{+EN9Wpb=CMq}u4|mHRFa4$e0A_`7^_;B{$Me<KESAT$8N
zRE9JLONJB%69x+gGX_J3Bp?eUW5i$#lrd&71&WvhNi(3BC6HwdhG{@mCO}<g42eK8
KY4h$ouFL=}E>UCv

delta 238
zcmZoTz}#?vc|r$^63?AU8+(3i7l`o6tvtxl=(T`zq0u9oKOZ+w*-<8`k(6p?oM>X6
zYGiDbYLc9qoMd5XkeHZeZfu-vnPQxnl9pm&W@wUZzS-!~H)fVsCodeGtaB|u;ErlA
z!|qr6edfPYl<YZs^6=!IYfBZNf;so0f<V=-58{_^-zHvhZb#Hy?#+SMrCI%x7*ZL`
z7>pSb8B7?=fovln+XzUTFeC%XWQHUL3kFLD1E72&LmE(pF%TvLMN+_eQh;J9Kow>T
OhF~4$n|I%FWd;Bj<5Y71

diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/lib.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0/lib.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
old mode 100644
new mode 100755
similarity index 99%
rename from packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
index 36caaf3f63b08f275db0631e6bb1319617d76e91..c38d14a14d0b466f824e8f369693e0166125d1f8
GIT binary patch
delta 238
zcmZqp!QAkJc|r%vKAk5^H})*KA;7Vt=XCB;b?2o|HGWQC^T>L$!_6`g4I^`N1B28w
z%M=p}Gs7eka|0veG-J~wb5k<|OLJpm<1`bK6tl#Xq|Nu<-eP9ibhYKi<UJn)1ZMMG
zO+FdB-G4#sk7phhHD!}!J}p&%2`WGZfvO`81uCqQU3%T#=!2=?=7*nxS^bR|%z@AV
z2vZr-7%Ul57)%%}7|a+98Ipi3kc<(7F;K>s!4xQB4kXQhVwOObF&L%+Rha;FnK2{+
L$)wHAKWdo)v(8bl

delta 238
zcmZqp!QAkJc|r$^OX-5e8+(@A5Gb~C5_xA-;yRP7`ph+Pj`+<EH_Jpcl2Xl#6HUxh
zjf{;_O_EcSlPoL^5);$Rjg6BnQ;ZW+(o!tU3{8^FH{W}Ei<u=O^7*I9dp-sT%<Ge~
z%2izNv0ME3nHJWr=*cplmMTC6Gk!w_fvSso+Mno_=5G7-dAIuZ%@02Xv-&47q%xQ>
z7&9a?m@t?F*+xLN5s)@vNCuM03`q<Y43-QAK>0+5G@uG&AWQ~|q=5CL0L4;(D$E!R
N!8*)0H~*+*1^@%zQ5*mO

diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta

From 962db343964da9142dd094085c59afee1e334f79 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Wed, 6 Nov 2024 14:39:50 -0800
Subject: [PATCH 49/55] empty commit to bump CI


From 24c599778e030485d151f9033f5103ddb1897913 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Wed, 6 Nov 2024 14:45:39 -0800
Subject: [PATCH 50/55] fix unity sdk tests?

---
 .github/workflows/unity-test.yml               | 2 +-
 .github/workflows/unity-testsuite-bindings.yml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/unity-test.yml b/.github/workflows/unity-test.yml
index 29e50886..c0623c9b 100644
--- a/.github/workflows/unity-test.yml
+++ b/.github/workflows/unity-test.yml
@@ -16,7 +16,7 @@ jobs:
       - name: Checkout submodule
         run: |
           git submodule init
-          git submodule update
+          git submodule update --recursive
           cd unity-tests~
           git checkout jdetter/circle-game-testsuite
       # Grab the branch name from the PR description. If it's not found, master will be used instead.
diff --git a/.github/workflows/unity-testsuite-bindings.yml b/.github/workflows/unity-testsuite-bindings.yml
index 442abcd1..edb55783 100644
--- a/.github/workflows/unity-testsuite-bindings.yml
+++ b/.github/workflows/unity-testsuite-bindings.yml
@@ -16,7 +16,7 @@ jobs:
       - name: Checkout submodule
         run: |
           git submodule init
-          git submodule update
+          git submodule update --recursive
           cd unity-tests~
           git checkout jdetter/circle-game-testsuite
       # Grab the branch name from the PR description. If it's not found, master will be used instead.

From 43d9b8f40af58a47def063c7aa65f31e846c26bc Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Wed, 6 Nov 2024 14:51:15 -0800
Subject: [PATCH 51/55] fix unity tests?

---
 .github/workflows/unity-test.yml               | 2 +-
 .github/workflows/unity-testsuite-bindings.yml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/unity-test.yml b/.github/workflows/unity-test.yml
index c0623c9b..2f41ac81 100644
--- a/.github/workflows/unity-test.yml
+++ b/.github/workflows/unity-test.yml
@@ -98,7 +98,7 @@ jobs:
       - name: Install SpacetimeDB CLI from specific branch
         run: |
           cd unity-tests~
-          git clone https://github.com/clockworklabs/SpacetimeDB.git
+          git clone --recurse-submodules https://github.com/clockworklabs/SpacetimeDB.git
           cd SpacetimeDB
           # Sanitize the branch name by trimming any newlines or spaces
           branch_name=$(echo "${{ steps.extract-branch.outputs.branch }}" | tr -d '[:space:]')
diff --git a/.github/workflows/unity-testsuite-bindings.yml b/.github/workflows/unity-testsuite-bindings.yml
index edb55783..fb063fb2 100644
--- a/.github/workflows/unity-testsuite-bindings.yml
+++ b/.github/workflows/unity-testsuite-bindings.yml
@@ -90,7 +90,7 @@ jobs:
       - name: Install SpacetimeDB CLI from specific branch
         run: |
           cd unity-tests~
-          git clone https://github.com/clockworklabs/SpacetimeDB.git
+          git clone --recurse-submodules https://github.com/clockworklabs/SpacetimeDB.git
           cd SpacetimeDB
           # Sanitize the branch name by trimming any newlines or spaces
           branch_name=$(echo "${{ steps.extract-branch.outputs.branch }}" | tr -d '[:space:]')

From a12594a4d39d80f37aae882a43e6e73a3a7dc94b Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Wed, 6 Nov 2024 15:01:31 -0800
Subject: [PATCH 52/55] fix unit tests?

---
 .github/workflows/unity-test.yml               | 4 +++-
 .github/workflows/unity-testsuite-bindings.yml | 4 +++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/unity-test.yml b/.github/workflows/unity-test.yml
index 2f41ac81..0f59654e 100644
--- a/.github/workflows/unity-test.yml
+++ b/.github/workflows/unity-test.yml
@@ -98,7 +98,7 @@ jobs:
       - name: Install SpacetimeDB CLI from specific branch
         run: |
           cd unity-tests~
-          git clone --recurse-submodules https://github.com/clockworklabs/SpacetimeDB.git
+          git clone https://github.com/clockworklabs/SpacetimeDB.git
           cd SpacetimeDB
           # Sanitize the branch name by trimming any newlines or spaces
           branch_name=$(echo "${{ steps.extract-branch.outputs.branch }}" | tr -d '[:space:]')
@@ -107,6 +107,8 @@ jobs:
             branch_name="master"
           fi
           git checkout "$branch_name"
+          git submodule init
+          git submodule update --recursive
           echo "Checked out branch: $branch_name"
           cargo build --release -p spacetimedb-cli
           sudo mv target/release/spacetime /usr/bin/spacetime
diff --git a/.github/workflows/unity-testsuite-bindings.yml b/.github/workflows/unity-testsuite-bindings.yml
index fb063fb2..08fa5f9b 100644
--- a/.github/workflows/unity-testsuite-bindings.yml
+++ b/.github/workflows/unity-testsuite-bindings.yml
@@ -90,7 +90,7 @@ jobs:
       - name: Install SpacetimeDB CLI from specific branch
         run: |
           cd unity-tests~
-          git clone --recurse-submodules https://github.com/clockworklabs/SpacetimeDB.git
+          git clone https://github.com/clockworklabs/SpacetimeDB.git
           cd SpacetimeDB
           # Sanitize the branch name by trimming any newlines or spaces
           branch_name=$(echo "${{ steps.extract-branch.outputs.branch }}" | tr -d '[:space:]')
@@ -99,6 +99,8 @@ jobs:
             branch_name="master"
           fi
           git checkout "$branch_name"
+          git submodule init
+          git submodule update --recursive
           echo "Checked out branch: $branch_name"
           cargo build --release -p spacetimedb-cli
           sudo mv target/release/spacetime /usr/bin/spacetime

From ecffc4a495aaad8dbd1ab93b706ddbfd07d18f24 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Wed, 6 Nov 2024 15:20:06 -0800
Subject: [PATCH 53/55] empty


From a7e0fe56cc9f3829c3ddf9b9be55a16d710f7fa1 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Mon, 11 Nov 2024 18:04:42 -0800
Subject: [PATCH 54/55] updates

---
 SpacetimeDB.ClientSDK.csproj                  |   4 ++--
 ...{1.0.0-rc1.meta => 1.0.0-rc1-hotfix1.meta} |   0
 .../analyzers.meta                            |   0
 .../analyzers/dotnet.meta                     |   0
 .../analyzers/dotnet/cs.meta                  |   0
 .../dotnet/cs/SpacetimeDB.BSATN.Codegen.dll   | Bin 57344 -> 57344 bytes
 .../cs/SpacetimeDB.BSATN.Codegen.dll.meta     |   0
 .../{1.0.0-rc1 => 1.0.0-rc1-hotfix1}/lib.meta |   0
 .../lib/netstandard2.1.meta                   |   0
 .../SpacetimeDB.BSATN.Runtime.dll             | Bin 0 -> 66048 bytes
 .../SpacetimeDB.BSATN.Runtime.dll.meta        |   0
 .../SpacetimeDB.BSATN.Runtime.dll             | Bin 64512 -> 0 bytes
 12 files changed, 2 insertions(+), 2 deletions(-)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0-rc1.meta => 1.0.0-rc1-hotfix1.meta} (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0-rc1 => 1.0.0-rc1-hotfix1}/analyzers.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0-rc1 => 1.0.0-rc1-hotfix1}/analyzers/dotnet.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0-rc1 => 1.0.0-rc1-hotfix1}/analyzers/dotnet/cs.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0-rc1 => 1.0.0-rc1-hotfix1}/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll (91%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0-rc1 => 1.0.0-rc1-hotfix1}/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0-rc1 => 1.0.0-rc1-hotfix1}/lib.meta (100%)
 rename packages/spacetimedb.bsatn.runtime/{1.0.0-rc1 => 1.0.0-rc1-hotfix1}/lib/netstandard2.1.meta (100%)
 create mode 100755 packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
 rename packages/spacetimedb.bsatn.runtime/{1.0.0-rc1 => 1.0.0-rc1-hotfix1}/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta (100%)
 delete mode 100755 packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll

diff --git a/SpacetimeDB.ClientSDK.csproj b/SpacetimeDB.ClientSDK.csproj
index 6bf4edcf..ddd2f9b3 100644
--- a/SpacetimeDB.ClientSDK.csproj
+++ b/SpacetimeDB.ClientSDK.csproj
@@ -17,14 +17,14 @@
     <PackageReadmeFile>README.md</PackageReadmeFile>
     <RepositoryUrl>https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk</RepositoryUrl>
     <AssemblyVersion>1.0.0</AssemblyVersion>
-    <Version>1.0.0-rc1</Version>
+    <Version>1.0.0-rc1-hotfix1</Version>
     <DefaultItemExcludes>$(DefaultItemExcludes);*~/**</DefaultItemExcludes>
     <!-- We want to save DLLs for Unity which doesn't support NuGet. -->
     <RestorePackagesPath>packages</RestorePackagesPath>
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="SpacetimeDB.BSATN.Runtime" Version="1.0.0-rc1" />
+    <PackageReference Include="SpacetimeDB.BSATN.Runtime" Version="1.0.0-rc1-hotfix1" />
 
     <InternalsVisibleTo Include="SpacetimeDB.Tests" />
   </ItemGroup>
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0-rc1.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers/dotnet.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers/dotnet.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers/dotnet/cs.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers/dotnet/cs.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
similarity index 91%
rename from packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll
index 5a2ceb283098edb4405a918b43bb8b7b3dcd675a..d90254a8922ee67bae5352ecc9ae8118877da17e 100755
GIT binary patch
delta 1730
zcmXw)e{2(F7{{Nt*SWbLIM!~rUR&1fHs&0Ib)#&ffpxaYT$He62pL4v?%G?o2@@fP
zAZA^PK;kqk4>87pcBw-!#(<sCX^34m6Vbnv1V(~bG7?NQA_0xY7=7L+qs@Kuz0dP~
zpL^a*@0!ReiL7$+g!QivP9K|`aEXs6&+l5*{|CT!kRJiXd6U()Vh<TQUH1TB2Uc6w
zVZW#svp6p5Eya2Gq1Y+jKw+`v&Av-(@Zz<$Ot0mHPrRME-gd81youi#-L`X%^)Lc+
zqz7Qh(Fz(=VqLVW?Hlbi@>O<}L_0<5uusD)aK0?PqJ`{}a95k*WJV_OOjIqYaDL6?
z3X}P0S4pL&3)xK<N!Wsq#TrB(cEogX7@s3OiQ_Td(dSHy*Qw_WCo`m#+5+W2!%H!>
z@uqW`tM|DImM5qxEOH*jl7u@>#Uj^QEeJjMUrgQeuTy8z#hD;wYF$A~8g4p+%zG@d
ze;;dPMP)aGlAB!yXATgrvM1<T4*NLwNm8{J_nWGt*Olf>miavEf}8}WO;yz5oax@P
z#i=NADvu(ktyW}zT}guJ(wTQL2@;{%n1qxm%Je8TuttllC{INl9CkyI^B9yrg5E*B
z<cKTDtJ1P3Mh4Zov}=LMWlB2im%0Bk_g`kNSd;KAo*C3__guPF&emX+{e#3S@yg&f
zQHj;@{*pCXAW!m89!-MB<8IM_GjYGor`;m*j3ypI*iA|v@5j6H$25^&1Bm`1e_ex?
z%9m@?tl50I_bmGb)|@0bHRKkZI5*U1OKA%Qa(4>_a(A~1Y9NJG!@BqggTosJ!|v)r
z$!iO1AnXnl%FbO(LQKL;B21!8#@SD^zRx7fnRzCQL`K{>CbyW}mISX4cW<XTi)8=#
zq8g~P=ZfUyIVMmnxhR(0Q!KfMNq~KTeTb`J_EGXF935E}Utr%0{;{w-TPiy&mdah^
z*xzOkt0lLtmfXWWz#3u_B^_}eWz8{%GMV?3@eJ$(>;vq>tO+Iw_9^MHWUpJijE#H!
z^du(ivcplkd|D6e)yHTr<&q>=kCw~lBE>#iF0YbhzsNktB*z3Qc=8IF_f+saOaiQ-
z3Iv}Ps;Gf+cbKbT=27CiwJ7t1Bx}l2T(GJLW13Z^8>e~HA{wZc{0O%0)9FXKYu{I-
z>gWc#q1~g?jWkxBynL=sUO2}d)=J`8%cHOlNT0F2xc{lr)1l+HcPyTL@~u0`SJheT
z#>}bD<BqMJ0ycZsH?MDQddcuM#YYdCLx;SL-hs$~VH)kej!nMyNK2dHZ5}X9v(;xb
z$6{u*BeJo@N12XH%MX7l<;Q+9e+IFw*Fvx2Pv}U{>o|d1uBv%0^u}(%{;PWFvuA(#
z{?h(EPp5vg*UxnNhjHTSOw$VdC%gh>qr1Jf<%_{{J0E}W+o$8S{NZN`pTFj$*ZJXV
z6S!(=Ysm%c!wSF!>|c6Ml;Yn@y7)EYzOE|DJK)E*8?BKhh{Grx1QUkf5O|@Hjsb|!
zVGuK*9emIMn@HP<wm=&(FEmr#<Zmlg3_6d|*Mul#Be0QjzLh>5nJ;f_5|924{6}=b
Nmsx%Du9$4j{~t(7!)E{h

delta 1735
zcmXw)ZERCz6vxlgTio26Wi4%b+q!m_L0|%1@7l{;Vp`X*5khz~0us%--gaX+kQW2^
z5;{9{5k62KK9DSE=a`BizR<+T2V-mT1L2Di9V{Vo$uOufz63Eb!RR?B+r7E}{`))s
z=iKu&yLY*=k}E5x#_b<{7OECb`o(*N^V^%Y+y~eMbO?B0FNB;8K>-c;b?ILKPsxz&
zF}YJL7Z>EHSZ;e@mmi9!#c?TY&P5mA#x=5X-6(CgjYq|)(yZ}kyLeq*P4_yB-qo-N
zK1DqU-*|OU!6Dnsgi%(Hqi=CZBI;>WuWJ%shV#u+^IFF~4|mmRPL?Ps&zhdbCg0ag
zt}&^YiAIO23F@YaJVfOqnH6G#?8<23fP5BpT#jZm?*`wLIDtK<Iaxw=s8!5=EWgNj
z+Gl)oT)oFtu&u<Zu+cn<Ef2SRijCIVZ4wglzl>+seV@i8!I>V+`29V$DVXu~Fkf$@
z{@Ykn^Ge;)n2h+-oH>ZR#g)T*d0nI2Cy&)Wxj*ai_W7qcQ)XUat<ofNGV2k3c_|y%
z74<0!O%+sV+K@v1H6;(v`8DPVCOt@SHYQ1B0yFECR&cASdF83FgV&W-Xr46Y56O-}
zt?`gQ&#R`Wr%Vlc+9v!}CRZ@&bzR~9bKHN9xnj@5SMuzj=KR^O*=e>FcIw}Q+##<G
zZWIm~8rs?DR^y9^Cl}!)@{OT@2+8T8Zs#iXHj<<&9+I#X6}`MSl&CqZiken9A-i{X
zw}sSV4XvGGE!WWA%j~PH77;nIJ0J{sY4<kg8MRtVyQ|jH?rzt%!Wr2ztci27XL!xv
zjzFl6_|m#o*b#`=QRf7cB$Iw7DJCY9QTCIp=a`f^Q(<x$NjhLLxy|Gb5ji{Dy9wv4
zr~Z}tR%mls^)$J~1R98o2I9d6;z1^H_Hp(}uJ*Gx(Vvm~_RNWka@+IW$94qD4(f2(
zLA$Wn-(e4niQ5+w53-N5CYhM1>A)DP#T=R`A8h6s*vHw&+4r;NnB>?O$;-x(fY>YB
zN4oJz%(<w;n2Vm)gCp88+{+RoIo7cy^js9#mzU68%Iq&Qx0qN=z|E7pDIaw6JWS%O
zNw<VmYSP^bM+5y_?PqQx->RC-b3`6(E^@){k#JbGd+>)-gPwXEXes)%)c0!mN4b6P
zm#Ch7Yw!o{-8b2eW3|!ktv0%`#U7Rs2`=MN*vHA2oG<L}bKF%g)%-N}?z+*r%&WgV
zW4={7{rQkLW(bIMtPZaZuR4(KXpb01IGo9LnVoB69Rr<4IHG6u=ztN8g}V%0*R!3S
zW-Mh6lpg=~Z>8gvLhl%ejhk)w3ciTf5qu3FnL#su2>f*7wH&XN`0idQQ!|?5CCfkj
z+b7n#i{HPPe)3%CS9yA7I<f#G^N?Cce*ErM(yC18egD3H6qhd?l6<fba^uVWwd*Gf
z;ab^r<B7(ieIWo)lsj*{BS8LhLlZYkfmx5Dya~EAZt7dwAp!=TVLUUCg)T6m6V^fu
zI$!`DRU)8cMTaO712u-M3!Tnq7E_(LDh4Ukfzs8RF(Ko^@$etO|BXI~mKOi;yC{Tf
F{s--Gxo7|Y

diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0-rc1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/analyzers/dotnet/cs/SpacetimeDB.BSATN.Codegen.dll.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/lib.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/lib.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/lib/netstandard2.1.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/lib/netstandard2.1.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
new file mode 100755
index 0000000000000000000000000000000000000000..a13680f9557f9ce320a0dd7603d91fcf30645eec
GIT binary patch
literal 66048
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
Prw`-M(QiKg|0M9=+-bOc

literal 0
HcmV?d00001

diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta
similarity index 100%
rename from packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta
rename to packages/spacetimedb.bsatn.runtime/1.0.0-rc1-hotfix1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll.meta
diff --git a/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll b/packages/spacetimedb.bsatn.runtime/1.0.0-rc1/lib/netstandard2.1/SpacetimeDB.BSATN.Runtime.dll
deleted file mode 100755
index c38d14a14d0b466f824e8f369693e0166125d1f8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 64512
zcmeFa3wTu3^*+4!K9k90Cbvm42{$DWz#+kKM{Z&u0l6v4MG+AaLeyYjFbP%+fk9BK
z^?tuQ2-wnU>xI@<t&M`#OSRTp6>S{^Ypu3cYrSFdd)K>9W`>aPv;U9Z^F815{L#F#
z-nG_Vd#|<k+2_pUoXH6bu2zmx%7dS8zg6m&c$I$@#6v?A=Iq{&WUK8NFZB7Pp7}zb
zxo6im6|ZcJoYh#fytuYz#fnIC@shgY##Jkd>sJ(4&6-oZJhHT|JS)rJ&kcRjWTj?m
zM?F4h@7DI-;;L_PKo3#sQ)qlvJ1VG^Du!H)SEX_(8#``M$oToM8g}UApQEZT5?A>@
z`RY<p;ot6Dt!9aUxH}U;MB)Cc&?*z+_8hI|w(GvjYjI-e^!9;IO=(x&Tz7sm`1nr%
zurXJ6++h4ytW<S*V^d=-7{`V&Dlf=qG$)_}(^cMB*ARiDj8$RGtijg_7YY?hO*&Ac
zR7mQIe=;_s($v)rO7+{Ul-1JoU%`<ke56wT(na>w6kTx)g7q(SZf`|MPw7}!?{uUx
zmnl}PNl$5euw*05kf>YQU(<y5HBKvqq#vq8Kfa!l=rbK^<7vg3qE)CwBTqKYaMkUv
ze&Nyyg=A)<ZDx13W{E?xJt@MvueKoVxpeiKY@Y3Q-~O7@-aUm*y2tWP?Vc3f^Ywy6
z?m>8AI_#i5cemzAt7K_t_E;?%3zgE)t9{JN62bB%Sm71jP=VHh0|U|Iv04NWDuL+L
z9;p4b{G}6>>KX1WD@LjOAx2eTwPB$In~I_HdmACIjP!v#z}r}qkc~Ie7rH?i-rmKL
z5?Xt=x<aHMc&WdzwA?u1{*Vjz>(UdAQ=Vl8`HT}8Am+l-qS7hhqad0{7#JBS+EK<?
zB?GcP=b=rJGbqn`IP?o+n6@=iC=<E;bpqB0Mk31#Lu1PAucAgf<~Inh2KhOwx<eS0
z<7|~zzww5T#j#!L9Bqn98&Qvyjo6h|Ho@J0!DZ%LadN^F;4;XBO56Ey<VDDav8xbU
z{+VzE3=VPlVACS~JH%spr?TNWrbWi+5cj9CDz<T{%*Fp4Z{(rkIgDqAfyv+i3YYEo
zAht)1;z*S$itq0w$-TKhr@u{Wz0jhjqmg+SvtJe-45@JK5W)SrX((P%%={r*g%HC*
zElqeL^7ZGb{e{I?J$3=WCOP0Bl5<1QEc1JNA6M&b8Uxq%)iDLKtd0RW$_Y;s!`<Ow
zh;Pdh84j^{;JkTT7r0s}B(?KP7r7IdW$X;v=7ptCrv$Kdjf_B;K}9Jc>|9Wf63N2B
znv{iu)yjp_{wiwbYLu)S>~UB(Jy0H5H}Wd$1`D=*-JE{Vx)CQQjHTqR8_Q23Ppq4h
z5nKM5FeI!S!Qtagi*)Z0!;7Ih`ltg`brK}cw8&r`BE8&2Brz~_&cSzxU;Ulpi<i5o
z7=KERS|fuDFNA?h3;i9qwj^P@wnSPlP}DRMGZMy8_?_0)Y{c%cw)}Q;IYoMHUp}YF
z*zOKvU1Rx3O(Hn)wJ#s5m7!A0<s(BGB+EyHFq_NrNd~Y*jbOu;<&z9yr-XWU`C#*s
z<%5lk%cuQS)a`R1>&MIW(^LAz`jJ;zKZ|7GcHjBILF-4H9L}rVcPy8A7=(?gu=H`$
zBE2|7*<F%Mb{83mLv(kS1N>$8=+fWr9tX{*48YE(Nb3cP<e2t{u@ii!`K-a<JD*Qk
z(TVvyTguYD9Y`JrZwE5=<aQuK;e3h^X7l8BkSxT3+d(q@)a?M1CG&~%3+J=_Rn)2T
ziOU!42fd_U%%{A{d@h%P+xdL-p!pOhC%ghKc0MhSkjs32YFeZhhnP6(Q&jCoy^P6e
z5lkNS2R3d$qz~OVaY$o*c06`vaCWXmS}#!4G*;#sJNkE;>y=2X^SN$@B{A3E14$ga
zlGDM*u4Iusc4a7>YZ1b1o;-Gwr8)4}O%|g4*mZNpb|i0ef<;%Hii?l_g=UMqHjR@^
z(~v1LkgEf~od5leAIhYD42a<L@8@+X&Xw)w37l+H24dx5Touv=2Yp$1H4^mZ>HQ&G
zS(x<jI?$ujy-kxOK%UtjT7dq1Jm=$jK>5+WsS>Zfb9wdd_eO9j;P-|vK)XPm4o{YL
z!%U0x8^$UuYd@h%;6zm~1i?j?-MGY+^^-HFjDqD8Axyu*(nTqr4nx~A$%S{hBsd)_
zmnorEWma{hY1$~gU@YPiM&^mJT$(zT%k5aEVBpp@a=he#u@twDMT9W@WGqQfhoK`=
z#lQR|T#6cdy^6m3YxIrR5%Ox!br|3Q*RP+*M4{0^*RRu{JH+)XvX)B<bP3@)H<gsD
z*qbCFxr)X0=XCLtYgZXugcdZ9%n<chT*Tt4H#}2Fk*t>R2_m8yE*xlY#pQwDy_zk5
zX(5(Edx9-u;R>TL%!IKt%H;Y$F2Q(i@0f48?jm2DMh}(mjo~?Pa2k6i+B+sZ7plw8
zz<?t2APp#DF;0OfYb>Q0I9%*S`Q7d%{d_2RN$+01;p~cemn0%s>i+qxmSh@X)7Md?
z!Ooyk6Oo1vkyrXS?<Si%Ho)m{VdYP>H8WPvDwd9NN4;J~U3!7z8IIGWGbrF0<a4g9
z_gq<DZVF2sPxvP?efdKi)dO`5;CL(amt`C8HIDZh@$eSS_j}Ei^}{|Ya@SQc{4(L!
zJLq=;g_&hJ>Aq{SyuEub$e8c<70u7|rNjF}Z>blDNsg8aB7blHvW2Zf<;Xc@9fl*^
zv<P1y=X^gL*BuAug#U`cSjXvBW8K0Z$RHVRaeFvi9eYYAF_MT2!qsl1iex1EOkYQh
zX%S{4$%QU1spZUuUCL8>rCB$Tt!fa%TGnAl!hqHp49NOe7t<mQ!%N_3T}+FZ!%;Zm
zpbRGt%9p!cfj4!ge_`WMSV*SnVWhBynxe*`(5%H?>q%;xme?aWTq|jG_WpBRVm)?v
z|G5+`{)gjNT)1T0Fp3UKcBj<VJ$`Xcwa2gI5uxRv<M&MQk)yroX=y3P@mZpp6vpZ)
zYdRNsL?yTO<FZgGm4)>Z#-foEh}mC=rQS303|h-x)e~zECm4Bu6l|(TB)_+58D0W8
zD&28?&jI&F8i1L9E=V8bO^+a||84Ieuh&YxQl;e#h@QIjm(zyGUNvyAm3!j-*Vr!l
zaJzU`hVwskk?5nSU$T#Ixs~Ob0jDbddr1yD?p=nvhFl8yk1pjq>BduKJy4x=i>!b{
zI09(Gm4g2QQ+i?2=tRyHYa?JQ12;j!8N(A6!FJFLDY8oRw>oRj!)yPeiw3Oy9)$hg
z^MOq`@%sBm#S+16l-c*`SdS_Pb$22-q56*wt!=>z<_LAilIa;)16nF)Yw0#!+BoWH
zw8@n=9`;<YUq@QuX4#-*2#*_Mt;9eZS<|w|NZXG6tb<SZQCUvqVXT9)sEh-Rq|G3-
z2`0zbV{H_+4r6RuFa9!6tWFG6#)&m($C<+uyX@2)s7nX+Oay{v1KJ;IydC;HXuM)C
zJ<^u3w6Eh~Pf{-}^;LNoKRy%)9f@V>ZMu_(x}8-zbKW}lea!XUC>==Pi$v($cbDsX
zal7v&UHg9N`hLIN_tLI?3uSNPTofRee9ncm!}&>GyiE&a=2keU<LQth5=scReoML-
z?}$X)V#Gyk)(HEn!3qq2h}MC2AzgL`d!CXt8#>SzePPG&hCc$J1t>NQOS_tb+0r*A
z>@rDP>iPo_I<M<}ZmlkF_r0QP-{)Q5E8Bgq>e}}M*Z1mn-)p+|O;6OSi#Zr0_2C?h
zg_M|saqXmw-1;Zteup`jE`7+c)%hIEfH`FjX13F==AhD@gKOLKzpm^2Yh2&!+kJ27
z+IOY+uIRnL=|=eAv%IshC$!!qveSCAG~+pE3f2+MBG|{mI7G`LGEtsLPoTf7mp9T4
zLSXH!z|1`3q^E2S-bfL&N5B1NfAai;y-H(aGdMcJ<J!*$Df^woN!hbx|7eQJ^t=0=
z*h{CZyA3Z+_;z3z(aK6kS&b)rr`U(N_Pd05afRnZWSK=`!lyX6rehLV%$r1m{A4}L
zdO2|akv+xs?k!yqz8k*lux4<zgWte-Bb%k|B3C0uPh<-)oF~I|V;;PxT_x5j>$bwv
zO#pkgBtT6f0c&>?u;cT093N6EPhLx4y%~PKYLEH;`$Mup*zG}1YVMdEnM-$HX!r5h
zw}rARVBq;f(o~t-S5f=5*=C%JlN+;aNGX?Oaw%i?J@l<G>DZqTdj$Lc2ckCNv~fWH
z2l{yITfvVH(f^|d^e>xI$NurQsdYSN$Aqy)<Pvi-x=*|<5)0oJQQ#h3fw5|gwW%0$
zf!|xa*41_6G}sSu-6(aRfLJ&Xf~Yt4Chwq3r}3RcIH&Qwq-?^t%(b6zU~{maeA{=M
z_Px>|SUX&JVr|+BPyA*Ghqc#zhx9`X%d|*7ksm>{?~s@@8zinr@5Wmtx%k9^?ZvyJ
zWHZM$-iF5Rb#2oy>1sBdZ-F!3CP{Qwm2Z<|<m+YB@*cJI*wkWUlSmd@EG#w!sZYmR
ze~~CihimljSnKXx*E++rzn#S!yHOZ1wv+vZ;m&G}cM2VAeVi0PF7gko^^aL=Nhk7?
zM6H=K8+29cWHYCQjqgpV^+f3^rPkuWqO#U9^7S%m9@o`aUp<iXIxIBoKTlx&XJxFy
zsovy!f}TNvpeIj79)Py2C}Y(!QKtpd1`Q0R<>^S9sB`dv)Xy-d`~W1gEQF7Q9ug{_
zgJhO@o9@HFE|AZY9JLsIVRsKYe$OgdPKh3LWH`Lbiae_%bM|l)dN7emqRvil`l&?R
zEMqGx@HIUs>_IX&K1c7(2tNs>>=$WjI{K15H}M`&4#MO<BNtT3<Gg=SqpX{*%=Vq3
zT&#o<vJAf>!a9BcgD90f%~Ac)S1<I{bQ_}jy-q8xPCVWg;(qV#(iOHze<WWTGYrlM
zZkV6jFo`%vNSr&|I5@W;4spNt&O{vSg>D?|xNe+Zb%=xO++fpPZXBFg5r??n8%xB&
zUMX?pked$=6MjsBl)r?_hU6h979MgGI^Ew&5(h?yV-D|NzRUg=z*tey$I*Mo{jDq!
z8pqr`tOg!)nB0T+w*|0v*xwdG)qc!9f#~l3hSh}qP4bCg<+}SDlV*d1j=7yOu%d9X
znPVH@kH+o$TeWm0$K2C!#{MSJS=G`3?#Sn|(5Iyq`h?U%i-m=z(AnNLE>VpCuFg+(
zQCwX8xt~X3h)a<`>PKt!2bXhs=jFtafO5*HBRDeMaxyhG=&GE_W{z!)Z6i_6NQZJt
z^i~!|$|++#ndMxNTFw(w%PAI?lR~HKc1|My!&A@NL_CbK31dvH=lS3rmggEt(mf@l
zEKge)8ForNnHw7%x}MU^X<_5kdajkOQkJJUv<h%}%2;hZPlqb856nufr&w4|3Z2%o
zC6WK(spln$c&O)v7-MQZF9GjR&mTyV2iJ2u*QX3Sg5B0#pUjO7x~gZgnbX3?zeri1
zS4dYW^%RFzRz}vRjMdh2VQM{3O0B0@SWgO_))S|b&VOI<9rsl^|8;TbZ%c&6aIe8|
zxv%1+VR*+x>UHCduy!c)t&;u0g?^ZYmV6?=Oca_)vq4vdPBwE|*!Wi|g}z<7N-4BB
zw6bLK@w$wBy^NZh!5OK=J~_46Vqvi<bhfwtCQ*?8Ztb>TqaUKy&n7}+#4(Jx>soJx
zwL`79Ndda5wWO0$Yv#-bhpx3Wb6VIqwbnn8u2O0(4y^*bZj_NHYrP2S#6~eYwbo)`
zttoU?>$egGIqbFGod}Iu{|qDUy4Kra?NIAqN&&j6wWO0$Yv#-bhpx3Wb6VIqwbqYF
zS1Gj?hgJdBT1K9%HLjbJwVsn&Yq7A_6gsQ*$BBX*_FDft5gN6A93$?!);nPBQ0w1H
z0lKQSq?1x>=FA3%uC+9CTG%+X*3U{;DYX`dRsq&pMxLy7HPnf9JvX)1VqvW*bXIG}
z`Cr?w1BuY6^$Qqr*R_5b)(*9PT?)`uttFk5S~F)hICQP0nbX3?skMGXx=N|FIJ63|
z)-v*Bt!to8)OucOt;NDxQ|PSLJre~v?CZKD5gN6A8zb(z*1KWtP-}c5({-&Sos?QL
zXEr!=t)-dM!p5n!eqXvuskJz?3b58P@?@>?>(XScPf4w{SXgTcoz;4Hq9BL8*5eYP
zQR@#e;;w7`PgpzD`ZFm&SL<5RNvSn+W`jf5TADd6Y@Ax_&!wxBT8l%g0BbEHPu98?
z>cqM}HMQ1aVXY~2R_hswf*kf*&q;(vt-r>IyRP-Ouy&}mgO3fmthJ<*QfubS28XV-
zG;><mIJMSk(p5^W#i3PzwU&`5YmH0cWUcY0JNdzdSXgTcoz=QFQINx4>vIyJQEPl~
zc!*kO!`h+Nd55aCq?1x>=FA3%uC+9CTG%+X)&(7EEe@>$thJ0hS?fBe6YKi4)LM&$
zwWiQnty>ZWIqbFGkO+-hcf*LgUe`y!+M(8cqySy*A(Bo?t(h|$9J<!h%xPic)LNHF
zS1IdS99jifYZ-a6)@MSUs5RcGC)c%DSZfNM)%v<bK@NMZ??{A3t&hTpyRP*hSUc1j
zpVxO?Ye^@i*36j=4qa<$=CrVJYORM!S1Gj?hgJdBT1K9%^;u9SYK=GX$y$qrwWiQn
zt$&s%$YHPbuM(kA>rohS*R{qcgB@#qoD`s|buH<n)S5Z7!J%s{&72lCPObGs=_;kx
z;?OF<TFc0jwZ?CPleNbC_++ic!dg@4tk%yb3Ub(M{aPY4YCRbv?z+~~VePQ4Pm}_5
zRclEnrPj=u4GvvvY38)BacZqklCDx}Ee@>$thJ0hS!?_jCs}K}k5ATGEUYz!&T9RB
zq9BL8)}JIoqt<gV;;w6b8mt{^eTEdEt6EDsDYa(KY;fpWOEag1jZ<sASh`B7wK%j2
zu+}p2WUcY5v1G0BK0aA%v9Q(@I;*wg`QLlrm<Wwp<MZi5)cR~#JJh;C3eZ)pC7qO7
zGiNq9bgiYC)56B7wO%1zrPNv+S_N2Z8F{kS=Rlp<ukk)US!=Pd))YFcb<adW4*R+;
zNrXnN8!_Up*Y)>c?NDocc;0obC7qO7GiNq9bgiYC)56B7wQiNJQfe&@tpcpIjNH~*
z>Q`ix>W$Bl*ELA2@FVzWHjqBKK=BDQ`E9Nmil5{0gM&>q;pbBP+=U-})~=q%&u;vD
zfuAg`R0)1Y;b$6t7UBoL=27^tT-|`5(YO;tty|7+;O}jkBX3bg-z?e{)IN&N`MX&E
zXlb-AlGMtLBL2}0qFqVtI%L5+Z2Y575$(Cu_JUi}RrIY8ZDUe<C$*)bMHWbvzV}gE
zAll}n_AzSrBdK+(lG^8~{i|rtOKNvf`?6@im(+eh?PH=nKdJqa+IvL1I;oW#&-|mW
z7VQN|t^5YtU)H*=C8?4-$^2!@)~!jZ<bE1|*{SPVld4Lps@APds%BF)bltk7s)ni~
z*F}@6l~e^9hhv>LVd(w~_`7!8x9(A@7;D6{N`8r&Ul1%9lpQR<eFHVfXY?m1o@bT(
zJ}^HN48ek11R^WNf_L<=$Zxjt3xkEQ6yjI@>%{UgE%G~>{GwnHEJb;^(@HG=phbSE
zkl!uX4VG?sp2!_y`8zH05qN(0V0T!$=cPsNO<Lpw+x#BE9<cPt^G0yrPkS5rcrm|c
zuqP}%^U@>FB`xw{SbncyFIalz`66#7E%MP#{t>|=U^yZ$Bl6dzMLuZAKQeeEEJx<~
zBe=1kebn-{IKOwWH!QvL0ue9j>1HZ#;_{1w#jq6TWky0`vDG<EEPaA~VCj>W73n7y
zTT!_{&hH!S3rpX;?8tDje99V}E|!vD2`nXfIgv?X`4=s6@sZyz*bkO|dAX63#e&a7
zFbi_3%<muU4@>{NV5C|s|E5JY_WS|C0k90n%Zo(Bf=@%xMz*2+qk>0`>4i-qcvN0~
zWNmvuyImB9e~o2gk7;lCOB~dt)=*>(Jgn2@7yo|O(9IfnWcyML-K~KKcZR*!--ha8
z4LrVsp70SUw;QXcweT1ZrlneXSqqQzpf}ZWgthQk52mMDj<gmY??GRxrFVuk@t_Z8
z9ANTW6Oa6${{U0Knt1pJ0|%Hgt%-X;F!KOYmNjuB2xc8%%C;tM2*K<FOgYxXjUkwG
zfGO9SxIqMS4=@F-i5o>Qcz`L-nz&&E^A0fOTN5{qV7@ga@000+mD02c%S7&z!JdZu
zQi%J#cSC9Klj&yfODS*q4HiZewM#x(|8?@7{BRo#Yo7q5+-UzKXwweSMa2^Cj!@wq
z0DBM5FemxYN9mdE&+N251y>_?Zunb&3&1@w_<gLSkb>%q@tPKK;Jv0r<ueLPO~|$|
zEzdyDJ3w2Xg=7j_pTkSpafWxT;^{c+k#Z}4E6#|1Q^fW~i9jvVEYslG9R@JurbS{7
zd#Df(dbCKh(jHB}!^;JDz)dLc{pUSgl^AD9Vw}DA5ASALBoAgZJb+;_L4R3#A#cdV
z<3uet!QT1;0P@WuODggJTlhr?xCscKw<WHt!oL??r@y1VBXQBw;d<&NG&#h*jks_L
ziwmELxgJyB;d1C^sCem#5&c2@<e4@ZQ-qepbx-><Z8*WY&&1p+EhYRbqC)dBdHqG=
zhSNteVm{hrc!yT_Z*r~iFo4en@#&dPT74j`DzIJ+@5ef1tNbBeg|iy}CGJ0S(hy)G
z16&0Rzlu>MyTu)7@^sO<NlAzGay)b~E;*jO>RxQS@~?M6`^~iYglQ$WTf?I&{M7-u
zNhjhU+pg>I+JU3!)+qPH@WQHdhwhEI>|DufEZ5<{VfOFQc$+xLcI-MFi5)qaNB^FU
zzYz!7l{<In)%cb;$mZO+!x4@0OHE#nb?$Ivqx>e0mu8(i^v-CM-yiWZtqTu-qx{x`
zmuy{l1RCYDdS1SD;gQ)WpD^=Mt_zQ>M)_QnmvvouWH-vEdA!Q&!Xu|qK7-;#Ul$&^
zjq=F}uK~O82sX<5eO?lF;gQ!U?^1b%*o8-aqrA7`1!Jckb_bT54X>A}4PPzCY57Zd
zKb_cTTExQlZxlLv|0cI_+PhQ!yZuIDO~A3zPxeVCd@VZfc(36B_fl_#1K+=)!NK>$
z{20~_8`e)H9rwNR4UpY?4PVCrW|&vxj}Yy>)XbR;68qTQ?!DBqyWw8LWHZM$eglo&
z{jlkN=}O+e$ySGZ4W(EtD&N1!$k)rLc~8s@skO%Y>13_N!dg@4tkzxLOZ`9W?d`Sh
z-*v6=i-qK^hubk?)*1~CuJx~A?NIAqL)A&G-(;;Noye|4t(h|$bXDtQGpB`(-%6=9
zHmd__Ee@@$nB0FPBVRA0=6QH3*4F^!yzWLgIpMbvCLoVW7L|v}2CTyw7s}&hH{6V7
z{<0(2;lvBo3{gEu)q!uW<QfE5`SPp}-do9{$@C5K``T~FF7WV%?5vDI<1*Us#_n$W
zE)4$(o!c(G;i<eP=AeqKfgPuZXNn<tZ5Bp9O;5={aBX%A#^!Ay?)N?orM))mX|K)N
zPpdo+9dxdfgOr^c1_<Nre(EW}-fhk7U5676aIiZCzMyQ*^hsK2RKR|h*?A+%hm;Q=
zGJNP5(WEJSB%!+D1A`J=p>D)$W;e)lnj7m^oQ1Q8QdeJu=MU4Mn>R<rF5|O^s^s{2
z)2d**AG}%oCpAQth%^4-bgECi>+V3tksx2|;qpL>^p5wg><h(EsD#419De^BYOGK*
zwbaAwM9R3>;CINKgV%KYoQEHYAwOa(!VhXF&r{;xl3bgeSN%Ne{(P@`Gh48KU_pM4
zdMO_#Z}nK<yd1A;%PtCf)%Hxm0OeOGk0j0}ewroLr2)Z>e!)NZCEDM!@5%M5uL=aS
z0)ij;M;CZiAHT>q(>lw4JmeVx!8b$nQGydQB*MQkL=NQLT!d>5j_?hiXkMaEpS<bt
z$=9O!G<dP`s?+lXpQ3d&^SYVV;zIHHPp;sviGB689*maODkJ(MiMQlRgg+~>wghAh
zqv*Mh{a%rG9mc=cCulMkz*<FXW{yO-otVclmr#FeQ1m_7%ZEAFz(0~Fn)^5gPrk^1
zERbGy6^VQodw(=2HJr}2QR?6GJq^wB9I3;ZLGf>7%qV@XWp*PV%goNh8j)GY{Nk~+
zJN@$uCMMVzWF$=1Tdt}{MJGbWA_A*Hy(Z$DtgvjsuFpCzXCf?Kvhy>=hM6Gq(KB71
z?1tz4nCpr7whwd;Hi0p-<jFIz5_)E1?M1<+6yBd-gJ-?5_=UMP%l^q8vQ>B5Zgm;n
zKf!YVV`j_h1$!+p8X0BFa}Qu2lI5ymvL2aY3(9*E@yrsIFS{7nh1r(jxB>ei+x5W{
z#v1IFz#=nI^}+Ma>yd|7FETY?<thWVGPB4m2OC3HK-LdWd5CQY*-_Xlg>@$@RrSpF
zj9iIwv^t-*d4&??XtkQ`F9oUW>mp(0Y6E*O3oSAe)L?Z5*$j?lu)2-yrsWmqE>}a;
zkI9b77dBM=l&mM&F!i9?gdAQDF2f`bSHGZbec>|nFkC&1xzANEW-K!o;2G&h=o!Hm
zGT^gO^$gip%CZ;OE>lapQ8?ZtzlU7*D%n=DW7HdD8*{~Tw0fItqOt59vVHU%t==VD
z?6UXB{_L{9l3nDn?LH*y?ne0s*#wt;LiUB*?lZE}UG@dpE|+~xw#JS5AF={BiqewN
zsjjC(_PWcw+6UVYT$VxG(_~}tS+cZyu}H=_Rt3p!&k;6Gg~)zG&vB}o_QNxZ+Ade)
zRj&hB?*mw0ZQyxt2F@k$>`yilhto!NtQwKxIYCvXu;bM6DXc=xNMRGzES-i8;7LT;
zif<;E!<Y+ll!~eOF8dX1F?E_+LfiWxVGGo`WV>*(h^f=Dj%8%Gv)w{<71>6%J44+`
zHUas?)FO2s*+jC%>M=50#lcpso+sN!R-<;2oldqyeL%LDtX6$Vh7YdMZmCK)()*vu
z>Qo^a9?OC4Ox2$Zm)2lssS#uaWM`{NvhHN{YBt%ajIvDCkiAZJ4!(;aIY$j@opJi)
zsw=S_*5KINU>x-R2=>w%%)}+e!I2ZjnQ=Cb%&TadMB5eWwiI@yx`XUg+OAS}k@?B4
zR+~(6R<2Q-ITo4s%k}jxlX<^f-=H2$8QG2M2}Y5tjv94~dddt?JqynF4^U_4tO0t1
zKlb%elhfDv@h!2wb^bo;Cdhr%FVZgrE~0z^t^Z8l?wk_+N5MM(DbWXkebiXr#lWLz
zoyWF)sCfmReUz0~Qa{#r8Coq0N!y2rvxt`wtBCgo#X5@eGeshAp?m{zXO3v1x$FFM
zqVsZO%opcfiQXpxlbUO&xh6%^wND>al_UODIX3|F(_i$AQa|(E;`ge}IadNV<_q4P
zu@3lR#-09AYF^=;{-Nqt^J!W;-b?wPzB|3rb~CIZ_fd1az0>-rTf9GlW{tVeKO8Y1
z1a8b1ygTDz;ENeg`n}#?IBSsCf}Gz1f0Zlven@avk>KsrZ=`;L5zR#67h2?f#M6n3
ziMxn@CYI522(f_Jop>s(uLJw2WnQV|^WNV<-c8)+y%TcO`!aAlaUgL5aZ{S;A0`eb
zP9v@&{(!iTm`DE?DDNd6L0k+Rt`_CI4qT8E2mUJeJ>dHx!Cgg90&max6u2>0aDow>
zNc=*JypMP~aWQch@z2CEdJZ8L5W5pkrS)~-D0Q;=by}giSvB|yRk6Asht*R5k9}G#
zFM83V)n7a!d-Aq<z3SVbV0povz=1%m&evjn5$ILBgI{269E9$i-kb3a=4fQ@H>lVg
zuMWt1@CGFJ0Px<75O8E}kARJEQZWutb#b?BT%Tz*KfyL*bSo2VE5^4j!NhiDg2`3e
z9SJ5;wkB9E*mlc&JAH#4qaJhFrMbd(y6l?VTwK$=kkZakZ@acjG6v(rl)VYt{D4P&
z?b`m6vDm>?Z6Aey7yC|zr&l3uVaNzqMXI}NI|sIO)yHKf_hFN+2D&VmyFV>m4NGa~
zQ_~adT3jcd=6dFb76<&QCSgNws{R0W?g4D|0c`yN?9v3wMU<N@^WEne>;zQIWh+9$
ze&n(>p<G<eK9JHbQ$3qt*W%jt4cGIYg2jPs6;Ifff_<A{%L2J7)YsOmXU@a;_L3u9
zChhQ@0hV!1<f)?*EEmrRPff6M1Nmx^+wT6N!A?k>>9YLL`GJsHk?{25t>JkGu(f16
zGoB1Bb_&(yWKXNBa|VOGVQu=!f)cQ|$Zqs~R5aWvQt!Jg4%S`mbKCvW_mHQj%EARS
z-f^nS3myjRX_>yfpwhurH~&42b=w*^LXDwqBl3I9bEKM>U|#(0ej1sqo{Iy$)oElK
zd~5QiV0W!?*=Vu`vcKpDf|uhM+mc|{1p2CH$Zqt#n|o8BM0M*Y-QVbY1+2e1+cGsh
z=dQp}s+nxPI=^shAgq2#W-Ad^Z@cZr7XAdb&s|Tc%Ru#&Yx}6^ra-Am>u-CAgAGzS
zWKS!pOSu~DGO0_sI*IHrsLKO^!RkUX$@byE5Opn?Wc!=IFm<cTMw4xE+ex;=)Y}QR
z6T69gj3fEIoBLc~gsOJgD`2D4uPsBiF9$}em&k0kV^jg&<j9Q4ypK^M$<`~$Z;TpE
zCiDJWV63WgSsZM<I?-(>`AtyYbD88fL0v^A`MnW1PCY?pXR|{6fy~b4B=x4tWHu+M
zy>2_nZ<6XIA5<ur+dl^?)p2B!-`+r#l5exNv$;1gMa9T$MpM;ZGMmv<l{Qd3ZAMd-
zk4!S!8<?gFTownLp^hZ8Gj@VH-er=}32HH!Wb{$sM0E|Bov~SJ6PcZ{lhrnt$&8(>
zw!7^lqm$J~3HE7Vw#vchSa!y~49rn8UG_@umw|ceax$CIsp=&%o6)K26W1nlbgKHy
zZTC^pmx1~A0~@S@IM@RGUQc?k87)-9T_zbVR5QpVBb9lEijv)^o-FcaE>cgBZNQ4m
z%B)tub8Xvm^D}Ey<{*w5pG5S|T%yL3*^w<#$CKGwFHzI2Cu-d<vsRtrvN%|ss&?DS
z>N!g_x=coPmb#2gMm8w(Y;`x8jAdA6z4{56RDP>x8UE^m9n1FI(V6F{r^)PC8q_Of
zb}S9*b?b?-RAeq!@474w7EvF$?PM(Hs{JmLv7D<4kCq-}EYmX^RXN#CpX``TYAo4}
zzOjWTXEv!x3AP}!S<NJ~V_Btcw(WRStx}s@&yR{~GtX1^xhxKLzIwuKCu6xlJ?k<V
z%LVF>WPiclx;(Q*#jOn^i)OBoLE_)jxI(xjvsHaeo9wN(WUf_TCYV>@x8LRBDYol8
z>r@VzJqJWpPqK@BD?B?)RF$}Fl_!=NRf8-;J1>r=@nkl?_3Ha%J9)NPuYO7<$JpOI
z7pg~G76;p?UUb_@eiy4RTqgNltkMQE2W0e(=MoX|PtF!U%KW|>N1KfL!OTn5EV7H$
z$Dv<mUZ&0<lR4U%`2)2^n7&5&(|(tEh1%lUe(8HP^D6Zc*)`n?^8e(yTD?prYiU>J
z)#^RV)NQ`qnb)X&ZoB3A?}KFzk+J+mpP&Da%xhI2GHLhk%<I$$%h2wd%<I);*HhYE
zujZ$;!w2yE_jFo!zsb5$os)=Ckad%4NojYBx+|sKt!f9EU3Isq-;-UZ1_pa&-KIQ4
zCFpw2%IzwX%+AW~YChRcuDaV*4VlbJ|ExRIa+k%y?o#XBb}}oQ)TJ(yS=pp+B9m1&
zIO}c|vo_SaF>AB>nd_<5>Z~p5VKSMcN3*u7HZoi5du-~MO{q(gNj-n4UZv-aYM<xH
ztRJZ_UG{1I^I6-}!eP?%M)hg_Ygs=@MA_#VpLTD8t@T%>-Irj`XE@%UsW!H|MosbG
zly<+$!Rb-vPue}8hPX`HJ*cL-OxkT%D^omwuC}CjKCI#?p1)Gw5fanp_lPPWlOFz*
z^@y73vbFxdWj(5{cA50>YxRqic8{wk6YajtdR#r1X!mW_Z`7+P?VeB{Cp^=$pHyEY
zJhQWRD1L1r@{=B(QawkuXIq&4v?_7gTK^H*zg2@=CZ5l#;}f3!v!7G55}t#ypI7r!
zJYP`qo%6PWBeGvqEeX$Y*}qpCQ#}8mVhPX6?3Yzr!gEIUE9&hO&)3wK3D3FNud9Be
zY!7Sw3$y>I=DSSB`KD@e**;HQ_Ab?u@NCF_OKnW?{FAyX;n|%1XZ6E`XG``w>i!hZ
z-Rk*-=Z5Te)hh|l%d+>Vw^KadQ(q)Jug(68`ZnQtOZNN9cZ?mijPnE4&t>~Oo3j6=
zs$90#zb*SiRh{DbceN(r`C#@x)Q=LLk7R$W-cIrSM17I)+>!mM`ZnSDT=u_|Z*;Qv
zf2$Ig?en~x{kbZ0*;@ab*<Yv;DV|@cSxHat*Qz1m`FHO=^-_xGf7It>c9ri}hQGy<
zRsL4`epTSIwf<SYZ&hEHNhP!%OlI2|ZGZbE?RIAyeO#j52icCEo6;^#H>b4o>hoON
zKF_DwUVTNP-B;P^`bR14GW3pwr_S-~*AkxDIRU*V#WPF)lgy4RTYr{l*DEJm`^UDg
z!G1Y8I@4v6QBZet**?$FIeB_~!gFL!zOGL34C$K_o)dBk^<xRo<8z91JjJuSE*dBO
z*)vcNJ%G&a^F8%2Yx6zs?9S||$GYqp=j5E8x{A#1^S$)dwjKBRUV0aq?DGq9j?jN`
zSsbjl{@QIP`+OhWeZ2H;->db}N0G@sAI<EmhggPverZmLKF#%%tBZcRhD^>m=j8O)
z=aI>|xG`sd-e?)mjYsM0$ZSSoeV4WQzHz?E4C^1d%<s7%C#>%$vl$K4-`IA{XrP{Q
ztc+7K+K^MKXS*y8Hb|dI=Dy3)7r9K%T;=*YGMmw0eY<7I=!%>n`YG2_G8(F1Ad`%)
z&l#rQC6kP9%Nef!>9*VF*_<;%FO(ZHu+y&f-<va1KjSi4A;;(=j}x0+S)+9^nXLI=
z<c!u~m#y{xCTENu;WBAAPS>Th8?Vnww0kyZyp}J?xBb1GbF5yI((X8YUrM_Q{j)^7
zw{t4=!-;n9<xJE&Q`%MPf2Xvo(qE9t8r1lmq_;x)vokhX=aF6Pd)ax&Gg<d=*;~%X
zIg@oiGCN~a^hz>&tuaMELMAizdCu|rX_v*prs-X7J6VG>^j9vE8JnTgCo24t8Eed%
zsdFvEjH%oc^cb?I@mbdDtP}M_GMTaT+*$e*GMTaL+>>;*Wv~_Go~$EeHlx|P#oBy>
zJiT&f>kTd&=_vuboXlo4N55g)aShJV8IxpWlF`w*b9KmNaj;YLKr*`q=j*91lZ@u;
zQ^;&ar|HF(A){k*7wGT1o|4h&`f4)CXhQBny_HNdnw)!v{+VUWXpw%L%x1J$KWA;e
z3CL)%e%WO+kkMlOHkr++T8Aqo2RldA`ZO}h=)~L_UFWhmSgl@7W;3eOH@i$Ss?+z7
z*^JKAKeG%O&Cfkczu|gHMrZ3dnPjv$w_g97%x1Jqe`^_Rk7k{tv#U5VzOQP~J;*Nh
z&G(#{+o1cptk%;2Hi*n-v|OKW+i{MT>uqF`(W=}P`sXf-gRRuhy6t4uHR`{*OfqWJ
zpOe{)n)J7pA)|G<&HP&tvPVirtMrh`GET|p;@tD}WHQO<irnw%S(d?eL+<%{5t*H%
z)q0t=`Sv=u<*wF^F8ikw16xC8GrB-OW7{#K3v}KT=}$8HQErPq(q(b5Ry~Z&&e1x3
zvdbi+b$T(G%_yqRwhS3Pn7dwI<9bR)7wTKcB%@#DZqPp^lZ@JOH|obMV@4P0=gDkF
z7wbP-o3ESaw%m*LJ1*<%iGlr<%w}|n9&x<nU{~EGdM%k`^xNF;>&sjg2fIw)NoF&;
zT>si-lF{Y*c`}>P75Y`nkkKD<uhjo>Jtd>7blOzuPcnKV_iEjP%w}|r4qL{IuGPno
z*^I8!mDc9F5p#5%p5d}PF-O<wxnwq@>vhbw;~ZVD|3)Smy_0)`{@i78u$#1hnvBI}
zbc-J7GRf!`eGHk+=vG}}88Z4H_cmScdP+vO>vPE@qkrb!p)V%08QrO`w~QIxr8kq=
zjAHs{*5<nh8O8L&F8e7mis?2oo6#nnIbFtS=V+5Yg-kN~BKK~+#AR`?E&4n%o6$Y`
z2A4@j_vp=JHlrWvdo4poI`|{~n(HYUZPR}ulZ<@9AL~!aY(_uPYKDwO&PO-o-m7!S
zY)1F#p4R5;i;V8mB`zyNM)&DKWHzIp>ho<o&e2cxlVp-nPVi^?MVH0F9?<W)?PO<o
zNb8x>`_niBJq(sZW;5EZyIF>ex(9!*C%T@J(J%BgGRdeo_^@6?W;6PwZm^6Q{Ytlx
z*^D01msp!`1TuO=U*)o6k<laiW-^=6qk6Ax$BZ7;<tNBEC8MK)kLj^4i-SF`Pb9N*
z)TWoaOfqWIEo3&MC-g?kkkQcKllnf_Q!?72e@-SDjSlYA&ym@Tp3-kv#*CiU?~~b#
zeyjgwZN6vBZMnbI`&{-169e;{XsauqH9w<IBD1UR8GS36WOQ8cS$&Vo;$Y9~N8ENY
zM=$6%T_zd5px-C68NI0gX&Ew_7W}>LKFjte8NH<YkV!@-1^=K&k=cx1)>W1<qgV7C
zGMmw>da<?nb|Irz^;s_4gN$C)E6MB}y`~?t?KnrTY41txb98F(b)Dz3c+siBH}n89
zJ4d_pWS2=syYw6~o6%c(p=HRZCiu3#$n}(r{-m!UlZ?&|{#oBmW;1$6-)|W+itFEy
z*^GAU=dI1R9~te|uedB7t8TY`o6KhPu9iQR)4nsjs~gE=jv~Q5dacXiVDIT`$!tdN
z>jzvW8NIK6LuNDjtA55ZWVAZ?f&Rqxl#KqSzao>2qQMV!_H60hX7rKnWf?R2yDlTM
z8T~^aV{N`%97q4q$GNOKGWv&}N@g?qSYL13agILLe<qWRE(!iq|IKA_uut`Vx1FrI
z&-4*<WGqi}XZTE)k=cy?tw&gfjIIfOuFr5iC8IBN9hqcwbMQ-j0h!I{EB$@Tn9<kz
zCNi7RKE2u6d@GRAKK&DyosW$6>Fs1Tqi@_l>}!vsZ}jxJGET|puHb+4DK3kHeXEy|
z**VhYQkTgbX>${q&B&OTWyok-&@s=to|2Kr{DDj|x<8m^{z7Im@|w>qV@B!5nI~hh
z8Tm{O*~PvKk&(|7x$JUe<TJ%&HlqyFVB2wyGR!Z?B%_Cee)FWu;$WHPb+?_&QMUQF
z%Os<0<D4SB+l+Edre(<JiD0f7NoKF>g63E<$>^D2o|#Q%Gs-vBmNBCO6Ctx1g-naJ
z`KBPFklEm}laNu!Tux>)Dl~7{cFd^I^gUHZCK>%cSY*mw76<EYCXv}W>S=0RCK>fK
z^5>q~GwNl|w+tD*89c&lay?~^jx^iIB%^q+w|Sh*W>jo`XBji<W8NaO8TB>qTbpkI
zGU{tScG*&7)Yp7TW-}@=Rr6&mcGZ=bE6F6I_k;b+tuBj$4KP0?vl)fW3oet4!sab9
zJ4XY}UdxctC&5yab(-{G=cvqt$RwjLgM&;dna${EGukp{RBnzZvl$IGbF9tx3+#1+
z&FL=t4R-IrW+|D?Xo$Jrw&NTPF<+BOM&Aa98t(!bi~L^g+u(51gUn_$(u{GLWHizo
zPi8Y3WlpjT8D-=hV^+JKGDoA$dNRo<H*bu&k<4Z^)@-qi8I3a!k=cyKo8MTQ?;~V1
z-u%{O|3*gR%}Zo9qhn34(`D3lj*c~Fl1WBIc@s>d%i>@a=3+9N(Im6gWs=b(^AMTM
zsM0)U88YgVS7qLFJtd>b=I>;ZQ8;gkF$<-4o6+$mmrOnn8JsuOj94T#`5a|*-ZZmt
ziDmM6$P9A@nf)APrn%|>b{m;o9eUMFvzcsz8i?O4%rx)1Y?Jz)?*#L4!c(ggO-8Ns
zuv?emo}F0+zm6oks_0=e%iL^PhPP-3Sj@HU3yJ3sUE8FhXJFgz+HT2v)tqFUr8deR
z^Zsm3HUTm_N3%^4nN-4y`v{B4?5xZ-4c3$EY_?fNCbKdrZ;n~-vN+g0bA#JXcDGZ_
z9WIkuIo14xOlD<f-h8v&+Au4N^G-86Tu-ge%v)fdCzIdHoS%2Pd6mpoaG`mdOzt0k
zI&Gox*GWd!c819#v$iu#MT%{anVMo-WbRI}EjIV2*cO|mXSc^(msf3?$ZVBr%sOks
zXPg)3)tF0M_Kb5m*wtjVW=qW5wjFD>#0;pHm{PMF@@ma6m&L*A%oH-alFu@AE|Z#_
zW#sPx+5K~I-q~i2WvJO*dG%(i>nSx`X6_@C`MW3Y9P=cZtmOOh8jL*uWvle_yyfN{
zGMmu~^P#ojGtS5IR+xXe%<p*;>>DzhQN&DLCQ<CM88O$ANk-4-tu%MKEDqLa9wf6F
zHJd-UOfqUV?~utVSe&=Y{M9mK^jh9|CU}nYAp7T;dEYbL$t0t<^UgQrWRlUIywzqr
znH-xR=3QW}cG+70XL&8=OP9&9*=hzhNKAWdt~F(3cD<}MBgpJ}k>^dcddVkPl_Pjd
zhG3Roo>{4;+(NY0I}63yCnWf|N6_j&42t~w0>LuGG0JMJZ1s;8iB-@rf{ai!-SY$o
zBeGE=7(Z2hhNBt;ANx<Muc)bn#;8l!){enqYTHyf)#tnRsMY^jFaLY-|G$siJ`0t(
zGHY8nry<V!e=#<;wXOc!woh|4PGE%Z-s8dRXLZWz{jPD^bN?#GAa@%fb&aLUcHP?1
z;t!p`|7>D5kCar+032&t{SbK>^)|Chwf>Eo?>a)Q4$d?+nw9V4F_?NpBz=r~MDOM}
ztxxCH_G)x)mAiA>vpz89|JB>t{@*$rx(>f{Wc}C`_<y?o<v6u*vi}c`_l`%CM6+@J
zx99Gi!<4&?Gv+YmZsW{4Ownwdvkp@<8|SmbR5u%Ez+oDjjdS;58k>#t;9-hp;|xAb
z(QKTFhbfwk^BS*F|KINeHqQHpDVmKFI82$^I7b|&Xg1E8!xYWNx%x0gvvKAgrf4?K
z*@r2bjkDu0tq>dMtHTt{#_8(3)4-idt|8?)DSKshAb$7vSsl-M64S;%82|rxj&AUD
zlV_dq98q^Xt=%0@n)kr7Iz1rwz_T|!fjuGjR7c_o^uG96jh_K{+NE3-<4I{e%?Rz8
zcmjPHzVT%X{zBgtJb%6g-_WoY-@>p9&ztX3N8|ei%GJAg#``a7i29ovs{WydsZa5I
z_UCGZ`dW=t`w_|LWAG&UXyw;qRJI<g^7J@WsK=`w`dD?Oo}fzgajINbs9|~{zN280
zDpi$;QiZ3IC#xy=Z#upk^F%dOtx(fcBiMOrrn(T{C~+~gm*JZtu2d(fYt_lPD|fcK
zRn1X%;+rMzR`b+7>J&U*ekz_SpO0tBPgB3ZQ^AkmS>VUjLiHrRYx8M5?fV@5qT-9H
zTD`26r~!J3`U773;`If*KCAGQ0G@$gfC?;9=RlL8<gTP3Q0khU@5d*7@<iECBC>;w
zC;EZYh$j<IBjWo4psy#M3k;#&66YFVPdp1N@;2hHfPK^lln3hU{A<;E-~;9wJprE<
z-lFAG!YWgPPX}+&JqkrrgHHozn$Phm;3oY!KK<JUf4M7OaFgnnk?ZWHyjy+WcZAby
z<Vg*Y2RcviIh$r9&rUTPc`j;=Sx`7neDF-c8uLrvQfHHj7cGOQM0*pFLu#YR&R^$z
zpuf()*ty({E!^yUqW_V*-O;c<>|D<X*R$>Qi215>JN>s%zlHiO)Za_}cH&N8xkqA-
z^!(1eQ8e50iM~2#zUK+O$+rlav4xGW?(?kkyb90jJYO-#uXLbbD>P>o?l5mN{@aZI
zHsi11=W}cL%+nM6P1zbCazrkVc?9tt7)GA9)n=RTWzSwl-pl%AnBV362^x9!Kx(xY
zvOF`e7m>dKN_{?KkDsx}&)DM_9VzIUHby^^(;K+DpkLZVY9{In3(C^IF>=TEH%9LC
z{*1kU#u0wT5q`$8iT*JUzF?`_32Emt$L_#oY4_r@=_+X6C^|Q7npSD&rS&mW@%-Ww
z`q5Bp+CYpvgs1p*&PG`O82Wyi$B}!@hZ=v*ooU_Cc5_;$BhQy+I`YJ6rX!zG7dYAZ
zZ>0tGZ}H?~FGrpw-i`{7r~iJ)(&KjC#XX4D5%9mxGr~Cr&j*fhf;l@(P=BjOcqRU5
zZ&26jV<}IB{H~rtc{=1TvTG>ULH3(vlvhArp&#-{TO3pR@46@ZZGwJO#`*MF135io
zJ>`qM<I%fT;~jbSb-W`_!;Uc*6g}pxa^%V9nT|Z|T;<?yW9Z)~dI$1a|KEY~Nnud`
zHGd!DZ1qeuBMoltGq>cV15H6z`dqdhW4>Q>MEXKU*8f6BR{laqR_{`3mQu5nnrW!E
zS2a-IKz#%C&D1ng(@f18YSvJ*hMJAkY@}u*HJ4+|<I}DOzLkC&BIl~hG4d*C<WA;H
zWbMVb{l1f52U(sI&cqS<J>Tt|yD=sn`o3?xBhL)inCCtBL6&ER$2;=O@OVd_5FYQy
z6T;&id7`+UBOmX`Q^eyP`MtpwuEQ-{hg-M~w{RVb{xQ!tMyhu`Yq*6Y-@=h^;mGf$
z=3Z*<rDi*G+0OB2;~dc~BO7Oiqk(hPOyGQV4sfCRKCoJC1uj*O0MAyx2R5iTfGhEB
zIoYaN?FXK(dit}~8Z{aiRmb^#_y&V1z^l~^;O&%u1UXIR>XU#4dN#0|o(t@yPXQL|
z`M`d90Who=0te|uz#+OCI6^N0j@C<o<Mo-q3Vk-PN-qOW)eXRzdIj(#y%IQAHv;GD
zX5d179&oCWerKB5{{A?-4#Cr#rD|EXay*keFTWh$*|G@OQ?&w1)WyIu^&)V%dKWlO
zeGIHrUjb*R(+kRR_BtDQx{3j7)dRqD)Jp}!8MzYQ4V@dR#Q8ioR7<(mm0Q%jP!oJY
zp=Mz3z<OFYxG4S`REt^@+C<G}7e&7r`puyysM&$@eJHepeeHn$ImjE}^9nV)>9Yqu
zy#srw*#n<=Xb*ip!_`FpfYLHTO?0$)I$CPt=oXb;=xB*nOlu!v34KcFQv#nO3QOqI
zPyYa(!=Vp_D(E?pSV{j%`d7j~9;&4OG<wdVz83nb!dmK^sBZ@L4n!GYgT79kQ@DZF
z>*&9U`psz7T)3I~E$savwr!*J3E~d;TvoV)KCiHCoci7L+)a58d>$y=!(R5#^8?*O
zO%G`!m2pgq`fZ_Oqz-9#!g@#`gZg~Pp-?g9KEx6u)hnS-30gfDDq*XBMk>>v`r*V1
z`cEWQvQ;JZm1y;+!b-N9Y<j3s0sOWLZEJ|N^sJ?4Ej?@LSw~G1FceykR?~sfY6E;c
zMH}d|kz?3M>qYdxj<}gIH@k9+Dl6Jd|1I>~O8rB`Hpbk6n6q&eBh`3{`d5IV&>rYl
z7wtu><GTHeddJ~fa-?D&NAzjHiGdR5Hni<W%|JW>iKBy>DrzRve;W0*)Ynn7f$~QB
zTtv;Kz}|sN=@}z#fwg~NE3MmT-9~*IMiL6OQQpBgJL&lpJ>#^-Y28EXd(?lx2p>@I
zcx23Jc!M(}P~zFFVnrn$&NVgti35SX0|PyhQ3bJ*K9#giCe~6@>&g<dj&eQyH_*C)
znhl<1IyZC?<ruA-Y28fCW?HvW-bQO1aR+^#qJ9tMJ+3U#-lO~hJ)N}8>fs_MO)BH0
z^-zPmIcegPmc|^R?;Yq5{mj5XXpmPL^CDK#I+@mLYHHJ%3pAqw_4Kc&egi!>Fy;pO
zTtuJEl(#a%Hu`U)e;aWJTkT-09rS#Pa-7!P#69%cL;W85yhr&1VDG>O^ud?!p~8-r
z>(DECIbO~q<ziY(Xf2_pgx3C)2Lh2beJY5R^sJ<{lAe<(SJPSpITWg;Pc8Me^r`c*
zCeZW_)YCHxpHL`Dc?117(0>E{FQOcybrV}{rq5>TH`8Y;<!!WXqh}j&2R(Ptx`Uoi
zQI6BPoBn&~vxoXU^m&i+2ef`bPbZxfOJ~K>Sux6e(q%oA&{{%G39bDp4+NrO={%z8
zQ%QX#eI`?`VT4**YpJQFwT^N<5LIG?D15M+QQkoR4fNSS|BEPZqIEN^o2l7M>sHF!
zfV~6T=(B@9JE-45pQkAAp?;4mOQ!Ep{s4$o#I}x))$p+zK30QrAD_%@39Tj6l+fCr
z@<1S};p0(5pGp@cP9;4j)3cWPT343%b(HHFp`H<<#0~V^K<frZxQKF$*3GbnLYt}C
zO56rS1!!#}?x4>OTAw1usoz6+4`aSZ`2!#-K&#5&ag@OdWUvC1i>WW6Tta<+%9SpP
z=VZ#Y8GVs;T?UT@XfVrcyMfk=h?i1-DfKb<BNt%rz-C&v5_eFugYr|vXMw!~&$87X
zTK7=@9?`+qs}2dI5le{uiIv33#A?6vQcJmx81+lO8z^7omodkv*-T9v<sFpcl=o0p
z0coX)4!(P3NT8T<A7TkL6De0xuAy8@c|GL~lw<hTkx*z8HJhn<g7OZ^JAu6eyQ$ej
zjmGx|V3*633Okun^FGv+5G$bX9hgYDl2}cwA=YNfxvUmG*t;@i%(a<v7KqZip16S+
zBW@yYCbkiuAnqW>iMxq=h$@RUAv#$y!akHsvZSwxlq)IMP_Bg!=7O49JeiJ>KobgW
zptU$#tQFZ3vzizs#)xgiII$u}JeTH3c1v^Q+9OI$EJxaIp?(YW{R3^(#EB|bti{9%
zVpXoRtpUyqETtUHmB<?@<9<fSTPU|tj<eP7T*+=P_4sC4#MD92c!JVnF*SXt=|@ck
zH4~|+rW_^4h?}T?g1DQg@;FXnMV{2Bf^s$GYRXaKdSZ<F80AgGHsTX`GO9SOaccHL
z6AGz(#wYg47oRBQ7_p703g|<uAXXK~6-8A6u0Oj~Qxhd_q<$mx3%bP$WVA8rx8N_O
z^bWL9juRE$5260V3Vf|mC=?IL8t7Ljo>j!^LeXr2913}g1S^WTDvG3S6*RpA)zmDd
z9HShgwT*Hc<v3AwV~@lNVl^>Jj1k+cz6X2hDOlX+C#q*?V?SA48~e$eZt2Hd`iZrz
zpTvw4Re#3s&sLNxC|6LfCPs-dVjD3|R0G(S*l&RJ)o+0GRY6VF0A@-#HbCOXD7O*g
zM0J$t)lrN?xtMYVv6>hq#)xgiI8lY!idaG1IZ)<z=Rldqy#uB9XsN`HmWpSL*hY*~
zAE&I!IEFGtBUTWriA&2Q=F&2W8KovhY$L{rY7pBJtBFx!jMzqu6Xgr8uzHUcf6vhp
z*>ki+E~dVi`U+w-HPw`(l%temlw*|Jh;gDSmzWjAYGRZaBW@{|zP6N0Uv1RH%ei_f
ztHB)AU}izApr(RyHRWo`QOZ%uF=87rPAne6F%YYUNRL%Rq{nJ%mJZ>JP>vDXhDg6{
zl;f1+l+{p<WT;q+DOXUgpj=J4nsSsFBeoIu4wZiQ4wZh@FwX2SiRKw5y%$riAXd{_
zO*u+AN;yVsBgTnpILAY*AXXEj#ErwH$Bo0K#~3wRhD%@Z;nI7Y8a09uh!rD5UqQK=
zay8{BF-B}7#))bq+Y<YYl)n0nl)fscsTwJLRa1@<+eS+KHp+3L8pQ~sL|;s~f^r4r
zYGRZaBeoHDj*`B1j*`CO)a)H4eW_y@jaWgfCdQ7D_%X_D#5hrn7QGtHR+Nh=R}ia-
zOGiszOGiszQEE1hmcC+?+lX<Z8pAlm3SxAO#E(*r5!;Ay>f@BvSdL+=wDpXYzC2^4
zuVQNYjg`JCC|47s#2B%S7$>T6?44LWPGVM5juK<UE#oBqmT?lljXrJE?;Iz+#Hoo>
zqsB8Dv4U7lj1ptSHe#HpjurokW2N5;%2mfoUscCSU)9tsJyv>&QjXCxM!Ai08|64r
zO<?cD3Su=eN{kWPh;icH3DVcz3DTG6IO(PMI2lRtaU2z~ni!=%N;yV3M!Ag`C#nke
zPOKnS6Qjh971Gzn3h66G&6W!3v5m5t$l0982*e6vHTBh$qm-kRW5hOMoTw(TEwSGu
z>8sx)>8pa8s!7sUHRUKVMvPCAe&du?B_j|kDmf#Rt0`AgjuK<UHsa1o>1$`D^cAOO
zZ>995su+z}L98Z5iEUL9zm0O7s3y~YvgnH`S5U5?Tuod$S^8Q!S^A1nvvIQY6{Fln
zj1$!qMk7`btBJ8G5<f<{jTk4Y<3+EImsXzRr5Dff(n~S*#nksZUizw_TuqD;W5hOM
zoT#R<cVY!GI#uFFDaVLgrb;hcrb;hu)a;xp@#FN2Q=_JFRMQxZSV62NMu{<E8!=AY
zJ58=0)pX`EUF2fQ{U}#YmzdSmM2RtC8})6J<CNo+)eOd&A=g5l8FFP_Oicx`iux+(
z`v<D2Svo_qh*FLb+lX<ZnkmsLX37{UC|47s#2EE4%59X}D94HF1lECAL99AKMpbnJ
zd#7gU3GAJ6jMzqu6N^ujev41!7>L!xDD_dwG0HK@ZNxZn?}^ga-V>!SHH$TwC4CiB
zt{_$uqr@1ojToQBc|3`|6Jx~qNgtvb>SVzRVl^>Jj1k+2@sp)({A5;OHsj1@7L+R}
zR}-Ve7_p5QC#pGYORTUsSK>rn6l-j*U>h+`eVnqIC!T5^BM>Wy)x;<<Mr<R-iRu*k
z6RS^=2-TFM#2B%S`ZmgO%5lo-RJJ8n5UYt%VvN{Ej1$#-@t6Bj6z<ZnuO;qlnfp4(
zeLdQJEq7lByRSps*P-s~F!y!1`#QpX9qGP~a$k>eUq`#IW8BxV?&~=BRlXWW#wTA(
zBd_umH1aB6<07vW?(0PNb&~s9>AqIEukxh{;y=}Wo#wtycVDaB*K<@ir_tHrJnOve
zeD3%>Jv>W2w|H{W^3xWiEl%5=_ElQYJJ>tRJI8yv_ov>$=_Avt(&wa~oxUOcs`MMu
zf1SQJ{WRYLzF*>-hhOo%>-)^-WO&hUx^k3Hd2ok^e0#4C_jqLBcU%FLuQFALf9U~#
z6#?2F(Da0+7yc4NA87hQ69${Cj=-HNy>VwsAKaNzf;&_C<Ia?$aA(Ru+?i6QX5(I&
zIk-<|F76eXr-tLcl99MG<rw@vbPVoH8K)MYey5{m3vvI*8TgIhB1Bw_`(BpdPLf*u
zZm=Gamm#WB&-nJ^e)Ai01%Hqsh+nDa<F92<ju1n+>ChB~0>B46;u8%C{<c6gy>rBB
z<?ThHFAC*C^K?k!MDs$x@x*9ecgliY>1`{Et35};Ggb3DrzD}t_6$tO?>K`K@)*zX
zggh%nKFc#Uq5sUONXP>`N%`&+{evm;;1qdciu{^MwtYWE4y5=Tks_~2k*`jX=cdSK
zr^q`}Vtz&WhlNs;cM2yb#&7HMJ7-!#lkJ(6Z?NhdWw7qjupa$DgSD3q%!baW9IQrz
z6_^Fg1JhWEIgksXGgy83z$39THCAB=a$l@agH_lah;P{kmcq+mE%pYMW1Sk@VO0Vg
z2QPy)b`)?X)~mrvECVjYnl)H;gMsH@-5UJ8fZ@Q~v38BR1FKi#UaMmuKY~?^Ui3KN
zQMjv1<2UWcLLP}byA1B>lE2h)4A9{B=as;DdNMSp0FA2E#{-w@Y0%UG4gMm`3}BN!
z0h(r@!TnFOfEVhMq1ga5>S{d)c#WP1&9y+I?$W0MWBN2`HUW+LsXiU}Gkpd$_XCak
zwO$N-T-QMJ8=z6Y)3v}CbR9G=0*!i0p9Oqd*F*CspizI*=Kw#{%c1!QXw+9a0{mK^
z3(Y<t=FT($Gt4Sz{6P7u&))-fGpnKL4n%!S3-Bn@3QZV@`j~aVQD!|f#{lvC2!0!C
z)MRrJG*f^^%`uk%=bB5QnFlm#34Z^Ix|u7WSqe1jTyqt$(Od&f6VRy3%yq!a%?-e-
z%uT>8<`&>qa~pi_0UGs?xdXV}+y%|gflKh0o{k3Qr40ra;O`17QH5#4f!)$Z0(+z#
z1MHPH1}kM4X1s#;<;}x7sl_U3#QkjR@t3P_RzFhrt6!=%+&}jw{&MvP>J!`v=+)V}
zNEhpYx?Z2FSL^lqQhklSMQ_sE^aJ`=`U(B4{)2u~@7DMR2K|-RCc^|x57XC_nq$la
zGa2`{%`pqi68zPZbIti?ow?XtX>K%km@Vc}^E<QG{N4Q9d}A`46P)ikw>vL5yPbbH
z`<yIKiD!UkhUW*KpLm}3?DnLm4NJQ!?MG?9Py1`y=V?cHkMdsTz25tbH$Qz``t<bM
z((g{cH~r`7PpAJreXZ{~-<!S<eV(X2FJbF-|2=@aPvr@T_J27USK+xr{H-k<f0a18
zs#Gy{?>;ym^g)IC;EdJ}yLf-xxp)+gvM`RZFwPNS?B-#dBf>aGgmI1t;~WvjIU<a6
zL>T9YFwPNSoFl?GM}%>X2;&?P#*rCDy~8+1gmI1t;~WvjeKcWJgClkc&LOqvaVdJN
zLyu>o$FpEP8`^r#Q7w++THIwLk5G2QeK~$yTNGft_ux4x`FmVf8_}P_R}cCfmM4E@
zXTHLp`h$Lf%NLL<bph^%5c>t{ZrBy>(y@Gv%P(~Kh2-7TlZ-3Rm|DM`uKp8Ozg$cI
zx%f-w@~YHL`XM7#zRBgc;Pni3lXHgp06&iB3>EUMR#QA1Apa9T8^HgGpH1ow&mYv>
zv`w%z=r_PKy~FW34nHU0=X%|m-hiL$^`&^d6t8pB8u+u=cd6d&8%H@KL!)Z=I}Erg
z*ovR!xH8y<{dhU{>0Q{LcVTzlg}r$fcHyn~S&n^p7k1|5sOT2#z^`Nf-6Cn=WLnt}
zSy4BkpBg`*cJbn>`lgi)HLEKdYMPpc4PQJ2+A)h4Q#ih^d1Av^bxRs+>TBn&URgI`
ziEHTC&Nk~1Yy@L<P>vL3XK@q#4(;4Nd@&5O>uQ!xSh^VEiK`kKYL+zARS#9uDkIBR
z)-<-W$tzYZuS>FXSJgDPo22=vjrGmaYHrP0XVongXAm*WTG6n2&dQn<5^*wGHPkn+
zwvp=^sk3pLBf@6ZH#Os>YDr~eMRVQxB2O7UOijbjJp4$!dDB)jyP}oG*G5*YXr3@~
z@#0}>%BmH$)x%WEScj=oY8qD6&0Vz;Nx5X!%I5mW3b5IAXC`EJJxon(Y^+%g)A)Lc
zI9yE`H9}3p&piCJckhbmUW`NWM_TaHZgfQ$Ax#@L5>|nfQ9wO(*l08YoK@Gnc;4J8
zqt!GhMyGm>mIb56pAcEPs-bRzLJ4c@n(LR>RZU8j%O}m5IQK+!zOvCub5=Js*DWuf
zHVeo3v=uAr8fTxX>fP7L4Ry=wRy0FXmyl!tDDh&|)Gmky1-BXs9Avu&^RSr1MrGVq
zBCu7v1_iSkRL%NOpwG}zZe$S{xm|-Qx^Yl2*NGCn5;`fT>xT-q2NTIgYu8DAUB7m(
zb|06|!|QpnIu={MxhSuVXC;Y;C1O<+L}UMKqE)ubqQ{KaH6ollq68D$q)5coTZwU2
zEq8;6AexgJG1;}vR+}JV;i|NHR}^j463!Z4WI@eoUb=*fiURf^<*tRwNJB$itt|Pb
z^5g5UB<gF~T~&R}St}w<&Gog@ma3(xM1ohYYHY+}IiY4n4G!qJXE);5gWvcG4T~4o
zuc&XXuW3jqW$mkJO;vSg)~~2rs(6?;&0BFEdW|&JUjWs3Sz{B<S-f~sP3<}OtCLge
z>+pRP<7Igrtd%8puvXUF!CF~r2Ww@y9jwKn+KE<{T_?V>$_`d@@g1y|`gi8txq4cs
zzMUz#4iD~5*5bihcQGDpNUY3*O<ax#tLI=z9;|I&k_TJtqC8k%wWJeW%1S%fdO}@O
z6Bb-&hUT*)OHZs>-id8WT}|_<#=6dpC*d5nybi}^=jKVP>Km5UHS#=s(E6NRhqx=a
zcON{WX-)RzQPXg+ZC+z1$`k6AFR5#6I@o(+<5@Vlu4wMWgg{dwjmvAA4{kMQ^@`@2
z^AFPhKkc1=Xk6KK$L|}>FG;rS8QaY!m7FO_TbEr+vh1wAt+QFJWv`X`x8#ir8|2Z<
zlV;-4%<Rm_mK%r8zy=a<zyU*3x(hb!!WK3q2`y~{flw%<G=WkGZJ_<9ki!1cHl=^0
zP`dqm@4au{lYi{G&0nP%N$=cy&bhzNJ@=gR-o0-$-)@J^s%eJ3Zm-;|mOE9m+`=Zv
zNi=XG<^)T*7cMqMCi_y@J6-P9PPD3_H4A<Q%!ZqZWE_A8A4UNtjFXEBc3NG<1J(~N
zv^H%Lzl=$hXiw7<h_t2LsZMLdV`Ms(FbEJAt&_HW&{X-(M6*tRhDq6{#GIS8c>Zmv
zZBuR(#0(X{G*z|M)x&Od`jYFgy16YtGv#EsX1XmmDDSQrkZm=gNoF<HDkQQ_SmRX8
z^u!%G=~!&jE*YxIdX?!hC#!Xg=Zl@z4J+5Bo{-0%KeV#KypddFx#KK0JLQICXyY$4
z-|eDfjhkn~UYT0T^F98@@9L(iL-nfFuo`0&gw-2i#|!dO`08f8^C$-EGiWkV_T*Nj
zv01hAD7`t+x=v`g9>$dqQ<t@xhdHwlu5PZcOHpE66m!Oy2gV)~qVX-)d&wFWk!~4j
zSs|S*S8BMSxR5k1&RuSHE3I}|#fHYn<#Gp|Iwd{1(dt}_2`9JO_)D$LawEpNg?z5n
zQ`cj(8(i2qT}RT*7{87EGqofs8qg_b;$>_DPC70Z5f__l)&xK-Hy+|TQO3P@A`?P~
zJ1pF7_4ujno@rIe3IiT)fpB}RzK$+En!FHpE1kNHn&YyO!no1J_&D6~3nC_2N7QaL
zq)g6RIV;eKSzNrk=mHEvhXjckTPm-Gy_=Vah`VtSYc_mrE5nf>MI*n^39r|~8(!5D
z3~mwFVP6Ux<t>{^(3h~H+XtE;M)TwSV%(#MaH7?|*{QGBdNFC~TD`4#XmmBk82@<D
zc;67SM(f4jBgF(KQs)+8tTl$#LC3g72IX$eVqDy5Zu^=yV}iGe_NJ{@U#;s7E<u$6
zfAJ<JMpfFxa?1i)Y3n+zbxgQY(}~@xrQv@Z<8?*jM3U#ib!Or^mJ$`9;x)6fB7ei(
zr8(8$a<W-zRdE}UDfNAv_Nzk_IX(S@b6InrI$N)FTHUbHYF4{Aol1DJ-Kx~g<z{`$
zr#f}hTKyc=cZnyKHrLkbl{$<6<W^YO)Y`zpRIV9RzSX&Tw%qB~$_+z^yIyBy+M&cj
zfsM@**~A^(w4H4gi9$2((cIlbG$2WvrwIh$*w==++^aVp@35w;jfT0h(J%_<Y&QrS
zZ2N+)w}>DtZ}{rXCH!$~!^jaEf<1f3Y(2W0MXCwQP19<xyhJJauA0l9!M51+V)snF
zhY>#6<j$dK<WO~&Z~O$9sy8Olc$h<f6JpMmuZ1phGMLb%&33!h!64vMLTh5U2Y2Dn
z`OV(>HF~-p#<Zmy^<JeGTe+CB*hG8k)$<r^yNY8<R9}qwbhp(sR-rrLa!V2-Fq4^$
zx_hSHe3gI%&*8jxr`$nn<;RuUu>9slX1#M$Y9DrR&4*W35SG$T-MsmWVgcCKHQnnl
zw0bqJ_Ws;W7cpDMtRM=27LQ%8zJp+FL)OK2%ndzh5w3>;xE><9j;-TN>xSxRSP%tj
zIK^m4v0WbC22Mw8_~YZ=f<DhZV$X+pk13rf^#Jocx0%=FiOsZb{kU2XX@?$Dn59ZB
z)H99wp3N?xUZS60TjLRg<8aR~&gp?uz0!>a5Z|wMt(Mw*$gZ(s@#*9OkBUX6!7jB{
zdx@L$dL<mz8j&Szg+oKS^X3>3t-!9Vh;=SQGuOq!XsWtIT@J$H66bhy<x;DbA+p#q
zU0tUs$Dcp4veK*7hy6&5Zdx(bJm%qM7rGl$Ypu5(y^eKVu2-(ne6{KlTFoxy?!Y4n
zBxc@fic@z9(S>|b{sQK*7iFA|!{lP((_sVMw2djgpzIo2P5=rj3Nl?3)g^}QU=yII
zkI~}mnsRiPlTZO3INC{e_c-RI&3e@*BfaohYY)3<zR#=b;k{90>O4)_>ywe@C9--T
z>9cAhkyV{ma`q8rlciqiG0EpwKgWX%v&2I)fOqypvbYh<0U~&WoQErmRWN-iM6*pa
zAgAc25w7)&4Gv^x7dP4sTul$(cXEpr&EzXSkZbB$G4gDsyxHhU4Xvv@--$42pEWFI
zetjJi#gP0;#;9MfcUnzFuS4NKs;~Z`P_oalHSo`Y9#t-~0~+J|u)S~flKK0TO*WBa
zJ^uXM%1XsOqQa1)qg<^uWWw|)*PP{^MC&l>__EU1d9?g8fuQN!uu^rglIhwzX-b|B
zx6tf$u3Em<2!nNyS&Edy&RCPxW1nW5MWX#4I>Sv?o2x$imf5RW=O<*J<|N-~vB{2s
z$(79K*)=jV^X#LoTU-dO2X2F0*QQn}Q=)W<y`4j5&Tukg{5tst9DK#;6PKN1|CUo8
zPso2cYU_#lef=W`O%RxUOYAt+>}WUXX=vsdi`lclZq*6XvSSQ+%Nrd3MRk?2eUd-D
zCDdZ%jB1o%11?g(I8S-WZ50`n?T*$mdyZ|<e)Hv_93;tE^95?DBexQzH?8zq?1z<X
z$)>GE6k#N1&4J1tqMZ5A3cG4$W~T~wNF81BE5>|S*E(1?Gj(dc=_sSi;B9X+&rpvk
zMEMnRc07eeKhh4GrWrFIeh@R{&0V5}HDh);7~_|0Kg})&hxlC==x2+5Z6ayp_@V9j
zA>X)kOOito_r&QTediLTJB&o~(Y(dEA<yWGwA51n3sGuF%PdMGcj_ABE?b<gLtIYU
zi~j9$Fvd&Mgm*B;FLLT&&hiV!c%7pW-oY5ZNG+UdqJF^`f7#<59O6fZtBF~1>nf%V
zwZ9OhV%j3D+m%E)mx^hZhqNd)q~%Weemj`NyMCYA-f#Z-O4DnNw6Dax$bytSPHSIU
z*JG7AjhD43^CxT31*;X%uqB-Z*`z*ccG<4XGV4j}l5=BIk6NqJ!Z!To;92UgkZMtD
zNJ{InN_xraOa<IYI9s+>^Wn#Fo6&Q$Y*!2BF#o5w|7zo{Up?{Gj}QFE@4oYozhTm)
zAjprDOpqZ_C@4FTDW!r5t{_g@>u-(iD~7?o;?-b}$tqc>0>0n?xthxfkZZV{0J*ly
zwR8K5{kMa{mc!oiSwWck{k$Xh`)Y7%VwW1*SLpv<s?dL<(7$iliv8Cd9PIV*DOU_a
zvcR1}|E_1a?ctjqzU>PPZjY;B8vPPug4q9qU@8-J;!c#f8zo-<l<&|t^ZBVl|8@Np
z`}Yc4`k|lS%)4ZC1@*_-C?n|F@89$NnDy|8hsQiT?%@j_E_is_!!sUU@Nn6~D;~b$
z;Z+Z-9@ac;c&O<JgW{m)q3_?|mY0w1DD$;HfC0$4JPR4uSDg}oOfi>$i~~6bMjaS;
z<qB#L9;*hxw4-Jn$U89RdDL0)N{@g$9N6hwF804e%TkZxMHDtA=Dz@wE^!tM#H0{n
z87&!4%9Kp8{{uIqDL2h;GtI8viDA7zawC#<=M1$M`ae$Rg5s;RReV+JAm!5|G&8Zw
zq*87vxa%l%mr@7br99_VY|8enc##V7syUS^UMyau<^lsP^naq|!%Eu~<ah55r0hQl
zGWNRPq{r;qvZ&ogv@g;*OWb2p+0=Mx#33`ORE7%sgOOY?rg6O+jOR)z4i?fl1m@kg
zR8x&o0vHMnQJ5G@X^3Jm=!C_zg=yz=Q49N7AL_t<lhxYXV|;hNXuB&s1t40c3^Io$
zV}gk((y57wiJiHT!mYwB$X^W#w{{GN1KT(Q=MbH0&!`bGXojKWQd5#fgqebFJKtsw
z@|daAB!c%gNhGb~kt{9m4mcM?kH~V82uav!oGjRBvuvJw%ud|U0KBUbxgej*rSq7A
z4DF1ivzQ-7&6TeL1Kb}QrBmNXO%w(Mk(4O*zno_hi~X-)8fkiJzsVrJ{_DtizZuJo
z6#IV$5v7yj4tAogq^&MYX3faN#N;Fm2{VbNNCxjvD{a{s#4JzBBx~@4*TC5|@%2=3
zFpKrk^0C-FirT*i5~J3SsIuadPi1qdJ(P33rp^EvA(VjbaiQvzFWmo{WQO)Yv~qWa
z{z$5X5pe5XinB$3b1Io5F{;EUiE$;yk>7YOht2+ep<(s%`;gKirAcI!u$M7%JCxf&
z0+|HC&QZqlCEJ+#`tLS{Mn}nX7D=N?3{Z<+os#lsZGQ(rtISVrnH?orb=d(GfQ1?H
zOgr5~c`|CDX*Q-f_$AU-UBOIH)gW!FDri|2`#+M3x@PQ{{@PyOP}3}?{u?%XKg!<U
zn?q^jg78Yk!R_MU&Enu~kZ6JPWfr-&IC#n`${mUq2X}1xu1&k^*W7B(BNv*Hzi}-v
z(S9Xt<#Q?dpusbFM*mJgV%&-W-ooGj^U4ZC2%pOxc-Utpebe@|bZc;=I5<`u94`)D
zC=M2igVV*qnd0C=aj;w*TqzD-DGsg{2i4-BRva{ngEoGoIM^x<ZjCw#%K&IpuQMuo
zh&E466fau)^mUd_|8={hUPshYS0O&KTSiq=>1NML{OhUxd|_dB%yOi%dDe42n;XgR
z3G(Aur$}F{{H@E@bV!~EKbnra64KyyVQ?=J(!GgX+E0+38r#!vsHcP5`R{*z&wD>O
z_zxHNx|;zPl)FH`YxWEID$!lt#&cCp6^2Asit;+dW&3r5wP8cDE-VTNPl4enr40`!
z7krd>o;a?-UBM%X(XC99xHr0Q-G+S0cBHzkn*68fhvLMKoP(;MPd6BqZ9HQdh3@ON
z%w*KsBfAt4ml#r+I+LwuFWZ{4S7@YR(tK;a{IE`L2AGs!BuEFDARAy#gVA6t7!P&?
zJ2{fNE7%<rf?}{|Bs-N!W%->L$>PqlQ^2XoRF<!KDKz+N%ktjVqQ9rqf9i6d%itZQ
zzGn@Cv%*65b$KR})heOz7BPrl5aRxOjHaxETNYx?tKzRIWoy49uDioR!VOBgd_2Q=
z3}2+l`BQf)6$BrTNYKPE9?0Xs2ag<k@#2K6y$z>R6T+mXESQ+WsGF(DyaE+P9WvG9
zvY`1%EK#2L00&X17OEK>7}t`)!;>yl^U%TI;&IxzZ72;}q-KlM3N>4#X4!Pj<LFfx
z%ogXk+ZNX@v@NcU;|eBlT-f14gKrf>T=Kh9nKU<^w=6FX-11uYT%bIQtUr|*Ro(qQ
zzbt8`@&r)**D!QZ;=Wj93i-7T_o}Lo;(C=5zmvpvf-1ttesos;%f@u_@px^S2qh^T
z@FIocov91~0u2e$PaL?2GR~5nTsXCT*@3S((tS(1Uzn9&p0$?9xm5{w0>!f<xJSZ`
zK&cnw5&Um&1ZZ4Vdww|LpP?cd*F1B#UuJ$36FQZV#ms?HO0LlPZMi~5g$wcs*NZP}
zs322hGw}GVWS5JxIkKa1c9iURoF&{uX~_F92z>+5P9WM8NXG@zWaZ3#V_CBKIGZOs
z7H7v)S(SWLJE~70n?Tekup=(8gY3>YyA$>)4b7LgdcovItxvdcL3aQkBN@r(ORora
z;-cKcfw+}G+``48@?gB*lm1(UMdhs03~=*%=@BkS07ctNCBbg356|e<$KWaA0mmo+
z<5QmTK8$wxM2(QK?cPbYd&i;(IU+8(K=qEh)EFhd%W}%QzTxI)U6TS@1Tp}-^J-X@
zG>eS_5N1=xrnHh38XR%O1SocdhJxKO1A)Ua#~=X1F;<#1)mB8pHBWGH+_4G3cHE8_
zy0t@FvTYJMjbqVm(*z?gxFP}+v0!&ZCQw;$WC6$vt{BnFX@?g8f7;;*Y0fyj0QfTw
zPn>hX;RV27aCm~BWrr64zwGctL{}VM0Q?n)Cro<9;RV3I;_$>yR~=pe{8fi1psG5&
z0QjoI6J<%uk-Y%;n!^)%H5^_5e8b_1$J!1r0KV<;1Zh2o7XaULcp|qghZg|v#eIv2
z&fx{XOW~QHSfz%Od0RnkY#e3Y6#~1`x3`;jPoTcrs#YPJjI>l(bKSq=di7>;@TMy-
z0QZ}IMci?v?%Gn)a$D-IEA=+Pwkst-skeP8F{+cp<v?cS0RML5fFS@mU{WNel$)9)
zH%<cgdVm{^3@QAGuJ@tjv#_u%Krni-ZGoM%^gH%?Hy;@Lf(oXX5Mep>3!mwf+vi%%
z;kGyDbvaE&Y-HmKV_xEwrRj4gmpRm6&j~)`H}5}reQx>?HB9Uso`~{qGiV32pdzKH
zObJ%Lu6KfWA1c>$cB*uyyxKKp2QOQ4q9!bNL!R#Q-*e_>=XhFM4$LddwXl>p3{kQN
z*Gqn%u~cU#%pOzkmgX-kc1vrmj_2sI8_b5wZ`<Ad8TMq8`BJ@EI`J`{ZmQu!)3f?9
zyp3k&Z02C6a_H%~qeo|F!?owCM~*#vX!Xd^*}21Ohd;4;^b^m{K6mu+;lpc3j#Qs5
zbBda8nKk2yF7jF~qDmm#vHRh9LGvm8#TZ-HEjB1Q7{b2fGqql?-Tn2Mne}?Fwz)c8
zX>H6@A`$V1MRz7q8$qn%JAypIx#__CT7u?V@*DE((_fu?I`O_n6cYxN{FT7G#w$O1
zi)`n7gL439*)XglO%S7tO->xJeOeXUnY~ZMMx7s6+rGfO$7@B>x9x367eA;g6yA}3
zRN?o2=TU`&2iw^31RX@%ZSZVp>;?EA?&)plPta2h=z+pi`On#hun73OzGDfIJUA%<
zY$eb30n^pDZ=yX|!9x=N?h{CyMkhbGZ-y7XH2G<5pXcqt3C`9Sb0gs0He*KE{2$@e
zP|oj#XY2-P)}4Au>kLwA@mT8eu@Mg3k8r$xgk%0A9O@t8u>J@~^V2#mpVs>sX}utm
z)}i_lUJw}Ji2r*Jf7s*Eo7?(umnYzFgw#b(;zd12@_BnhC|0I_T+n^K^~2Zx&ID&K
zsN}c!BZ@WofAd6uYUg!bJIZfE`*wmRF5Pe@KbMvkmVST74=aE9**`gd@3TMsr_;x7
zT~{45HI4|+VEw8yvWfB1KZp$|H)_@7^5@tEXJ*2gHixF`m6;01m%{GMYMql+&GqiV
z3Wv-(?HOw&Ba1V`A+;HAUS|>~y)nkgnzx&&={BZq>GV9(Hc_WbzS9Wi%Aa2>{o&MG
zfBUJqfBi&Zv|t5o$NDj)OUYr!>3s=4V^&VIItz`)*>b&UHaKS62}64{&GWza%T)8A
z2;;i`&!+Ttq~4q~{p~|=mIpWV5MF$z`MXl$|L9=>qfaf3k2EivCH6C4W}od6sYTu%
zJx6|#>nYOud?)=c|K+qbnkEPJZ4COTO6hp=vp|Nov3aJ_p`N<k4b-0F8c%NY`M52$
z3{_8Ey3n<|$azR|?(>cG_w;O=KE->+57+dj<(Xx7-u)cmNfk0Mf5Y3X{0B<v+pv#_
zbnbybf%nvOZlFZ1dfub`MYXDjNDI7cTjFnt(*(<mzJxrqs~OR?_pb+E+Se4ntFZ+4
z1*D}@0UBH9fjYFSsmD{=pRe;)Ydp#s_BnMD;Bj=d*QB-+yiZT0!RLAVhJN$_PI9|R
zKjVGR6SSe7(rf01?a4JtpMlPcTekcwe6Iv=fK#u=uwYx)-fNvvC1w9;*-R&7GyQ;U
z3^M0Q!m#d_?WpvCFq+RpjA3^8XL#RuKm5`NJwogNC82mU|MNafBhLmu1U1^3VdQ!O
zs9GhlHnP%4*O~twJahDBPCNR1s<toZJzY{)sYp)BX}-;4bmsl!68GsCZ}tXgO7c`i
zJle<AZTMd_haW2Upmbx|9;E&X=MA1_Y)ARgn$WqA=NRJ=&PzNCZIzTLbJV=XpWebh
z%Jo@r&yhN8f7akSLaApNeH9LUj@db$N1LRzdM2zVyd_q-W-y-ZxIdcnpMQR42@o47
Q_&lbs+xhwD|D6Q>8;j+CRsaA1


From f17ba3ef54b2575eb8db112f76363f1a624b7b91 Mon Sep 17 00:00:00 2001
From: Zeke Foppa <bfops@users.noreply.github.com>
Date: Mon, 11 Nov 2024 18:05:27 -0800
Subject: [PATCH 55/55] empty commit to bump CI