Init
This commit is contained in:
commit
54ae6eae4a
|
@ -0,0 +1,454 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# Tye
|
||||
.tye/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
##
|
||||
## Visual studio for Mac
|
||||
##
|
||||
|
||||
|
||||
# globs
|
||||
Makefile.in
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
config.make
|
||||
config.status
|
||||
aclocal.m4
|
||||
install-sh
|
||||
autom4te.cache/
|
||||
*.tar.gz
|
||||
tarballs/
|
||||
test-results/
|
||||
|
||||
# Mac bundle stuff
|
||||
*.dmg
|
||||
*.app
|
||||
|
||||
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
##
|
||||
## Visual Studio Code
|
||||
##
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
|
@ -0,0 +1,12 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MessagePack" Version="2.3.85" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,943 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace BlueWest.Collections
|
||||
{
|
||||
internal static class DictionaryHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimum size we're willing to let hashtables be.
|
||||
/// Must be a power of two, and at least 4.
|
||||
/// Note, however, that for a given hashtable, the initial size is a function of the first constructor arg, and may be > kMinBuckets.
|
||||
/// </summary>
|
||||
internal const int kMinBuckets = 4;
|
||||
|
||||
/// <summary>
|
||||
/// By default, if you don't specify a hashtable size at construction-time, we use this size. Must be a power of two, and at least kMinBuckets.
|
||||
/// </summary>
|
||||
internal const int kInitialCapacity = 32;
|
||||
|
||||
internal const int kPowerOfTableSize = 2048;
|
||||
|
||||
private readonly static int[] nextPowerOf2Table = new int[kPowerOfTableSize];
|
||||
|
||||
static DictionaryHelper()
|
||||
{
|
||||
for (int i = 0; i <= kMinBuckets; i++)
|
||||
nextPowerOf2Table[i] = kMinBuckets;
|
||||
|
||||
for (int i = kMinBuckets + 1; i < kPowerOfTableSize; i++)
|
||||
nextPowerOf2Table[i] = NextPowerOf2Internal(i);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int NextPowerOf2(int v)
|
||||
{
|
||||
if (v < kPowerOfTableSize)
|
||||
{
|
||||
return nextPowerOf2Table[v];
|
||||
}
|
||||
else
|
||||
{
|
||||
return NextPowerOf2Internal(v);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int NextPowerOf2Internal(int v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
public class FastDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
{
|
||||
const int InvalidNodePosition = -1;
|
||||
|
||||
public const uint kUnusedHash = 0xFFFFFFFF;
|
||||
public const uint kDeletedHash = 0xFFFFFFFE;
|
||||
|
||||
// TLoadFactor4 - controls hash map load. 4 means 100% load, ie. hashmap will grow
|
||||
// when number of items == capacity. Default value of 6 means it grows when
|
||||
// number of items == capacity * 3/2 (6/4). Higher load == tighter maps, but bigger
|
||||
// risk of collisions.
|
||||
static int tLoadFactor = 6;
|
||||
|
||||
private struct Entry
|
||||
{
|
||||
public uint Hash;
|
||||
public TKey Key;
|
||||
public TValue Value;
|
||||
|
||||
public Entry ( uint hash, TKey key, TValue value)
|
||||
{
|
||||
this.Hash = hash;
|
||||
this.Key = key;
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private Entry[] _entries;
|
||||
|
||||
private int _capacity;
|
||||
|
||||
private int _initialCapacity; // This is the initial capacity of the dictionary, we will never shrink beyond this point.
|
||||
private int _size; // This is the real counter of how many items are in the hash-table (regardless of buckets)
|
||||
private int _numberOfUsed; // How many used buckets.
|
||||
private int _numberOfDeleted; // how many occupied buckets are marked deleted
|
||||
private int _nextGrowthThreshold;
|
||||
|
||||
|
||||
private readonly IEqualityComparer<TKey> comparer;
|
||||
public IEqualityComparer<TKey> Comparer
|
||||
{
|
||||
get { return comparer; }
|
||||
}
|
||||
|
||||
public int Capacity
|
||||
{
|
||||
get { return _capacity; }
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _size; }
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return Count == 0; }
|
||||
}
|
||||
|
||||
public FastDictionary(int initialBucketCount, IEnumerable<KeyValuePair<TKey, TValue>> src, IEqualityComparer<TKey> comparer)
|
||||
: this(initialBucketCount, comparer)
|
||||
{
|
||||
Contract.Requires(src != null);
|
||||
Contract.Ensures(_capacity >= initialBucketCount);
|
||||
|
||||
foreach (var item in src)
|
||||
this[item.Key] = item.Value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FastDictionary(FastDictionary<TKey, TValue> src, IEqualityComparer<TKey> comparer)
|
||||
: this(src._capacity, src, comparer)
|
||||
{ }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FastDictionary(FastDictionary<TKey, TValue> src)
|
||||
: this(src._capacity, src, src.comparer)
|
||||
{ }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FastDictionary(int initialBucketCount, FastDictionary<TKey, TValue> src, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Contract.Requires(src != null);
|
||||
Contract.Ensures(_capacity >= initialBucketCount);
|
||||
Contract.Ensures(_capacity >= src._capacity);
|
||||
|
||||
this.comparer = comparer ?? EqualityComparer<TKey>.Default;
|
||||
|
||||
this._initialCapacity = DictionaryHelper.NextPowerOf2(initialBucketCount);
|
||||
this._capacity = Math.Max(src._capacity, initialBucketCount);
|
||||
this._size = src._size;
|
||||
this._numberOfUsed = src._numberOfUsed;
|
||||
this._numberOfDeleted = src._numberOfDeleted;
|
||||
this._nextGrowthThreshold = src._nextGrowthThreshold;
|
||||
|
||||
int newCapacity = _capacity;
|
||||
|
||||
if (comparer == src.comparer)
|
||||
{
|
||||
// Initialization through copy (very efficient) because the comparer is the same.
|
||||
this._entries = new Entry[newCapacity];
|
||||
Array.Copy(src._entries, _entries, newCapacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Initialization through rehashing because the comparer is not the same.
|
||||
var entries = new Entry[newCapacity];
|
||||
BlockCopyMemoryHelper.Memset(entries, new Entry(kUnusedHash, default(TKey), default(TValue)));
|
||||
|
||||
// Creating a temporary alias to use for rehashing.
|
||||
this._entries = src._entries;
|
||||
|
||||
// This call will rewrite the aliases
|
||||
Rehash(entries);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FastDictionary(IEqualityComparer<TKey> comparer)
|
||||
: this(DictionaryHelper.kInitialCapacity, comparer)
|
||||
{ }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FastDictionary(int initialBucketCount, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
Contract.Ensures(_capacity >= initialBucketCount);
|
||||
|
||||
this.comparer = comparer ?? EqualityComparer<TKey>.Default;
|
||||
|
||||
// Calculate the next power of 2.
|
||||
int newCapacity = initialBucketCount >= DictionaryHelper.kMinBuckets ? initialBucketCount : DictionaryHelper.kMinBuckets;
|
||||
newCapacity = DictionaryHelper.NextPowerOf2(newCapacity);
|
||||
|
||||
this._initialCapacity = newCapacity;
|
||||
|
||||
// Initialization
|
||||
this._entries = new Entry[newCapacity];
|
||||
BlockCopyMemoryHelper.Memset(this._entries, new Entry(kUnusedHash, default(TKey), default(TValue)));
|
||||
|
||||
this._capacity = newCapacity;
|
||||
|
||||
this._numberOfUsed = 0;
|
||||
this._numberOfDeleted = 0;
|
||||
this._size = 0;
|
||||
|
||||
this._nextGrowthThreshold = _capacity * 4 / tLoadFactor;
|
||||
}
|
||||
|
||||
public FastDictionary(int initialBucketCount = DictionaryHelper.kInitialCapacity)
|
||||
: this(initialBucketCount, EqualityComparer<TKey>.Default)
|
||||
{ }
|
||||
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
Contract.Ensures(this._numberOfUsed <= this._capacity);
|
||||
Contract.EndContractBlock();
|
||||
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
ResizeIfNeeded();
|
||||
|
||||
int hash = GetInternalHashCode(key);
|
||||
int bucket = hash % _capacity;
|
||||
|
||||
uint uhash = (uint)hash;
|
||||
int numProbes = 1;
|
||||
do
|
||||
{
|
||||
uint nHash = _entries[bucket].Hash;
|
||||
if (nHash == kUnusedHash)
|
||||
{
|
||||
_numberOfUsed++;
|
||||
_size++;
|
||||
|
||||
goto SET;
|
||||
}
|
||||
|
||||
if (nHash == uhash && comparer.Equals(_entries[bucket].Key, key))
|
||||
throw new ArgumentException("Cannot add duplicated key.", "key");
|
||||
|
||||
bucket = (bucket + numProbes) % _capacity;
|
||||
numProbes++;
|
||||
}
|
||||
while (true);
|
||||
|
||||
SET:
|
||||
this._entries[bucket].Hash = uhash;
|
||||
this._entries[bucket].Key = key;
|
||||
this._entries[bucket].Value = value;
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
Contract.Ensures(this._numberOfUsed < this._capacity);
|
||||
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
int bucket = Lookup(key);
|
||||
if (bucket == InvalidNodePosition)
|
||||
return false;
|
||||
|
||||
SetDeleted(bucket);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void SetDeleted(int node)
|
||||
{
|
||||
Contract.Ensures(_size <= Contract.OldValue<int>(_size));
|
||||
|
||||
if (_entries[node].Hash < kDeletedHash)
|
||||
{
|
||||
_entries[node].Hash = kDeletedHash;
|
||||
_entries[node].Key = default(TKey);
|
||||
_entries[node].Value = default(TValue);
|
||||
|
||||
_numberOfDeleted++;
|
||||
_size--;
|
||||
}
|
||||
|
||||
Contract.Assert(_numberOfDeleted >= Contract.OldValue<int>(_numberOfDeleted));
|
||||
Contract.Assert(_entries[node].Hash == kDeletedHash);
|
||||
|
||||
if (3 * this._numberOfDeleted / 2 > this._capacity - this._numberOfUsed)
|
||||
{
|
||||
// We will force a rehash with the growth factor based on the current size.
|
||||
Shrink(Math.Max(_initialCapacity, _size * 2));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ResizeIfNeeded()
|
||||
{
|
||||
if (_size >= _nextGrowthThreshold)
|
||||
{
|
||||
Grow(_capacity * 2);
|
||||
}
|
||||
}
|
||||
|
||||
private void Shrink(int newCapacity)
|
||||
{
|
||||
Contract.Requires(newCapacity > _size);
|
||||
Contract.Ensures(this._numberOfUsed < this._capacity);
|
||||
|
||||
// Calculate the next power of 2.
|
||||
newCapacity = Math.Max(DictionaryHelper.NextPowerOf2(newCapacity), _initialCapacity);
|
||||
|
||||
var entries = new Entry[newCapacity];
|
||||
BlockCopyMemoryHelper.Memset(entries, new Entry(kUnusedHash, default(TKey), default(TValue)));
|
||||
|
||||
Rehash(entries);
|
||||
}
|
||||
|
||||
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
Contract.Requires(key != null);
|
||||
Contract.Ensures(this._numberOfUsed <= this._capacity);
|
||||
|
||||
int hash = GetInternalHashCode(key);
|
||||
int bucket = hash % _capacity;
|
||||
|
||||
var entries = _entries;
|
||||
|
||||
uint nHash;
|
||||
int numProbes = 1;
|
||||
do
|
||||
{
|
||||
nHash = entries[bucket].Hash;
|
||||
if (nHash == hash && comparer.Equals(entries[bucket].Key, key))
|
||||
return entries[bucket].Value;
|
||||
|
||||
bucket = (bucket + numProbes) % _capacity;
|
||||
numProbes++;
|
||||
|
||||
}
|
||||
while (nHash != kUnusedHash);
|
||||
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set
|
||||
{
|
||||
Contract.Requires(key != null);
|
||||
Contract.Ensures(this._numberOfUsed <= this._capacity);
|
||||
|
||||
ResizeIfNeeded();
|
||||
|
||||
int hash = GetInternalHashCode(key);
|
||||
int bucket = hash % _capacity;
|
||||
|
||||
uint uhash = (uint)hash;
|
||||
int numProbes = 1;
|
||||
do
|
||||
{
|
||||
uint nHash = _entries[bucket].Hash;
|
||||
if (nHash == kUnusedHash)
|
||||
{
|
||||
_numberOfUsed++;
|
||||
_size++;
|
||||
|
||||
goto SET;
|
||||
}
|
||||
|
||||
if (nHash == uhash && comparer.Equals(_entries[bucket].Key, key))
|
||||
goto SET;
|
||||
|
||||
bucket = (bucket + numProbes) % _capacity;
|
||||
numProbes++;
|
||||
|
||||
}
|
||||
while (true);
|
||||
|
||||
SET:
|
||||
this._entries[bucket].Hash = uhash;
|
||||
this._entries[bucket].Key = key;
|
||||
this._entries[bucket].Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
this._entries = new Entry[_capacity];
|
||||
BlockCopyMemoryHelper.Memset(this._entries, new Entry(kUnusedHash, default(TKey), default(TValue)));
|
||||
|
||||
this._numberOfUsed = 0;
|
||||
this._numberOfDeleted = 0;
|
||||
this._size = 0;
|
||||
}
|
||||
|
||||
public bool Contains(TKey key)
|
||||
{
|
||||
Contract.Ensures(this._numberOfUsed <= this._capacity);
|
||||
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
return (Lookup(key) != InvalidNodePosition);
|
||||
}
|
||||
|
||||
private void Grow(int newCapacity)
|
||||
{
|
||||
Contract.Requires(newCapacity >= _capacity);
|
||||
Contract.Ensures((_capacity & (_capacity - 1)) == 0);
|
||||
|
||||
var entries = new Entry[newCapacity];
|
||||
BlockCopyMemoryHelper.Memset(entries, new Entry(kUnusedHash, default(TKey), default(TValue)));
|
||||
|
||||
Rehash(entries);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryGetValue(TKey key, out TValue value)
|
||||
{
|
||||
Contract.Requires(key != null);
|
||||
Contract.Ensures(this._numberOfUsed <= this._capacity);
|
||||
|
||||
int hash = GetInternalHashCode(key);
|
||||
int bucket = hash % _capacity;
|
||||
|
||||
var entries = _entries;
|
||||
|
||||
uint nHash;
|
||||
int numProbes = 1;
|
||||
do
|
||||
{
|
||||
nHash = entries[bucket].Hash;
|
||||
if (nHash == hash && comparer.Equals(entries[bucket].Key, key))
|
||||
{
|
||||
value = entries[bucket].Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bucket = (bucket + numProbes) % _capacity;
|
||||
numProbes++;
|
||||
|
||||
}
|
||||
while (nHash != kUnusedHash);
|
||||
|
||||
value = default(TValue);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns>Position of the node in the array</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int Lookup(TKey key)
|
||||
{
|
||||
int hash = GetInternalHashCode(key);
|
||||
int bucket = hash % _capacity;
|
||||
|
||||
var entries = _entries;
|
||||
|
||||
uint uhash = (uint)hash;
|
||||
uint numProbes = 1; // how many times we've probed
|
||||
|
||||
uint nHash;
|
||||
do
|
||||
{
|
||||
nHash = entries[bucket].Hash;
|
||||
if (nHash == hash && comparer.Equals(entries[bucket].Key, key))
|
||||
return bucket;
|
||||
|
||||
bucket = (int)((bucket + numProbes) % _capacity);
|
||||
numProbes++;
|
||||
|
||||
}
|
||||
while (nHash != kUnusedHash);
|
||||
|
||||
return InvalidNodePosition;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private int GetInternalHashCode(TKey key)
|
||||
{
|
||||
return comparer.GetHashCode(key) & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
private void Rehash(Entry[] entries)
|
||||
{
|
||||
uint capacity = (uint)entries.Length;
|
||||
|
||||
var size = 0;
|
||||
|
||||
for (int it = 0; it < _entries.Length; it++)
|
||||
{
|
||||
uint hash = _entries[it].Hash;
|
||||
if (hash >= kDeletedHash) // No interest for the process of rehashing, we are skipping it.
|
||||
continue;
|
||||
|
||||
uint bucket = hash % capacity;
|
||||
|
||||
uint numProbes = 0;
|
||||
while (!(entries[bucket].Hash == kUnusedHash))
|
||||
{
|
||||
numProbes++;
|
||||
bucket = (bucket + numProbes) % capacity;
|
||||
}
|
||||
|
||||
entries[bucket].Hash = hash;
|
||||
entries[bucket].Key = _entries[it].Key;
|
||||
entries[bucket].Value = _entries[it].Value;
|
||||
|
||||
size++;
|
||||
}
|
||||
|
||||
this._capacity = entries.Length;
|
||||
this._size = size;
|
||||
this._entries = entries;
|
||||
|
||||
this._numberOfUsed = size;
|
||||
this._numberOfDeleted = 0;
|
||||
|
||||
this._nextGrowthThreshold = _capacity * 4 / tLoadFactor;
|
||||
}
|
||||
|
||||
|
||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int index)
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("The array cannot be null", "array");
|
||||
|
||||
if (array.Rank != 1)
|
||||
throw new ArgumentException("Multiple dimensions array are not supporter", "array");
|
||||
|
||||
if (index < 0 || index > array.Length)
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
|
||||
if (array.Length - index < Count)
|
||||
throw new ArgumentException("The array plus the offset is too small.");
|
||||
|
||||
int count = _capacity;
|
||||
|
||||
var entries = _entries;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (entries[i].Hash < kDeletedHash)
|
||||
array[index++] = new KeyValuePair<TKey, TValue>(entries[i].Key, entries[i].Value);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
|
||||
{
|
||||
private FastDictionary<TKey, TValue> dictionary;
|
||||
private int index;
|
||||
private KeyValuePair<TKey, TValue> current;
|
||||
|
||||
internal const int DictEntry = 1;
|
||||
internal const int KeyValuePair = 2;
|
||||
|
||||
internal Enumerator(FastDictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
this.dictionary = dictionary;
|
||||
this.index = 0;
|
||||
this.current = new KeyValuePair<TKey, TValue>();
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
var count = dictionary._capacity;
|
||||
var entries = dictionary._entries;
|
||||
|
||||
// Use unsigned comparison since we set index to dictionary.count+1 when the enumeration ends.
|
||||
// dictionary.count+1 could be negative if dictionary.count is Int32.MaxValue
|
||||
while (index < count)
|
||||
{
|
||||
if (entries[index].Hash < kDeletedHash)
|
||||
{
|
||||
current = new KeyValuePair<TKey, TValue>(entries[index].Key, entries[index].Value);
|
||||
index++;
|
||||
return true;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
index = count + 1;
|
||||
current = new KeyValuePair<TKey, TValue>();
|
||||
return false;
|
||||
}
|
||||
|
||||
public KeyValuePair<TKey, TValue> Current
|
||||
{
|
||||
get { return current; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index == 0 || (index == dictionary._capacity + 1))
|
||||
throw new InvalidOperationException("Can't happen.");
|
||||
|
||||
return new KeyValuePair<TKey, TValue>(current.Key, current.Value);
|
||||
}
|
||||
}
|
||||
|
||||
void IEnumerator.Reset()
|
||||
{
|
||||
index = 0;
|
||||
current = new KeyValuePair<TKey, TValue>();
|
||||
}
|
||||
}
|
||||
|
||||
public KeyCollection Keys
|
||||
{
|
||||
get { return new KeyCollection(this); }
|
||||
}
|
||||
|
||||
public ValueCollection Values
|
||||
{
|
||||
get { return new ValueCollection(this); }
|
||||
}
|
||||
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
if (key == null)
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
return (Lookup(key) != InvalidNodePosition);
|
||||
}
|
||||
|
||||
public bool ContainsValue(TValue value)
|
||||
{
|
||||
var entries = _entries;
|
||||
int count = _capacity;
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (entries[i].Hash < kDeletedHash && entries[i].Value == null)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EqualityComparer<TValue> c = EqualityComparer<TValue>.Default;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (entries[i].Hash < kDeletedHash && c.Equals(entries[i].Value, value))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public sealed class KeyCollection : IEnumerable<TKey>, IEnumerable
|
||||
{
|
||||
private FastDictionary<TKey, TValue> dictionary;
|
||||
|
||||
public KeyCollection(FastDictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
Contract.Requires(dictionary != null);
|
||||
|
||||
this.dictionary = dictionary;
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator(dictionary);
|
||||
}
|
||||
|
||||
public void CopyTo(TKey[] array, int index)
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("The array cannot be null", "array");
|
||||
|
||||
if (index < 0 || index > array.Length)
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
|
||||
if (array.Length - index < dictionary.Count)
|
||||
throw new ArgumentException("The array plus the offset is too small.");
|
||||
|
||||
int count = dictionary._capacity;
|
||||
var entries = dictionary._entries;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (entries[i].Hash < kDeletedHash)
|
||||
array[index++] = entries[i].Key;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return dictionary.Count; }
|
||||
}
|
||||
|
||||
|
||||
IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator()
|
||||
{
|
||||
return new Enumerator(dictionary);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return new Enumerator(dictionary);
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public struct Enumerator : IEnumerator<TKey>, IEnumerator
|
||||
{
|
||||
private FastDictionary<TKey, TValue> dictionary;
|
||||
private int index;
|
||||
private TKey currentKey;
|
||||
|
||||
internal Enumerator(FastDictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
this.dictionary = dictionary;
|
||||
index = 0;
|
||||
currentKey = default(TKey);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
var count = dictionary._capacity;
|
||||
|
||||
var entries = dictionary._entries;
|
||||
while (index < count)
|
||||
{
|
||||
if (entries[index].Hash < kDeletedHash)
|
||||
{
|
||||
currentKey = entries[index].Key;
|
||||
index++;
|
||||
return true;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
index = count + 1;
|
||||
currentKey = default(TKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
public TKey Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return currentKey;
|
||||
}
|
||||
}
|
||||
|
||||
Object System.Collections.IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index == 0 || (index == dictionary.Count + 1))
|
||||
throw new InvalidOperationException("Cant happen.");
|
||||
|
||||
return currentKey;
|
||||
}
|
||||
}
|
||||
|
||||
void System.Collections.IEnumerator.Reset()
|
||||
{
|
||||
index = 0;
|
||||
currentKey = default(TKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public sealed class ValueCollection : IEnumerable<TValue>, IEnumerable
|
||||
{
|
||||
private FastDictionary<TKey, TValue> dictionary;
|
||||
|
||||
public ValueCollection(FastDictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
Contract.Requires(dictionary != null);
|
||||
|
||||
this.dictionary = dictionary;
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator(dictionary);
|
||||
}
|
||||
|
||||
public void CopyTo(TValue[] array, int index)
|
||||
{
|
||||
if (array == null)
|
||||
throw new ArgumentNullException("The array cannot be null", "array");
|
||||
|
||||
if (index < 0 || index > array.Length)
|
||||
throw new ArgumentOutOfRangeException("index");
|
||||
|
||||
if (array.Length - index < dictionary.Count)
|
||||
throw new ArgumentException("The array plus the offset is too small.");
|
||||
|
||||
int count = dictionary._capacity;
|
||||
|
||||
var entries = dictionary._entries;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (entries[i].Hash < kDeletedHash)
|
||||
array[index++] = entries[i].Value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return dictionary.Count; }
|
||||
}
|
||||
|
||||
IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
|
||||
{
|
||||
return new Enumerator(dictionary);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return new Enumerator(dictionary);
|
||||
}
|
||||
|
||||
|
||||
[Serializable]
|
||||
public struct Enumerator : IEnumerator<TValue>, IEnumerator
|
||||
{
|
||||
private FastDictionary<TKey, TValue> dictionary;
|
||||
private int index;
|
||||
private TValue currentValue;
|
||||
|
||||
internal Enumerator(FastDictionary<TKey, TValue> dictionary)
|
||||
{
|
||||
this.dictionary = dictionary;
|
||||
index = 0;
|
||||
currentValue = default(TValue);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
var count = dictionary._capacity;
|
||||
|
||||
var entries = dictionary._entries;
|
||||
while (index < count)
|
||||
{
|
||||
if (entries[index].Hash < kDeletedHash)
|
||||
{
|
||||
currentValue = entries[index].Value;
|
||||
index++;
|
||||
return true;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
index = count + 1;
|
||||
currentValue = default(TValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
public TValue Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return currentValue;
|
||||
}
|
||||
}
|
||||
Object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index == 0 || (index == dictionary.Count + 1))
|
||||
throw new InvalidOperationException("Cant happen.");
|
||||
|
||||
return currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
void IEnumerator.Reset()
|
||||
{
|
||||
index = 0;
|
||||
currentValue = default(TValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class BlockCopyMemoryHelper
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Memset(Entry[] array, Entry value)
|
||||
{
|
||||
int block = 64, index = 0;
|
||||
int length = Math.Min(block, array.Length);
|
||||
|
||||
//Fill the initial array
|
||||
while (index < length)
|
||||
{
|
||||
array[index++] = value;
|
||||
}
|
||||
|
||||
length = array.Length;
|
||||
while (index < length)
|
||||
{
|
||||
Array.Copy(array, 0, array, index, Math.Min(block, (length - index)));
|
||||
index += block;
|
||||
|
||||
block *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BlueWest.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// very basic wrapper around an array that auto-expands it when it reaches capacity. Note that when iterating it should be done
|
||||
/// like this accessing the buffer directly but using the FastList.length field:
|
||||
///
|
||||
/// for( var i = 0; i <= list.length; i++ )
|
||||
/// var item = list.buffer[i];
|
||||
/// </summary>
|
||||
|
||||
public class FastList<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// direct access to the backing buffer. Do not use buffer.Length! Use FastList.length
|
||||
/// </summary>
|
||||
public T[] Buffer;
|
||||
|
||||
/// <summary>
|
||||
/// direct access to the length of the filled items in the buffer. Do not change.
|
||||
/// </summary>
|
||||
public int Length = 0;
|
||||
|
||||
|
||||
public FastList(int size)
|
||||
{
|
||||
Buffer = new T[size];
|
||||
}
|
||||
|
||||
|
||||
public FastList() : this(5)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// provided for ease of access though it is recommended to just access the buffer directly.
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
public T this[int index] => Buffer[index];
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// clears the list and nulls out all items in the buffer
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
Array.Clear(Buffer, 0, Length);
|
||||
Length = 0;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// works just like clear except it does not null our all the items in the buffer. Useful when dealing with structs.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
Length = 0;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// adds the item to the list
|
||||
/// </summary>
|
||||
public void Add(T item)
|
||||
{
|
||||
if (Length == Buffer.Length)
|
||||
Array.Resize(ref Buffer, Math.Max(Buffer.Length << 1, 10));
|
||||
Buffer[Length++] = item;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// removes the item from the list
|
||||
/// </summary>
|
||||
/// <param name="item">Item.</param>
|
||||
public void Remove(T item)
|
||||
{
|
||||
var comp = EqualityComparer<T>.Default;
|
||||
for (var i = 0; i < Length; ++i)
|
||||
{
|
||||
if (comp.Equals(Buffer[i], item))
|
||||
{
|
||||
RemoveAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// removes the item at the given index from the list
|
||||
/// </summary>
|
||||
public void RemoveAt(int index)
|
||||
{
|
||||
Length--;
|
||||
if (index < Length)
|
||||
Array.Copy(Buffer, index + 1, Buffer, index, Length - index);
|
||||
Buffer[Length] = default(T);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// removes the item at the given index from the list but does NOT maintain list order
|
||||
/// </summary>
|
||||
/// <param name="index">Index.</param>
|
||||
public void RemoveAtWithSwap(int index)
|
||||
{
|
||||
Buffer[index] = Buffer[Length - 1];
|
||||
Buffer[Length - 1] = default(T);
|
||||
--Length;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// checks to see if item is in the FastList
|
||||
/// </summary>
|
||||
/// <param name="item">Item.</param>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
var comp = EqualityComparer<T>.Default;
|
||||
for (var i = 0; i < Length; ++i)
|
||||
{
|
||||
if (comp.Equals(Buffer[i], item))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// if the buffer is at its max more space will be allocated to fit additionalItemCount
|
||||
/// </summary>
|
||||
public void EnsureCapacity(int additionalItemCount = 1)
|
||||
{
|
||||
if (Length + additionalItemCount >= Buffer.Length)
|
||||
Array.Resize(ref Buffer, Math.Max(Buffer.Length << 1, Length + additionalItemCount));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// adds all items from array
|
||||
/// </summary>
|
||||
/// <param name="array">Array.</param>
|
||||
public void AddRange(IEnumerable<T> array)
|
||||
{
|
||||
foreach (var item in array)
|
||||
Add(item);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// sorts all items in the buffer up to length
|
||||
/// </summary>
|
||||
public void Sort()
|
||||
{
|
||||
Array.Sort(Buffer, 0, Length);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// sorts all items in the buffer up to length
|
||||
/// </summary>
|
||||
public void Sort(IComparer comparer)
|
||||
{
|
||||
Array.Sort(Buffer, 0, Length, comparer);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// sorts all items in the buffer up to length
|
||||
/// </summary>
|
||||
public void Sort(IComparer<T> comparer)
|
||||
{
|
||||
Array.Sort(Buffer, 0, Length, comparer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
|
||||
<RootNamespace>BlueWest.Data</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MapTo" Version="0.8.2" />
|
||||
<PackageReference Include="MessagePack" Version="2.3.85" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="6.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BlueWest.Collections\BlueWest.Collections.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace BlueWest.Data
|
||||
{
|
||||
public class CodeGenerator
|
||||
{
|
||||
/*public string GetInviteCode(bool isBase64 = false)
|
||||
{
|
||||
var unix = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
var unixStr = unix.ToString("0000000000")[^6..];
|
||||
|
||||
byte[] bytes = RandomNumberGenerator.GetBytes(6);
|
||||
|
||||
var hexArray = Array.ConvertAll(bytes, x => x.ToString("X2"));
|
||||
var hexStr = string.Concat(hexArray);
|
||||
|
||||
var resultCode = isBase64
|
||||
? Convert.ToBase64String(Convert.FromHexString(unixStr + hexStr))
|
||||
: unixStr + hexStr;
|
||||
|
||||
return resultCode;
|
||||
}*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace BlueWest.Data
|
||||
{
|
||||
public class DataObject
|
||||
{
|
||||
public override string ToString()
|
||||
{
|
||||
return JsonConvert.SerializeObject(this, Formatting.Indented);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using MessagePack;
|
||||
|
||||
namespace BlueWest.Data
|
||||
{
|
||||
public enum FinanceSymbol
|
||||
{
|
||||
BTC_EUR,
|
||||
BTC_BUSD,
|
||||
BTC_USD,
|
||||
BTC_USDT,
|
||||
LTC_EUR,
|
||||
LTC_BUSD,
|
||||
LTC_USDT
|
||||
}
|
||||
|
||||
public enum FinanceTransactionType
|
||||
{
|
||||
Buy,
|
||||
Sell
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public struct FinanceTransaction
|
||||
{
|
||||
[Key(1)] public int Id { get; set; }
|
||||
[Key(2)] public int UserId { get; set; }
|
||||
[Key(3)] public FinanceTransactionType FinanceTransactionType { get; }
|
||||
[Key(4)] public FinanceSymbol FinanceSymbol { get; }
|
||||
[Key(5)] public double Amount { get; } // To Buy
|
||||
[Key(6)] public double Quantity { get; } // Bought
|
||||
[Key(7)] public double Fee { get; }
|
||||
[Key(8)] public DateTime DateTime { get; }
|
||||
|
||||
|
||||
public FinanceTransaction(int id, int userId, FinanceTransactionType financeTransactionType,
|
||||
FinanceSymbol financeSymbol, double amount, double quantity, double fee, DateTime dateTime)
|
||||
{
|
||||
Id = id;
|
||||
UserId = userId;
|
||||
FinanceTransactionType = financeTransactionType;
|
||||
FinanceSymbol = financeSymbol;
|
||||
Amount = amount;
|
||||
Quantity = quantity;
|
||||
Fee = fee;
|
||||
DateTime = dateTime;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using BlueWest.Collections;
|
||||
using MapTo;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BlueWest.Data
|
||||
{
|
||||
[MessagePackObject]
|
||||
[MapFrom(typeof(UserUpdateDto))]
|
||||
public partial class User : DataObject
|
||||
{
|
||||
[Key(1)]public int Id { get; set; } = -1;
|
||||
[Key(2)]public string Name { get; set; } = "";
|
||||
[Key(3)]public string Address { get; set; } = "";
|
||||
|
||||
[Key(4)]public string BTCAddress { get; set; } = "";
|
||||
[Key(5)]public string LTCAddress { get; set; } = "";
|
||||
|
||||
[Key(6)]public double BTCAmount { get; set; } = 0;
|
||||
[Key(7)]public double LTCAmount { get; set; } = 0;
|
||||
|
||||
[IgnoreProperty]
|
||||
[Key(8)] public List<FinanceTransaction> FinanceTransactions { get; set; }
|
||||
|
||||
public User(int id, string name, string address, string btcAddress, string ltcAddress, double btcAmount, double ltcAmount, List<FinanceTransaction> financeTransactions)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Address = address;
|
||||
BTCAddress = btcAddress;
|
||||
LTCAddress = ltcAddress;
|
||||
BTCAmount = btcAmount;
|
||||
LTCAmount = ltcAmount;
|
||||
FinanceTransactions = financeTransactions;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using System.Collections.Generic;
|
||||
using BlueWest.Collections;
|
||||
using MessagePack;
|
||||
|
||||
namespace BlueWest.Data
|
||||
{
|
||||
[MessagePackObject]
|
||||
public class UserList: DataObject
|
||||
{
|
||||
[Key(9)] public List<User> Users;
|
||||
|
||||
public UserList(List<User> users)
|
||||
{
|
||||
Users = users;
|
||||
}
|
||||
|
||||
[IgnoreMember]
|
||||
public int Length => Users.Count;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using MapTo;
|
||||
|
||||
namespace BlueWest.Data
|
||||
{
|
||||
[MapFrom(typeof(User))]
|
||||
|
||||
public partial class UserUpdateDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Address { get; set; }
|
||||
|
||||
public string BTCAddress { get; set; }
|
||||
public string LTCAddress { get; set; }
|
||||
|
||||
public double BTCAmount { get; set; }
|
||||
public double LTCAmount { get; set; }
|
||||
|
||||
|
||||
public UserUpdateDto()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BlueWest.Core.ComponentSystem;
|
||||
using BlueWest.Tools;
|
||||
using PerformanceSolution.Artefacts;
|
||||
|
||||
namespace BlueWest.DataAgent
|
||||
{
|
||||
|
||||
public class Binance : Artefact, EventListener<CommandRequestEvent>
|
||||
{
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
Console.WriteLine("Binance Started");
|
||||
}
|
||||
|
||||
public void TryGetExampleData()
|
||||
{
|
||||
var response = AgentHttp.GetAsync("/uri");
|
||||
}
|
||||
|
||||
public void OnEvent(CommandRequestEvent eventType)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Binance" />
|
||||
<Folder Include="FTXPro" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BlueWest\BlueWest.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,33 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using BlueWest.Core.Tests;
|
||||
|
||||
namespace BlueWest.DataAgent
|
||||
{
|
||||
public static class AgentHttp
|
||||
{
|
||||
private static readonly HttpClient Client = new HttpClient();
|
||||
|
||||
public static async Task<string> PostAsync<T>(string uri, object data)
|
||||
{
|
||||
var values = data.ToDictionary();
|
||||
|
||||
ByteArrayContent content = new FormUrlEncodedContent((IEnumerable<KeyValuePair<string?, string?>>) values);
|
||||
|
||||
var response = await Client.PostAsync(uri, content);
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync();
|
||||
|
||||
return responseString;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static async Task<string> GetAsync(string uri)
|
||||
{
|
||||
var responseString = await Client.GetStringAsync(uri);
|
||||
return responseString;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
|
@ -0,0 +1,38 @@
|
|||
# create-svelte
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte);
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm init svelte@next
|
||||
|
||||
# create a new project in my-app
|
||||
npm init svelte@next my-app
|
||||
```
|
||||
|
||||
> Note: the `@next` is temporary
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
Before creating a production version of your app, install an [adapter](https://kit.svelte.dev/docs#adapters) for your target environment. Then:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
> You can preview the built app with `npm run preview`, regardless of whether you installed an adapter. This should _not_ be used to serve your app in production.
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"$lib": ["src/lib"],
|
||||
"$lib/*": ["src/lib/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"]
|
||||
}
|
|
@ -0,0 +1,987 @@
|
|||
{
|
||||
"name": "bluewest.frontend",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bluewest.frontend",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"klinecharts": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/kit": "next",
|
||||
"svelte": "^3.42.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz",
|
||||
"integrity": "sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"estree-walker": "^2.0.1",
|
||||
"picomatch": "^2.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/kit": {
|
||||
"version": "1.0.0-next.198",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.198.tgz",
|
||||
"integrity": "sha512-BgXVrCOn0sYNAvmSIXxfztntGzb4ZhaO3KSmJzkSeQQg20+aQGqyOJnhTQ+wDX+YhyKURxVOhjTWHjeO6d7gdw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.30",
|
||||
"cheap-watch": "^1.0.4",
|
||||
"sade": "^1.7.4",
|
||||
"vite": "^2.6.12"
|
||||
},
|
||||
"bin": {
|
||||
"svelte-kit": "svelte-kit.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.44.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/vite-plugin-svelte": {
|
||||
"version": "1.0.0-next.30",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.0-next.30.tgz",
|
||||
"integrity": "sha512-YQqdMxjL1VgSFk4/+IY3yLwuRRapPafPiZTiaGEq1psbJYSNYUWx9F1zMm32GMsnogg3zn99mGJOqe3ld3HZSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": "^4.1.1",
|
||||
"debug": "^4.3.2",
|
||||
"kleur": "^4.1.4",
|
||||
"magic-string": "^0.25.7",
|
||||
"require-relative": "^0.8.7",
|
||||
"svelte-hmr": "^0.14.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.13.1 || >= 16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"diff-match-patch": "^1.0.5",
|
||||
"svelte": "^3.44.0",
|
||||
"vite": "^2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"diff-match-patch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/cheap-watch": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cheap-watch/-/cheap-watch-1.0.4.tgz",
|
||||
"integrity": "sha512-QR/9FrtRL5fjfUJBhAKCdi0lSRQ3rVRRum3GF9wDKp2TJbEIMGhUEr2yU8lORzm9Isdjx7/k9S0DFDx+z5VGtw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz",
|
||||
"integrity": "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"esbuild-android-arm64": "0.13.15",
|
||||
"esbuild-darwin-64": "0.13.15",
|
||||
"esbuild-darwin-arm64": "0.13.15",
|
||||
"esbuild-freebsd-64": "0.13.15",
|
||||
"esbuild-freebsd-arm64": "0.13.15",
|
||||
"esbuild-linux-32": "0.13.15",
|
||||
"esbuild-linux-64": "0.13.15",
|
||||
"esbuild-linux-arm": "0.13.15",
|
||||
"esbuild-linux-arm64": "0.13.15",
|
||||
"esbuild-linux-mips64le": "0.13.15",
|
||||
"esbuild-linux-ppc64le": "0.13.15",
|
||||
"esbuild-netbsd-64": "0.13.15",
|
||||
"esbuild-openbsd-64": "0.13.15",
|
||||
"esbuild-sunos-64": "0.13.15",
|
||||
"esbuild-windows-32": "0.13.15",
|
||||
"esbuild-windows-64": "0.13.15",
|
||||
"esbuild-windows-arm64": "0.13.15"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-darwin-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz",
|
||||
"integrity": "sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-darwin-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-freebsd-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz",
|
||||
"integrity": "sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-freebsd-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-linux-32": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz",
|
||||
"integrity": "sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-linux-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz",
|
||||
"integrity": "sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-linux-arm": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz",
|
||||
"integrity": "sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-linux-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-linux-mips64le": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz",
|
||||
"integrity": "sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-linux-ppc64le": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz",
|
||||
"integrity": "sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-netbsd-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz",
|
||||
"integrity": "sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-openbsd-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz",
|
||||
"integrity": "sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-sunos-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz",
|
||||
"integrity": "sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-windows-32": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz",
|
||||
"integrity": "sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-windows-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz",
|
||||
"integrity": "sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/esbuild-windows-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
|
||||
"integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"has": "^1.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz",
|
||||
"integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/klinecharts": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/klinecharts/-/klinecharts-8.1.0.tgz",
|
||||
"integrity": "sha512-LNRa3eRs81nmhuepLxsnDj1s2uj/17Ta4rA71SlMApu1YHGjs4LBcNSwuNRRCLpdCfHi2LQ3KWSpVwrBHoDTUQ=="
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.25.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
|
||||
"integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"sourcemap-codec": "^1.4.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mri": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
||||
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.1.30",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
|
||||
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.3.11",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.11.tgz",
|
||||
"integrity": "sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.1.30",
|
||||
"picocolors": "^1.0.0",
|
||||
"source-map-js": "^0.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
}
|
||||
},
|
||||
"node_modules/require-relative": {
|
||||
"version": "0.8.7",
|
||||
"resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
|
||||
"integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.60.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.1.tgz",
|
||||
"integrity": "sha512-akwfnpjY0rXEDSn1UTVfKXJhPsEBu+imi1gqBA1ZkHGydUnkV/fWCC90P7rDaLEW8KTwBcS1G3N4893Ndz+jwg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/sade": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz",
|
||||
"integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"mri": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
|
||||
"integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sourcemap-codec": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/svelte": {
|
||||
"version": "3.44.2",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.44.2.tgz",
|
||||
"integrity": "sha512-jrZhZtmH3ZMweXg1Q15onb8QlWD+a5T5Oca4C1jYvSURp2oD35h4A5TV6t6MEa93K4LlX6BkafZPdQoFjw/ylA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-hmr": {
|
||||
"version": "0.14.7",
|
||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.14.7.tgz",
|
||||
"integrity": "sha512-pDrzgcWSoMaK6AJkBWkmgIsecW0GChxYZSZieIYfCP0v2oPyx2CYU/zm7TBIcjLVUPP714WxmViE9Thht4etog==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"svelte": ">=3.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "2.6.14",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-2.6.14.tgz",
|
||||
"integrity": "sha512-2HA9xGyi+EhY2MXo0+A2dRsqsAG3eFNEVIo12olkWhOmc8LfiM+eMdrXf+Ruje9gdXgvSqjLI9freec1RUM5EA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.13.2",
|
||||
"postcss": "^8.3.8",
|
||||
"resolve": "^1.20.0",
|
||||
"rollup": "^2.57.0"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.2.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"less": "*",
|
||||
"sass": "*",
|
||||
"stylus": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@rollup/pluginutils": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.1.tgz",
|
||||
"integrity": "sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estree-walker": "^2.0.1",
|
||||
"picomatch": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"@sveltejs/kit": {
|
||||
"version": "1.0.0-next.198",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-1.0.0-next.198.tgz",
|
||||
"integrity": "sha512-BgXVrCOn0sYNAvmSIXxfztntGzb4ZhaO3KSmJzkSeQQg20+aQGqyOJnhTQ+wDX+YhyKURxVOhjTWHjeO6d7gdw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.30",
|
||||
"cheap-watch": "^1.0.4",
|
||||
"sade": "^1.7.4",
|
||||
"vite": "^2.6.12"
|
||||
}
|
||||
},
|
||||
"@sveltejs/vite-plugin-svelte": {
|
||||
"version": "1.0.0-next.30",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.0-next.30.tgz",
|
||||
"integrity": "sha512-YQqdMxjL1VgSFk4/+IY3yLwuRRapPafPiZTiaGEq1psbJYSNYUWx9F1zMm32GMsnogg3zn99mGJOqe3ld3HZSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@rollup/pluginutils": "^4.1.1",
|
||||
"debug": "^4.3.2",
|
||||
"kleur": "^4.1.4",
|
||||
"magic-string": "^0.25.7",
|
||||
"require-relative": "^0.8.7",
|
||||
"svelte-hmr": "^0.14.7"
|
||||
}
|
||||
},
|
||||
"cheap-watch": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cheap-watch/-/cheap-watch-1.0.4.tgz",
|
||||
"integrity": "sha512-QR/9FrtRL5fjfUJBhAKCdi0lSRQ3rVRRum3GF9wDKp2TJbEIMGhUEr2yU8lORzm9Isdjx7/k9S0DFDx+z5VGtw==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
|
||||
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.13.15.tgz",
|
||||
"integrity": "sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esbuild-android-arm64": "0.13.15",
|
||||
"esbuild-darwin-64": "0.13.15",
|
||||
"esbuild-darwin-arm64": "0.13.15",
|
||||
"esbuild-freebsd-64": "0.13.15",
|
||||
"esbuild-freebsd-arm64": "0.13.15",
|
||||
"esbuild-linux-32": "0.13.15",
|
||||
"esbuild-linux-64": "0.13.15",
|
||||
"esbuild-linux-arm": "0.13.15",
|
||||
"esbuild-linux-arm64": "0.13.15",
|
||||
"esbuild-linux-mips64le": "0.13.15",
|
||||
"esbuild-linux-ppc64le": "0.13.15",
|
||||
"esbuild-netbsd-64": "0.13.15",
|
||||
"esbuild-openbsd-64": "0.13.15",
|
||||
"esbuild-sunos-64": "0.13.15",
|
||||
"esbuild-windows-32": "0.13.15",
|
||||
"esbuild-windows-64": "0.13.15",
|
||||
"esbuild-windows-arm64": "0.13.15"
|
||||
}
|
||||
},
|
||||
"esbuild-android-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-darwin-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.13.15.tgz",
|
||||
"integrity": "sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-darwin-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-freebsd-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.13.15.tgz",
|
||||
"integrity": "sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-freebsd-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-32": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.13.15.tgz",
|
||||
"integrity": "sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.13.15.tgz",
|
||||
"integrity": "sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-arm": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.13.15.tgz",
|
||||
"integrity": "sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-mips64le": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.13.15.tgz",
|
||||
"integrity": "sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-linux-ppc64le": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.13.15.tgz",
|
||||
"integrity": "sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-netbsd-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.13.15.tgz",
|
||||
"integrity": "sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-openbsd-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.13.15.tgz",
|
||||
"integrity": "sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-sunos-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.13.15.tgz",
|
||||
"integrity": "sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-32": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.13.15.tgz",
|
||||
"integrity": "sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.13.15.tgz",
|
||||
"integrity": "sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"esbuild-windows-arm64": {
|
||||
"version": "0.13.15",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.13.15.tgz",
|
||||
"integrity": "sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"estree-walker": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
|
||||
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
|
||||
"dev": true
|
||||
},
|
||||
"fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
},
|
||||
"has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"is-core-module": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
|
||||
"integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"kleur": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz",
|
||||
"integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==",
|
||||
"dev": true
|
||||
},
|
||||
"klinecharts": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/klinecharts/-/klinecharts-8.1.0.tgz",
|
||||
"integrity": "sha512-LNRa3eRs81nmhuepLxsnDj1s2uj/17Ta4rA71SlMApu1YHGjs4LBcNSwuNRRCLpdCfHi2LQ3KWSpVwrBHoDTUQ=="
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.25.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
|
||||
"integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sourcemap-codec": "^1.4.4"
|
||||
}
|
||||
},
|
||||
"mri": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
|
||||
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.1.30",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
|
||||
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==",
|
||||
"dev": true
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.3.11",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.11.tgz",
|
||||
"integrity": "sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"nanoid": "^3.1.30",
|
||||
"picocolors": "^1.0.0",
|
||||
"source-map-js": "^0.6.2"
|
||||
}
|
||||
},
|
||||
"require-relative": {
|
||||
"version": "0.8.7",
|
||||
"resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
|
||||
"integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=",
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"rollup": {
|
||||
"version": "2.60.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.1.tgz",
|
||||
"integrity": "sha512-akwfnpjY0rXEDSn1UTVfKXJhPsEBu+imi1gqBA1ZkHGydUnkV/fWCC90P7rDaLEW8KTwBcS1G3N4893Ndz+jwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"sade": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz",
|
||||
"integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mri": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"source-map-js": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
|
||||
"integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
|
||||
"dev": true
|
||||
},
|
||||
"sourcemap-codec": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||
"dev": true
|
||||
},
|
||||
"svelte": {
|
||||
"version": "3.44.2",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.44.2.tgz",
|
||||
"integrity": "sha512-jrZhZtmH3ZMweXg1Q15onb8QlWD+a5T5Oca4C1jYvSURp2oD35h4A5TV6t6MEa93K4LlX6BkafZPdQoFjw/ylA==",
|
||||
"dev": true
|
||||
},
|
||||
"svelte-hmr": {
|
||||
"version": "0.14.7",
|
||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.14.7.tgz",
|
||||
"integrity": "sha512-pDrzgcWSoMaK6AJkBWkmgIsecW0GChxYZSZieIYfCP0v2oPyx2CYU/zm7TBIcjLVUPP714WxmViE9Thht4etog==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"vite": {
|
||||
"version": "2.6.14",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-2.6.14.tgz",
|
||||
"integrity": "sha512-2HA9xGyi+EhY2MXo0+A2dRsqsAG3eFNEVIo12olkWhOmc8LfiM+eMdrXf+Ruje9gdXgvSqjLI9freec1RUM5EA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esbuild": "^0.13.2",
|
||||
"fsevents": "~2.3.2",
|
||||
"postcss": "^8.3.8",
|
||||
"resolve": "^1.20.0",
|
||||
"rollup": "^2.57.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "bluewest.frontend",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "svelte-kit dev",
|
||||
"build": "svelte-kit build",
|
||||
"preview": "svelte-kit preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/kit": "next",
|
||||
"svelte": "^3.42.6"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"klinecharts": "^8.1.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="icon" href="/favicon.png"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<link href="https://cdn.jsdelivr.net/npm/beercss@1.2.9/dist/cdn/beer.min.css" rel="stylesheet"/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/beercss@1.2.9/dist/cdn/beer.min.js" type="text/javascript"></script>
|
||||
%svelte.head%
|
||||
</head>
|
||||
<body>
|
||||
<div id="svelte" class="container max">%svelte.body%</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
<script>
|
||||
var chart = klinecharts.init('chart')
|
||||
// 创建一个主图技术指标
|
||||
chart.createTechnicalIndicator('MA', false, { id: 'candle_pane' })
|
||||
// 创建一个副图技术指标VOL
|
||||
chart.createTechnicalIndicator('VOL')
|
||||
// 创建一个副图技术指标MACD
|
||||
chart.createTechnicalIndicator('MACD')
|
||||
// 加载数据
|
||||
var chartDataList = kLineDataList.map(function (data) {
|
||||
return {
|
||||
timestamp: new Date(data[0]).getTime(),
|
||||
open: +data[1],
|
||||
high: +data[2],
|
||||
low: +data[3],
|
||||
close: +data[4],
|
||||
volume: Math.ceil(+data[5]),
|
||||
}
|
||||
})
|
||||
chart.applyNewData(chartDataList)
|
||||
</script>
|
|
@ -0,0 +1,15 @@
|
|||
<div class="menu left border no-space grey-text m l">
|
||||
<div class="large-space"></div>
|
||||
<div class="medium-space"></div>
|
||||
<div class="space"></div>
|
||||
<a href="/" class="active"><i class="outlined">home</i>
|
||||
<div class="tooltip right">Blue West</div>
|
||||
</a>
|
||||
<a href="/users" class="active"><i class="outlined">person</i>
|
||||
<div class="tooltip right">Users</div>
|
||||
</a>
|
||||
<a href="/binance" class="active"><i class="outlined">bar_chart</i>
|
||||
<div class="tooltip right">Binance</div>
|
||||
</a>
|
||||
|
||||
</div>
|
|
@ -0,0 +1 @@
|
|||
/// <reference types="@sveltejs/kit" />
|
|
@ -0,0 +1,50 @@
|
|||
<script>
|
||||
import Menu from "../components/Menu.svelte";
|
||||
</script>
|
||||
|
||||
<Menu/>
|
||||
|
||||
<div class="menu top border">
|
||||
<div class="row no-wrap middle-align">
|
||||
<div class="col">
|
||||
<nav class="padding">
|
||||
<button data-ui="#modal-expanded" class="none color-2-text m l"><i>menu</i></button>
|
||||
<a><i class="outlined">bar_chart</i></a></nav>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="field round suffix prefix small no-margin m l"><i class="front">search</i><input type="text"
|
||||
class="white black-text"><i
|
||||
class="front">mic</i></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<nav class="right-align">
|
||||
<button data-ui="#modal-search" class="none color-2-text s"><i>search</i></button>
|
||||
<button data-ui="#dropdown-add" class="none color-2-text m l"><i>video_call</i>
|
||||
<div id="dropdown-add" data-ui="#dropdown-add" class="dropdown left no-wrap"><a class="row no-wrap">
|
||||
<div class="col min"><i>upload</i></div>
|
||||
<div class="col">Send a video</div>
|
||||
</a><a class="row no-wrap">
|
||||
<div class="col min"><i>sensors</i></div>
|
||||
<div class="col">Broadcast live</div>
|
||||
</a></div>
|
||||
</button>
|
||||
<button data-ui="#dropdown-apps" class="none color-2-text m l"><i>apps</i>
|
||||
<div id="dropdown-apps" data-ui="#dropdown-apps" class="dropdown left no-wrap"><a
|
||||
class="row no-wrap">
|
||||
<div class="col min"><img src="/youtube.png"></div>
|
||||
<div class="col">Youtube TV</div>
|
||||
</a>
|
||||
<div class="divider"></div>
|
||||
<a class="row no-wrap">
|
||||
<div class="col min"><img src="/youtube.png"></div>
|
||||
<div class="col">Youtube Music</div>
|
||||
</a><a class="row no-wrap">
|
||||
<div class="col min"><img src="/youtube.png"></div>
|
||||
<div class="col">Youtube Kids</div>
|
||||
</a></div>
|
||||
</button>
|
||||
<button data-ui="#modal-notifications" class="none color-2-text active"><i>notifications</i></button>
|
||||
<a href="/"><img src="/favicon.png" class="circle"></a></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,9 @@
|
|||
<script>
|
||||
import Menu from "../components/Menu.svelte";
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Blue West - Start</title>
|
||||
</svelte:head>
|
||||
|
||||
<Menu/>
|
|
@ -0,0 +1,166 @@
|
|||
<svelte:head>
|
||||
<title>Blue West - Users</title>
|
||||
</svelte:head>
|
||||
<script>
|
||||
import {onMount} from "svelte";
|
||||
import {AddUser, DeleteUser, GetUsers, UpdateUser} from "../tools/RestExtensions";
|
||||
import {UserUpdateDto} from "../tools/Dtos";
|
||||
import Menu from "../components/Menu.svelte";
|
||||
let users;
|
||||
let loaded = false;
|
||||
let addUserEnabled = false;
|
||||
let userEditTemp = undefined;
|
||||
|
||||
const menuDefinition = {
|
||||
title: 'Add User',
|
||||
cb: onAddUserClicked
|
||||
}
|
||||
|
||||
function addUser(user){
|
||||
users = [...users, user]
|
||||
}
|
||||
|
||||
function removeUser(id ) {
|
||||
users = users.filter((u) => u.id !== id);
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
await GetUsers().then(res => {
|
||||
users = res.users;
|
||||
loaded = true;
|
||||
})
|
||||
})
|
||||
|
||||
function onEditUserClicked(user) {
|
||||
userEditTemp = user;
|
||||
}
|
||||
|
||||
function onAddUserClicked(userId) {
|
||||
userEditTemp = new UserUpdateDto();
|
||||
addUserEnabled = true;
|
||||
}
|
||||
|
||||
function onAddUserSaveClicked(userId) {
|
||||
AddUser(userEditTemp);
|
||||
addUser(userEditTemp);
|
||||
userEditTemp = undefined;
|
||||
addUserEnabled = false;
|
||||
}
|
||||
|
||||
function onAddUserCancelClicked(userId) {
|
||||
addUserEnabled = false;
|
||||
}
|
||||
|
||||
function onRemoveUserClicked(userId) {
|
||||
DeleteUser(userId);
|
||||
removeUser(userId);
|
||||
}
|
||||
|
||||
function onSaveUserClicked(userId) {
|
||||
let userUpdateDto = UserUpdateDto.ConvertFromUser(userEditTemp);
|
||||
UpdateUser(userId, userUpdateDto);
|
||||
userEditTemp = undefined;
|
||||
}
|
||||
|
||||
function onSaveUserCancelClicked(userId) {
|
||||
userEditTemp = undefined;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<Menu menuDefinition={menuDefinition}/>
|
||||
<div class="table-container">
|
||||
{#if !loaded}
|
||||
<a class="loader large"></a>
|
||||
{/if}
|
||||
{#if loaded}
|
||||
<table class="pure-table">
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Address</th>
|
||||
<th>BTC Address</th>
|
||||
<th>BTC Amount</th>
|
||||
<th>LTC Address</th>
|
||||
<th>LTC Amount</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{#each users as user}
|
||||
{#if userEditTemp !== undefined && userEditTemp.id === user.id && !addUserEnabled}
|
||||
<tr>
|
||||
<td>{user.id}</td>
|
||||
<td><input type="text" bind:value={userEditTemp['name']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['address']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['btcAddress']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['btcAmount']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['ltcAddress']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['ltcAmount']} ></td>
|
||||
|
||||
<td>
|
||||
<button class="pure-button" on:click={() => onSaveUserClicked(user.id)}>Save</button>
|
||||
<button class="pure-button" on:click={() => onSaveUserCancelClicked()}>Cancel</button>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{:else}
|
||||
<tr>
|
||||
<td>{user.id}</td>
|
||||
<td>{user.name}</td>
|
||||
<td>{user.address}</td>
|
||||
<td>{user.btcAddress}</td>
|
||||
<td>{user.btcAmount}</td>
|
||||
<td>{user.ltcAddress}</td>
|
||||
<td>{user.ltcAmount}</td>
|
||||
|
||||
<td>
|
||||
<div class="buttons-container">
|
||||
<div class="table-button" on:click={() => onEditUserClicked(user)}>
|
||||
<i class="large">edit</i>
|
||||
</div>
|
||||
<div class="table-button" on:click={() => onRemoveUserClicked(user.id)}>
|
||||
<i class="large">remove</i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
|
||||
{/each}
|
||||
|
||||
{#if addUserEnabled}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><input type="text" bind:value={userEditTemp['name']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['address']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['btcAddress']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['btcAmount']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['ltcAddress']}></td>
|
||||
<td><input type="text" bind:value={userEditTemp['ltcAmount']} ></td>
|
||||
|
||||
<td>
|
||||
<button class="pure-button" on:click={() => onAddUserSaveClicked()}>Save</button>
|
||||
<button class="pure-button" on:click={() => onAddUserCancelClicked()}>Cancel</button>
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.table-container {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
input {
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
.buttons-container{
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,14 @@
|
|||
export class UserUpdateDto{
|
||||
constructor(name='', address='', btcAddress='', ltcAddress='', btcAmount='', ltcAmount='') {
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.btcAddress = btcAddress;
|
||||
this.ltcAddress = ltcAddress;
|
||||
this.btcAmount = btcAmount;
|
||||
this.ltcAmount = ltcAmount;
|
||||
}
|
||||
|
||||
static ConvertFromUser(user) {
|
||||
return new UserUpdateDto(user.name, user.address, user.btcAddress, user.ltcAddress, user.btcAmount, user.ltcAmount);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
async function RestRequest(url = '', type = 'get', data = {}) {
|
||||
|
||||
let answerData =
|
||||
{
|
||||
"credentials": "omit",
|
||||
"headers": {
|
||||
"Sec-Fetch-Dest": "empty",
|
||||
"Sec-Fetch-Mode": "no-cors",
|
||||
"Sec-Fetch-Site": "cross-site",
|
||||
"Pragma": "no-cache",
|
||||
"Cache-Control": "no-cache"
|
||||
}
|
||||
}
|
||||
|
||||
if (type.toLowerCase() === 'post' || type.toLowerCase() === 'put') {
|
||||
answerData['headers']['Content-Type'] = "application/json-patch+json";
|
||||
answerData['body'] = JSON.stringify(data);
|
||||
}
|
||||
|
||||
answerData['method'] = type.toUpperCase();
|
||||
|
||||
let response = await fetch(url, answerData);
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export function UpdateUser(userId, userData) {
|
||||
return RestRequest(`https://localhost:5001/User/${userId}`, 'put', userData);
|
||||
}
|
||||
|
||||
export function DeleteUser(userId) {
|
||||
return RestRequest(`https://localhost:5001/User/${userId}`, 'delete');
|
||||
}
|
||||
|
||||
export function AddUser(userData) {
|
||||
console.log(userData)
|
||||
return RestRequest(`https://localhost:5001/User`, 'post', userData);
|
||||
}
|
||||
|
||||
export function GetUsers() {
|
||||
return RestRequest("https://localhost:5001/User");
|
||||
}
|
||||
|
||||
export function GetUserById(id) {
|
||||
RestRequest(`http://localhost:5000/User/${id}`).then((res) => {
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,485 @@
|
|||
/*!
|
||||
* Bootstrap Reboot v5.1.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2021 The Bootstrap Authors
|
||||
* Copyright 2011-2021 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
:root {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-bg: #fff;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
background-color: currentColor;
|
||||
border: 0;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
hr:not([size]) {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-bs-original-title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.2em;
|
||||
background-color: #fcf8e3;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0d6efd;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
color: #0a58ca;
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
direction: ltr /* rtl:ignore */;
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: #d63384;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.2rem 0.4rem;
|
||||
font-size: 0.875em;
|
||||
color: #fff;
|
||||
background-color: #212529;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]::-webkit-calendar-picker-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: left;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
|
||||
/* rtl:raw:
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
*/
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,482 @@
|
|||
/*!
|
||||
* Bootstrap Reboot v5.1.3 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2021 The Bootstrap Authors
|
||||
* Copyright 2011-2021 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
:root {
|
||||
--bs-blue: #0d6efd;
|
||||
--bs-indigo: #6610f2;
|
||||
--bs-purple: #6f42c1;
|
||||
--bs-pink: #d63384;
|
||||
--bs-red: #dc3545;
|
||||
--bs-orange: #fd7e14;
|
||||
--bs-yellow: #ffc107;
|
||||
--bs-green: #198754;
|
||||
--bs-teal: #20c997;
|
||||
--bs-cyan: #0dcaf0;
|
||||
--bs-white: #fff;
|
||||
--bs-gray: #6c757d;
|
||||
--bs-gray-dark: #343a40;
|
||||
--bs-gray-100: #f8f9fa;
|
||||
--bs-gray-200: #e9ecef;
|
||||
--bs-gray-300: #dee2e6;
|
||||
--bs-gray-400: #ced4da;
|
||||
--bs-gray-500: #adb5bd;
|
||||
--bs-gray-600: #6c757d;
|
||||
--bs-gray-700: #495057;
|
||||
--bs-gray-800: #343a40;
|
||||
--bs-gray-900: #212529;
|
||||
--bs-primary: #0d6efd;
|
||||
--bs-secondary: #6c757d;
|
||||
--bs-success: #198754;
|
||||
--bs-info: #0dcaf0;
|
||||
--bs-warning: #ffc107;
|
||||
--bs-danger: #dc3545;
|
||||
--bs-light: #f8f9fa;
|
||||
--bs-dark: #212529;
|
||||
--bs-primary-rgb: 13, 110, 253;
|
||||
--bs-secondary-rgb: 108, 117, 125;
|
||||
--bs-success-rgb: 25, 135, 84;
|
||||
--bs-info-rgb: 13, 202, 240;
|
||||
--bs-warning-rgb: 255, 193, 7;
|
||||
--bs-danger-rgb: 220, 53, 69;
|
||||
--bs-light-rgb: 248, 249, 250;
|
||||
--bs-dark-rgb: 33, 37, 41;
|
||||
--bs-white-rgb: 255, 255, 255;
|
||||
--bs-black-rgb: 0, 0, 0;
|
||||
--bs-body-color-rgb: 33, 37, 41;
|
||||
--bs-body-bg-rgb: 255, 255, 255;
|
||||
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
|
||||
--bs-body-font-family: var(--bs-font-sans-serif);
|
||||
--bs-body-font-size: 1rem;
|
||||
--bs-body-font-weight: 400;
|
||||
--bs-body-line-height: 1.5;
|
||||
--bs-body-color: #212529;
|
||||
--bs-body-bg: #fff;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
:root {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--bs-body-font-family);
|
||||
font-size: var(--bs-body-font-size);
|
||||
font-weight: var(--bs-body-font-weight);
|
||||
line-height: var(--bs-body-line-height);
|
||||
color: var(--bs-body-color);
|
||||
text-align: var(--bs-body-text-align);
|
||||
background-color: var(--bs-body-bg);
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 1rem 0;
|
||||
color: inherit;
|
||||
background-color: currentColor;
|
||||
border: 0;
|
||||
opacity: 0.25;
|
||||
}
|
||||
|
||||
hr:not([size]) {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
h6, h5, h4, h3, h2, h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: calc(1.375rem + 1.5vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: calc(1.325rem + 0.9vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: calc(1.3rem + 0.6vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h3 {
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
h4 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-bs-original-title] {
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: 0.5rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
mark {
|
||||
padding: 0.2em;
|
||||
background-color: #fcf8e3;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0d6efd;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a:hover {
|
||||
color: #0a58ca;
|
||||
}
|
||||
|
||||
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: var(--bs-font-monospace);
|
||||
font-size: 1em;
|
||||
direction: ltr ;
|
||||
unicode-bidi: bidi-override;
|
||||
}
|
||||
|
||||
pre {
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
pre code {
|
||||
font-size: inherit;
|
||||
color: inherit;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 0.875em;
|
||||
color: #d63384;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
a > code {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
kbd {
|
||||
padding: 0.2rem 0.4rem;
|
||||
font-size: 0.875em;
|
||||
color: #fff;
|
||||
background-color: #212529;
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
kbd kbd {
|
||||
padding: 0;
|
||||
font-size: 1em;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img,
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
caption-side: bottom;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
color: #6c757d;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
text-align: -webkit-match-parent;
|
||||
}
|
||||
|
||||
thead,
|
||||
tbody,
|
||||
tfoot,
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus:not(:focus-visible) {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role=button] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
select:disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[list]::-webkit-calendar-picker-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button,
|
||||
[type=button],
|
||||
[type=reset],
|
||||
[type=submit] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
button:not(:disabled),
|
||||
[type=button]:not(:disabled),
|
||||
[type=reset]:not(:disabled),
|
||||
[type=submit]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
float: right;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: calc(1.275rem + 0.3vw);
|
||||
line-height: inherit;
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
legend {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
legend + * {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
::-webkit-datetime-edit-fields-wrapper,
|
||||
::-webkit-datetime-edit-text,
|
||||
::-webkit-datetime-edit-minute,
|
||||
::-webkit-datetime-edit-hour-field,
|
||||
::-webkit-datetime-edit-day-field,
|
||||
::-webkit-datetime-edit-month-field,
|
||||
::-webkit-datetime-edit-year-field {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-inner-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type=search] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: textfield;
|
||||
}
|
||||
|
||||
[type="tel"],
|
||||
[type="url"],
|
||||
[type="email"],
|
||||
[type="number"] {
|
||||
direction: ltr;
|
||||
}
|
||||
::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-color-swatch-wrapper {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
iframe {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,9 @@
|
|||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
kit: {
|
||||
// hydrate the <div id="svelte"> element in src/app.html
|
||||
target: '#svelte'
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
|
@ -0,0 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>9</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.2.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BlueWest\BlueWest.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,131 @@
|
|||
using BlueWest.Data;
|
||||
using BlueWest.WebApi.Tools;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using PerformanceSolution.Data;
|
||||
|
||||
namespace BlueWest.WebApi.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[HttpGet]
|
||||
public ActionResult Get()
|
||||
{
|
||||
if (MemoryData.UserList != null)
|
||||
{
|
||||
return Ok(MemoryData.UserList);
|
||||
|
||||
}
|
||||
|
||||
return new NotFoundResult();
|
||||
}
|
||||
|
||||
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[HttpGet("{userId}", Name = nameof(GetUserById))]
|
||||
public ActionResult GetUserById(int userId)
|
||||
{
|
||||
User user = MemoryData.GetUserById(userId);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
return Ok(user);
|
||||
|
||||
}
|
||||
|
||||
return new NotFoundResult();
|
||||
}
|
||||
|
||||
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[HttpGet("{userId}/transactions")]
|
||||
public ActionResult GetTransactions(int userId)
|
||||
{
|
||||
var user = MemoryData.GetUserById(userId);
|
||||
var transactions = user.FinanceTransactions;
|
||||
if (transactions != null)
|
||||
{
|
||||
return Ok(transactions);
|
||||
|
||||
}
|
||||
return new NotFoundResult();
|
||||
}
|
||||
|
||||
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[HttpGet("{userId}/transactions/{transactionId}")]
|
||||
public ActionResult GetTransactionsById(int userId, int transactionId)
|
||||
{
|
||||
var user = MemoryData.GetUserById(userId);
|
||||
|
||||
var transactions = user?.FinanceTransactions;
|
||||
|
||||
FinanceTransaction? transaction = transactions?.FirstOrNull(t => t.Id == transactionId);
|
||||
|
||||
if (transaction != null)
|
||||
{
|
||||
return Ok(transaction);
|
||||
}
|
||||
|
||||
return new NotFoundResult();
|
||||
}
|
||||
|
||||
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
[HttpPost]
|
||||
public ActionResult AddOrModifyUser(UserUpdateDto userUpdateDto)
|
||||
{
|
||||
var user = MemoryData.AddOrModify(userUpdateDto);
|
||||
return CreatedAtRoute(nameof(GetUserById), new {userId = user.Id}, user);
|
||||
}
|
||||
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[HttpPut("{userId}")]
|
||||
public ActionResult UpdateUser(int userId, UserUpdateDto userUpdate)
|
||||
{
|
||||
var result = MemoryData.UpdateUser(userId, userUpdate);
|
||||
|
||||
if (result != null) return Ok(result);
|
||||
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[HttpDelete("{id}")]
|
||||
public ActionResult DeleteUser(int id)
|
||||
{
|
||||
|
||||
bool result = MemoryData.RemoveUser(id);
|
||||
|
||||
if (result)
|
||||
{
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
return new BadRequestResult();
|
||||
}
|
||||
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[HttpPost("{userId}/transactions")]
|
||||
public ActionResult PostTransaction(int userId, FinanceTransaction financeTransaction)
|
||||
{
|
||||
FinanceTransaction? result = MemoryData.AddFinanceTransaction(userId, financeTransaction);
|
||||
|
||||
if(result != null) return Ok(result);
|
||||
|
||||
return new BadRequestResult();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BlueWest.Collections;
|
||||
using BlueWest.Core;
|
||||
using BlueWest.Tools;
|
||||
|
||||
namespace BlueWest.WebApi
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static readonly EventManager EventManager =
|
||||
new EventManager(new FastDictionary<Type, FastList<EventListenerBase>>(10000));
|
||||
|
||||
private static ThreadServer _threadServer;
|
||||
|
||||
public static IHost Host1 { get; private set; }
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Host1 = CreateHostBuilder(args).Build();
|
||||
Host1.RunAsync();
|
||||
System.Threading.Thread.Sleep(2500);
|
||||
_threadServer = new ThreadServer(EventManager);
|
||||
BlueWestConsoleBanner();
|
||||
_threadServer.Init();
|
||||
}
|
||||
|
||||
private static void BlueWestConsoleBanner()
|
||||
{
|
||||
Console.WriteLine(" |------------------------------«");
|
||||
Console.WriteLine(" » Blue West «");
|
||||
Console.WriteLine(" |------------------------------«\n");
|
||||
}
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:65056",
|
||||
"sslPort": 44398
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"BlueWest.WebApi": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace BlueWest.WebApi.Service
|
||||
{
|
||||
public readonly struct CommandEvent
|
||||
{
|
||||
|
||||
}
|
||||
public class CommandService
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BlueWest.WebApi.Tools;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace BlueWest.WebApi
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy(name: MyAllowSpecificOrigins,
|
||||
builder =>
|
||||
{
|
||||
builder.WithOrigins("http://localhost", "http://127.0.0.1", "http://localhost:3000",
|
||||
"http://127.0.0.1:3000", "localhost:3000", "127.0.0.1:3000")
|
||||
.AllowAnyHeader().AllowAnyMethod();
|
||||
});
|
||||
});
|
||||
|
||||
services.AddControllers().AddNewtonsoftJson();
|
||||
/*services
|
||||
.AddNewtonsoftJson(options =>
|
||||
options.SerializerSettings.Converters.Add(new StringEnumConverter()));
|
||||
// order is vital, this *must* be called *after* AddNewtonsoftJson()
|
||||
services.AddSwaggerGenNewtonsoftSupport();*/
|
||||
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.SchemaFilter<SwaggerEnumSchemaFilter>();
|
||||
options.SwaggerDoc("v1", new OpenApiInfo
|
||||
{
|
||||
Title = "BlueWest.WebApi",
|
||||
Version = "v1"
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "BlueWest.WebApi v1"));
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseRouting();
|
||||
app.UseCors(MyAllowSpecificOrigins);
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BlueWest.WebApi.Tools
|
||||
{
|
||||
public static class IEnumerableExtensions
|
||||
{
|
||||
|
||||
public static TSource? FirstOrNull<TSource>(this TSource[] source, Func<TSource, bool> predicate) where TSource : struct =>
|
||||
source.TryGetFirst(predicate);
|
||||
|
||||
private static TSource? TryGetFirst<TSource>(this TSource[] source, Func<TSource, bool> predicate) where TSource : struct
|
||||
{
|
||||
for (var i = 0; i < source.Length; i++)
|
||||
{
|
||||
if (predicate(source[i]))
|
||||
{
|
||||
return source[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TSource? FirstOrNull<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) where TSource : struct =>
|
||||
source.TryGetFirst(predicate);
|
||||
|
||||
private static TSource? TryGetFirst<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) where TSource : struct
|
||||
{
|
||||
foreach (TSource obj in source)
|
||||
{
|
||||
if (predicate(obj))
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace BlueWest.WebApi.Tools
|
||||
{
|
||||
public class SwaggerEnumSchemaFilter : ISchemaFilter
|
||||
{
|
||||
public void Apply(OpenApiSchema model, SchemaFilterContext context)
|
||||
{
|
||||
if (context.Type.IsEnum)
|
||||
{
|
||||
model.Enum.Clear();
|
||||
Enum.GetNames(context.Type)
|
||||
.ToList()
|
||||
.ForEach(n => model.Enum.Add(new OpenApiString(n)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace BlueWest.WebApi
|
||||
{
|
||||
public class WeatherForecast
|
||||
{
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
public int TemperatureC { get; set; }
|
||||
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
|
||||
public string Summary { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest", "BlueWest\BlueWest.csproj", "{293E7852-8AFD-4EFB-8C2D-F1BBE68AEE78}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.Data", "BlueWest.Data\BlueWest.Data.csproj", "{E518C62D-768C-4885-9C9D-FD5761605B54}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.WebApi", "BlueWest.WebApi\BlueWest.WebApi.csproj", "{6D3321B5-CF1A-4251-B28D-329EDA6DC278}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.Collections", "BlueWest.Collections\BlueWest.Collections.csproj", "{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.DataAgent", "BlueWest.DataAgent\BlueWest.DataAgent.csproj", "{DB41747D-C425-42A2-B5E5-E1A29E13D1F8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapTo", "MapTo\src\MapTo\MapTo.csproj", "{7D8CF461-E20D-48A0-981C-5B60792C56C8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{293E7852-8AFD-4EFB-8C2D-F1BBE68AEE78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{293E7852-8AFD-4EFB-8C2D-F1BBE68AEE78}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{293E7852-8AFD-4EFB-8C2D-F1BBE68AEE78}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{293E7852-8AFD-4EFB-8C2D-F1BBE68AEE78}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E518C62D-768C-4885-9C9D-FD5761605B54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E518C62D-768C-4885-9C9D-FD5761605B54}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E518C62D-768C-4885-9C9D-FD5761605B54}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E518C62D-768C-4885-9C9D-FD5761605B54}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6D3321B5-CF1A-4251-B28D-329EDA6DC278}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6D3321B5-CF1A-4251-B28D-329EDA6DC278}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6D3321B5-CF1A-4251-B28D-329EDA6DC278}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6D3321B5-CF1A-4251-B28D-329EDA6DC278}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F55019A2-E2A8-4AF1-8FBC-FA99476A1B1C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DB41747D-C425-42A2-B5E5-E1A29E13D1F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DB41747D-C425-42A2-B5E5-E1A29E13D1F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DB41747D-C425-42A2-B5E5-E1A29E13D1F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DB41747D-C425-42A2-B5E5-E1A29E13D1F8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7D8CF461-E20D-48A0-981C-5B60792C56C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7D8CF461-E20D-48A0-981C-5B60792C56C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7D8CF461-E20D-48A0-981C-5B60792C56C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7D8CF461-E20D-48A0-981C-5B60792C56C8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using BlueWest.Core.ComponentSystem;
|
||||
using BlueWest.Tools;
|
||||
using PerformanceSolution.Data;
|
||||
|
||||
namespace PerformanceSolution.Artefacts
|
||||
{
|
||||
public enum CommandRequestEventType
|
||||
{
|
||||
GetUsers, GetUserById
|
||||
}
|
||||
public readonly struct CommandRequestEvent
|
||||
{
|
||||
public readonly CommandRequestEventType CommandRequestEventType;
|
||||
public readonly int Id;
|
||||
|
||||
public CommandRequestEvent(CommandRequestEventType commandRequestEventType, int id = 0)
|
||||
{
|
||||
CommandRequestEventType = commandRequestEventType;
|
||||
Id = id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class AccountArtefact : Artefact, EventListener<CommandRequestEvent>
|
||||
{
|
||||
public AccountArtefact()
|
||||
{
|
||||
Frequency = ArtefactFrequency.T10Hz;
|
||||
LoopEnabled = false;
|
||||
}
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
_eventManager.EventStartListening(this);
|
||||
}
|
||||
|
||||
|
||||
private void GetAllUsersInConsole()
|
||||
{
|
||||
var data = MemoryData.UserList;
|
||||
if (data != null)
|
||||
{
|
||||
Console.WriteLine(MemoryData.UserList.ToString());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void GetUserByIdInConsole(int id)
|
||||
{
|
||||
var user = MemoryData.GetUserById(id);
|
||||
if (user != null)
|
||||
{
|
||||
Console.WriteLine(user.ToString());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void OnEvent(CommandRequestEvent commandRequestEvent)
|
||||
{
|
||||
switch (commandRequestEvent.CommandRequestEventType)
|
||||
{
|
||||
case CommandRequestEventType.GetUserById:
|
||||
GetUserByIdInConsole(commandRequestEvent.Id);
|
||||
break;
|
||||
case CommandRequestEventType.GetUsers:
|
||||
GetAllUsersInConsole();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using BlueWest.Core.ComponentSystem;
|
||||
using BlueWest.Tools;
|
||||
using PerformanceSolution.Artefacts;
|
||||
|
||||
namespace BlueWest.Core
|
||||
{
|
||||
public sealed class BlueConsole : Artefact
|
||||
{
|
||||
private static string _consolePrompt = ">> ";
|
||||
|
||||
public BlueConsole()
|
||||
{
|
||||
Frequency = ArtefactFrequency.T3Hz;
|
||||
}
|
||||
|
||||
public static void Log(object message)
|
||||
{
|
||||
Console.WriteLine($"Logging: {message}");
|
||||
}
|
||||
|
||||
private static void InternalLog(object message)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
protected override void Update(double delta)
|
||||
{
|
||||
Console.Write(_consolePrompt);
|
||||
var input = Console.ReadLine();
|
||||
ParseInput(input);
|
||||
}
|
||||
|
||||
void ParseInput(string? input)
|
||||
{
|
||||
if (input != null)
|
||||
{
|
||||
input = input.ToLower();
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
}
|
||||
|
||||
else if (input == "clear")
|
||||
{
|
||||
Console.Clear();
|
||||
}
|
||||
else if (input == "time")
|
||||
{
|
||||
//Console.WriteLine(Time.time);
|
||||
}
|
||||
else if (input == "user")
|
||||
{
|
||||
_eventManager.TriggerEvent(new CommandRequestEvent(CommandRequestEventType.GetUsers));
|
||||
//Console.WriteLine(Time.time);
|
||||
}
|
||||
else if (input.StartsWith("user"))
|
||||
{
|
||||
var a = input.Split(" ");
|
||||
int id;
|
||||
if (int.TryParse(a[1], out id))
|
||||
{
|
||||
_eventManager.TriggerEvent(new CommandRequestEvent(CommandRequestEventType.GetUserById, id));
|
||||
}
|
||||
//Console.WriteLine(Time.time);
|
||||
}
|
||||
|
||||
else if (input == "assembly")
|
||||
{
|
||||
AssemblyCommand();
|
||||
}
|
||||
else if (input.StartsWith("ls"))
|
||||
{
|
||||
LsCommand(input);
|
||||
}
|
||||
else if (input == "pwd")
|
||||
{
|
||||
PwdCommand();
|
||||
}
|
||||
|
||||
else if (input == "memory")
|
||||
{
|
||||
MemoryCommand();
|
||||
}
|
||||
else if (input.StartsWith("mkdir"))
|
||||
{
|
||||
MkdirCommand(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
InternalLog("# Command not recognized");
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssemblyCommand()
|
||||
{
|
||||
var assemblyPath = AssemblyUtils.GetAssemblyPath();
|
||||
Console.WriteLine(assemblyPath);
|
||||
}
|
||||
|
||||
private static void MkdirCommand(string? input)
|
||||
{
|
||||
var argument = input.Split(" ");
|
||||
if (argument.Length > 1 && argument[0] != "")
|
||||
{
|
||||
PathUtils.CreateDirectory(argument[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
Log("Error creating folder");
|
||||
}
|
||||
|
||||
private static void MemoryCommand()
|
||||
{
|
||||
var memory = AssemblyUtils.GetProcessMemory();
|
||||
InternalLog(memory);
|
||||
}
|
||||
|
||||
private static void PwdCommand()
|
||||
{
|
||||
var pwd = AssemblyUtils.GetAssemblyPath();
|
||||
InternalLog(pwd);
|
||||
}
|
||||
|
||||
private static void LsCommand(string? input)
|
||||
{
|
||||
var split = input.Split(" ");
|
||||
|
||||
foreach (var name in split)
|
||||
{
|
||||
if (name == "ls") continue;
|
||||
if (string.IsNullOrWhiteSpace(name)) continue;
|
||||
var assPath = AssemblyUtils.GetAssemblyPath();
|
||||
var fp = Path.GetFullPath(name);
|
||||
InternalLog(PathUtils.ListAll(fp));
|
||||
return;
|
||||
}
|
||||
|
||||
var pathFiles = PathUtils.ListAssemblyPathFiles();
|
||||
|
||||
InternalLog(pathFiles);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using BlueWest.Core;
|
||||
using BlueWest.Core.ComponentSystem;
|
||||
|
||||
namespace BlueWest.Artefacts
|
||||
{
|
||||
public class WorldArtefact: Artefact
|
||||
{
|
||||
|
||||
public WorldArtefact()
|
||||
{
|
||||
Frequency = ArtefactFrequency.T30Hz;
|
||||
}
|
||||
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
AddComponent<TimeManagement>();
|
||||
//BlueConsole.Log("World Artefact started");
|
||||
}
|
||||
|
||||
protected override void Update(double delta)
|
||||
{
|
||||
base.Update(delta);
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<RootNamespace>PerformanceSolution</RootNamespace>
|
||||
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BlueWest.Collections\BlueWest.Collections.csproj" />
|
||||
<ProjectReference Include="..\BlueWest.Data\BlueWest.Data.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MessagePack" Version="2.3.85" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="6.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using BlueWest.Core;
|
||||
using BlueWest.Core.ComponentSystem;
|
||||
using BlueWest.Coroutines;
|
||||
using BlueWest.Tools;
|
||||
|
||||
namespace BlueWest.Artefacts
|
||||
{
|
||||
public class TimeManagement : Component
|
||||
{
|
||||
public TimeManagement(EventManager eventManager) : base(eventManager) { }
|
||||
|
||||
public override void Update(double delta)
|
||||
{
|
||||
Time.time += delta;
|
||||
Time.deltaTime = delta;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System.Collections;
|
||||
using BlueWest.Collections;
|
||||
using BlueWest.Coroutines;
|
||||
using BlueWest.Tools;
|
||||
|
||||
namespace BlueWest.Core.ComponentSystem
|
||||
{
|
||||
public class Component
|
||||
{
|
||||
protected readonly EventManager _eventManager;
|
||||
|
||||
public bool IsActive { get; private set; } = true;
|
||||
|
||||
private readonly FastDictionary<int, IEnumerator> _coroutines = new FastDictionary<int, IEnumerator>(10000);
|
||||
|
||||
private int _coroutineCount = 0;
|
||||
|
||||
public Component(EventManager eventManager)
|
||||
{
|
||||
_eventManager = eventManager;
|
||||
}
|
||||
|
||||
public void StartCoroutine(IEnumerator routine)
|
||||
{
|
||||
_coroutines.Add(_coroutineCount, routine);
|
||||
_coroutineCount++;
|
||||
}
|
||||
|
||||
public void HandleCoroutines()
|
||||
{
|
||||
for (var i = 0; i < _coroutineCount; i++)
|
||||
{
|
||||
var yielded = _coroutines[i].Current is CustomYieldInstruction yielder && yielder.MoveNext();
|
||||
|
||||
if (yielded || _coroutines[i].MoveNext()) continue;
|
||||
_coroutines.Remove(i);
|
||||
_coroutineCount--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
public void EveryFrame(double delta)
|
||||
{
|
||||
if (!IsActive) return;
|
||||
Update(delta);
|
||||
HandleCoroutines();
|
||||
}
|
||||
|
||||
public virtual void Update(double delta) { }
|
||||
|
||||
public virtual void Start() { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace BlueWest.Tools
|
||||
{
|
||||
public static class PathUtils
|
||||
{
|
||||
public static void CreateDirectory(string directory)
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
private static string ListDirectories(string path)
|
||||
{
|
||||
var dirInfo = new DirectoryInfo(path);
|
||||
var sb = new StringBuilder();
|
||||
|
||||
|
||||
var dirs = dirInfo.EnumerateDirectories("*", new EnumerationOptions
|
||||
{ RecurseSubdirectories = false });
|
||||
|
||||
foreach (var name in dirs)
|
||||
{
|
||||
if (name.Name != "") sb.Append(name.Name + "\n");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string ListFiles(string path)
|
||||
{
|
||||
DirectoryInfo d = new(path);
|
||||
|
||||
FileInfo[] files = d.GetFiles();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
sb.Append(file.Name) ;
|
||||
if (i == files.Length - 1) continue;
|
||||
sb.Append("\n") ;
|
||||
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string ListAssemblyPathFiles()
|
||||
{
|
||||
var assemblyLcation = AssemblyUtils.GetAssemblyPath();
|
||||
return ListAll(assemblyLcation);
|
||||
}
|
||||
|
||||
|
||||
internal static string ListAll(string path)
|
||||
{
|
||||
var result = "";
|
||||
result += "-- Files:\n";
|
||||
result += ListFiles(path);
|
||||
result += "\n-- Folders:\n";
|
||||
result += ListDirectories(path);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BlueWest.Coroutines
|
||||
{
|
||||
public sealed class Coroutine : CustomYieldInstruction
|
||||
{
|
||||
private readonly IEnumerator routine;
|
||||
|
||||
public Coroutine(IEnumerator routine)
|
||||
{
|
||||
this.routine = routine;
|
||||
}
|
||||
|
||||
public override bool keepWaiting => routine.MoveNext();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BlueWest.Coroutines
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public abstract class CustomYieldInstruction : IEnumerator
|
||||
{
|
||||
public abstract bool keepWaiting { get; }
|
||||
|
||||
//
|
||||
// Properties
|
||||
//
|
||||
public object Current => null;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
public bool MoveNext()
|
||||
{
|
||||
return keepWaiting;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
namespace BlueWest.Coroutines
|
||||
{
|
||||
public class WaitForSeconds : CustomYieldInstruction
|
||||
{
|
||||
public double finishTime;
|
||||
|
||||
public WaitForSeconds(double seconds)
|
||||
{
|
||||
finishTime = Time.time + seconds;
|
||||
}
|
||||
|
||||
public override bool keepWaiting => finishTime > Time.time;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
using System;
|
||||
using BlueWest.Collections;
|
||||
|
||||
namespace BlueWest.Tools
|
||||
{
|
||||
|
||||
public sealed class EventManager
|
||||
{
|
||||
private readonly FastDictionary<Type, FastList<EventListenerBase>> _subscribersList;
|
||||
|
||||
private static EventManager _instance;
|
||||
|
||||
public EventManager(FastDictionary<Type, FastList<EventListenerBase>> subscribersList)
|
||||
{
|
||||
_subscribersList = subscribersList;
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Adds a new subscriber to a certain event.
|
||||
/// </suary>
|
||||
/// <param name="listener">listener.</param>
|
||||
/// <typeparam name="TEvent">The event type.</typeparam>
|
||||
public void AddListener<TEvent>( EventListener<TEvent> listener ) where TEvent : struct
|
||||
{
|
||||
var eventType = typeof( TEvent );
|
||||
|
||||
if( !_subscribersList.ContainsKey( eventType ) )
|
||||
_subscribersList[eventType] = new FastList<EventListenerBase>(10000);
|
||||
|
||||
//if( !SubscriptionExists( eventType, listener ) )
|
||||
_subscribersList[eventType].Add( listener );
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Removes a subscriber from a certain event.
|
||||
/// </suary>
|
||||
/// <param name="listener">listener.</param>
|
||||
/// <typeparam name="TEvent">The event type.</typeparam>
|
||||
public void RemoveListener<TEvent>( EventListener<TEvent> listener ) where TEvent : struct
|
||||
{
|
||||
var eventType = typeof( TEvent );
|
||||
|
||||
FastList<EventListenerBase> subscriberList = _subscribersList[eventType];
|
||||
|
||||
for (int i = 0; i<subscriberList.Length; i++)
|
||||
{
|
||||
if( subscriberList.Buffer[i] == listener )
|
||||
{
|
||||
subscriberList.Remove( subscriberList[i] );
|
||||
|
||||
if( subscriberList.Length == 0 )
|
||||
_subscribersList.Remove( eventType );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Triggers an event. All instances that are subscribed to it will receive it (and will potentially act on it).
|
||||
/// </suary>
|
||||
/// <param name="newEvent">The event to trigger.</param>
|
||||
/// <typeparam name="TEvent">The 1st type parameter.</typeparam>
|
||||
public void TriggerEvent<TEvent>( TEvent newEvent ) where TEvent : struct
|
||||
{
|
||||
var type = typeof(TEvent);
|
||||
|
||||
#if DEBUG
|
||||
|
||||
if (!_subscribersList.ContainsKey(type))
|
||||
{
|
||||
Console.WriteLine($"{type.FullName} has no actual trigger, fix it...");
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
FastList<EventListenerBase> list = _subscribersList[type];
|
||||
|
||||
for (int i=0; i<list.Length; i++)
|
||||
{
|
||||
var eventListener = list.Buffer[i];
|
||||
var casted = eventListener as EventListener<TEvent>;
|
||||
casted.OnEvent( newEvent );
|
||||
}
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Checks if there are subscribers for a certain type of events
|
||||
/// </suary>
|
||||
/// <returns><c>true</c>, if exists was subscriptioned, <c>false</c> otherwise.</returns>
|
||||
/// <param name="type">Type.</param>
|
||||
/// <param name="receiver">Receiver.</param>
|
||||
private bool SubscriptionExists( Type type, EventListenerBase receiver )
|
||||
{
|
||||
FastList<EventListenerBase> receivers;
|
||||
|
||||
if( !_subscribersList.TryGetValue( type, out receivers ) ) return false;
|
||||
|
||||
bool exists = false;
|
||||
|
||||
for (int i=0; i<receivers.Length; i++)
|
||||
{
|
||||
if( receivers.Buffer[i] == receiver )
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
public void EventStartListening<EventType>( EventListener<EventType> caller ) where EventType : struct
|
||||
{
|
||||
AddListener<EventType>( caller );
|
||||
}
|
||||
|
||||
public void EventStopListening<EventType>( EventListener<EventType> caller ) where EventType : struct
|
||||
{
|
||||
RemoveListener<EventType>( caller );
|
||||
}
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Static class that allows any class to start or stop listening to events
|
||||
/// </suary>
|
||||
public static class EventRegister
|
||||
{
|
||||
public delegate void Delegate<T>( T eventType );
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// TEvent listener basic interface
|
||||
/// </suary>
|
||||
public interface EventListenerBase { };
|
||||
|
||||
/// <suary>
|
||||
/// A public interface you'll need to implement for each type of event you want to listen to.
|
||||
/// </suary>
|
||||
public interface EventListener<T> : EventListenerBase
|
||||
{
|
||||
void OnEvent( T eventType );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
using System;
|
||||
using BlueWest.Collections;
|
||||
|
||||
namespace BlueWest.Tools
|
||||
{
|
||||
public struct EventManagerAsync
|
||||
{
|
||||
private static readonly FastDictionary<Type, FastList<EventListenerBaseAsync>> _subscribersList;
|
||||
|
||||
static EventManagerAsync()
|
||||
{
|
||||
_subscribersList = new FastDictionary<Type, FastList<EventListenerBaseAsync>>(12412);
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Adds a new subscriber to a certain event.
|
||||
/// </suary>
|
||||
/// <param name="listener">listener.</param>
|
||||
/// <typeparam name="TEvent">The event type.</typeparam>
|
||||
public static void AddListenerAsync<TEventAsync>(EventListenerAsync<TEventAsync> listener)
|
||||
where TEventAsync : struct
|
||||
{
|
||||
var eventType = typeof(TEventAsync);
|
||||
|
||||
if (!_subscribersList.ContainsKey(eventType))
|
||||
_subscribersList[eventType] = new FastList<EventListenerBaseAsync>(10000);
|
||||
|
||||
//if( !SubscriptionExistsAsync( eventType, listener ) )
|
||||
_subscribersList[eventType].Add(listener);
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Removes a subscriber from a certain event.
|
||||
/// </suary>
|
||||
/// <param name="listener">listener.</param>
|
||||
/// <typeparam name="TEvent">The event type.</typeparam>
|
||||
public static void RemoveListenerAsync<TEventAsync>(EventListenerAsync<TEventAsync> listener)
|
||||
where TEventAsync : struct
|
||||
{
|
||||
var eventType = typeof(TEventAsync);
|
||||
|
||||
/*
|
||||
if( !_subscribersList.ContainsKey( eventType ) )
|
||||
{
|
||||
#if EVENTROUTER_THROWEXCEPTIONS
|
||||
throw new ArgumentException( string.Format( "Removing listener \"{0}\", but the event type \"{1}\" isn't registered.", listener, eventType.ToString() ) );
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}*/
|
||||
|
||||
FastList<EventListenerBaseAsync> subscriberList = _subscribersList[eventType];
|
||||
|
||||
for (int i = 0; i < subscriberList.Length; i++)
|
||||
{
|
||||
if (subscriberList.Buffer[i] == listener)
|
||||
{
|
||||
subscriberList.Remove(subscriberList[i]);
|
||||
|
||||
if (subscriberList.Length == 0)
|
||||
_subscribersList.Remove(eventType);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Triggers an event. All instances that are subscribed to it will receive it (and will potentially act on it).
|
||||
/// </suary>
|
||||
/// <param name="newEvent">The event to trigger.</param>
|
||||
/// <typeparam name="TEvent">The 1st type parameter.</typeparam>
|
||||
public static void TriggerEventAsync<TEvent>(TEvent newEvent) where TEvent : struct
|
||||
{
|
||||
var type = typeof(TEvent);
|
||||
|
||||
FastList<EventListenerBaseAsync> list = _subscribersList[type];
|
||||
|
||||
for (int i = 0; i < list.Length; i++)
|
||||
{
|
||||
var baseListener = list.Buffer[i];
|
||||
var eventListenerCasted = baseListener as EventListenerAsync<TEvent>;
|
||||
eventListenerCasted.OnEventAsync(newEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Checks if there are subscribers for a certain type of events
|
||||
/// </suary>
|
||||
/// <returns><c>true</c>, if exists was subscriptioned, <c>false</c> otherwise.</returns>
|
||||
/// <param name="type">Type.</param>
|
||||
/// <param name="receiver">Receiver.</param>
|
||||
private static bool SubscriptionExistsAsync(Type type, EventListenerBaseAsync receiver)
|
||||
{
|
||||
FastList<EventListenerBaseAsync> receivers;
|
||||
|
||||
if (!_subscribersList.TryGetValue(type, out receivers)) return false;
|
||||
|
||||
bool exists = false;
|
||||
|
||||
for (int i = 0; i < receivers.Length; i++)
|
||||
{
|
||||
var eventListenerBase = receivers.Buffer[i];
|
||||
if (eventListenerBase == receiver)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// Static class that allows any class to start or stop listening to events
|
||||
/// </suary>
|
||||
public static class EventRegisterAsync
|
||||
{
|
||||
public delegate void DelegateAsync<T>(T eventType);
|
||||
|
||||
public static void EventStartListeningAsync<EventType>(this EventListenerAsync<EventType> caller)
|
||||
where EventType : struct
|
||||
{
|
||||
EventManagerAsync.AddListenerAsync<EventType>(caller);
|
||||
}
|
||||
|
||||
public static void EventStopListeningAsync<EventType>(this EventListenerAsync<EventType> caller)
|
||||
where EventType : struct
|
||||
{
|
||||
EventManagerAsync.RemoveListenerAsync<EventType>(caller);
|
||||
}
|
||||
}
|
||||
|
||||
/// <suary>
|
||||
/// TEvent listener basic interface
|
||||
/// </suary>
|
||||
public interface EventListenerBaseAsync
|
||||
{
|
||||
};
|
||||
|
||||
/// <suary>
|
||||
/// A public interface you'll need to implement for each type of event you want to listen to.
|
||||
/// </suary>
|
||||
public interface EventListenerAsync<T> : EventListenerBaseAsync
|
||||
{
|
||||
void OnEventAsync(T eventType);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Data;
|
||||
using System.Threading;
|
||||
using BlueWest.Collections;
|
||||
using BlueWest.Coroutines;
|
||||
using BlueWest.Tools;
|
||||
|
||||
namespace BlueWest.Core.ComponentSystem
|
||||
{
|
||||
|
||||
public enum ArtefactFrequency
|
||||
{
|
||||
T120Hz,
|
||||
T60Hz,
|
||||
T30Hz,
|
||||
T20Hz,
|
||||
T10Hz,
|
||||
T4Hz ,
|
||||
T3Hz ,
|
||||
T2Hz ,
|
||||
T1Hz
|
||||
}
|
||||
|
||||
public class Artefact
|
||||
{
|
||||
|
||||
public Artefact()
|
||||
{
|
||||
_autoTickTimer = new TimerTick();
|
||||
_autoTickTimer.Reset();
|
||||
_maximumElapsedTime = TimeSpan.FromMilliseconds(500.0);
|
||||
}
|
||||
// Time Management
|
||||
|
||||
private readonly TimeSpan _maximumElapsedTime;
|
||||
private TimeSpan _accumulatedElapsedGameTime;
|
||||
|
||||
private TimeSpan TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 30); // target elapsed time is by default 250Hz
|
||||
|
||||
private readonly TimerTick _autoTickTimer;
|
||||
private TimeSpan accumulatedElapsedGameTime;
|
||||
|
||||
private FastDictionary<ArtefactFrequency, int> behaviorConfigType =
|
||||
new FastDictionary<ArtefactFrequency, int>(10);
|
||||
|
||||
|
||||
private readonly FastList<IEnumerator> _coroutines = new FastList<IEnumerator>(10000);
|
||||
private bool? _prevVisibility;
|
||||
// Mini ECS
|
||||
protected EventManager _eventManager;
|
||||
|
||||
|
||||
private bool _startCalled;
|
||||
|
||||
internal VisibilityHandler _visibilityHandler = new VisibilityHandler();
|
||||
|
||||
internal FastList<Component> _components = new FastList<Component>(10);
|
||||
|
||||
private int _componentsCount = 0;
|
||||
|
||||
private readonly ArtefactFrequency BehaviorType;
|
||||
|
||||
|
||||
// OLD STUFF
|
||||
|
||||
|
||||
protected internal ArtefactFrequency Frequency;
|
||||
|
||||
protected internal bool IsActive { get { return _visibilityHandler.IsVisible; } set { SetActive(value); } }
|
||||
/// <summary>
|
||||
/// Initial setup of the entity. Triggers Awake method if the node is visible
|
||||
/// and triggers an visibility change event.
|
||||
/// </summary>
|
||||
public void SetupEntity(EventManager eventManager)
|
||||
{
|
||||
_eventManager = eventManager;
|
||||
|
||||
switch (BehaviorType)
|
||||
{
|
||||
|
||||
case ArtefactFrequency.T1Hz:
|
||||
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 1);
|
||||
break;
|
||||
case ArtefactFrequency.T2Hz:
|
||||
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 2);
|
||||
break;
|
||||
case ArtefactFrequency.T3Hz:
|
||||
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 3);
|
||||
break;
|
||||
case ArtefactFrequency.T4Hz:
|
||||
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 4);
|
||||
break;
|
||||
case ArtefactFrequency.T10Hz:
|
||||
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 10);
|
||||
break;
|
||||
case ArtefactFrequency.T20Hz:
|
||||
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 20);
|
||||
break;
|
||||
case ArtefactFrequency.T30Hz:
|
||||
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 30);
|
||||
break;
|
||||
case ArtefactFrequency.T60Hz:
|
||||
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 60);
|
||||
break;
|
||||
case ArtefactFrequency.T120Hz:
|
||||
TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 120);
|
||||
break;
|
||||
default:
|
||||
throw new EvaluateException(
|
||||
$"BehaviorType of class can't be null. Please assign it in the Constructor.");
|
||||
|
||||
}
|
||||
|
||||
if (!_visibilityHandler.IsVisible) return;
|
||||
|
||||
Awake();
|
||||
|
||||
OnVisibilityChange();
|
||||
|
||||
if (!_visibilityHandler.IsVisible) return;
|
||||
|
||||
if (!_startCalled)
|
||||
{
|
||||
_startCalled = true;
|
||||
|
||||
Start();
|
||||
|
||||
}
|
||||
}
|
||||
public void AddComponent<T>() where T : Component
|
||||
{
|
||||
var component = Activator.CreateInstance(typeof(T), _eventManager) as Component;
|
||||
_components.Add(component);
|
||||
_componentsCount += 1;
|
||||
component.Start();
|
||||
}
|
||||
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ProcessComponents(double delta)
|
||||
{
|
||||
for (int i = 0; i < _components.Length; i++)
|
||||
{
|
||||
var component = _components.Buffer[i];
|
||||
component.EveryFrame(delta);
|
||||
component.HandleCoroutines();
|
||||
}
|
||||
}
|
||||
|
||||
public void StartCoroutine(IEnumerator routine)
|
||||
{
|
||||
_coroutines.Add(routine);
|
||||
}
|
||||
|
||||
public bool LoopEnabled = true;
|
||||
|
||||
/// <summary>
|
||||
/// Called every frame
|
||||
/// </summary>
|
||||
public void RunLoop()
|
||||
{
|
||||
RetryTick:
|
||||
|
||||
if (!LoopEnabled) return;
|
||||
|
||||
if (!_visibilityHandler.IsVisible) return;
|
||||
|
||||
_autoTickTimer.Tick();
|
||||
|
||||
var elapsedAdjustedTime = _autoTickTimer.ElapsedTimeWithPause;
|
||||
|
||||
int updateCount = 1;
|
||||
|
||||
// then make ElapsedAdjustedTime = TargetElapsedTime. We take the same internal rules as XNA
|
||||
if (Math.Abs(elapsedAdjustedTime.Ticks - TargetElapsedTime.Ticks) < (TargetElapsedTime.Ticks >> 6))
|
||||
{
|
||||
elapsedAdjustedTime = TargetElapsedTime;
|
||||
}
|
||||
|
||||
// Update the accumulated time
|
||||
accumulatedElapsedGameTime += elapsedAdjustedTime;
|
||||
|
||||
|
||||
if (accumulatedElapsedGameTime < TargetElapsedTime)
|
||||
{
|
||||
var sleepTime = (TargetElapsedTime - accumulatedElapsedGameTime).TotalMilliseconds;
|
||||
if (sleepTime >= 2.0)
|
||||
{
|
||||
System.Threading.Thread.Sleep(1);
|
||||
}
|
||||
|
||||
goto RetryTick;
|
||||
}
|
||||
|
||||
// We are going to call Update updateCount times, so we can subtract this from accumulated elapsed game time
|
||||
accumulatedElapsedGameTime =
|
||||
new TimeSpan(accumulatedElapsedGameTime.Ticks - (updateCount * TargetElapsedTime.Ticks));
|
||||
|
||||
for (int i = 0; i < updateCount; i++)
|
||||
{
|
||||
double delta = TargetElapsedTime.TotalSeconds;
|
||||
Update(delta);
|
||||
ProcessComponents(delta);
|
||||
}
|
||||
|
||||
if (!_visibilityHandler.IsVisible) return; // Added to avoid running after deactivating node
|
||||
|
||||
HandleCoroutines();
|
||||
|
||||
goto RetryTick;
|
||||
}
|
||||
|
||||
protected virtual void Update(double delta)
|
||||
{
|
||||
}
|
||||
|
||||
public void HandleCoroutines()
|
||||
{
|
||||
for (var i = 0; i < _coroutines.Length; i++)
|
||||
{
|
||||
var yielded = _coroutines.Buffer[i].Current is CustomYieldInstruction yielder && yielder.MoveNext();
|
||||
|
||||
if (yielded || _coroutines.Buffer[i].MoveNext()) continue;
|
||||
_coroutines.RemoveAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Trigger OnEnable and OnDisable methods regarding the current and previous visibility.
|
||||
/// </summary>
|
||||
internal void OnVisibilityChange()
|
||||
{
|
||||
var curVisibility = _visibilityHandler.IsVisible;
|
||||
|
||||
if (curVisibility == _prevVisibility) return;
|
||||
|
||||
if (curVisibility) OnEnable();
|
||||
|
||||
if (!curVisibility) OnDisable();
|
||||
|
||||
_prevVisibility = curVisibility;
|
||||
}
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetActive(bool status)
|
||||
{
|
||||
_visibilityHandler.SetVisibility(status);
|
||||
OnVisibilityChange();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using BlueWest.Collections;
|
||||
using BlueWest.Tools;
|
||||
using BlueWest.Core.Threading;
|
||||
|
||||
|
||||
namespace BlueWest.Core
|
||||
{
|
||||
public sealed class BlueProgram
|
||||
{
|
||||
|
||||
private static readonly FastDictionary<Type, FastList<EventListenerBase>> Events = new(10000);
|
||||
|
||||
private static readonly EventManager EventManager = new(Events);
|
||||
|
||||
private readonly BlueConsole _blueConsole = new BlueConsole();
|
||||
|
||||
public void Run()
|
||||
{
|
||||
|
||||
new ThreadServer(EventManager);
|
||||
BlueWestConsoleBanner();
|
||||
|
||||
}
|
||||
|
||||
private void BlueWestConsoleBanner()
|
||||
{
|
||||
Console.WriteLine(" |------------------------------«");
|
||||
Console.WriteLine(" » Blue West «");
|
||||
Console.WriteLine(" |------------------------------«\n");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue