implement level1 and level2
This commit is contained in:
parent
f7f3a2b2a0
commit
377ef9afe8
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
**/bin
|
||||
**/obj
|
||||
.gitea/conventional_commits/tmp/*
|
14
Common/Common.csproj
Normal file
14
Common/Common.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LevelInputProvider" Version="*" />
|
||||
<PackageReference Include="TextParser" Version="*" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
37
Common/LevelSolverBase.cs
Normal file
37
Common/LevelSolverBase.cs
Normal file
@ -0,0 +1,37 @@
|
||||
namespace AoC24.Common;
|
||||
|
||||
using AoCLevelInputProvider;
|
||||
using Parsing;
|
||||
using Parsing.Schema;
|
||||
using Parsing.Tokenization;
|
||||
|
||||
public abstract class LevelSolverBase
|
||||
{
|
||||
public abstract int LevelNumber { get; }
|
||||
private int Year = 2024;
|
||||
private LevelInputProvider inputProvider = new LevelInputProvider();
|
||||
|
||||
protected string GetLevelInput()
|
||||
{
|
||||
return inputProvider.WithYear(this.Year).WithLevel(this.LevelNumber).Provide();
|
||||
}
|
||||
|
||||
public abstract string SolveFirstStar();
|
||||
|
||||
public abstract string SolveSecondStar();
|
||||
|
||||
protected abstract InputSchemaBuilder DefineInputSchema(InputSchemaBuilder schemaBuilder);
|
||||
|
||||
public TokenConverter GetData()
|
||||
{
|
||||
var schemaBuilder = new InputSchemaBuilder();
|
||||
var schema = this.DefineInputSchema(schemaBuilder).Build();
|
||||
|
||||
var parser = new TextParser(schema);
|
||||
var data = parser
|
||||
.SetInputText(this.GetLevelInput())
|
||||
.Parse();
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
3096
Common/msbuild.log
Normal file
3096
Common/msbuild.log
Normal file
File diff suppressed because one or more lines are too long
14
Level1/Level1.csproj
Normal file
14
Level1/Level1.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Common/Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
74
Level1/Level1Solver.cs
Normal file
74
Level1/Level1Solver.cs
Normal file
@ -0,0 +1,74 @@
|
||||
namespace AoC24;
|
||||
|
||||
using AoC24.Common;
|
||||
using AoCLevelInputProvider;
|
||||
using Parsing;
|
||||
using Parsing.Schema;
|
||||
|
||||
public class Level1Solver : LevelSolverBase
|
||||
{
|
||||
public override int LevelNumber
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
protected override InputSchemaBuilder DefineInputSchema(InputSchemaBuilder schemaBuilder)
|
||||
{
|
||||
return schemaBuilder
|
||||
.Repeat(2)
|
||||
.Expect(InputType.Integer)
|
||||
.EndRepetition();
|
||||
}
|
||||
|
||||
public override string SolveFirstStar()
|
||||
{
|
||||
var data = this.GetData()
|
||||
.AsListColumns<int>();
|
||||
|
||||
var sortedLeftColumn = data[0];
|
||||
sortedLeftColumn.Sort();
|
||||
var sortedRightColumn = data[1];
|
||||
sortedRightColumn.Sort();
|
||||
|
||||
var sumDifferences = 0;
|
||||
|
||||
for (var i = 0; i < sortedLeftColumn.Count; i++)
|
||||
{
|
||||
sumDifferences += Math.Abs(sortedLeftColumn[i]-sortedRightColumn[i]);
|
||||
}
|
||||
|
||||
return sumDifferences.ToString();
|
||||
}
|
||||
|
||||
public override string SolveSecondStar()
|
||||
{
|
||||
var data = this.GetData()
|
||||
.AsListColumns<int>();
|
||||
|
||||
var uniqueLeftColumn = data[0].Distinct();
|
||||
var rightColumn = data[1];
|
||||
|
||||
Dictionary<int, int> numInstances = new Dictionary<int, int>();
|
||||
foreach(var value in uniqueLeftColumn)
|
||||
{
|
||||
numInstances[value] = 0;
|
||||
}
|
||||
|
||||
foreach(var value in rightColumn)
|
||||
{
|
||||
if (numInstances.ContainsKey(value))
|
||||
{
|
||||
numInstances[value] = numInstances[value] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
var sumScore = 0;
|
||||
|
||||
foreach(var key in numInstances.Keys)
|
||||
{
|
||||
sumScore = sumScore + numInstances[key] * key;
|
||||
}
|
||||
|
||||
return sumScore.ToString();
|
||||
}
|
||||
}
|
24
Level1/Program.cs
Normal file
24
Level1/Program.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
|
||||
using AoC24;
|
||||
|
||||
var levelSolver = new Level1Solver();
|
||||
var solution1 = levelSolver.SolveFirstStar();
|
||||
var solution2 = levelSolver.SolveSecondStar();
|
||||
|
||||
if (!string.IsNullOrEmpty(solution1))
|
||||
{
|
||||
Console.WriteLine("Solution for example 1 is: " + solution1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Example 1 has not been solved yet!");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(solution2))
|
||||
{
|
||||
Console.WriteLine("Solution for example 2 is: " + solution2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Example 2 has not been solved yet!");
|
||||
}
|
212
Level2/DataStreamConstraintVerifier.cs
Normal file
212
Level2/DataStreamConstraintVerifier.cs
Normal file
@ -0,0 +1,212 @@
|
||||
namespace AoC24;
|
||||
|
||||
using AoC24.Common;
|
||||
using AoCLevelInputProvider;
|
||||
using Parsing;
|
||||
using Parsing.Schema;
|
||||
|
||||
public class DataStreamConstraintVerifier<T>
|
||||
{
|
||||
public interface IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(T leftValue, T rightValue);
|
||||
}
|
||||
|
||||
private class DefaultTrendChecker : IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(T leftValue, T rightValue)
|
||||
{
|
||||
return string.Compare(leftValue?.ToString(), rightValue?.ToString()) < 0 ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class DefaultDistanceChecker : IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(T leftValue, T rightValue)
|
||||
{
|
||||
return string.Compare(leftValue?.ToString(), rightValue?.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private List<T> dataSet = new List<T>();
|
||||
private int distanceLowerLimit = 0;
|
||||
private int distanceUpperLimit = 1;
|
||||
private int faultTolerance = int.MaxValue;
|
||||
private int allowedIgnores = 0;
|
||||
private int numFaults = 0;
|
||||
private bool checkFaults = false;
|
||||
|
||||
private IIntegerDataStreamConstraint trendChecker = new DefaultTrendChecker();
|
||||
private IIntegerDataStreamConstraint distanceChecker = new DefaultDistanceChecker();
|
||||
|
||||
// compute a trend value between two items in the dataset
|
||||
// the same trend has to be returned by all checks for the constraint to pass
|
||||
public DataStreamConstraintVerifier<T> WithTrendChecker(IIntegerDataStreamConstraint trendChecker)
|
||||
{
|
||||
this.trendChecker = trendChecker;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DataStreamConstraintVerifier<T> OnData(List<T> dataSet)
|
||||
{
|
||||
this.dataSet = dataSet;
|
||||
return this;
|
||||
}
|
||||
|
||||
// set number of faults that get ignored until check is considered failed
|
||||
public DataStreamConstraintVerifier<T> WithFaultTolerance(int faultTolerance)
|
||||
{
|
||||
if(this.allowedIgnores > 0)
|
||||
{
|
||||
throw new Exception("Cannot enable fault tolerance along with allowed ignores!");
|
||||
}
|
||||
this.faultTolerance = faultTolerance;
|
||||
this.checkFaults = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
// set number of faults that get ignored until check is considered failed
|
||||
public DataStreamConstraintVerifier<T> WithAllowedIgnores(int allowedIgnores)
|
||||
{
|
||||
if(this.checkFaults)
|
||||
{
|
||||
throw new Exception("Cannot enable allowed ignores along with fault tolerance!");
|
||||
}
|
||||
this.allowedIgnores = allowedIgnores;
|
||||
return this;
|
||||
}
|
||||
|
||||
// set specific limits for the distance checks
|
||||
public DataStreamConstraintVerifier<T> WithDistanceLimits(int lowerLimit, int upperLimit)
|
||||
{
|
||||
this.distanceLowerLimit = lowerLimit;
|
||||
this.distanceUpperLimit = upperLimit;
|
||||
return this;
|
||||
}
|
||||
|
||||
// compute a distance value between two items in the dataset
|
||||
// the distance returned by all checks has to be within distance limits for constraint to pass
|
||||
public DataStreamConstraintVerifier<T> WithDistanceChecker(IIntegerDataStreamConstraint distanceChecker)
|
||||
{
|
||||
this.distanceChecker = distanceChecker;
|
||||
return this;
|
||||
}
|
||||
|
||||
private int TranslateIndex(int index, List<int> indicesToIgnore)
|
||||
{
|
||||
var newIndex = index;
|
||||
foreach(var value in indicesToIgnore)
|
||||
{
|
||||
if(value <= index)
|
||||
{
|
||||
newIndex++;
|
||||
}
|
||||
}
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
private bool VerifyDistance(int remainingAllowedIgnores, List<int> indicesToIgnore)
|
||||
{
|
||||
for(int i = 0; i < (this.dataSet.Count-indicesToIgnore.Count-1); i++)
|
||||
{
|
||||
T comparisonLeft = this.dataSet[TranslateIndex(i,indicesToIgnore)];
|
||||
T comparisonRight = this.dataSet[TranslateIndex(i+1,indicesToIgnore)];
|
||||
int distance = this.distanceChecker.Verify(comparisonLeft, comparisonRight);
|
||||
if(distance < this.distanceLowerLimit || distance > this.distanceUpperLimit)
|
||||
{
|
||||
this.numFaults++;
|
||||
// small optimization:
|
||||
if (!this.checkFaults || this.numFaults > this.faultTolerance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool VerifyTrend(int remainingAllowedIgnores, List<int> indicesToIgnore)
|
||||
{
|
||||
T firstComparisonLeft = this.dataSet[TranslateIndex(0,indicesToIgnore)];
|
||||
T firstComparisonRight = this.dataSet[TranslateIndex(1,indicesToIgnore)];
|
||||
int initialTrend = this.trendChecker.Verify(firstComparisonLeft, firstComparisonRight);
|
||||
|
||||
|
||||
for(int i = 0; i < (this.dataSet.Count-indicesToIgnore.Count-1); i++)
|
||||
{
|
||||
T comparisonLeft = this.dataSet[TranslateIndex(i,indicesToIgnore)];
|
||||
T comparisonRight = this.dataSet[TranslateIndex(i+1,indicesToIgnore)];
|
||||
int trend = this.trendChecker.Verify(comparisonLeft, comparisonRight);
|
||||
if(initialTrend != trend)
|
||||
{
|
||||
this.numFaults++;
|
||||
// small optimization:
|
||||
if (!this.checkFaults || this.numFaults > this.faultTolerance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool Verify(int remainingAllowedIgnores, List<int> indicesToIgnore)
|
||||
{
|
||||
if(remainingAllowedIgnores > 0)
|
||||
{
|
||||
bool success = this.Verify(0, indicesToIgnore);
|
||||
if (success)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for(int i = 0; i < this.dataSet.Count; i++)
|
||||
{
|
||||
if(indicesToIgnore.Contains(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
List<int> newIndicesToIgnore = new List<int>();
|
||||
newIndicesToIgnore.AddRange(indicesToIgnore);
|
||||
newIndicesToIgnore.Add(i);
|
||||
success = this.Verify(remainingAllowedIgnores-1, newIndicesToIgnore);
|
||||
if (success)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.numFaults = 0;
|
||||
bool success = true;
|
||||
if(this.distanceChecker != null)
|
||||
{
|
||||
success = this.VerifyDistance(this.allowedIgnores, indicesToIgnore);
|
||||
}
|
||||
if (!success || (this.checkFaults && this.numFaults > this.faultTolerance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(this.trendChecker != null)
|
||||
{
|
||||
success = this.VerifyTrend(this.allowedIgnores, indicesToIgnore);
|
||||
}
|
||||
if (this.checkFaults && this.numFaults > this.faultTolerance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Verify()
|
||||
{
|
||||
return this.Verify(this.allowedIgnores, new List<int>());
|
||||
}
|
||||
}
|
14
Level2/Level2.csproj
Normal file
14
Level2/Level2.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Common/Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
93
Level2/Level2Solver.cs
Normal file
93
Level2/Level2Solver.cs
Normal file
@ -0,0 +1,93 @@
|
||||
namespace AoC24;
|
||||
|
||||
using AoC24.Common;
|
||||
using AoCLevelInputProvider;
|
||||
using Parsing;
|
||||
using Parsing.Schema;
|
||||
|
||||
public class Level2Solver : LevelSolverBase
|
||||
{
|
||||
public override int LevelNumber
|
||||
{
|
||||
get { return 2; }
|
||||
}
|
||||
|
||||
protected override InputSchemaBuilder DefineInputSchema(InputSchemaBuilder schemaBuilder)
|
||||
{
|
||||
return schemaBuilder
|
||||
.Repeat()
|
||||
.Expect(InputType.Integer)
|
||||
.EndRepetition();
|
||||
}
|
||||
|
||||
private class MyDistanceChecker : DataStreamConstraintVerifier<int>.IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(int leftValue, int rightValue)
|
||||
{
|
||||
return Math.Abs(leftValue - rightValue);
|
||||
}
|
||||
}
|
||||
|
||||
private class MyTrendChecker : DataStreamConstraintVerifier<int>.IIntegerDataStreamConstraint
|
||||
{
|
||||
public int Verify(int leftValue, int rightValue)
|
||||
{
|
||||
return (leftValue - rightValue) < 0 ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
public override string SolveFirstStar()
|
||||
{
|
||||
var data = this.GetData()
|
||||
.AsListRows<int>();
|
||||
|
||||
var distanceChecker = new MyDistanceChecker();
|
||||
|
||||
var trendChecker = new MyTrendChecker();
|
||||
|
||||
var verifier = new DataStreamConstraintVerifier<int>()
|
||||
.WithDistanceChecker(distanceChecker)
|
||||
.WithDistanceLimits(1, 3)
|
||||
.WithTrendChecker(trendChecker);
|
||||
|
||||
int numSafeReports = 0;
|
||||
|
||||
foreach(var row in data)
|
||||
{
|
||||
if(verifier.OnData(row).Verify())
|
||||
{
|
||||
numSafeReports++;
|
||||
}
|
||||
}
|
||||
|
||||
return numSafeReports.ToString();
|
||||
}
|
||||
|
||||
public override string SolveSecondStar()
|
||||
{
|
||||
var data = this.GetData()
|
||||
.AsListRows<int>();
|
||||
|
||||
var distanceChecker = new MyDistanceChecker();
|
||||
|
||||
var trendChecker = new MyTrendChecker();
|
||||
|
||||
var verifier = new DataStreamConstraintVerifier<int>()
|
||||
.WithDistanceChecker(distanceChecker)
|
||||
.WithDistanceLimits(1, 3)
|
||||
.WithTrendChecker(trendChecker)
|
||||
.WithAllowedIgnores(1);
|
||||
|
||||
int numSafeReports = 0;
|
||||
|
||||
foreach(var row in data)
|
||||
{
|
||||
if(verifier.OnData(row).Verify())
|
||||
{
|
||||
numSafeReports++;
|
||||
}
|
||||
}
|
||||
|
||||
return numSafeReports.ToString();
|
||||
}
|
||||
}
|
24
Level2/Program.cs
Normal file
24
Level2/Program.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
|
||||
using AoC24;
|
||||
|
||||
var levelSolver = new Level2Solver();
|
||||
var solution1 = levelSolver.SolveFirstStar();
|
||||
var solution2 = levelSolver.SolveSecondStar();
|
||||
|
||||
if (!string.IsNullOrEmpty(solution1))
|
||||
{
|
||||
Console.WriteLine("Solution for example 1 is: " + solution1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Example 1 has not been solved yet!");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(solution2))
|
||||
{
|
||||
Console.WriteLine("Solution for example 2 is: " + solution2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Example 2 has not been solved yet!");
|
||||
}
|
14
LevelTemplate/LevelX.csproj
Normal file
14
LevelTemplate/LevelX.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Common/Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
43
LevelTemplate/LevelXSolver.cs
Normal file
43
LevelTemplate/LevelXSolver.cs
Normal file
@ -0,0 +1,43 @@
|
||||
namespace AoC24;
|
||||
|
||||
using AoC24.Common;
|
||||
using AoCLevelInputProvider;
|
||||
using Parsing;
|
||||
using Parsing.Schema;
|
||||
|
||||
public class LevelXSolver : LevelSolverBase
|
||||
{
|
||||
public override int LevelNumber
|
||||
{
|
||||
// TODO: update level number, csproj file and rename class!
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
protected override InputSchemaBuilder DefineInputSchema(InputSchemaBuilder schemaBuilder)
|
||||
{
|
||||
return schemaBuilder
|
||||
.Repeat()
|
||||
.Expect(InputType.Integer)
|
||||
.EndRepetition();
|
||||
}
|
||||
|
||||
public override string SolveFirstStar()
|
||||
{
|
||||
var data = this.GetData()
|
||||
.AsListRows<int>();
|
||||
|
||||
// TODO: implement
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public override string SolveSecondStar()
|
||||
{
|
||||
var data = this.GetData()
|
||||
.AsListRows<int>();
|
||||
|
||||
// TODO: implement
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
24
LevelTemplate/Program.cs
Normal file
24
LevelTemplate/Program.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
|
||||
using AoC24;
|
||||
|
||||
var levelSolver = new LevelXSolver();
|
||||
var solution1 = levelSolver.SolveFirstStar();
|
||||
var solution2 = levelSolver.SolveSecondStar();
|
||||
|
||||
if (!string.IsNullOrEmpty(solution1))
|
||||
{
|
||||
Console.WriteLine("Solution for example 1 is: " + solution1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Example 1 has not been solved yet!");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(solution2))
|
||||
{
|
||||
Console.WriteLine("Solution for example 2 is: " + solution2);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Example 2 has not been solved yet!");
|
||||
}
|
22
nuget.config
Normal file
22
nuget.config
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
|
||||
<clear />
|
||||
<add key="gitea-projects" value="https://git.disi.dev/api/packages/Projects/nuget/index.json" />
|
||||
<add key="gitea-homelab" value="https://git.disi.dev/api/packages/Homelab/nuget/index.json" />
|
||||
<add key="gitea-artifacts" value="https://git.disi.dev/api/packages/Artifacts/nuget/index.json" />
|
||||
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
|
||||
<packageSourceMapping>
|
||||
<!-- ensure TextParser is pulled from private feed - there are public conflicts-->
|
||||
<packageSource key="nuget">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
<packageSource key="gitea-projects">
|
||||
<package pattern="TextParser" />
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
</packageSourceMapping>
|
||||
</configuration>
|
Loading…
x
Reference in New Issue
Block a user