Add day 3
This commit is contained in:
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
bin/
|
||||
obj/
|
||||
riderModule.iml
|
||||
_ReSharper.Caches/
|
||||
.idea/
|
||||
*.user
|
||||
*.DotSettings
|
||||
.DS_Store
|
||||
result
|
||||
.profile*
|
||||
|
||||
inputs/
|
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Arr2D.fs" />
|
||||
<Compile Include="Day3.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
102
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Arr2D.fs
Normal file
102
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Arr2D.fs
Normal file
@@ -0,0 +1,102 @@
|
||||
namespace AdventOfCode2023
|
||||
|
||||
#if DEBUG
|
||||
#else
|
||||
#nowarn "9"
|
||||
#endif
|
||||
|
||||
open Microsoft.FSharp.NativeInterop
|
||||
|
||||
[<Struct>]
|
||||
#if DEBUG
|
||||
type Arr2D<'a> =
|
||||
{
|
||||
Elements : 'a array
|
||||
Width : int
|
||||
}
|
||||
|
||||
member this.Height = this.Elements.Length / this.Width
|
||||
#else
|
||||
type Arr2D<'a when 'a : unmanaged> =
|
||||
{
|
||||
Elements : nativeptr<'a>
|
||||
Length : int
|
||||
Width : int
|
||||
}
|
||||
|
||||
member this.Height = this.Length / this.Width
|
||||
#endif
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Arr2D =
|
||||
|
||||
/// It's faster to iterate forward over the first argument, `x`.
|
||||
let inline get (arr : Arr2D<'a>) (x : int) (y : int) : 'a =
|
||||
#if DEBUG
|
||||
arr.Elements.[y * arr.Width + x]
|
||||
#else
|
||||
NativePtr.get arr.Elements (y * arr.Width + x)
|
||||
#endif
|
||||
|
||||
let inline set (arr : Arr2D<'a>) (x : int) (y : int) (newVal : 'a) : unit =
|
||||
#if DEBUG
|
||||
arr.Elements.[y * arr.Width + x] <- newVal
|
||||
#else
|
||||
NativePtr.write (NativePtr.add arr.Elements (y * arr.Width + x)) newVal
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
let create (width : int) (height : int) (value : 'a) : Arr2D<'a> =
|
||||
let arr = Array.create (width * height) value
|
||||
|
||||
{
|
||||
Width = width
|
||||
Elements = arr
|
||||
}
|
||||
#else
|
||||
/// The input array must be at least of size width * height
|
||||
let create (arr : nativeptr<'a>) (width : int) (height : int) (value : 'a) : Arr2D<'a> =
|
||||
{
|
||||
Width = width
|
||||
Elements = arr
|
||||
Length = width * height
|
||||
}
|
||||
#endif
|
||||
|
||||
[<RequiresExplicitTypeArguments>]
|
||||
#if DEBUG
|
||||
let zeroCreate<'a when 'a : unmanaged> (width : int) (height : int) : Arr2D<'a> =
|
||||
{
|
||||
Elements = Array.zeroCreate (width * height)
|
||||
Width = width
|
||||
}
|
||||
#else
|
||||
let zeroCreate<'a when 'a : unmanaged> (elts : nativeptr<'a>) (width : int) (height : int) : Arr2D<'a> =
|
||||
{
|
||||
Elements = elts
|
||||
Width = width
|
||||
Length = width * height
|
||||
}
|
||||
#endif
|
||||
|
||||
/// The closure is given x and then y.
|
||||
#if DEBUG
|
||||
let inline init (width : int) (height : int) (f : int -> int -> 'a) : Arr2D<'a> =
|
||||
let result = zeroCreate<'a> width height
|
||||
#else
|
||||
let inline init (arr : nativeptr<'a>) (width : int) (height : int) (f : int -> int -> 'a) : Arr2D<'a> =
|
||||
let result = zeroCreate<'a> arr width height
|
||||
#endif
|
||||
|
||||
for y = 0 to height - 1 do
|
||||
for x = 0 to width - 1 do
|
||||
set result x y (f x y)
|
||||
|
||||
result
|
||||
|
||||
let inline clear (a : Arr2D<'a>) : unit =
|
||||
#if DEBUG
|
||||
System.Array.Clear a.Elements
|
||||
#else
|
||||
NativePtr.initBlock a.Elements 0uy (uint32 sizeof<'a> * uint32 a.Length)
|
||||
#endif
|
133
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day3.fs
Normal file
133
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.Lib/Day3.fs
Normal file
@@ -0,0 +1,133 @@
|
||||
namespace AdventOfCode2023
|
||||
|
||||
open System.Collections.Generic
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Day3 =
|
||||
let inline private isSymbol (i : byte) =
|
||||
i > 200uy
|
||||
|
||||
let inline private isGear (i : byte) =
|
||||
i = 255uy
|
||||
|
||||
/// Returns the parsed board as a buffer, the length of the buffer (there may be garbage at the end), and
|
||||
/// the number of lines the resulting 2D array has.
|
||||
let parse (fileContents : byte[]) =
|
||||
let mutable lineCount = 0
|
||||
let mutable len = 0
|
||||
let resultArr = Array.zeroCreate fileContents.Length
|
||||
for b in fileContents do
|
||||
if b = byte '.' then
|
||||
resultArr.[len] <- 100uy
|
||||
len <- len + 1
|
||||
elif b = byte '*' then
|
||||
resultArr.[len] <- 255uy
|
||||
len <- len + 1
|
||||
elif byte '0' <= b && b <= byte '9' then
|
||||
resultArr.[len] <- b - byte '0'
|
||||
len <- len + 1
|
||||
elif b = 10uy then
|
||||
lineCount <- lineCount + 1
|
||||
else
|
||||
resultArr.[len] <- 254uy
|
||||
len <- len + 1
|
||||
|
||||
resultArr, len, lineCount
|
||||
|
||||
let part1 (contents : Arr2D<byte>) =
|
||||
let lineLength = contents.Width
|
||||
|
||||
let isNearSymbol (row : int) (numStart : int) (curCol : int) : bool =
|
||||
let mutable isNearSymbol = false
|
||||
if row > 0 then
|
||||
for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do
|
||||
if isSymbol (Arr2D.get contents col (row - 1)) then
|
||||
isNearSymbol <- true
|
||||
if row < contents.Height - 1 then
|
||||
for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do
|
||||
if isSymbol (Arr2D.get contents col (row + 1)) then
|
||||
isNearSymbol <- true
|
||||
if (numStart > 0 && isSymbol (Arr2D.get contents (numStart - 1) row)) || (curCol < lineLength && isSymbol (Arr2D.get contents curCol row)) then
|
||||
isNearSymbol <- true
|
||||
isNearSymbol
|
||||
|
||||
let mutable total = 0
|
||||
for row = 0 to contents.Height - 1 do
|
||||
let mutable currNum = 0
|
||||
let mutable numStart = -1
|
||||
for col = 0 to lineLength - 1 do
|
||||
if Arr2D.get contents col row < 10uy then
|
||||
if numStart = -1 then
|
||||
numStart <- col
|
||||
currNum <- currNum * 10 + int (Arr2D.get contents col row)
|
||||
elif numStart > -1 then
|
||||
if isNearSymbol row numStart col then
|
||||
total <- total + currNum
|
||||
currNum <- 0
|
||||
numStart <- -1
|
||||
|
||||
if numStart >= 0 then
|
||||
if isNearSymbol row numStart lineLength then
|
||||
total <- total + currNum
|
||||
currNum <- 0
|
||||
numStart <- -1
|
||||
|
||||
total
|
||||
|
||||
let part2 (contents : Arr2D<byte>) =
|
||||
let lineLength = contents.Width
|
||||
|
||||
let isNearGear (row : int) (numStart : int) (curCol : int) : (int * int) IReadOnlyList =
|
||||
let gearsNear = ResizeArray ()
|
||||
if row > 0 then
|
||||
for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do
|
||||
if isGear (Arr2D.get contents col (row - 1)) then
|
||||
gearsNear.Add (row - 1, col)
|
||||
if row < lineLength - 1 then
|
||||
for col = max (numStart - 1) 0 to min curCol (lineLength - 1) do
|
||||
if isGear (Arr2D.get contents col (row + 1)) then
|
||||
gearsNear.Add (row + 1, col)
|
||||
if (numStart > 0 && isGear (Arr2D.get contents (numStart - 1) row)) then
|
||||
gearsNear.Add (row, numStart - 1)
|
||||
if (curCol < lineLength && isGear (Arr2D.get contents curCol row)) then
|
||||
gearsNear.Add (row, curCol)
|
||||
gearsNear
|
||||
|
||||
let gears = Dictionary<int * int, ResizeArray<int>> ()
|
||||
let addGear (gearPos : int * int) (num : int) =
|
||||
match gears.TryGetValue gearPos with
|
||||
| false, _ ->
|
||||
let arr = ResizeArray ()
|
||||
arr.Add num
|
||||
gears.Add (gearPos, arr)
|
||||
| true, arr when arr.Count < 3 ->
|
||||
arr.Add num
|
||||
| _ -> ()
|
||||
|
||||
for row = 0 to contents.Height - 1 do
|
||||
let mutable currNum = 0
|
||||
let mutable numStart = -1
|
||||
for col = 0 to lineLength - 1 do
|
||||
if Arr2D.get contents col row < 10uy then
|
||||
if numStart = -1 then
|
||||
numStart <- col
|
||||
currNum <- currNum * 10 + int (Arr2D.get contents col row)
|
||||
elif numStart > -1 then
|
||||
for gearPos in isNearGear row numStart col do
|
||||
addGear gearPos currNum
|
||||
currNum <- 0
|
||||
numStart <- -1
|
||||
|
||||
if numStart >= 0 then
|
||||
for gearPos in isNearGear row numStart lineLength do
|
||||
addGear gearPos currNum
|
||||
currNum <- 0
|
||||
numStart <- -1
|
||||
|
||||
let mutable answer = 0
|
||||
for KeyValue(_gearPos, gears) in gears do
|
||||
if gears.Count = 2 then
|
||||
answer <- answer + gears.[0] * gears.[1]
|
||||
|
||||
answer
|
||||
|
28
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.sln
Normal file
28
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp.sln
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "AdventOfCode2023.FSharp", "AdventOfCode2023.FSharp\AdventOfCode2023.FSharp.fsproj", "{E2EC7715-E2C9-4671-AFBD-84D740B604FE}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Test", "Test\Test.fsproj", "{AC9C7858-2F5D-4DE1-8E13-0A87E1EA8598}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "AdventOfCode2023.FSharp.Lib", "AdventOfCode2023.FSharp.Lib\AdventOfCode2023.FSharp.Lib.fsproj", "{95CE0568-3D1A-4060-BB54-52460FB1E399}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E2EC7715-E2C9-4671-AFBD-84D740B604FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E2EC7715-E2C9-4671-AFBD-84D740B604FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E2EC7715-E2C9-4671-AFBD-84D740B604FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E2EC7715-E2C9-4671-AFBD-84D740B604FE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AC9C7858-2F5D-4DE1-8E13-0A87E1EA8598}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AC9C7858-2F5D-4DE1-8E13-0A87E1EA8598}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AC9C7858-2F5D-4DE1-8E13-0A87E1EA8598}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AC9C7858-2F5D-4DE1-8E13-0A87E1EA8598}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{95CE0568-3D1A-4060-BB54-52460FB1E399}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{95CE0568-3D1A-4060-BB54-52460FB1E399}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{95CE0568-3D1A-4060-BB54-52460FB1E399}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{95CE0568-3D1A-4060-BB54-52460FB1E399}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@@ -0,0 +1,28 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<PublishAot>true</PublishAot>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<UseSystemResourceKeys>true</UseSystemResourceKeys>
|
||||
|
||||
<IlcOptimizationPreference>Speed</IlcOptimizationPreference>
|
||||
<IlcGenerateStackTraceData>false</IlcGenerateStackTraceData>
|
||||
|
||||
<DebuggerSupport>false</DebuggerSupport>
|
||||
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
|
||||
<EventSourceSupport>false</EventSourceSupport>
|
||||
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
|
||||
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AdventOfCode2023.FSharp.Lib\AdventOfCode2023.FSharp.Lib.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
65
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs
Normal file
65
AdventOfCode2023.FSharp/AdventOfCode2023.FSharp/Program.fs
Normal file
@@ -0,0 +1,65 @@
|
||||
namespace AdventOfCode2023
|
||||
|
||||
#if DEBUG
|
||||
#else
|
||||
#nowarn "9"
|
||||
#endif
|
||||
|
||||
open System.Diagnostics
|
||||
open System.IO
|
||||
|
||||
module Program =
|
||||
|
||||
let inline toUs (ticks : int64) =
|
||||
1_000_000.0 * float ticks / float Stopwatch.Frequency
|
||||
|
||||
[<EntryPoint>]
|
||||
let main argv =
|
||||
let endToEnd = Stopwatch.StartNew ()
|
||||
endToEnd.Restart ()
|
||||
|
||||
let sw = Stopwatch.StartNew ()
|
||||
sw.Restart ()
|
||||
let contents = File.ReadAllBytes argv.[0]
|
||||
sw.Stop ()
|
||||
System.Console.Error.WriteLine ("Reading file (us): " + (toUs sw.ElapsedTicks).ToString ())
|
||||
|
||||
sw.Restart ()
|
||||
let resultArr, len, lineCount = Day3.parse contents
|
||||
|
||||
sw.Stop ()
|
||||
System.Console.Error.WriteLine ("Populating array (us): " + (toUs sw.ElapsedTicks).ToString ())
|
||||
|
||||
#if DEBUG
|
||||
let contents =
|
||||
{
|
||||
Elements = Array.take len resultArr
|
||||
Width = len / lineCount
|
||||
}
|
||||
#else
|
||||
use ptr = fixed resultArr
|
||||
let contents =
|
||||
{
|
||||
Elements = ptr
|
||||
Length = len
|
||||
Width = len / lineCount
|
||||
}
|
||||
#endif
|
||||
// |> Array.map (fun s -> Array.init s.Length (fun i -> if s.[i] = '.' then 100uy elif s.[i] = '*' then 255uy elif '0' <= s.[i] && s.[i] <= '9' then byte s.[i] - byte '0' else 254uy))
|
||||
|
||||
sw.Restart ()
|
||||
let part1 = Day3.part1 contents
|
||||
sw.Stop ()
|
||||
System.Console.Error.WriteLine ("Part 1 (us): " + (toUs sw.ElapsedTicks).ToString ())
|
||||
System.Console.WriteLine (part1.ToString ())
|
||||
|
||||
sw.Restart ()
|
||||
let part2 = Day3.part2 contents
|
||||
sw.Stop ()
|
||||
System.Console.Error.WriteLine ("Part 2 (us): " + (toUs sw.ElapsedTicks).ToString ())
|
||||
System.Console.WriteLine (part2.ToString ())
|
||||
|
||||
endToEnd.Stop ()
|
||||
System.Console.Error.WriteLine ("Total (us): " + (toUs endToEnd.ElapsedTicks).ToString ())
|
||||
|
||||
0
|
23
AdventOfCode2023.FSharp/Test/Test.fsproj
Normal file
23
AdventOfCode2023.FSharp/Test/Test.fsproj
Normal file
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<RootNamespace>TestProject1</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="TestDay3.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
|
||||
<PackageReference Include="NUnit" Version="3.13.3"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.6.1"/>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
18
AdventOfCode2023.FSharp/Test/TestDay3.fs
Normal file
18
AdventOfCode2023.FSharp/Test/TestDay3.fs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Test
|
||||
|
||||
open NUnit.Framework
|
||||
|
||||
[<TestFixture>]
|
||||
module TestDay3 =
|
||||
|
||||
[<Test>]
|
||||
let day1Sample () =
|
||||
()
|
||||
|
||||
[<Test>]
|
||||
let day1Actual () =
|
||||
540131
|
||||
|
||||
[<Test>]
|
||||
let day2Actual () =
|
||||
86879020
|
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1701253981,
|
||||
"narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
26
flake.nix
Normal file
26
flake.nix
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
description = "Advent of Code 2023";
|
||||
inputs = {
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
}: flake-utils.lib.eachDefaultSystem (system:
|
||||
let pkgs = nixpkgs.legacyPackages.${system}; in
|
||||
{
|
||||
devShells = { default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
(with dotnetCorePackages;
|
||||
combinePackages [
|
||||
dotnet-sdk_8
|
||||
dotnetPackages.Nuget
|
||||
])
|
||||
] ++ [pkgs.swift darwin.apple_sdk.frameworks.Foundation darwin.apple_sdk.frameworks.CryptoKit darwin.apple_sdk.frameworks.GSS pkgs.zlib pkgs.zlib.dev pkgs.openssl pkgs.icu];
|
||||
};};
|
||||
}
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user