Merge pull request 'flake-app' (#1) from flake-app into main

Reviewed-on: #1
This commit is contained in:
vinzenz 2025-09-29 18:57:37 +02:00
commit 74834f2052
18 changed files with 302 additions and 125 deletions

2
.gitignore vendored
View file

@ -4,4 +4,4 @@ obj
client
*.sarif
.direnv
out

7
.gitmodules vendored
View file

@ -1,3 +1,4 @@
[submodule "tanks-backend/servicepoint"]
path = tanks-backend/servicepoint
url = https://github.com/cccb/servicepoint.git
[submodule "tanks-backend/servicepoint-binding-csharp"]
path = tanks-backend/servicepoint-binding-csharp
url = https://git.berlin.ccc.de/servicepoint/servicepoint-binding-csharp.git
branch = main

View file

@ -2,7 +2,56 @@
<!-- TODO: image -->
### Backend
## Building and running
### With Nix
Using the power of nix, you can just `nix run git+https://git.berlin.ccc.de/vinzenz/servicepoint-tanks`!
To build from local source:
```bash
# no submodules required
git clone https://github.com/kaesaecracker/servicepoint-tanks.git
cd servicepoint-tanks
nix build .#
result/bin/TanksServer
```
You can also use the provided devShells (`nix develop .#`) and follow the manual steps.
For proper IDE suggestions, you may need to initialize the submodules. They are not used for building by Nix though.
### The hard way
```bash
# initialize the submodules
git clone https://github.com/kaesaecracker/servicepoint-tanks.git
cd servicepoint-tanks
git submodule update --init --recursive
# build
cd tank-frontent
npm install
npm run build
cd ../tanks-backend
dotnet build
```
The Docker builds are currently broken and need some updates for the new library repo structure.
<!-- TODO currently broken
# build with docker/podman - probably broken rifht
cd tanks-backend
docker build .
cd ../tank-frontend
docker build .
cd ..
docker build .
```
-->
## Backend
<!-- TODO: image -->
@ -18,7 +67,7 @@
- some values (like tank speed) can be configured but are fixed at run time
- By default, the backend also hosts the frontend
### Frontend
## Frontend
<!-- TODO: image -->
@ -28,9 +77,9 @@
- Sends user input to server
- real time communication via WebSockets, HTTP for the REST
### Binary formats
## Binary formats
#### Controls WebSocket
### Controls WebSocket
- Client sends 2 byte messages.
- on or off: `0x01` or `0x02`
@ -55,31 +104,3 @@
- 10: bullet
- 11: (reserved)
- client responds with empty message to request the next frame
# Building
```bash
# checkout repo and submodules
git clone https://github.com/kaesaecracker/servicepoint-tanks.git
cd servicepoint-tanks
git submodule update --init
cd tanks-backend/servicepoint
git submodule update --init
cd ../..
# build with nix-shell
nix-shell
cd tank-frontent
npm install
npm run build
cd ../tanks-backend
dotnet build
# build with docker/podman
cd tanks-backend
docker build .
cd ../tank-frontend
docker build .
cd ..
docker build .
```

43
flake.lock generated
View file

@ -1,5 +1,47 @@
{
"nodes": {
"binding": {
"inputs": {
"binding": "binding_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1759096792,
"narHash": "sha256-CW4D1yJecw7Id6AxIEJOW3OpcX3Y4Ehng76/YlR1I9w=",
"ref": "refs/heads/main",
"rev": "8df2996504866f3193fbe51860ab173d25724e5e",
"revCount": 307,
"type": "git",
"url": "https://git.berlin.ccc.de/servicepoint/servicepoint-binding-csharp.git"
},
"original": {
"type": "git",
"url": "https://git.berlin.ccc.de/servicepoint/servicepoint-binding-csharp.git"
}
},
"binding_2": {
"inputs": {
"nixpkgs": [
"binding",
"nixpkgs"
]
},
"locked": {
"lastModified": 1759093963,
"narHash": "sha256-nis9Xps/P1f/v9FC3LoMLGGCOMMbdrOniDSklqLsH8o=",
"ref": "refs/heads/main",
"rev": "44ef4bb6d707c46af1bed6244f17a16f26f246c1",
"revCount": 304,
"type": "git",
"url": "https://git.berlin.ccc.de/servicepoint/servicepoint-binding-uniffi.git"
},
"original": {
"type": "git",
"url": "https://git.berlin.ccc.de/servicepoint/servicepoint-binding-uniffi.git"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1758589230,
@ -18,6 +60,7 @@
},
"root": {
"inputs": {
"binding": "binding",
"nixpkgs": "nixpkgs"
}
}

View file

@ -1,31 +1,41 @@
{
description = "Dev shell flake for servicepoint-tanks";
description = "flake for servicepoint-tanks";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.05";
binding = {
url = "git+https://git.berlin.ccc.de/servicepoint/servicepoint-binding-csharp.git";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{ self, nixpkgs }:
{
self,
nixpkgs,
binding,
}:
let
supported-systems = [
"x86_64-linux"
"aarch64-linux"
];
forAllSystems =
f:
fn:
nixpkgs.lib.genAttrs supported-systems (
system:
f rec {
pkgs = nixpkgs.legacyPackages.${system};
lib = nixpkgs.lib;
fn {
inherit system;
inherit (nixpkgs) lib;
pkgs = nixpkgs.legacyPackages.${system};
selfPkgs = self.packages.${system};
bindingPkgs = binding.packages.${system};
}
);
in
{
devShells = forAllSystems (
apps = forAllSystems (
{
pkgs,
lib,
@ -33,30 +43,87 @@
...
}:
{
frontend = pkgs.mkShell {
default = {
type = "app";
program = "${lib.getBin selfPkgs.servicepoint-tanks}/bin/TanksServer";
};
}
);
devShells = forAllSystems (
{
pkgs,
lib,
selfPkgs,
...
}:
let
frontend-set = {
inputsFrom = [ selfPkgs.servicepoint-tanks-frontend ];
packages = with pkgs; [
typescript
nodejs
];
};
default = import ./shell.nix {
inherit pkgs lib;
backend-set = {
inputsFrom = [ selfPkgs.servicepoint-tanks ];
packages = with pkgs; [
nuget-to-json
cargo-tarpaulin
];
};
in
{
frontend = pkgs.mkShell frontend-set;
backend = pkgs.mkShell backend-set;
default = pkgs.mkShell (frontend-set // backend-set);
}
);
packages = forAllSystems (
{ pkgs, lib, ... }:
{
pkgs,
lib,
selfPkgs,
bindingPkgs,
...
}:
{
servicepoint-tanks-frontend = pkgs.buildNpmPackage (finalAttrs: {
pname = "tank-frontend";
pname = "servicepoint-tanks-frontend";
version = "0.0.0";
src = ./tank-frontend;
npmDepsHash = "sha256-HvwoSeKHBDkM/5OHDkgSOxfHx1gbnKif/3QfDb6r5mE=";
installPhase = ''
cp -rv dist/ $out
'';
});
servicepoint-tanks-assets = ./tanks-backend/TanksServer/assets;
servicepoint-tanks = pkgs.buildDotnetModule {
pname = "servicepoint-tanks";
version = "0.0.0";
dotnet-sdk = pkgs.dotnetCorePackages.sdk_8_0;
dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_0;
src = ./tanks-backend;
projectFile = "TanksServer/TanksServer.csproj";
nugetDeps = ./tanks-backend/deps.json;
selfContainedBuild = true;
buildInputs = [ bindingPkgs.servicepoint-binding-csharp ];
runtimeDeps = [ bindingPkgs.servicepoint-binding-uniffi ];
makeWrapperArgs = [
"--set-default TANKSSERVER_CLIENT ${selfPkgs.servicepoint-tanks-frontend}"
"--set-default TANKSSERVER_ASSETS ${selfPkgs.servicepoint-tanks-assets}"
];
};
}
);

View file

@ -1,35 +0,0 @@
{
pkgs ? import <nixpkgs> { },
...
}:
let
rust-toolchain = pkgs.symlinkJoin {
name = "rust-toolchain";
paths = with pkgs; [
rustc
cargo
rustPlatform.rustcSrc
rustfmt
clippy
];
};
in
pkgs.mkShell {
nativeBuildInputs = with pkgs.buildPackages; [
rust-toolchain
pkg-config
xe
xz
cargo-tarpaulin
gnumake
iconv
typescript
nodejs
dotnet-sdk_8
];
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
}

View file

@ -10,19 +10,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{12DB7D
..\.envrc = ..\.envrc
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "servicepoint", "servicepoint", "{A10FB29A-9078-4E90-9CE1-E6C2B5209E19}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "servicepoint-binding-csharp", "servicepoint-binding-csharp", "{919DCD05-B92D-48A6-BB1F-8ABD460BD788}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "crates", "crates", "{656A7CBA-9445-41CC-B1AF-A6897AAC9F17}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint", "servicepoint-binding-csharp\ServicePoint\ServicePoint.csproj", "{3C856AD4-DBC6-419D-8373-9D99A2E2AA04}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "servicepoint_binding_uniffi", "servicepoint_binding_uniffi", "{5FD9FAD7-07BA-4DF9-8C84-15A9558373F1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libraries", "libraries", "{6082A0DC-5345-48C8-BA2E-667754A2F0E9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "csharp", "csharp", "{D8A3290B-5DFB-43C6-99EE-56AB5F53F468}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint", "servicepoint\crates\servicepoint_binding_uniffi\libraries\csharp\ServicePoint\ServicePoint.csproj", "{D1DDCD0D-6152-45E6-B673-DD78C466BDC3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint.Tests", "servicepoint\crates\servicepoint_binding_uniffi\libraries\csharp\ServicePoint.Tests\ServicePoint.Tests.csproj", "{EF42D6B7-70B1-490B-BB5F-5A44D1309A7C}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServicePoint.Tests", "servicepoint-binding-csharp\ServicePoint.Tests\ServicePoint.Tests.csproj", "{D0B09E1D-B20F-4883-8D32-5E5420224CC3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -34,21 +26,17 @@ Global
{D88BF376-47A4-4C72-ADD1-983F9285C351}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D88BF376-47A4-4C72-ADD1-983F9285C351}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D88BF376-47A4-4C72-ADD1-983F9285C351}.Release|Any CPU.Build.0 = Release|Any CPU
{D1DDCD0D-6152-45E6-B673-DD78C466BDC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1DDCD0D-6152-45E6-B673-DD78C466BDC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1DDCD0D-6152-45E6-B673-DD78C466BDC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1DDCD0D-6152-45E6-B673-DD78C466BDC3}.Release|Any CPU.Build.0 = Release|Any CPU
{EF42D6B7-70B1-490B-BB5F-5A44D1309A7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF42D6B7-70B1-490B-BB5F-5A44D1309A7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF42D6B7-70B1-490B-BB5F-5A44D1309A7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF42D6B7-70B1-490B-BB5F-5A44D1309A7C}.Release|Any CPU.Build.0 = Release|Any CPU
{3C856AD4-DBC6-419D-8373-9D99A2E2AA04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C856AD4-DBC6-419D-8373-9D99A2E2AA04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C856AD4-DBC6-419D-8373-9D99A2E2AA04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C856AD4-DBC6-419D-8373-9D99A2E2AA04}.Release|Any CPU.Build.0 = Release|Any CPU
{D0B09E1D-B20F-4883-8D32-5E5420224CC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D0B09E1D-B20F-4883-8D32-5E5420224CC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D0B09E1D-B20F-4883-8D32-5E5420224CC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D0B09E1D-B20F-4883-8D32-5E5420224CC3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{656A7CBA-9445-41CC-B1AF-A6897AAC9F17} = {A10FB29A-9078-4E90-9CE1-E6C2B5209E19}
{5FD9FAD7-07BA-4DF9-8C84-15A9558373F1} = {656A7CBA-9445-41CC-B1AF-A6897AAC9F17}
{6082A0DC-5345-48C8-BA2E-667754A2F0E9} = {5FD9FAD7-07BA-4DF9-8C84-15A9558373F1}
{D8A3290B-5DFB-43C6-99EE-56AB5F53F468} = {6082A0DC-5345-48C8-BA2E-667754A2F0E9}
{D1DDCD0D-6152-45E6-B673-DD78C466BDC3} = {D8A3290B-5DFB-43C6-99EE-56AB5F53F468}
{EF42D6B7-70B1-490B-BB5F-5A44D1309A7C} = {D8A3290B-5DFB-43C6-99EE-56AB5F53F468}
{3C856AD4-DBC6-419D-8373-9D99A2E2AA04} = {919DCD05-B92D-48A6-BB1F-8ABD460BD788}
{D0B09E1D-B20F-4883-8D32-5E5420224CC3} = {919DCD05-B92D-48A6-BB1F-8ABD460BD788}
EndGlobalSection
EndGlobal

View file

@ -4,7 +4,7 @@ namespace TanksServer.GameLogic;
internal sealed class CollideBullets : ITickStep
{
private readonly Sprite _explosiveSprite = Sprite.FromImageFile("assets/explosion.png");
private readonly Sprite _explosiveSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "explosion.png"));
private readonly Predicate<Bullet> _removeBulletsPredicate;
private readonly MapEntityManager _entityManager;
private readonly MapService _map;

View file

@ -22,9 +22,10 @@ internal sealed class MapService
public MapService()
{
foreach (var file in Directory.EnumerateFiles("./assets/maps/", "*.txt"))
var dir = Path.Combine(Program.AssetsDir, "maps");
foreach (var file in Directory.EnumerateFiles(dir, "*.txt"))
LoadMapString(file);
foreach (var file in Directory.EnumerateFiles("./assets/maps/", "*.png"))
foreach (var file in Directory.EnumerateFiles(dir, "*.png"))
LoadMapPng(file);
Current = GetRandomMap();
}

View file

@ -1,6 +1,7 @@
global using System;
global using System.Collections.Concurrent;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Threading;
global using System.Threading.Tasks;

View file

@ -4,11 +4,11 @@ namespace TanksServer.Graphics;
internal sealed class DrawPowerUpsStep(MapEntityManager entityManager) : IDrawStep
{
private readonly Sprite _genericSprite = Sprite.FromImageFile("assets/powerup_generic.png");
private readonly Sprite _smartSprite = Sprite.FromImageFile("assets/powerup_smart.png");
private readonly Sprite _magazineSprite = Sprite.FromImageFile("assets/powerup_magazine.png");
private readonly Sprite _explosiveSprite = Sprite.FromImageFile("assets/powerup_explosive.png");
private readonly Sprite _fastSprite = Sprite.FromImageFile("assets/powerup_fastbullet.png");
private readonly Sprite _genericSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_generic.png"));
private readonly Sprite _smartSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_smart.png"));
private readonly Sprite _magazineSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_magazine.png"));
private readonly Sprite _explosiveSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_explosive.png"));
private readonly Sprite _fastSprite = Sprite.FromImageFile(Path.Combine(Program.AssetsDir, "powerup_fastbullet.png"));
public void Draw(GamePixelGrid pixels)
{

View file

@ -5,7 +5,7 @@ namespace TanksServer.Graphics;
internal sealed class DrawTanksStep(MapEntityManager entityManager) : IDrawStep
{
private readonly SpriteSheet _tankSprites =
SpriteSheet.FromImageFile("assets/tank.png", (int)MapService.TileSize, (int)MapService.TileSize);
SpriteSheet.FromImageFile(Path.Combine(Program.AssetsDir, "tank.png"), (int)MapService.TileSize, (int)MapService.TileSize);
public void Draw(GamePixelGrid pixels)
{

View file

@ -11,22 +11,44 @@ namespace TanksServer;
public static class Program
{
internal static string AssetsDir = (Environment.GetEnvironmentVariable("TANKSSERVER_ASSETS") ?? "./assets") + "/";
[RequiresUnreferencedCode("Calls Endpoints.Map")]
[RequiresDynamicCode("Calls Endpoints.Map")]
public static async Task Main(string[] args)
{
var app = Configure(args);
var clientFileProvider = new PhysicalFileProvider(Path.Combine(app.Environment.ContentRootPath, "client"));
app.Logger.LogInformation("Running in {}", app.Environment.ContentRootPath);
app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = clientFileProvider });
app.UseStaticFiles(new StaticFileOptions { FileProvider = clientFileProvider });
AddStaticClientHost(app);
app.Services.GetRequiredService<Endpoints>().Map(app);
await app.RunAsync();
}
private static void AddStaticClientHost(WebApplication app)
{
var clientDir = Environment.GetEnvironmentVariable("TANKSSERVER_CLIENT");
bool required = clientDir != null;
clientDir ??= Path.Combine(app.Environment.ContentRootPath, "client");
bool available = Directory.Exists(clientDir);
if (!available)
{
if (required)
throw new InvalidOperationException($"The environment variable TANKSSERVER_CLIENT is set, but the specified directory {clientDir} does not exist.");
app.Logger.LogError("Not providing static file host for client because {} does not exist", clientDir);
return;
}
var clientFileProvider = new PhysicalFileProvider(clientDir);
app.UseDefaultFiles(new DefaultFilesOptions { FileProvider = clientFileProvider });
app.UseStaticFiles(new StaticFileOptions { FileProvider = clientFileProvider });
}
[RequiresUnreferencedCode("Calls Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<TOptions>(IConfiguration)")]
[RequiresDynamicCode("Calls Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<TOptions>(IConfiguration)")]
private static WebApplication Configure(string[] args)

View file

@ -7,7 +7,7 @@
</PropertyGroup>
<PropertyGroup>
<PublishAot>true</PublishAot>
<!--<PublishAot>true</PublishAot>-->
<IsAotCompatible>true</IsAotCompatible>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
@ -26,11 +26,12 @@
</ItemGroup>
<ItemGroup>
<None Include="./assets/**" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always"/>
<None Include="./assets/**" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" Condition="'$(ContinuousIntegrationBuild)'!='true'" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\servicepoint\crates\servicepoint_binding_uniffi\libraries\csharp\ServicePoint\ServicePoint.csproj" />
<ProjectReference Include="..\servicepoint-binding-uniffi\SericePoint\ServicePoint.csproj" Condition="'$(ContinuousIntegrationBuild)'!='true'" />
<PackageReference Include="ServicePoint" Version="*" Condition="'$(ContinuousIntegrationBuild)'=='true'"/>
</ItemGroup>
</Project>

57
tanks-backend/deps.json Normal file
View file

@ -0,0 +1,57 @@
[
{
"pname": "DotNext",
"version": "5.3.0",
"hash": "sha256-q+VOteFEYhqkndjZq08ZGNlbR/SIqj/mwkAythFCo+c="
},
{
"pname": "DotNext.Threading",
"version": "5.3.0",
"hash": "sha256-P8ITHieqi7fZSKJsyQNm0iusf9J1c+dmeiXLFrtr+d8="
},
{
"pname": "Microsoft.Extensions.Configuration.Abstractions",
"version": "8.0.0",
"hash": "sha256-4eBpDkf7MJozTZnOwQvwcfgRKQGcNXe0K/kF+h5Rl8o="
},
{
"pname": "Microsoft.Extensions.Configuration.Binder",
"version": "8.0.0",
"hash": "sha256-GanfInGzzoN2bKeNwON8/Hnamr6l7RTpYLA49CNXD9Q="
},
{
"pname": "Microsoft.Extensions.DependencyInjection.Abstractions",
"version": "8.0.0",
"hash": "sha256-75KzEGWjbRELczJpCiJub+ltNUMMbz5A/1KQU+5dgP8="
},
{
"pname": "Microsoft.Extensions.Options",
"version": "8.0.0",
"hash": "sha256-n2m4JSegQKUTlOsKLZUUHHKMq926eJ0w9N9G+I3FoFw="
},
{
"pname": "Microsoft.Extensions.Options.ConfigurationExtensions",
"version": "8.0.0",
"hash": "sha256-A5Bbzw1kiNkgirk5x8kyxwg9lLTcSngojeD+ocpG1RI="
},
{
"pname": "Microsoft.Extensions.Primitives",
"version": "8.0.0",
"hash": "sha256-FU8qj3DR8bDdc1c+WeGZx/PCZeqqndweZM9epcpXjSo="
},
{
"pname": "SixLabors.ImageSharp",
"version": "3.1.5",
"hash": "sha256-3UehX9T+I81nfgv2dTHlpoPgYzXFk7kHr1mmlQOCBfw="
},
{
"pname": "System.IO.Hashing",
"version": "8.0.0",
"hash": "sha256-szOGt0TNBo6dEdC3gf6H+e9YW3Nw0woa6UnCGGGK5cE="
},
{
"pname": "System.Threading.Channels",
"version": "8.0.0",
"hash": "sha256-c5TYoLNXDLroLIPnlfyMHk7nZ70QAckc/c7V199YChg="
}
]

10
tanks-backend/gen-deps.sh Executable file
View file

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -euxo pipefail
# first time
# dotnet restore --packages out
# nuget-to-json out > deps.json
# update
nix build .#servicepoint-tanks-backend.fetch-deps
./result deps.json

@ -1 +0,0 @@
Subproject commit 93657c9f85d021c04270e1f5af573a6cda51f18a

@ -0,0 +1 @@
Subproject commit dcf8d12a8a23286aa1054e45f15f9757ec9cfcb6