aboutsummaryrefslogtreecommitdiff
path: root/docker
diff options
context:
space:
mode:
Diffstat (limited to 'docker')
-rw-r--r--docker/auto-backup/.dockerignore2
-rw-r--r--docker/auto-backup/AutoBackup/.dockerignore2
-rw-r--r--docker/auto-backup/AutoBackup/.gitignore2
-rw-r--r--docker/auto-backup/AutoBackup/AutoBackup.csproj10
-rw-r--r--docker/auto-backup/AutoBackup/Program.cs121
-rw-r--r--docker/auto-backup/AutoBackup/TencentCloudCOS.cs211
-rw-r--r--docker/auto-backup/Dockerfile24
-rwxr-xr-xdocker/auto-backup/daemon.bash57
-rw-r--r--docker/auto-certbot/Dockerfile20
-rwxr-xr-xdocker/auto-certbot/daemon.bash107
-rwxr-xr-xdocker/auto-certbot/get-cert-domains.py38
-rw-r--r--docker/blog/Dockerfile9
-rwxr-xr-xdocker/blog/daemon.bash19
-rwxr-xr-xdocker/blog/install-hugo.bash22
-rwxr-xr-xdocker/blog/update.bash30
-rw-r--r--docker/debian-dev/Dockerfile21
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/11/add-deb-src.bash14
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/11/get-domain.bash5
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/11/replace-domain.bash7
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/11/replace-http.bash7
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/12/add-deb-src.bash22
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/12/get-domain.bash6
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/12/replace-domain.bash7
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/12/replace-http.bash7
-rw-r--r--docker/debian-dev/bootstrap/apt-source/china-source.txt1
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/install-apt-https.bash8
-rwxr-xr-xdocker/debian-dev/bootstrap/apt-source/setup.bash34
-rw-r--r--docker/debian-dev/bootstrap/bash/bash-completion.bash4
-rw-r--r--docker/debian-dev/bootstrap/bash/code-server.bash2
-rw-r--r--docker/debian-dev/bootstrap/bash/dquilt.bash4
-rwxr-xr-xdocker/debian-dev/bootstrap/extra/setup-cmake.bash9
-rwxr-xr-xdocker/debian-dev/bootstrap/extra/setup-dotnet.bash10
-rwxr-xr-xdocker/debian-dev/bootstrap/extra/setup-llvm.bash26
-rw-r--r--docker/debian-dev/bootstrap/func.bash19
-rwxr-xr-xdocker/debian-dev/bootstrap/get-debian-version.bash13
-rw-r--r--docker/debian-dev/bootstrap/home-dot/devscripts1
-rw-r--r--docker/debian-dev/bootstrap/home-dot/quiltrc-dpkg13
-rwxr-xr-xdocker/debian-dev/bootstrap/setup-base.bash25
-rwxr-xr-xdocker/debian-dev/bootstrap/setup-code-server.bash28
-rwxr-xr-xdocker/debian-dev/bootstrap/setup-dev.bash18
-rwxr-xr-xdocker/debian-dev/bootstrap/setup-user.bash20
-rwxr-xr-xdocker/debian-dev/bootstrap/setup.bash30
-rwxr-xr-xdocker/debian-dev/bootstrap/start/code-server.bash18
-rwxr-xr-xdocker/debian-dev/bootstrap/wait.bash5
-rw-r--r--docker/nginx/Dockerfile8
-rw-r--r--docker/nginx/sites/www/.dockerignore3
-rw-r--r--docker/nginx/sites/www/.gitignore26
-rw-r--r--docker/nginx/sites/www/avatar.pngbin0 -> 12038 bytes
-rw-r--r--docker/nginx/sites/www/favicon.icobin0 -> 15406 bytes
-rw-r--r--docker/nginx/sites/www/github-mark.pngbin0 -> 6393 bytes
-rw-r--r--docker/nginx/sites/www/index.html111
-rw-r--r--docker/nginx/sites/www/package.json17
-rw-r--r--docker/nginx/sites/www/pnpm-lock.yaml2016
-rw-r--r--docker/nginx/sites/www/src/main.ts47
-rw-r--r--docker/nginx/sites/www/src/style.css148
-rw-r--r--docker/nginx/sites/www/tsconfig.json19
-rw-r--r--docker/v2ray/Dockerfile5
57 files changed, 3458 insertions, 0 deletions
diff --git a/docker/auto-backup/.dockerignore b/docker/auto-backup/.dockerignore
new file mode 100644
index 0000000..7a09751
--- /dev/null
+++ b/docker/auto-backup/.dockerignore
@@ -0,0 +1,2 @@
+AutoBackup/bin
+AutoBackup/obj
diff --git a/docker/auto-backup/AutoBackup/.dockerignore b/docker/auto-backup/AutoBackup/.dockerignore
new file mode 100644
index 0000000..7de5508
--- /dev/null
+++ b/docker/auto-backup/AutoBackup/.dockerignore
@@ -0,0 +1,2 @@
+obj
+bin
diff --git a/docker/auto-backup/AutoBackup/.gitignore b/docker/auto-backup/AutoBackup/.gitignore
new file mode 100644
index 0000000..7de5508
--- /dev/null
+++ b/docker/auto-backup/AutoBackup/.gitignore
@@ -0,0 +1,2 @@
+obj
+bin
diff --git a/docker/auto-backup/AutoBackup/AutoBackup.csproj b/docker/auto-backup/AutoBackup/AutoBackup.csproj
new file mode 100644
index 0000000..694035b
--- /dev/null
+++ b/docker/auto-backup/AutoBackup/AutoBackup.csproj
@@ -0,0 +1,10 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>net9.0</TargetFramework>
+ <ImplicitUsings>enable</ImplicitUsings>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+
+</Project>
diff --git a/docker/auto-backup/AutoBackup/Program.cs b/docker/auto-backup/AutoBackup/Program.cs
new file mode 100644
index 0000000..c2e7a0d
--- /dev/null
+++ b/docker/auto-backup/AutoBackup/Program.cs
@@ -0,0 +1,121 @@
+// Read args to determine what file to upload
+
+const string DefaultUploadFilePath = "/tmp/data.tar.xz";
+string uploadFilePath = DefaultUploadFilePath;
+string? uploadDestinationPath = null;
+if (args.Length == 0)
+{
+ Console.WriteLine("You don't specify the file to upload, will upload /tmp/data.tar.xz by default.");
+ Console.WriteLine("You don't specify the destination to upload, will use timestamp with proper file extension.");
+}
+else if (args.Length == 1)
+{
+ if (args[0].Length == 0)
+ {
+ Console.Error.WriteLine("File to upload can't be empty string.");
+ Environment.Exit(2);
+ }
+ uploadFilePath = args[0];
+ Console.WriteLine("You don't specify the destination to upload, will use timestamp with proper file extension.");
+}
+else if (args.Length == 2)
+{
+ if (args[0].Length == 0)
+ {
+ Console.Error.WriteLine("File to upload can't be empty string.");
+ Environment.Exit(2);
+ }
+
+ if (args[1].Length == 0)
+ {
+ Console.Error.WriteLine("Destination to upload can't be empty string.");
+ Environment.Exit(2);
+ }
+
+ uploadFilePath = args[0];
+ uploadDestinationPath = args[1];
+}
+else
+{
+ // Write to stderr
+ Console.Error.WriteLine("You can only specify one optional file and one optional destination to upload.");
+ Environment.Exit(2);
+}
+
+// Check the upload exists
+if (!File.Exists(uploadFilePath))
+{
+ Console.Error.WriteLine($"The file {uploadFilePath} doesn't exist.");
+ Environment.Exit(3);
+}
+
+// Check the upload file is not a directory
+if (File.GetAttributes(uploadFilePath).HasFlag(FileAttributes.Directory))
+{
+ Console.Error.WriteLine($"The file {uploadFilePath} is a directory.");
+ Environment.Exit(4);
+}
+
+// Check the upload file is not bigger than 5G
+if (new FileInfo(uploadFilePath).Length > 5L * 1024L * 1024L * 1024L)
+{
+ Console.Error.WriteLine($"The file {uploadFilePath} is bigger than 5G, which is not support now.");
+ Environment.Exit(5);
+}
+
+// Get config from environment variables
+var configNameList = new List<string>{
+ "CRUPEST_AUTO_BACKUP_COS_SECRET_ID",
+ "CRUPEST_AUTO_BACKUP_COS_SECRET_KEY",
+ "CRUPEST_AUTO_BACKUP_COS_REGION",
+ "CRUPEST_AUTO_BACKUP_BUCKET_NAME"
+};
+
+var config = new Dictionary<string, string>();
+foreach (var configName in configNameList)
+{
+ var configValue = Environment.GetEnvironmentVariable(configName);
+ if (configValue is null)
+ {
+ Console.Error.WriteLine($"Environment variable {configName} is required.");
+ Environment.Exit(5);
+ }
+ config.Add(configName, configValue);
+}
+
+var region = config["CRUPEST_AUTO_BACKUP_COS_REGION"];
+var secretId = config["CRUPEST_AUTO_BACKUP_COS_SECRET_ID"];
+var secretKey = config["CRUPEST_AUTO_BACKUP_COS_SECRET_KEY"];
+var bucketName = config["CRUPEST_AUTO_BACKUP_BUCKET_NAME"];
+
+var credentials = new TencentCloudCOSHelper.Credentials(secretId, secretKey);
+
+if (uploadDestinationPath is null)
+{
+ var uploadFileName = Path.GetFileName(uploadFilePath);
+ var firstDotPosition = uploadFileName.IndexOf('.');
+ uploadDestinationPath = DateTime.Now.ToString("s");
+ if (firstDotPosition != -1)
+ {
+ uploadDestinationPath += uploadFileName.Substring(firstDotPosition + 1);
+ }
+}
+
+Console.WriteLine($"Upload file source: {uploadFilePath}");
+Console.WriteLine($"Upload COS region: {config["CRUPEST_AUTO_BACKUP_COS_REGION"]}");
+Console.WriteLine($"Upload bucket name: {config["CRUPEST_AUTO_BACKUP_BUCKET_NAME"]}");
+Console.WriteLine($"Upload file destination: {uploadDestinationPath}");
+
+await using var fileStream = new FileStream(uploadFilePath, FileMode.Open, FileAccess.Read);
+
+// 上传对象
+try
+{
+ await TencentCloudCOSHelper.PutObject(credentials, region, bucketName, uploadDestinationPath, fileStream);
+ Console.WriteLine("Upload completed!");
+}
+catch (Exception e)
+{
+ Console.Error.WriteLine("Exception: " + e);
+ Environment.Exit(6);
+}
diff --git a/docker/auto-backup/AutoBackup/TencentCloudCOS.cs b/docker/auto-backup/AutoBackup/TencentCloudCOS.cs
new file mode 100644
index 0000000..28d032c
--- /dev/null
+++ b/docker/auto-backup/AutoBackup/TencentCloudCOS.cs
@@ -0,0 +1,211 @@
+using System.Net;
+using System.Security.Cryptography;
+using System.Text;
+
+
+public static class TencentCloudCOSHelper
+{
+ public class Credentials
+ {
+ public Credentials(string secretId, string secretKey)
+ {
+ SecretId = secretId;
+ SecretKey = secretKey;
+ }
+
+ public string SecretId { get; }
+ public string SecretKey { get; }
+ }
+
+ public class RequestInfo
+ {
+ public RequestInfo(string method, string urlPathname, IEnumerable<KeyValuePair<string, string>> parameters, IEnumerable<KeyValuePair<string, string>> headers)
+ {
+ Method = method;
+ UrlPathname = urlPathname;
+ Parameters = new Dictionary<string, string>(parameters);
+ Headers = new Dictionary<string, string>(headers);
+ }
+
+ public string Method { get; }
+ public string UrlPathname { get; }
+ public IReadOnlyDictionary<string, string> Parameters { get; }
+ public IReadOnlyDictionary<string, string> Headers { get; }
+ }
+
+ public class TimeDuration
+ {
+ public TimeDuration(DateTimeOffset start, DateTimeOffset end)
+ {
+ if (start > end)
+ {
+ throw new ArgumentException("Start time must be earlier than end time.");
+ }
+
+ Start = start;
+ End = end;
+ }
+
+ public DateTimeOffset Start { get; }
+ public DateTimeOffset End { get; }
+ }
+
+ public static string GenerateSign(Credentials credentials, RequestInfo request, TimeDuration signValidTime)
+ {
+ List<(string key, string value)> Transform(IEnumerable<KeyValuePair<string, string>> raw)
+ {
+ if (raw == null)
+ return new List<(string key, string value)>();
+
+ var sorted = raw.Select(p => (key: WebUtility.UrlEncode(p.Key.ToLower()), value: WebUtility.UrlEncode(p.Value))).ToList();
+ sorted.Sort((left, right) => string.CompareOrdinal(left.key, right.key));
+ return sorted;
+ }
+
+ var transformedParameters = Transform(request.Parameters);
+ var transformedHeaders = Transform(request.Headers);
+
+
+ const string signAlgorithm = "sha1";
+
+ static string ByteArrayToString(byte[] bytes)
+ {
+ return BitConverter.ToString(bytes).Replace("-", "").ToLower();
+ }
+
+ var keyTime = $"{signValidTime.Start.ToUnixTimeSeconds().ToString()};{signValidTime.End.ToUnixTimeSeconds().ToString()}";
+ using HMACSHA1 hmac = new HMACSHA1(Encoding.ASCII.GetBytes(credentials.SecretKey));
+ var signKey = ByteArrayToString(hmac.ComputeHash(Encoding.UTF8.GetBytes(keyTime)));
+
+ static string Join(IEnumerable<(string key, string value)> raw)
+ {
+ return string.Join('&', raw.Select(p => string.Concat(p.key, "=", p.value)));
+ }
+
+ var httpParameters = Join(transformedParameters);
+ var urlParamList = string.Join(';', transformedParameters.Select(p => p.key));
+ var httpHeaders = Join(transformedHeaders);
+ var headerList = string.Join(';', transformedHeaders.Select(h => h.key));
+
+ var httpString = new StringBuilder()
+ .Append(request.Method.ToLower()).Append('\n')
+ .Append(request.UrlPathname).Append('\n')
+ .Append(httpParameters).Append('\n')
+ .Append(httpHeaders).Append('\n')
+ .ToString();
+
+ using var sha1 = SHA1.Create();
+ string Sha1(string data)
+ {
+ var result = sha1.ComputeHash(Encoding.UTF8.GetBytes(data));
+ return ByteArrayToString(result);
+ }
+
+ var stringToSign = new StringBuilder()
+ .Append(signAlgorithm).Append('\n')
+ .Append(keyTime).Append('\n')
+ .Append(Sha1(httpString)).Append('\n')
+ .ToString();
+
+ hmac.Key = Encoding.UTF8.GetBytes(signKey);
+ var signature = ByteArrayToString(hmac.ComputeHash(
+ Encoding.UTF8.GetBytes(stringToSign)));
+
+
+ List<(string, string)> result = new List<(string, string)>();
+ result.Add(("q-sign-algorithm", signAlgorithm));
+ result.Add(("q-ak", credentials.SecretId));
+ result.Add(("q-sign-time", keyTime));
+ result.Add(("q-key-time", keyTime));
+ result.Add(("q-header-list", headerList));
+ result.Add(("q-url-param-list", urlParamList));
+ result.Add(("q-signature", signature));
+ return Join(result);
+ }
+
+ private static string GetHost(string bucket, string region)
+ {
+ return $"{bucket}.cos.{region}.myqcloud.com";
+ }
+
+ public static async Task<bool> IsObjectExists(Credentials credentials, string region, string bucket, string key)
+ {
+ var host = GetHost(bucket, region);
+ var encodedKey = WebUtility.UrlEncode(key);
+
+ using var request = new HttpRequestMessage();
+ request.Method = HttpMethod.Head;
+ request.RequestUri = new Uri($"https://{host}/{encodedKey}");
+ request.Headers.Host = host;
+ request.Headers.Date = DateTimeOffset.Now;
+ request.Headers.TryAddWithoutValidation("Authorization", GenerateSign(credentials, new RequestInfo(
+ "head", "/" + key, new Dictionary<string, string>(),
+ new Dictionary<string, string>
+ {
+ ["Host"] = host
+ }
+ ), new TimeDuration(DateTimeOffset.Now, DateTimeOffset.Now.AddMinutes(5))));
+
+ using var client = new HttpClient();
+ using var response = await client.SendAsync(request);
+
+ if (response.IsSuccessStatusCode)
+ return true;
+ if (response.StatusCode == HttpStatusCode.NotFound)
+ return false;
+
+ throw new Exception($"Unknown response code. {response.ToString()}");
+ }
+
+ public static async Task PutObject(Credentials credentials, string region, string bucket, string key, Stream dataStream)
+ {
+ if (!dataStream.CanSeek)
+ {
+ throw new ArgumentException("Data stream must be seekable.");
+ }
+
+ if (dataStream.Seek(0, SeekOrigin.End) > 5L * 1024L * 1024L * 1024L)
+ {
+ throw new ArgumentException("Data stream must be smaller than 5GB.");
+ }
+
+ dataStream.Seek(0, SeekOrigin.Begin);
+
+ var host = GetHost(bucket, region);
+ var encodedKey = WebUtility.UrlEncode(key);
+ using var md5Handler = MD5.Create();
+ var md5 = Convert.ToBase64String(await md5Handler.ComputeHashAsync(dataStream));
+
+ dataStream.Seek(0, SeekOrigin.Begin);
+
+ const string kContentMD5HeaderName = "Content-MD5";
+
+ using var httpRequest = new HttpRequestMessage()
+ {
+ Method = HttpMethod.Put,
+ RequestUri = new Uri($"https://{host}/{encodedKey}")
+ };
+ httpRequest.Headers.Host = host;
+ httpRequest.Headers.Date = DateTimeOffset.Now;
+
+ using var httpContent = new StreamContent(dataStream);
+ httpContent.Headers.Add(kContentMD5HeaderName, md5);
+ httpRequest.Content = httpContent;
+
+ var signedHeaders = new Dictionary<string, string>
+ {
+ ["Host"] = host,
+ [kContentMD5HeaderName] = md5
+ };
+
+ httpRequest.Headers.TryAddWithoutValidation("Authorization", GenerateSign(credentials, new RequestInfo(
+ "put", "/" + key, new Dictionary<string, string>(), signedHeaders
+ ), new TimeDuration(DateTimeOffset.Now, DateTimeOffset.Now.AddMinutes(10))));
+
+ using var client = new HttpClient();
+ using var response = await client.SendAsync(httpRequest);
+
+ if (!response.IsSuccessStatusCode)
+ throw new Exception($"Not success status code: {response.StatusCode}\n{await response.Content.ReadAsStringAsync()}");
+ }
+} \ No newline at end of file
diff --git a/docker/auto-backup/Dockerfile b/docker/auto-backup/Dockerfile
new file mode 100644
index 0000000..c7ff4fc
--- /dev/null
+++ b/docker/auto-backup/Dockerfile
@@ -0,0 +1,24 @@
+FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build
+COPY AutoBackup /AutoBackup
+WORKDIR /AutoBackup
+RUN dotnet publish AutoBackup.csproj --configuration Release --output ./publish/ -r linux-x64 --self-contained false
+
+FROM mcr.microsoft.com/dotnet/runtime:9.0-alpine
+RUN apk add --no-cache tini coreutils bash tar xz
+ARG CRUPEST_AUTO_BACKUP_INIT_DELAY=0
+ARG CRUPEST_AUTO_BACKUP_INTERVAL=1d
+ARG CRUPEST_AUTO_BACKUP_COS_SECRET_ID
+ARG CRUPEST_AUTO_BACKUP_COS_SECRET_KEY
+ARG CRUPEST_AUTO_BACKUP_COS_REGION
+ARG CRUPEST_AUTO_BACKUP_BUCKET_NAME
+ENV CRUPEST_AUTO_BACKUP_INIT_DELAY=${CRUPEST_AUTO_BACKUP_INIT_DELAY}
+ENV CRUPEST_AUTO_BACKUP_INTERVAL=${CRUPEST_AUTO_BACKUP_INTERVAL}
+ENV CRUPEST_AUTO_BACKUP_COS_SECRET_ID=${CRUPEST_AUTO_BACKUP_COS_SECRET_ID}
+ENV CRUPEST_AUTO_BACKUP_COS_SECRET_KEY=${CRUPEST_AUTO_BACKUP_COS_SECRET_KEY}
+ENV CRUPEST_AUTO_BACKUP_COS_REGION=${CRUPEST_AUTO_BACKUP_COS_REGION}
+ENV CRUPEST_AUTO_BACKUP_BUCKET_NAME=${CRUPEST_AUTO_BACKUP_BUCKET_NAME}
+VOLUME [ "/data" ]
+COPY daemon.bash /daemon.bash
+COPY --from=build /AutoBackup/publish /AutoBackup
+ENTRYPOINT ["tini", "--"]
+CMD [ "/daemon.bash" ]
diff --git a/docker/auto-backup/daemon.bash b/docker/auto-backup/daemon.bash
new file mode 100755
index 0000000..a4dd5dc
--- /dev/null
+++ b/docker/auto-backup/daemon.bash
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+
+set -e
+
+# Check I'm root.
+if [[ $EUID -ne 0 ]]; then
+ echo "This script must be run as root" 1>&2
+ exit 1
+fi
+
+
+# Check xz, tar and coscmd
+xz --version
+tar --version
+
+function backup {
+ # Output "Begin backup..." in yellow and restore default
+ echo -e "\e[0;103m\e[K\e[1mBegin backup..." "\e[0m"
+
+ # Get current time and convert it to YYYY-MM-DDTHH:MM:SSZ
+ current_time=$(date +%Y-%m-%dT%H:%M:%SZ)
+ echo "Current time: $current_time"
+
+ echo "Create tar.xz for data..."
+
+ # tar and xz /data to tmp
+ tar -cJf /tmp/data.tar.xz -C / data
+
+ # Output /tmp/data.tar.xz size
+ du -h /tmp/data.tar.xz | cut -f1 | xargs echo "Size of data.tar.xz:"
+
+ destination="${current_time}.tar.xz"
+
+ # upload to remote
+ dotnet /AutoBackup/AutoBackup.dll /tmp/data.tar.xz "$destination"
+
+ echo "Remove tmp file..."
+ # remove tmp
+ rm /tmp/data.tar.xz
+
+ echo "$destination" >> /data/backup.log
+
+ # echo "Backup finished!" in green and restore default
+ echo -e "\e[0;102m\e[K\e[1mFinish backup!\e[0m"
+}
+
+echo "Initial delay: $CRUPEST_AUTO_BACKUP_INIT_DELAY"
+sleep "$CRUPEST_AUTO_BACKUP_INIT_DELAY"
+
+# forever loop
+while true; do
+ backup
+
+ # sleep for CRUPEST_AUTO_BACKUP_INTERVAL
+ echo "Sleep for $CRUPEST_AUTO_BACKUP_INTERVAL for next backup..."
+ sleep "$CRUPEST_AUTO_BACKUP_INTERVAL"
+done
diff --git a/docker/auto-certbot/Dockerfile b/docker/auto-certbot/Dockerfile
new file mode 100644
index 0000000..eeb6475
--- /dev/null
+++ b/docker/auto-certbot/Dockerfile
@@ -0,0 +1,20 @@
+FROM certbot/certbot:latest
+
+ARG CRUPEST_AUTO_CERTBOT_ADDITIONAL_PACKAGES=""
+RUN apk add --no-cache tini coreutils bash ${CRUPEST_AUTO_CERTBOT_ADDITIONAL_PACKAGES} && python -m pip install cryptography
+
+
+ARG CRUPEST_DOMAIN
+ARG CRUPEST_ADDITIONAL_DOMAIN_LIST=""
+ARG CRUPEST_EMAIL
+ARG CRUPEST_AUTO_CERTBOT_POST_HOOK=""
+# install bash
+ENV CRUPEST_DOMAIN=${CRUPEST_DOMAIN}
+ENV CRUPEST_ADDITIONAL_DOMAIN_LIST=${CRUPEST_ADDITIONAL_DOMAIN_LIST}
+ENV CRUPEST_EMAIL=${CRUPEST_EMAIL}
+ENV CRUPEST_AUTO_CERTBOT_POST_HOOK=${CRUPEST_AUTO_CERTBOT_POST_HOOK}
+COPY daemon.bash /daemon.bash
+COPY get-cert-domains.py /get-cert-domains.py
+VOLUME ["/var/www/certbot", "/etc/letsencrypt", "/var/lib/letsencrypt"]
+ENTRYPOINT ["tini", "--"]
+CMD [ "/daemon.bash" ]
diff --git a/docker/auto-certbot/daemon.bash b/docker/auto-certbot/daemon.bash
new file mode 100755
index 0000000..d79387e
--- /dev/null
+++ b/docker/auto-certbot/daemon.bash
@@ -0,0 +1,107 @@
+#!/usr/bin/env bash
+
+set -e
+
+# Check I'm root.
+if [[ $EUID -ne 0 ]]; then
+ echo "This script must be run as root" 1>&2
+ exit 1
+fi
+
+# Check certbot version.
+certbot --version
+
+# Check domain
+if [[ -z "$CRUPEST_DOMAIN" ]]; then
+ echo "CRUPEST_DOMAIN can't be empty!" 1>&2
+ exit 1
+fi
+
+# Check email
+if [[ -z "$CRUPEST_EMAIL" ]]; then
+ echo "CRUPEST_EMAIL can't be empty!" 1>&2
+ exit 2
+fi
+
+# Check CRUPEST_CERT_PATH, default to /etc/letsencrypt/live/$CRUPEST_DOMAIN/fullchain.pem
+if [ -z "$CRUPEST_CERT_PATH" ]; then
+ CRUPEST_CERT_PATH="/etc/letsencrypt/live/$CRUPEST_DOMAIN/fullchain.pem"
+fi
+
+# Check CRUPEST_CERT_PATH exists.
+if [ ! -f "$CRUPEST_CERT_PATH" ]; then
+ echo "Cert file does not exist. You may want to generate it manually with aio script." 1>&2
+ exit 3
+fi
+
+echo "Root domain:" "$CRUPEST_DOMAIN"
+echo "Email:" "$CRUPEST_EMAIL"
+echo "Cert path: ${CRUPEST_CERT_PATH}"
+
+# Check CRUPEST_AUTO_CERTBOT_RENEW_COMMAND is defined.
+if [ -z "$CRUPEST_AUTO_CERTBOT_RENEW_COMMAND" ]; then
+ echo "CRUPEST_AUTO_CERTBOT_RENEW_COMMAND is not defined or empty. Will use the default one."
+else
+ printf "CRUPEST_AUTO_CERTBOT_RENEW_COMMAND is defined as:\n%s\n" "$CRUPEST_AUTO_CERTBOT_RENEW_COMMAND"
+fi
+
+domains_str="$(/get-cert-domains.py "${CRUPEST_CERT_PATH}")"
+
+printf "Domain list:\n%s\n" "$domains_str"
+
+mapfile -t domains <<< "$domains_str"
+
+for domain in "${domains[@]}"; do
+ domain_options=("${domain_options[@]}" -d "$domain")
+done
+
+options=(-n --agree-tos -m "$CRUPEST_EMAIL" --webroot -w /var/www/certbot "${domain_options[@]}")
+if [ -n "$CRUPEST_AUTO_CERTBOT_POST_HOOK" ]; then
+ printf "You have defined a post hook:\n%s\n" "$CRUPEST_AUTO_CERTBOT_POST_HOOK"
+ options=("${options[@]}" --post-hook "$CRUPEST_AUTO_CERTBOT_POST_HOOK")
+fi
+
+# Use test server to test.
+certbot certonly --force-renewal --test-cert --dry-run "${options[@]}"
+
+function check_and_renew_cert {
+ expire_info=$(openssl x509 -enddate -noout -in "$CRUPEST_CERT_PATH")
+
+ # Get ssl certificate expire date.
+ expire_date=$(echo "$expire_info" | cut -d= -f2)
+
+ echo "SSL certificate expire date: $expire_date"
+
+ # Convert expire date to UNIX timestamp.
+ expire_timestamp="$(date -d "$expire_date" +%s)"
+
+ # Minus expire timestamp with 30 days in UNIX timestamp.
+ renew_timestamp="$((expire_timestamp - 2592000))"
+ echo "Renew SSL certificate at: $(date -d @$renew_timestamp)"
+
+ # Get rest time til renew.
+ rest_time_in_second="$((renew_timestamp - $(date +%s)))"
+ rest_time_in_day=$((rest_time_in_second / 86400))
+ echo "Rest time til renew: $rest_time_in_second seconds, aka, about $rest_time_in_day days"
+
+ # Do we have rest time?
+ if [ $rest_time_in_second -gt 0 ]; then
+ # Sleep 1 hour.
+ echo "I'm going to sleep for 1 day to check again."
+ sleep 1d
+ else
+ # No, renew now.
+ echo "Renewing now..."
+
+ if [ -n "$CRUPEST_AUTO_CERTBOT_RENEW_COMMAND" ]; then
+ $CRUPEST_AUTO_CERTBOT_RENEW_COMMAND
+ else
+ certbot certonly "${options[@]}"
+ fi
+ fi
+}
+
+# Run check_and_renew_cert in infinate loop.
+while true; do
+ check_and_renew_cert
+done
diff --git a/docker/auto-certbot/get-cert-domains.py b/docker/auto-certbot/get-cert-domains.py
new file mode 100755
index 0000000..9bd28c8
--- /dev/null
+++ b/docker/auto-certbot/get-cert-domains.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+
+import sys
+import os
+from os.path import *
+from cryptography.x509 import *
+from cryptography.x509.oid import ExtensionOID
+
+# Check only one argument
+if len(sys.argv) != 2:
+ print("You should only specify one argument, aka, the path of cert.",
+ file=sys.stderr)
+ exit(1)
+
+cert_path = sys.argv[1]
+
+if not exists(cert_path):
+ print("Cert file does not exist.", file=sys.stderr)
+ exit(2)
+
+if not isfile(cert_path):
+ print("Cert path is not a file.")
+ exit(3)
+
+if not 'CRUPEST_DOMAIN' in os.environ:
+ print("Please set CRUPEST_DOMAIN environment variable to root domain.", file=sys.stderr)
+ exit(4)
+
+root_domain = os.environ['CRUPEST_DOMAIN']
+
+with open(cert_path, 'rb') as f:
+ cert = load_pem_x509_certificate(f.read())
+ ext = cert.extensions.get_extension_for_oid(
+ ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
+ domains: list = ext.value.get_values_for_type(DNSName)
+ domains.remove(root_domain)
+ domains = [root_domain, *domains]
+ print('\n'.join(domains))
diff --git a/docker/blog/Dockerfile b/docker/blog/Dockerfile
new file mode 100644
index 0000000..7414d4e
--- /dev/null
+++ b/docker/blog/Dockerfile
@@ -0,0 +1,9 @@
+FROM debian:latest
+ARG CRUPEST_BLOG_UPDATE_INTERVAL=1d
+COPY install-hugo.bash /install-hugo.bash
+RUN /install-hugo.bash && rm /install-hugo.bash
+ENV CRUPEST_BLOG_UPDATE_INTERVAL=${CRUPEST_BLOG_UPDATE_INTERVAL}
+COPY daemon.bash update.bash /scripts/
+VOLUME [ "/public" ]
+ENTRYPOINT ["tini", "--"]
+CMD [ "/scripts/daemon.bash" ]
diff --git a/docker/blog/daemon.bash b/docker/blog/daemon.bash
new file mode 100755
index 0000000..561a80a
--- /dev/null
+++ b/docker/blog/daemon.bash
@@ -0,0 +1,19 @@
+#! /usr/bin/env bash
+
+set -e
+
+# Check I'm root.
+if [[ $EUID -ne 0 ]]; then
+ echo "This script must be run as root" 1>&2
+ exit 1
+fi
+
+hugo version
+
+while true; do
+ /scripts/update.bash
+
+ # sleep for CRUPEST_AUTO_BACKUP_INTERVAL
+ echo "Sleep for $CRUPEST_BLOG_UPDATE_INTERVAL for next build..."
+ sleep "$CRUPEST_BLOG_UPDATE_INTERVAL"
+done
diff --git a/docker/blog/install-hugo.bash b/docker/blog/install-hugo.bash
new file mode 100755
index 0000000..a448138
--- /dev/null
+++ b/docker/blog/install-hugo.bash
@@ -0,0 +1,22 @@
+#! /usr/bin/env bash
+
+set -e
+
+apt-get update
+apt-get install -y tini locales curl git
+rm -rf /var/lib/apt/lists/*
+localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
+
+VERSION=$(curl -s https://api.github.com/repos/gohugoio/hugo/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
+
+echo "The latest version of hugo is $VERSION."
+
+url="https://github.com/gohugoio/hugo/releases/download/v${VERSION}/hugo_extended_${VERSION}_linux-amd64.deb"
+
+echo "Download hugo from $url."
+
+curl -sSfOL "$url"
+dpkg -i "hugo_extended_${VERSION}_linux-amd64.deb"
+rm "hugo_extended_${VERSION}_linux-amd64.deb"
+
+echo "Hugo version: $(hugo version)."
diff --git a/docker/blog/update.bash b/docker/blog/update.bash
new file mode 100755
index 0000000..d4bcadc
--- /dev/null
+++ b/docker/blog/update.bash
@@ -0,0 +1,30 @@
+#! /usr/bin/env bash
+
+set -e
+
+echo -e "\e[0;103m\e[K\e[1mBegin to build blog...\e[0m"
+echo "Begin time: $(date +%Y-%m-%dT%H:%M:%SZ)"
+
+mkdir -p /public
+
+# check /blog directory exists
+if [[ ! -d /blog ]]; then
+ echo "Directory /blog not found, clone blog repository..."
+ git clone https://github.com/crupest/blog.git /blog
+ cd /blog
+ git submodule update --init --recursive
+else
+ echo "Directory /blog founded, update blog repository..."
+ cd /blog
+ git fetch -p
+ git reset --hard origin/master
+ git submodule update --init --recursive
+fi
+
+# Now hugo it
+echo "Run hugo to generate blog..."
+hugo -d /public
+
+echo "Finish time: $(date +%Y-%m-%dT%H:%M:%SZ)"
+echo -e "\e[0;102m\e[K\e[1mFinish build!\e[0m"
+
diff --git a/docker/debian-dev/Dockerfile b/docker/debian-dev/Dockerfile
new file mode 100644
index 0000000..95f0602
--- /dev/null
+++ b/docker/debian-dev/Dockerfile
@@ -0,0 +1,21 @@
+FROM debian:latest
+
+ARG USER=crupest
+ARG IN_CHINA=
+ARG CODE_SERVER=true
+
+ENV CRUPEST_DEBIAN_DEV_USER=${USER}
+ENV CRUPEST_DEBIAN_DEV_IN_CHINA=${IN_CHINA}
+ENV CRUPEST_DEBIAN_DEV_SETUP_CODE_SERVER=${CODE_SERVER}
+
+ADD bootstrap /bootstrap
+
+RUN /bootstrap/setup.bash
+ENV LANG=en_US.utf8
+
+USER ${USER}
+WORKDIR /home/${USER}
+
+EXPOSE 8080
+VOLUME [ "/data", "/home/${USER}" ]
+CMD [ "bash", "-l" ]
diff --git a/docker/debian-dev/bootstrap/apt-source/11/add-deb-src.bash b/docker/debian-dev/bootstrap/apt-source/11/add-deb-src.bash
new file mode 100755
index 0000000..e134a00
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/11/add-deb-src.bash
@@ -0,0 +1,14 @@
+#! /usr/bin/env bash
+
+set -e
+
+dir=$(dirname "$0")
+domain=$("$dir/get-domain.bash")
+
+cat <<EOF >> /etc/apt/sources.list
+
+deb-src https://$domain/debian/ bullseye main
+deb-src https://$domain/debian-security/ bullseye-security main
+deb-src https://$domain/debian-updates/ bullseye-updates main
+
+EOF
diff --git a/docker/debian-dev/bootstrap/apt-source/11/get-domain.bash b/docker/debian-dev/bootstrap/apt-source/11/get-domain.bash
new file mode 100755
index 0000000..d44ea65
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/11/get-domain.bash
@@ -0,0 +1,5 @@
+#! /usr/bin/env bash
+
+set -e
+
+sed "s|.*https\?://\([-_.a-zA-Z0-9]\+\)/.*|\\1|;q" /etc/apt/sources.list
diff --git a/docker/debian-dev/bootstrap/apt-source/11/replace-domain.bash b/docker/debian-dev/bootstrap/apt-source/11/replace-domain.bash
new file mode 100755
index 0000000..86e88dc
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/11/replace-domain.bash
@@ -0,0 +1,7 @@
+#! /usr/bin/env bash
+
+set -e
+
+echo "Backup /etc/apt/sources.list to /etc/apt/sources.list.bak."
+echo "Replace source domain in /etc/apt/sources.list to $1."
+sed -i.bak "s|\(https\?://\)[-_.a-zA-Z0-9]\+/|\\1$1/|" /etc/apt/sources.list
diff --git a/docker/debian-dev/bootstrap/apt-source/11/replace-http.bash b/docker/debian-dev/bootstrap/apt-source/11/replace-http.bash
new file mode 100755
index 0000000..fae082a
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/11/replace-http.bash
@@ -0,0 +1,7 @@
+#! /usr/bin/env bash
+
+set -e
+
+echo "Backup /etc/apt/sources.list to /etc/apt/sources.list.bak."
+echo "Replace http to https in /etc/apt/sources.list."
+sed -i.bak 's/https\?/https/' /etc/apt/sources.list
diff --git a/docker/debian-dev/bootstrap/apt-source/12/add-deb-src.bash b/docker/debian-dev/bootstrap/apt-source/12/add-deb-src.bash
new file mode 100755
index 0000000..cf741d6
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/12/add-deb-src.bash
@@ -0,0 +1,22 @@
+#! /usr/bin/env bash
+
+set -e
+
+dir=$(dirname "$0")
+domain=$("$dir/get-domain.bash")
+
+cat <<EOF >> /etc/apt/sources.list.d/debian.sources
+
+Types: deb-src
+URIs: https://$domain/debian
+Suites: bookworm bookworm-updates
+Components: main
+Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
+
+Types: deb-src
+URIs: https://$domain/debian-security
+Suites: bookworm-security
+Components: main
+Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
+
+EOF \ No newline at end of file
diff --git a/docker/debian-dev/bootstrap/apt-source/12/get-domain.bash b/docker/debian-dev/bootstrap/apt-source/12/get-domain.bash
new file mode 100755
index 0000000..a24538c
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/12/get-domain.bash
@@ -0,0 +1,6 @@
+#! /usr/bin/env bash
+
+set -e
+
+grep -e 'URIs:' /etc/apt/sources.list.d/debian.sources | \
+ sed -E 's|URIs:\s*https?://([-_.a-zA-Z0-9]+)/.*|\1|;q'
diff --git a/docker/debian-dev/bootstrap/apt-source/12/replace-domain.bash b/docker/debian-dev/bootstrap/apt-source/12/replace-domain.bash
new file mode 100755
index 0000000..d55307c
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/12/replace-domain.bash
@@ -0,0 +1,7 @@
+#! /usr/bin/env bash
+
+set -e
+
+echo "Backup /etc/apt/sources.list.d/debian.sources to /etc/apt/sources.list.d/debian.sources.bak."
+echo "Replace source domain in /etc/apt/sources.list.d/debian.sources to $1."
+sed -i.bak -E "s|(URIs:\\s*https?://)[-_.a-zA-Z0-9]+(/.*)|\\1$1\\2|" /etc/apt/sources.list.d/debian.sources
diff --git a/docker/debian-dev/bootstrap/apt-source/12/replace-http.bash b/docker/debian-dev/bootstrap/apt-source/12/replace-http.bash
new file mode 100755
index 0000000..ed4391d
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/12/replace-http.bash
@@ -0,0 +1,7 @@
+#! /usr/bin/env bash
+
+set -e
+
+echo "Backup /etc/apt/sources.list to /etc/apt/sources.list.d/debian.sources.bak."
+echo "Replace http to https in /etc/apt/sources.list.d/debian.sources."
+sed -i.bak -E "s|(URIs:\\s*)https?(://[-_.a-zA-Z0-9]+/.*)|\\1https\\2|" /etc/apt/sources.list.d/debian.sources
diff --git a/docker/debian-dev/bootstrap/apt-source/china-source.txt b/docker/debian-dev/bootstrap/apt-source/china-source.txt
new file mode 100644
index 0000000..4312686
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/china-source.txt
@@ -0,0 +1 @@
+mirrors.tuna.tsinghua.edu.cn \ No newline at end of file
diff --git a/docker/debian-dev/bootstrap/apt-source/install-apt-https.bash b/docker/debian-dev/bootstrap/apt-source/install-apt-https.bash
new file mode 100755
index 0000000..70fb371
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/install-apt-https.bash
@@ -0,0 +1,8 @@
+#! /usr/bin/env bash
+
+set -e
+
+echo "Install apt https transport."
+apt-get update
+apt-get install -y apt-utils
+apt-get install -y apt-transport-https ca-certificates
diff --git a/docker/debian-dev/bootstrap/apt-source/setup.bash b/docker/debian-dev/bootstrap/apt-source/setup.bash
new file mode 100755
index 0000000..cdf68af
--- /dev/null
+++ b/docker/debian-dev/bootstrap/apt-source/setup.bash
@@ -0,0 +1,34 @@
+#! /usr/bin/env bash
+
+set -e
+
+dir=/bootstrap/apt-source
+
+echo "Getting debian version..."
+debian_version=$("$dir/../get-debian-version.bash")
+
+if [[ -z $debian_version ]]; then
+ echo "Debian version not found."
+ exit 1
+else
+ echo "Debian version: $debian_version"
+fi
+
+if [[ $debian_version -ge 12 ]]; then
+ setup_dir=$dir/12
+else
+ setup_dir=$dir/11
+fi
+
+echo "Setting up apt source..."
+
+if [[ -n $CRUPEST_DEBIAN_DEV_IN_CHINA ]]; then
+ echo "In China, using China source..."
+ "$setup_dir/replace-domain.bash" "$(cat "$dir/china-source.txt")"
+fi
+
+"$dir/install-apt-https.bash"
+"$setup_dir/replace-http.bash"
+"$setup_dir/add-deb-src.bash"
+
+echo "Setting up apt source done."
diff --git a/docker/debian-dev/bootstrap/bash/bash-completion.bash b/docker/debian-dev/bootstrap/bash/bash-completion.bash
new file mode 100644
index 0000000..75f8333
--- /dev/null
+++ b/docker/debian-dev/bootstrap/bash/bash-completion.bash
@@ -0,0 +1,4 @@
+if [ -f /etc/bash_completion ]; then
+ . /etc/bash_completion
+fi
+
diff --git a/docker/debian-dev/bootstrap/bash/code-server.bash b/docker/debian-dev/bootstrap/bash/code-server.bash
new file mode 100644
index 0000000..255c280
--- /dev/null
+++ b/docker/debian-dev/bootstrap/bash/code-server.bash
@@ -0,0 +1,2 @@
+mkdir -p ~/.local/share/code-server
+/bootstrap/start/code-server.bash > ~/.local/share/code-server/log 2> ~/.local/share/code-server/error &
diff --git a/docker/debian-dev/bootstrap/bash/dquilt.bash b/docker/debian-dev/bootstrap/bash/dquilt.bash
new file mode 100644
index 0000000..96a4eb2
--- /dev/null
+++ b/docker/debian-dev/bootstrap/bash/dquilt.bash
@@ -0,0 +1,4 @@
+alias dquilt="quilt --quiltrc=${HOME}/.quiltrc-dpkg"
+. /usr/share/bash-completion/completions/quilt
+complete -F _quilt_completion $_quilt_complete_opt dquilt
+
diff --git a/docker/debian-dev/bootstrap/extra/setup-cmake.bash b/docker/debian-dev/bootstrap/extra/setup-cmake.bash
new file mode 100755
index 0000000..76c1ae4
--- /dev/null
+++ b/docker/debian-dev/bootstrap/extra/setup-cmake.bash
@@ -0,0 +1,9 @@
+#! /usr/bin/env bash
+
+set -e
+
+CMAKE_VERSION=$(curl -s https://api.github.com/repos/Kitware/CMake/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
+wget -O cmake-installer.sh https://github.com/Kitware/CMake/releases/download/v"$CMAKE_VERSION"/cmake-"$CMAKE_VERSION"-linux-x86_64.sh
+chmod +x cmake-installer.sh
+./cmake-installer.sh --skip-license --prefix=/usr
+rm cmake-installer.sh
diff --git a/docker/debian-dev/bootstrap/extra/setup-dotnet.bash b/docker/debian-dev/bootstrap/extra/setup-dotnet.bash
new file mode 100755
index 0000000..0ef7743
--- /dev/null
+++ b/docker/debian-dev/bootstrap/extra/setup-dotnet.bash
@@ -0,0 +1,10 @@
+#! /usr/bin/env bash
+
+set -e
+
+wget https://packages.microsoft.com/config/debian/11/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
+dpkg -i packages-microsoft-prod.deb
+rm packages-microsoft-prod.deb
+
+apt-get update
+apt-get install -y dotnet-sdk-7.0
diff --git a/docker/debian-dev/bootstrap/extra/setup-llvm.bash b/docker/debian-dev/bootstrap/extra/setup-llvm.bash
new file mode 100755
index 0000000..48dde86
--- /dev/null
+++ b/docker/debian-dev/bootstrap/extra/setup-llvm.bash
@@ -0,0 +1,26 @@
+#! /usr/bin/env bash
+
+set -e
+
+LLVM_VERSION=18
+
+. /bootstrap/func.bash
+
+if is_true "$CRUPEST_DEBIAN_DEV_IN_CHINA"; then
+ base_url=https://mirrors.tuna.tsinghua.edu.cn/llvm-apt
+else
+ base_url=https://apt.llvm.org
+fi
+
+wget "$base_url/llvm.sh"
+chmod +x llvm.sh
+./llvm.sh $LLVM_VERSION all -m "$base_url"
+rm llvm.sh
+
+update-alternatives --install /usr/bin/clang clang /usr/bin/clang-$LLVM_VERSION 100 \
+ --slave /usr/bin/clang++ clang++ /usr/bin/clang++-$LLVM_VERSION \
+ --slave /usr/bin/clangd clangd /usr/bin/clangd-$LLVM_VERSION \
+ --slave /usr/bin/clang-format clang-format /usr/bin/clang-format-$LLVM_VERSION \
+ --slave /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-$LLVM_VERSION \
+ --slave /usr/bin/lldb lldb /usr/bin/lldb-$LLVM_VERSION \
+ --slave /usr/bin/lld lld /usr/bin/lld-$LLVM_VERSION
diff --git a/docker/debian-dev/bootstrap/func.bash b/docker/debian-dev/bootstrap/func.bash
new file mode 100644
index 0000000..7782035
--- /dev/null
+++ b/docker/debian-dev/bootstrap/func.bash
@@ -0,0 +1,19 @@
+is_true() {
+ if [[ "$1" =~ 1|on|true ]]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+append-bash-profile() {
+ cat "/bootstrap/bash/$1" >> /home/$CRUPEST_DEBIAN_DEV_USER/.bash_profile
+}
+
+append-bashrc() {
+ cat "/bootstrap/bash/$1" >> /home/$CRUPEST_DEBIAN_DEV_USER/.bashrc
+}
+
+copy-home-dot-file() {
+ cp "/bootstrap/home-dot/$1" "/home/$CRUPEST_DEBIAN_DEV_USER/.$1"
+}
diff --git a/docker/debian-dev/bootstrap/get-debian-version.bash b/docker/debian-dev/bootstrap/get-debian-version.bash
new file mode 100755
index 0000000..2cc10b9
--- /dev/null
+++ b/docker/debian-dev/bootstrap/get-debian-version.bash
@@ -0,0 +1,13 @@
+#! /usr/bin/env bash
+
+set -e
+
+if [ -f /etc/os-release ]; then
+ . /etc/os-release
+ if [ "$ID" = "debian" ]; then
+ echo "$VERSION_ID"
+ exit 0
+ fi
+fi
+
+exit 1
diff --git a/docker/debian-dev/bootstrap/home-dot/devscripts b/docker/debian-dev/bootstrap/home-dot/devscripts
new file mode 100644
index 0000000..a15b041
--- /dev/null
+++ b/docker/debian-dev/bootstrap/home-dot/devscripts
@@ -0,0 +1 @@
+export DGET_VERIFY=no \ No newline at end of file
diff --git a/docker/debian-dev/bootstrap/home-dot/quiltrc-dpkg b/docker/debian-dev/bootstrap/home-dot/quiltrc-dpkg
new file mode 100644
index 0000000..e8fc3c5
--- /dev/null
+++ b/docker/debian-dev/bootstrap/home-dot/quiltrc-dpkg
@@ -0,0 +1,13 @@
+d=.
+while [ ! -d $d/debian -a `readlink -e $d` != / ];
+ do d=$d/..; done
+if [ -d $d/debian ] && [ -z $QUILT_PATCHES ]; then
+ # if in Debian packaging tree with unset $QUILT_PATCHES
+ QUILT_PATCHES="debian/patches"
+ QUILT_PATCH_OPTS="--reject-format=unified"
+ QUILT_DIFF_ARGS="-p ab --no-timestamps --no-index --color=auto"
+ QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index"
+ QUILT_COLORS="diff_hdr=1;32:diff_add=1;34:diff_rem=1;31:diff_hunk=1;33:"
+ QUILT_COLORS="${QUILT_COLORS}diff_ctx=35:diff_cctx=33"
+ if ! [ -d $d/debian/patches ]; then mkdir $d/debian/patches; fi
+fi
diff --git a/docker/debian-dev/bootstrap/setup-base.bash b/docker/debian-dev/bootstrap/setup-base.bash
new file mode 100755
index 0000000..31ded36
--- /dev/null
+++ b/docker/debian-dev/bootstrap/setup-base.bash
@@ -0,0 +1,25 @@
+#! /usr/bin/env bash
+
+set -e
+
+. /bootstrap/func.bash
+
+echo "Setting up basic system function..."
+
+echo "Installing basic packages..."
+apt-get install -y apt-utils
+apt-get install -y locales procps vim less man bash-completion software-properties-common rsync curl wget
+echo "Installing basic packages done."
+
+echo "Setting up locale..."
+localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
+echo "Setting up locale done."
+
+echo "Creating data dir..."
+mkdir -p /data
+chown $CRUPEST_DEBIAN_DEV_USER:$CRUPEST_DEBIAN_DEV_USER /data
+echo "Creating data dir done."
+
+append-bashrc bash-completion.bash
+
+echo "Setting up basic system function done."
diff --git a/docker/debian-dev/bootstrap/setup-code-server.bash b/docker/debian-dev/bootstrap/setup-code-server.bash
new file mode 100755
index 0000000..34c9697
--- /dev/null
+++ b/docker/debian-dev/bootstrap/setup-code-server.bash
@@ -0,0 +1,28 @@
+#! /usr/bin/env bash
+
+set -e
+
+. /bootstrap/func.bash
+
+echo "Setting up code server..."
+
+echo "Get latest version of code-server..."
+VERSION=$(curl -s https://api.github.com/repos/coder/code-server/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
+echo "Current latest version of code-server is $VERSION"
+
+echo "Downloading code-server..."
+url="https://github.com/coder/code-server/releases/download/v${VERSION}/code-server_${VERSION}_amd64.deb"
+curl -sSfOL "$url"
+echo "Downloading code-server done."
+
+echo "Installing code-server..."
+apt-get install -y "./code-server_${VERSION}_amd64.deb"
+echo "Installing code-server done."
+
+echo "Cleaning up deb..."
+rm "code-server_${VERSION}_amd64.deb"
+echo "Cleaning up deb done."
+
+append-bash-profile code-server.bash
+
+echo "Setting up code server done."
diff --git a/docker/debian-dev/bootstrap/setup-dev.bash b/docker/debian-dev/bootstrap/setup-dev.bash
new file mode 100755
index 0000000..92deacb
--- /dev/null
+++ b/docker/debian-dev/bootstrap/setup-dev.bash
@@ -0,0 +1,18 @@
+#! /usr/bin/env bash
+
+set -e
+
+. /bootstrap/func.bash
+
+echo "Setting up dev function..."
+
+echo "Installing dev packages..."
+apt-get install -y build-essential git devscripts debhelper quilt
+apt-get build-dep -y linux
+echo "Installing dev packages done."
+
+append-bashrc dquilt.bash
+copy-home-dot-file devscripts
+copy-home-dot-file quiltrc-dpkg
+
+echo "Setting up dev function done."
diff --git a/docker/debian-dev/bootstrap/setup-user.bash b/docker/debian-dev/bootstrap/setup-user.bash
new file mode 100755
index 0000000..f74dcdb
--- /dev/null
+++ b/docker/debian-dev/bootstrap/setup-user.bash
@@ -0,0 +1,20 @@
+#! /usr/bin/env bash
+
+set -e
+
+echo "Setting up user..."
+
+echo "Installing sudo..."
+apt-get install -y sudo
+echo "Installing sudo done."
+
+echo "Setting up sudo..."
+sed -i.bak 's|%sudo[[:space:]]\+ALL=(ALL:ALL)[[:space:]]\+ALL|%sudo ALL=(ALL:ALL) NOPASSWD: ALL|' /etc/sudoers
+echo "Setting up sudo done."
+
+echo "Adding user $CRUPEST_DEBIAN_DEV_USER ..."
+useradd -m -G sudo -s /usr/bin/bash "$CRUPEST_DEBIAN_DEV_USER"
+echo "Adding user done."
+
+echo "Setting up user done."
+
diff --git a/docker/debian-dev/bootstrap/setup.bash b/docker/debian-dev/bootstrap/setup.bash
new file mode 100755
index 0000000..09b8137
--- /dev/null
+++ b/docker/debian-dev/bootstrap/setup.bash
@@ -0,0 +1,30 @@
+#! /usr/bin/env bash
+
+set -e
+
+export DEBIAN_FRONTEND=noninteractive
+
+echo "Setting up crupest-debian-dev..."
+
+. /bootstrap/func.bash
+
+/bootstrap/apt-source/setup.bash
+
+echo "Updating apt source index..."
+apt-get update
+echo "Updating apt source index done."
+
+/bootstrap/setup-user.bash
+/bootstrap/setup-base.bash
+/bootstrap/setup-dev.bash
+
+if is_true "$CRUPEST_DEBIAN_DEV_SETUP_CODE_SERVER"; then
+ echo "CRUPEST_DEBIAN_DEV_SETUP_CODE_SERVER is true, setting up code-server..."
+ /bootstrap/setup-code-server.bash
+fi
+
+echo "Cleaning up apt source index..."
+rm -rf /var/lib/apt/lists/*
+echo "Cleaning up apt source index done."
+
+echo "Setting up crupest-debian-dev done."
diff --git a/docker/debian-dev/bootstrap/start/code-server.bash b/docker/debian-dev/bootstrap/start/code-server.bash
new file mode 100755
index 0000000..7dfc0e9
--- /dev/null
+++ b/docker/debian-dev/bootstrap/start/code-server.bash
@@ -0,0 +1,18 @@
+#! /usr/bin/env bash
+
+export CODE_SERVER_CONFIG="/data/code-server-config.yaml"
+
+CODE_SERVER_PROGRAM=code-server
+CODE_SERVER_PORT=8080
+
+if which "$CODE_SERVER_PROGRAM" > /dev/null 2>&1; then
+ if ! pgrep -x "$CODE_SERVER_PROGRAM" > /dev/null 2>&1; then
+ echo "code-server is not running, starting..."
+ "$CODE_SERVER_PROGRAM" "--bind-addr" "0.0.0.0:$CODE_SERVER_PORT"
+ else
+ echo "code-server is already running."
+ fi
+else
+ echo "code-server not found, skipping code-server setup." >&2
+ exit 1
+fi
diff --git a/docker/debian-dev/bootstrap/wait.bash b/docker/debian-dev/bootstrap/wait.bash
new file mode 100755
index 0000000..501c706
--- /dev/null
+++ b/docker/debian-dev/bootstrap/wait.bash
@@ -0,0 +1,5 @@
+#! /usr/bin/env bash
+
+set -e
+
+tail -f /dev/null
diff --git a/docker/nginx/Dockerfile b/docker/nginx/Dockerfile
new file mode 100644
index 0000000..6d0400b
--- /dev/null
+++ b/docker/nginx/Dockerfile
@@ -0,0 +1,8 @@
+FROM node:lts AS build-www
+RUN npm install -g pnpm
+COPY sites/www /sites/www
+WORKDIR /sites/www
+RUN pnpm install --frozen-lockfile && pnpm run build
+
+FROM nginx:mainline
+COPY --from=build-www /sites/www/dist /srv/www
diff --git a/docker/nginx/sites/www/.dockerignore b/docker/nginx/sites/www/.dockerignore
new file mode 100644
index 0000000..ef718b9
--- /dev/null
+++ b/docker/nginx/sites/www/.dockerignore
@@ -0,0 +1,3 @@
+.parcel-cache
+dist
+node_modules
diff --git a/docker/nginx/sites/www/.gitignore b/docker/nginx/sites/www/.gitignore
new file mode 100644
index 0000000..0b1e50b
--- /dev/null
+++ b/docker/nginx/sites/www/.gitignore
@@ -0,0 +1,26 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+.parcel-cache
diff --git a/docker/nginx/sites/www/avatar.png b/docker/nginx/sites/www/avatar.png
new file mode 100644
index 0000000..d890d8d
--- /dev/null
+++ b/docker/nginx/sites/www/avatar.png
Binary files differ
diff --git a/docker/nginx/sites/www/favicon.ico b/docker/nginx/sites/www/favicon.ico
new file mode 100644
index 0000000..922a523
--- /dev/null
+++ b/docker/nginx/sites/www/favicon.ico
Binary files differ
diff --git a/docker/nginx/sites/www/github-mark.png b/docker/nginx/sites/www/github-mark.png
new file mode 100644
index 0000000..6cb3b70
--- /dev/null
+++ b/docker/nginx/sites/www/github-mark.png
Binary files differ
diff --git a/docker/nginx/sites/www/index.html b/docker/nginx/sites/www/index.html
new file mode 100644
index 0000000..6fae9ef
--- /dev/null
+++ b/docker/nginx/sites/www/index.html
@@ -0,0 +1,111 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="UTF-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <link rel="icon" href="./favicon.ico" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>crupest</title>
+</head>
+
+<body>
+ <div class="slogan-container">
+ <div class="slogan happy">
+ <span>🙃The world is full of pain, but we can fix it with love!</span>
+ </div>
+ <div class="slogan angry">
+ <span>😡The world is a piece of shit, so let's make it a little better!</span>
+ </div>
+ </div>
+ <article id="main-article">
+ <img id="avatar" src="./avatar.png" alt="My avatar" width="80" height="80"/>
+ <h1 id="title">Hello! This is <span id="title-name">crupest</span> !</h1>
+ <hr/>
+ <section>
+ <p>Welcome to my home page! Nice to meet you here! 🥰</p>
+ <p>If you have something interesting to share with me, feel free to email me at
+ <a rel="noopener noreferrer" href="mailto:crupest@crupest.life">crupest@crupest.life</a>.</p>
+ <p>You can also create an issue in any of my repos on GitHub to talk anything to me,
+ <a rel="noopener noreferrer" href="https://github.com/crupest">https://github.com/crupest</a>.</p>
+ </section>
+ <section>
+ <h2 id="friends">My Friends <small>(more links are being collected ...)</small></h2>
+ <div id="friends-container">
+ <div class="friend">
+ <a rel="noopener noreferrer" href="https://wsmcs.cn">
+ <img class="friend-avatar" alt="Friend WSM's avatar"
+ src="https://wsmcs.cn/wp-content/uploads/2023/02/BifengxiaPanda_ZH-CN8879969527_UHD-scaled.jpg"
+ width="80" height="80"/><br/>
+ wsm</a>
+ <a rel="noopener noreferrer" href="https://github.com/wushuming666"><img
+ class="friend-github" src="./github-mark.png"/></a>
+ </div>
+ <div class="friend">
+ <a rel="noopener noreferrer" href="https://www.hszsoft.com">
+ <img class="friend-avatar" alt="Friend HSZ's avatar"
+ src="https://avatars.githubusercontent.com/u/63097618?v=4"
+ width="80" height="80"/><br/>
+ hsz</a>
+ <a rel="noopener noreferrer" href="https://github.com/hszSoft"><img
+ class="friend-github" src="./github-mark.png"/></a><br/>
+ <span class="friend-tag">随性の程序员</span>
+ </div>
+ </div>
+ </section>
+ <section>
+ <h2>Other Links</h2>
+ <ul>
+ <li><a rel="noopener noreferrer" href="https://crupest.life">https://crupest.life</a>
+ : home page, aka the one you are reading, built with
+ <a rel="noopener noreferrer" href="https://parceljs.org">Parcel</a>
+ and
+ <a rel="noopener noreferrer" href="https://pnpm.io">pnpm</a>.</li>
+ <li><a rel="noopener noreferrer" href="https://crupest.life/blog">https://crupest.life/blog</a>
+ : blogs, built with
+ <a rel="noopener noreferrer" href="https://gohugo.io">hugo</a>.</li>
+ <li><a rel="noopener noreferrer" href="https://git.crupest.life">https://git.crupest.life</a>
+ : self-hosted
+ <a rel="noopener noreferrer" href="https://forgejo.org">Forgejo</a>
+ instance.</li>
+ <li><del><span class="fake-link">https://timeline.crupest.life</span> : micro-blog with my own web app
+ <a rel="noopener noreferrer" href="https://github.com/crupest/Timeline">Timeline</a>.</del>
+ No longer maintain, so it stops serving due to security concerns.
+ </li>
+ </ul>
+ </section>
+ <section>
+ <h2>Always Remember</h2>
+ <figure class="citation">
+ <blockquote>
+ <p>Die Philosophen haben die Welt nur verschieden interpretiert, es kömmt aber darauf an, sie zu verändern.</p>
+ <p><small>Translated from German:</small>
+ The philosophers have only interpreted the world in various ways, the point is to change it.</p>
+ </blockquote>
+ <figcaption>
+ <cite>Karl Marx, Theses on Feuerbach (1845)</cite>
+ </figcaption>
+ </figure>
+ </section>
+ <hr/>
+ <footer>
+ <p id="license">
+ <small>This work is licensed under
+ <a rel="license noopener noreferrer"
+ href="https://creativecommons.org/licenses/by-nc/4.0/"
+ target="_blank">
+ <span id="license-text">CC BY-NC 4.0</span>
+ <span id="license-img-container">
+ <img src="https://mirrors.creativecommons.org/presskit/icons/cc.svg"/>
+ <img src="https://mirrors.creativecommons.org/presskit/icons/by.svg"/>
+ <img src="https://mirrors.creativecommons.org/presskit/icons/nc.svg"/>
+ </span>
+ </a>
+ </small>
+ </p>
+ </footer>
+ </article>
+ <script type="module" src="./src/main.ts"></script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/docker/nginx/sites/www/package.json b/docker/nginx/sites/www/package.json
new file mode 100644
index 0000000..c5c5d4f
--- /dev/null
+++ b/docker/nginx/sites/www/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "crupest-www",
+ "private": true,
+ "version": "0.1.0",
+ "source": "index.html",
+ "scripts": {
+ "start": "parcel",
+ "build": "tsc && parcel build"
+ },
+ "devDependencies": {
+ "@tsconfig/recommended": "^1.0.8",
+ "@types/parcel-env": "^0.0.8",
+ "parcel": "^2.13.3",
+ "prettier": "^3.4.2",
+ "typescript": "^5.7.3"
+ }
+} \ No newline at end of file
diff --git a/docker/nginx/sites/www/pnpm-lock.yaml b/docker/nginx/sites/www/pnpm-lock.yaml
new file mode 100644
index 0000000..1d440a9
--- /dev/null
+++ b/docker/nginx/sites/www/pnpm-lock.yaml
@@ -0,0 +1,2016 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ devDependencies:
+ '@tsconfig/recommended':
+ specifier: ^1.0.8
+ version: 1.0.8
+ '@types/parcel-env':
+ specifier: ^0.0.8
+ version: 0.0.8
+ parcel:
+ specifier: ^2.13.3
+ version: 2.13.3(@swc/helpers@0.5.15)(typescript@5.7.3)
+ prettier:
+ specifier: ^3.4.2
+ version: 3.4.2
+ typescript:
+ specifier: ^5.7.3
+ version: 5.7.3
+
+packages:
+
+ '@babel/code-frame@7.26.2':
+ resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.25.9':
+ resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@lezer/common@1.2.3':
+ resolution: {integrity: sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==}
+
+ '@lezer/lr@1.4.2':
+ resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==}
+
+ '@lmdb/lmdb-darwin-arm64@2.8.5':
+ resolution: {integrity: sha512-KPDeVScZgA1oq0CiPBcOa3kHIqU+pTOwRFDIhxvmf8CTNvqdZQYp5cCKW0bUk69VygB2PuTiINFWbY78aR2pQw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@lmdb/lmdb-darwin-x64@2.8.5':
+ resolution: {integrity: sha512-w/sLhN4T7MW1nB3R/U8WK5BgQLz904wh+/SmA2jD8NnF7BLLoUgflCNxOeSPOWp8geP6nP/+VjWzZVip7rZ1ug==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@lmdb/lmdb-linux-arm64@2.8.5':
+ resolution: {integrity: sha512-vtbZRHH5UDlL01TT5jB576Zox3+hdyogvpcbvVJlmU5PdL3c5V7cj1EODdh1CHPksRl+cws/58ugEHi8bcj4Ww==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@lmdb/lmdb-linux-arm@2.8.5':
+ resolution: {integrity: sha512-c0TGMbm2M55pwTDIfkDLB6BpIsgxV4PjYck2HiOX+cy/JWiBXz32lYbarPqejKs9Flm7YVAKSILUducU9g2RVg==}
+ cpu: [arm]
+ os: [linux]
+
+ '@lmdb/lmdb-linux-x64@2.8.5':
+ resolution: {integrity: sha512-Xkc8IUx9aEhP0zvgeKy7IQ3ReX2N8N1L0WPcQwnZweWmOuKfwpS3GRIYqLtK5za/w3E60zhFfNdS+3pBZPytqQ==}
+ cpu: [x64]
+ os: [linux]
+
+ '@lmdb/lmdb-win32-x64@2.8.5':
+ resolution: {integrity: sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@mischnic/json-sourcemap@0.1.1':
+ resolution: {integrity: sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==}
+ engines: {node: '>=12.0.0'}
+
+ '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
+ resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
+ resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
+ resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
+ resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==}
+ cpu: [arm]
+ os: [linux]
+
+ '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
+ resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==}
+ cpu: [x64]
+ os: [linux]
+
+ '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
+ resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/bundler-default@2.13.3':
+ resolution: {integrity: sha512-mOuWeth0bZzRv1b9Lrvydis/hAzJyePy0gwa0tix3/zyYBvw0JY+xkXVR4qKyD/blc1Ra2qOlfI2uD3ucnsdXA==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/cache@2.13.3':
+ resolution: {integrity: sha512-Vz5+K5uCt9mcuQAMDo0JdbPYDmVdB8Nvu/A2vTEK2rqZPxvoOTczKeMBA4JqzKqGURHPRLaJCvuR8nDG+jhK9A==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ '@parcel/core': ^2.13.3
+
+ '@parcel/codeframe@2.13.3':
+ resolution: {integrity: sha512-L/PQf+PT0xM8k9nc0B+PxxOYO2phQYnbuifu9o4pFRiqVmCtHztP+XMIvRJ2gOEXy3pgAImSPFVJ3xGxMFky4g==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/compressor-raw@2.13.3':
+ resolution: {integrity: sha512-C6vjDlgTLjYc358i7LA/dqcL0XDQZ1IHXFw6hBaHHOfxPKW2T4bzUI6RURyToEK9Q1X7+ggDKqgdLxwp4veCFg==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/config-default@2.13.3':
+ resolution: {integrity: sha512-WUsx83ic8DgLwwnL1Bua4lRgQqYjxiTT+DBxESGk1paNm1juWzyfPXEQDLXwiCTcWMQGiXQFQ8OuSISauVQ8dQ==}
+ peerDependencies:
+ '@parcel/core': ^2.13.3
+
+ '@parcel/core@2.13.3':
+ resolution: {integrity: sha512-SRZFtqGiaKHlZ2YAvf+NHvBFWS3GnkBvJMfOJM7kxJRK3M1bhbwJa/GgSdzqro5UVf9Bfj6E+pkdrRQIOZ7jMQ==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/diagnostic@2.13.3':
+ resolution: {integrity: sha512-C70KXLBaXLJvr7XCEVu8m6TqNdw1gQLxqg5BQ8roR62R4vWWDnOq8PEksxDi4Y8Z/FF4i3Sapv6tRx9iBNxDEg==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/events@2.13.3':
+ resolution: {integrity: sha512-ZkSHTTbD/E+53AjUzhAWTnMLnxLEU5yRw0H614CaruGh+GjgOIKyukGeToF5Gf/lvZ159VrJCGE0Z5EpgHVkuQ==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/feature-flags@2.13.3':
+ resolution: {integrity: sha512-UZm14QpamDFoUut9YtCZSpG1HxPs07lUwUCpsAYL0PpxASD3oWJQxIJGfDZPa2272DarXDG9adTKrNXvkHZblw==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/fs@2.13.3':
+ resolution: {integrity: sha512-+MPWAt0zr+TCDSlj1LvkORTjfB/BSffsE99A9AvScKytDSYYpY2s0t4vtV9unSh0FHMS2aBCZNJ4t7KL+DcPIg==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ '@parcel/core': ^2.13.3
+
+ '@parcel/graph@3.3.3':
+ resolution: {integrity: sha512-pxs4GauEdvCN8nRd6wG3st6LvpHske3GfqGwUSR0P0X0pBPI1/NicvXz6xzp3rgb9gPWfbKXeI/2IOTfIxxVfg==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/logger@2.13.3':
+ resolution: {integrity: sha512-8YF/ZhsQgd7ohQ2vEqcMD1Ag9JlJULROWRPGgGYLGD+twuxAiSdiFBpN3f+j4gQN4PYaLaIS/SwUFx11J243fQ==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/markdown-ansi@2.13.3':
+ resolution: {integrity: sha512-B4rUdlNUulJs2xOQuDbN7Hq5a9roq8IZUcJ1vQ8PAv+zMGb7KCfqIIr/BSCDYGhayfAGBVWW8x55Kvrl1zrDYw==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/namer-default@2.13.3':
+ resolution: {integrity: sha512-A2a5A5fuyNcjSGOS0hPcdQmOE2kszZnLIXof7UMGNkNkeC62KAG8WcFZH5RNOY3LT5H773hq51zmc2Y2gE5Rnw==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/node-resolver-core@3.4.3':
+ resolution: {integrity: sha512-IEnMks49egEic1ITBp59VQyHzkSQUXqpU9hOHwqN3KoSTdZ6rEgrXcS3pa6tdXay4NYGlcZ88kFCE8i/xYoVCg==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/optimizer-css@2.13.3':
+ resolution: {integrity: sha512-A8o9IVCv919vhv69SkLmyW2WjJR5WZgcMqV6L1uiGF8i8z18myrMhrp2JuSHx29PRT9uNyzNC4Xrd4StYjIhJg==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/optimizer-htmlnano@2.13.3':
+ resolution: {integrity: sha512-K4Uvg0Sy2pECP7pdvvbud++F0pfcbNkq+IxTrgqBX5HJnLEmRZwgdvZEKF43oMEolclMnURMQRGjRplRaPdbXg==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/optimizer-image@2.13.3':
+ resolution: {integrity: sha512-wlDUICA29J4UnqkKrWiyt68g1e85qfYhp4zJFcFJL0LX1qqh1QwsLUz3YJ+KlruoqPxJSFEC8ncBEKiVCsqhEQ==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+ peerDependencies:
+ '@parcel/core': ^2.13.3
+
+ '@parcel/optimizer-svgo@2.13.3':
+ resolution: {integrity: sha512-piIKxQKzhZK54dJR6yqIcq+urZmpsfgUpLCZT3cnWlX4ux5+S2iN66qqZBs0zVn+a58LcWcoP4Z9ieiJmpiu2w==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/optimizer-swc@2.13.3':
+ resolution: {integrity: sha512-zNSq6oWqLlW8ksPIDjM0VgrK6ZAJbPQCDvs1V+p0oX3CzEe85lT5VkRpnfrN1+/vvEJNGL8e60efHKpI+rXGTA==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/package-manager@2.13.3':
+ resolution: {integrity: sha512-FLNI5OrZxymGf/Yln0E/kjnGn5sdkQAxW7pQVdtuM+5VeN75yibJRjsSGv88PvJ+KvpD2ANgiIJo1RufmoPcww==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ '@parcel/core': ^2.13.3
+
+ '@parcel/packager-css@2.13.3':
+ resolution: {integrity: sha512-ghDqRMtrUwaDERzFm9le0uz2PTeqqsjsW0ihQSZPSAptElRl9o5BR+XtMPv3r7Ui0evo+w35gD55oQCJ28vCig==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/packager-html@2.13.3':
+ resolution: {integrity: sha512-jDLnKSA/EzVEZ3/aegXO3QJ/Ij732AgBBkIQfeC8tUoxwVz5b3HiPBAjVjcUSfZs7mdBSHO+ELWC3UD+HbsIrQ==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/packager-js@2.13.3':
+ resolution: {integrity: sha512-0pMHHf2zOn7EOJe88QJw5h/wcV1bFfj6cXVcE55Wa8GX3V+SdCgolnlvNuBcRQ1Tlx0Xkpo+9hMFVIQbNQY6zw==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/packager-raw@2.13.3':
+ resolution: {integrity: sha512-AWu4UB+akBdskzvT3KGVHIdacU9f7cI678DQQ1jKQuc9yZz5D0VFt3ocFBOmvDfEQDF0uH3jjtJR7fnuvX7Biw==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/packager-svg@2.13.3':
+ resolution: {integrity: sha512-tKGRiFq/4jh5u2xpTstNQ7gu+RuZWzlWqpw5NaFmcKe6VQe5CMcS499xTFoREAGnRvevSeIgC38X1a+VOo+/AA==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/packager-wasm@2.13.3':
+ resolution: {integrity: sha512-SZB56/b230vFrSehVXaUAWjJmWYc89gzb8OTLkBm7uvtFtov2J1R8Ig9TTJwinyXE3h84MCFP/YpQElSfoLkJw==}
+ engines: {node: '>=16.0.0', parcel: ^2.13.3}
+
+ '@parcel/plugin@2.13.3':
+ resolution: {integrity: sha512-cterKHHcwg6q11Gpif/aqvHo056TR+yDVJ3fSdiG2xr5KD1VZ2B3hmofWERNNwjMcnR1h9Xq40B7jCKUhOyNFA==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/profiler@2.13.3':
+ resolution: {integrity: sha512-ok6BwWSLvyHe5TuSXjSacYnDStFgP5Y30tA9mbtWSm0INDsYf+m5DqzpYPx8U54OaywWMK8w3MXUClosJX3aPA==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/reporter-cli@2.13.3':
+ resolution: {integrity: sha512-EA5tKt/6bXYNMEavSs35qHlFdx6cZmRazlZxPBgxPePQYoouNAPMNLUOEQozaPhz9f5fvNDN7EHOFaAWcdO2LA==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/reporter-dev-server@2.13.3':
+ resolution: {integrity: sha512-ZNeFp6AOIQFv7mZIv2P5O188dnZHNg0ymeDVcakfZomwhpSva2dFNS3AnvWo4eyWBlUxkmQO8BtaxeWTs7jAuA==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/reporter-tracer@2.13.3':
+ resolution: {integrity: sha512-aBsVPI8jLZTDkFYrI69GxnsdvZKEYerkPsu935LcX9rfUYssOnmmUP+3oI+8fbg+qNjJuk9BgoQ4hCp9FOphMQ==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/resolver-default@2.13.3':
+ resolution: {integrity: sha512-urBZuRALWT9pFMeWQ8JirchLmsQEyI9lrJptiwLbJWrwvmlwSUGkcstmPwoNRf/aAQjICB7ser/247Vny0pFxA==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/runtime-browser-hmr@2.13.3':
+ resolution: {integrity: sha512-EAcPojQFUNUGUrDk66cu3ySPO0NXRVS5CKPd4QrxPCVVbGzde4koKu8krC/TaGsoyUqhie8HMnS70qBP0GFfcQ==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/runtime-js@2.13.3':
+ resolution: {integrity: sha512-62OucNAnxb2Q0uyTFWW/0Hvv2DJ4b5H6neh/YFu2/wmxaZ37xTpEuEcG2do7KW54xE5DeLP+RliHLwi4NvR3ww==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/runtime-react-refresh@2.13.3':
+ resolution: {integrity: sha512-PYZ1klpJVwqE3WuifILjtF1dugtesHEuJcXYZI85T6UoRSD5ctS1nAIpZzT14Ga1lRt/jd+eAmhWL1l3m/Vk1Q==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/runtime-service-worker@2.13.3':
+ resolution: {integrity: sha512-BjMhPuT7Us1+YIo31exPRwomPiL+jrZZS5UUAwlEW2XGHDceEotzRM94LwxeFliCScT4IOokGoxixm19qRuzWg==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/rust@2.13.3':
+ resolution: {integrity: sha512-dLq85xDAtzr3P5200cvxk+8WXSWauYbxuev9LCPdwfhlaWo/JEj6cu9seVdWlkagjGwkoV1kXC+GGntgUXOLAQ==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/source-map@2.1.1':
+ resolution: {integrity: sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==}
+ engines: {node: ^12.18.3 || >=14}
+
+ '@parcel/transformer-babel@2.13.3':
+ resolution: {integrity: sha512-ikzK9f5WTFrdQsPitQgjCPH6HmVU8AQPRemIJ2BndYhtodn5PQut5cnSvTrqax8RjYvheEKCQk/Zb/uR7qgS3g==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/transformer-css@2.13.3':
+ resolution: {integrity: sha512-zbrNURGph6JeVADbGydyZ7lcu/izj41kDxQ9xw4RPRW/3rofQiTU0OTREi+uBWiMENQySXVivEdzHA9cA+aLAA==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/transformer-html@2.13.3':
+ resolution: {integrity: sha512-Yf74FkL9RCCB4+hxQRVMNQThH9+fZ5w0NLiQPpWUOcgDEEyxTi4FWPQgEBsKl/XK2ehdydbQB9fBgPQLuQxwPg==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/transformer-image@2.13.3':
+ resolution: {integrity: sha512-wL1CXyeFAqbp2wcEq/JD3a/tbAyVIDMTC6laQxlIwnVV7dsENhK1qRuJZuoBdixESeUpFQSmmQvDIhcfT/cUUg==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+ peerDependencies:
+ '@parcel/core': ^2.13.3
+
+ '@parcel/transformer-js@2.13.3':
+ resolution: {integrity: sha512-KqfNGn1IHzDoN2aPqt4nDksgb50Xzcny777C7A7hjlQ3cmkjyJrixYjzzsPaPSGJ+kJpknh3KE8unkQ9mhFvRQ==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+ peerDependencies:
+ '@parcel/core': ^2.13.3
+
+ '@parcel/transformer-json@2.13.3':
+ resolution: {integrity: sha512-rrq0ab6J0w9ePtsxi0kAvpCmrUYXXAx1Z5PATZakv89rSYbHBKEdXxyCoKFui/UPVCUEGVs5r0iOFepdHpIyeA==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/transformer-postcss@2.13.3':
+ resolution: {integrity: sha512-AIiWpU0QSFBrPcYIqAnhqB8RGE6yHFznnxztfg1t2zMSOnK3xoU6xqYKv8H/MduShGGrC3qVOeDfM8MUwzL3cw==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/transformer-posthtml@2.13.3':
+ resolution: {integrity: sha512-5GSLyccpHASwFAu3uJ83gDIBSvfsGdVmhJvy0Vxe+K1Fklk2ibhvvtUHMhB7mg6SPHC+R9jsNc3ZqY04ZLeGjw==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/transformer-raw@2.13.3':
+ resolution: {integrity: sha512-BFsAbdQF0l8/Pdb7dSLJeYcd8jgwvAUbHgMink2MNXJuRUvDl19Gns8jVokU+uraFHulJMBj40+K/RTd33in4g==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/transformer-react-refresh-wrap@2.13.3':
+ resolution: {integrity: sha512-mOof4cRyxsZRdg8kkWaFtaX98mHpxUhcGPU+nF9RQVa9q737ItxrorsPNR9hpZAyE2TtFNflNW7RoYsgvlLw8w==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/transformer-svg@2.13.3':
+ resolution: {integrity: sha512-9jm7ZF4KHIrGLWlw/SFUz5KKJ20nxHvjFAmzde34R9Wu+F1BOjLZxae7w4ZRwvIc+UVOUcBBQFmhSVwVDZg6Dw==}
+ engines: {node: '>= 16.0.0', parcel: ^2.13.3}
+
+ '@parcel/types-internal@2.13.3':
+ resolution: {integrity: sha512-Lhx0n+9RCp+Ipktf/I+CLm3zE9Iq9NtDd8b2Vr5lVWyoT8AbzBKIHIpTbhLS4kjZ80L3I6o93OYjqAaIjsqoZw==}
+
+ '@parcel/types@2.13.3':
+ resolution: {integrity: sha512-+RpFHxx8fy8/dpuehHUw/ja9PRExC3wJoIlIIF42E7SLu2SvlTHtKm6EfICZzxCXNEBzjoDbamCRcN0nmTPlhw==}
+
+ '@parcel/utils@2.13.3':
+ resolution: {integrity: sha512-yxY9xw2wOUlJaScOXYZmMGoZ4Ck4Kqj+p6Koe5kLkkWM1j98Q0Dj2tf/mNvZi4yrdnlm+dclCwNRnuE8Q9D+pw==}
+ engines: {node: '>= 16.0.0'}
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==}
+ engines: {node: '>= 10.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ '@parcel/watcher@2.5.1':
+ resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==}
+ engines: {node: '>= 10.0.0'}
+
+ '@parcel/workers@2.13.3':
+ resolution: {integrity: sha512-oAHmdniWTRwwwsKbcF4t3VjOtKN+/W17Wj5laiYB+HLkfsjGTfIQPj3sdXmrlBAGpI4omIcvR70PHHXnfdTfwA==}
+ engines: {node: '>= 16.0.0'}
+ peerDependencies:
+ '@parcel/core': ^2.13.3
+
+ '@swc/core-darwin-arm64@1.10.12':
+ resolution: {integrity: sha512-pOANQegUTAriW7jq3SSMZGM5l89yLVMs48R0F2UG6UZsH04SiViCnDctOGlA/Sa++25C+rL9MGMYM1jDLylBbg==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@swc/core-darwin-x64@1.10.12':
+ resolution: {integrity: sha512-m4kbpIDDsN1FrwfNQMU+FTrss356xsXvatLbearwR+V0lqOkjLBP0VmRvQfHEg+uy13VPyrT9gj4HLoztlci7w==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@swc/core-linux-arm-gnueabihf@1.10.12':
+ resolution: {integrity: sha512-OY9LcupgqEu8zVK+rJPes6LDJJwPDmwaShU96beTaxX2K6VrXbpwm5WbPS/8FfQTsmpnuA7dCcMPUKhNgmzTrQ==}
+ engines: {node: '>=10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@swc/core-linux-arm64-gnu@1.10.12':
+ resolution: {integrity: sha512-nJD587rO0N4y4VZszz3xzVr7JIiCzSMhEMWnPjuh+xmPxDBz0Qccpr8xCr1cSxpl1uY7ERkqAGlKr6CwoV5kVg==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@swc/core-linux-arm64-musl@1.10.12':
+ resolution: {integrity: sha512-oqhSmV+XauSf0C//MoQnVErNUB/5OzmSiUzuazyLsD5pwqKNN+leC3JtRQ/QVzaCpr65jv9bKexT9+I2Tt3xDw==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@swc/core-linux-x64-gnu@1.10.12':
+ resolution: {integrity: sha512-XldSIHyjD7m1Gh+/8rxV3Ok711ENLI420CU2EGEqSe3VSGZ7pHJvJn9ZFbYpWhsLxPqBYMFjp3Qw+J6OXCPXCA==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@swc/core-linux-x64-musl@1.10.12':
+ resolution: {integrity: sha512-wvPXzJxzPgTqhyp1UskOx1hRTtdWxlyFD1cGWOxgLsMik0V9xKRgqKnMPv16Nk7L9xl6quQ6DuUHj9ID7L3oVw==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+
+ '@swc/core-win32-arm64-msvc@1.10.12':
+ resolution: {integrity: sha512-TUYzWuu1O7uyIcRfxdm6Wh1u+gNnrW5M1DUgDOGZLsyQzgc2Zjwfh2llLhuAIilvCVg5QiGbJlpibRYJ/8QGsg==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@swc/core-win32-ia32-msvc@1.10.12':
+ resolution: {integrity: sha512-4Qrw+0Xt+Fe2rz4OJ/dEPMeUf/rtuFWWAj/e0vL7J5laUHirzxawLRE5DCJLQTarOiYR6mWnmadt9o3EKzV6Xg==}
+ engines: {node: '>=10'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@swc/core-win32-x64-msvc@1.10.12':
+ resolution: {integrity: sha512-YiloZXLW7rUxJpALwHXaGjVaAEn+ChoblG7/3esque+Y7QCyheoBUJp2DVM1EeVA43jBfZ8tvYF0liWd9Tpz1A==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@swc/core@1.10.12':
+ resolution: {integrity: sha512-+iUL0PYpPm6N9AdV1wvafakvCqFegQus1aoEDxgFsv3/uNVNIyRaupf/v/Zkp5hbep2EzhtoJR0aiJIzDbXWHg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@swc/helpers': '*'
+ peerDependenciesMeta:
+ '@swc/helpers':
+ optional: true
+
+ '@swc/counter@0.1.3':
+ resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
+
+ '@swc/helpers@0.5.15':
+ resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==}
+
+ '@swc/types@0.1.17':
+ resolution: {integrity: sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==}
+
+ '@tsconfig/recommended@1.0.8':
+ resolution: {integrity: sha512-TotjFaaXveVUdsrXCdalyF6E5RyG6+7hHHQVZonQtdlk1rJZ1myDIvPUUKPhoYv+JAzThb2lQJh9+9ZfF46hsA==}
+
+ '@types/parcel-env@0.0.8':
+ resolution: {integrity: sha512-6Sa7yWgEPn6jxv1A4AdEMUTAth909LMjJhMfQOp3icwA3fVHZo1wPY+tQTWE/tZvomSa2M82V05pdk1CW8T7Xw==}
+
+ ansi-styles@4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+
+ argparse@2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+
+ base-x@3.0.10:
+ resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==}
+
+ braces@3.0.3:
+ resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
+ engines: {node: '>=8'}
+
+ browserslist@4.24.4:
+ resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001696:
+ resolution: {integrity: sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==}
+
+ chalk@4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+
+ chrome-trace-event@1.0.4:
+ resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==}
+ engines: {node: '>=6.0'}
+
+ clone@2.1.2:
+ resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
+ engines: {node: '>=0.8'}
+
+ color-convert@2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+
+ color-name@1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+
+ commander@12.1.0:
+ resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==}
+ engines: {node: '>=18'}
+
+ cosmiconfig@9.0.0:
+ resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ typescript: '>=4.9.5'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+
+ detect-libc@1.0.3:
+ resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==}
+ engines: {node: '>=0.10'}
+ hasBin: true
+
+ detect-libc@2.0.3:
+ resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
+ engines: {node: '>=8'}
+
+ dom-serializer@1.4.1:
+ resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
+
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@4.3.1:
+ resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==}
+ engines: {node: '>= 4'}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@2.8.0:
+ resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
+
+ domutils@3.2.2:
+ resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
+
+ dotenv-expand@11.0.7:
+ resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==}
+ engines: {node: '>=12'}
+
+ dotenv@16.4.7:
+ resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
+ engines: {node: '>=12'}
+
+ electron-to-chromium@1.5.90:
+ resolution: {integrity: sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug==}
+
+ entities@2.2.0:
+ resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
+
+ entities@3.0.1:
+ resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==}
+ engines: {node: '>=0.12'}
+
+ entities@4.5.0:
+ resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
+ engines: {node: '>=0.12'}
+
+ env-paths@2.2.1:
+ resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==}
+ engines: {node: '>=6'}
+
+ error-ex@1.3.2:
+ resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ fill-range@7.1.1:
+ resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
+ engines: {node: '>=8'}
+
+ get-port@4.2.0:
+ resolution: {integrity: sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==}
+ engines: {node: '>=6'}
+
+ globals@13.24.0:
+ resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+ engines: {node: '>=8'}
+
+ has-flag@4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+
+ htmlnano@2.1.1:
+ resolution: {integrity: sha512-kAERyg/LuNZYmdqgCdYvugyLWNFAm8MWXpQMz1pLpetmCbFwoMxvkSoaAMlFrOC4OKTWI4KlZGT/RsNxg4ghOw==}
+ peerDependencies:
+ cssnano: ^7.0.0
+ postcss: ^8.3.11
+ purgecss: ^6.0.0
+ relateurl: ^0.2.7
+ srcset: 5.0.1
+ svgo: ^3.0.2
+ terser: ^5.10.0
+ uncss: ^0.17.3
+ peerDependenciesMeta:
+ cssnano:
+ optional: true
+ postcss:
+ optional: true
+ purgecss:
+ optional: true
+ relateurl:
+ optional: true
+ srcset:
+ optional: true
+ svgo:
+ optional: true
+ terser:
+ optional: true
+ uncss:
+ optional: true
+
+ htmlparser2@7.2.0:
+ resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==}
+
+ htmlparser2@9.1.0:
+ resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==}
+
+ import-fresh@3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+
+ is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+
+ is-extglob@2.1.1:
+ resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
+ engines: {node: '>=0.10.0'}
+
+ is-glob@4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+
+ is-json@2.0.1:
+ resolution: {integrity: sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==}
+
+ is-number@7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ js-yaml@4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+
+ json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ lightningcss-darwin-arm64@1.29.1:
+ resolution: {integrity: sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.29.1:
+ resolution: {integrity: sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.29.1:
+ resolution: {integrity: sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.29.1:
+ resolution: {integrity: sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.29.1:
+ resolution: {integrity: sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-arm64-musl@1.29.1:
+ resolution: {integrity: sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-x64-gnu@1.29.1:
+ resolution: {integrity: sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-linux-x64-musl@1.29.1:
+ resolution: {integrity: sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-win32-arm64-msvc@1.29.1:
+ resolution: {integrity: sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.29.1:
+ resolution: {integrity: sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.29.1:
+ resolution: {integrity: sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q==}
+ engines: {node: '>= 12.0.0'}
+
+ lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ lmdb@2.8.5:
+ resolution: {integrity: sha512-9bMdFfc80S+vSldBmG3HOuLVHnxRdNTlpzR6QDnzqCQtCzGUEAGTzBKYMeIM+I/sU4oZfgbcbS7X7F65/z/oxQ==}
+ hasBin: true
+
+ micromatch@4.0.8:
+ resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
+ engines: {node: '>=8.6'}
+
+ msgpackr-extract@3.0.3:
+ resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==}
+ hasBin: true
+
+ msgpackr@1.11.2:
+ resolution: {integrity: sha512-F9UngXRlPyWCDEASDpTf6c9uNhGPTqnTeLVt7bN+bU1eajoR/8V9ys2BRaV5C/e5ihE6sJ9uPIKaYt6bFuO32g==}
+
+ node-addon-api@6.1.0:
+ resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
+
+ node-addon-api@7.1.1:
+ resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==}
+
+ node-gyp-build-optional-packages@5.1.1:
+ resolution: {integrity: sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==}
+ hasBin: true
+
+ node-gyp-build-optional-packages@5.2.2:
+ resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==}
+ hasBin: true
+
+ node-releases@2.0.19:
+ resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
+
+ nullthrows@1.1.1:
+ resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==}
+
+ ordered-binary@1.5.3:
+ resolution: {integrity: sha512-oGFr3T+pYdTGJ+YFEILMpS3es+GiIbs9h/XQrclBXUtd44ey7XwfsMzM31f64I1SQOawDoDr/D823kNCADI8TA==}
+
+ parcel@2.13.3:
+ resolution: {integrity: sha512-8GrC8C7J8mwRpAlk7EJ7lwdFTbCN+dcXH2gy5AsEs9pLfzo9wvxOTx6W0fzSlvCOvZOita+8GdfYlGfEt0tRgA==}
+ engines: {node: '>= 16.0.0'}
+ hasBin: true
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ picomatch@2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+
+ postcss-value-parser@4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+
+ posthtml-parser@0.11.0:
+ resolution: {integrity: sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==}
+ engines: {node: '>=12'}
+
+ posthtml-parser@0.12.1:
+ resolution: {integrity: sha512-rYFmsDLfYm+4Ts2Oh4DCDSZPtdC1BLnRXAobypVzX9alj28KGl65dIFtgDY9zB57D0TC4Qxqrawuq/2et1P0GA==}
+ engines: {node: '>=16'}
+
+ posthtml-render@3.0.0:
+ resolution: {integrity: sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==}
+ engines: {node: '>=12'}
+
+ posthtml@0.16.6:
+ resolution: {integrity: sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==}
+ engines: {node: '>=12.0.0'}
+
+ prettier@3.4.2:
+ resolution: {integrity: sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==}
+ engines: {node: '>=14'}
+ hasBin: true
+
+ react-error-overlay@6.0.9:
+ resolution: {integrity: sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==}
+
+ react-refresh@0.14.2:
+ resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
+ engines: {node: '>=0.10.0'}
+
+ regenerator-runtime@0.14.1:
+ resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ safe-buffer@5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+
+ semver@7.7.0:
+ resolution: {integrity: sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==}
+ engines: {node: '>=10'}
+ hasBin: true
+
+ srcset@4.0.0:
+ resolution: {integrity: sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==}
+ engines: {node: '>=12'}
+
+ supports-color@7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+
+ term-size@2.2.1:
+ resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
+ engines: {node: '>=8'}
+
+ timsort@0.3.0:
+ resolution: {integrity: sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==}
+
+ to-regex-range@5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
+ type-fest@0.20.2:
+ resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+ engines: {node: '>=10'}
+
+ typescript@5.7.3:
+ resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ update-browserslist-db@1.1.2:
+ resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ utility-types@3.11.0:
+ resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==}
+ engines: {node: '>= 4'}
+
+ weak-lru-cache@1.2.2:
+ resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==}
+
+snapshots:
+
+ '@babel/code-frame@7.26.2':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.25.9
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/helper-validator-identifier@7.25.9': {}
+
+ '@lezer/common@1.2.3': {}
+
+ '@lezer/lr@1.4.2':
+ dependencies:
+ '@lezer/common': 1.2.3
+
+ '@lmdb/lmdb-darwin-arm64@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-darwin-x64@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-linux-arm64@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-linux-arm@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-linux-x64@2.8.5':
+ optional: true
+
+ '@lmdb/lmdb-win32-x64@2.8.5':
+ optional: true
+
+ '@mischnic/json-sourcemap@0.1.1':
+ dependencies:
+ '@lezer/common': 1.2.3
+ '@lezer/lr': 1.4.2
+ json5: 2.2.3
+
+ '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
+ optional: true
+
+ '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
+ optional: true
+
+ '@parcel/bundler-default@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/graph': 3.3.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/rust': 2.13.3
+ '@parcel/utils': 2.13.3
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/cache@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/core': 2.13.3(@swc/helpers@0.5.15)
+ '@parcel/fs': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/logger': 2.13.3
+ '@parcel/utils': 2.13.3
+ lmdb: 2.8.5
+
+ '@parcel/codeframe@2.13.3':
+ dependencies:
+ chalk: 4.1.2
+
+ '@parcel/compressor-raw@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/config-default@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)(typescript@5.7.3)':
+ dependencies:
+ '@parcel/bundler-default': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/compressor-raw': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/core': 2.13.3(@swc/helpers@0.5.15)
+ '@parcel/namer-default': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/optimizer-css': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/optimizer-htmlnano': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(typescript@5.7.3)
+ '@parcel/optimizer-image': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/optimizer-svgo': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/optimizer-swc': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)
+ '@parcel/packager-css': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/packager-html': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/packager-js': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/packager-raw': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/packager-svg': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/packager-wasm': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/reporter-dev-server': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/resolver-default': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/runtime-browser-hmr': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/runtime-js': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/runtime-react-refresh': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/runtime-service-worker': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-babel': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-css': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-html': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-image': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-js': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-json': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-postcss': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-posthtml': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-raw': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-react-refresh-wrap': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/transformer-svg': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ transitivePeerDependencies:
+ - '@swc/helpers'
+ - cssnano
+ - postcss
+ - purgecss
+ - relateurl
+ - srcset
+ - svgo
+ - terser
+ - typescript
+ - uncss
+
+ '@parcel/core@2.13.3(@swc/helpers@0.5.15)':
+ dependencies:
+ '@mischnic/json-sourcemap': 0.1.1
+ '@parcel/cache': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/events': 2.13.3
+ '@parcel/feature-flags': 2.13.3
+ '@parcel/fs': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/graph': 3.3.3
+ '@parcel/logger': 2.13.3
+ '@parcel/package-manager': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/profiler': 2.13.3
+ '@parcel/rust': 2.13.3
+ '@parcel/source-map': 2.1.1
+ '@parcel/types': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ '@parcel/workers': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ base-x: 3.0.10
+ browserslist: 4.24.4
+ clone: 2.1.2
+ dotenv: 16.4.7
+ dotenv-expand: 11.0.7
+ json5: 2.2.3
+ msgpackr: 1.11.2
+ nullthrows: 1.1.1
+ semver: 7.7.0
+ transitivePeerDependencies:
+ - '@swc/helpers'
+
+ '@parcel/diagnostic@2.13.3':
+ dependencies:
+ '@mischnic/json-sourcemap': 0.1.1
+ nullthrows: 1.1.1
+
+ '@parcel/events@2.13.3': {}
+
+ '@parcel/feature-flags@2.13.3': {}
+
+ '@parcel/fs@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/core': 2.13.3(@swc/helpers@0.5.15)
+ '@parcel/feature-flags': 2.13.3
+ '@parcel/rust': 2.13.3
+ '@parcel/types-internal': 2.13.3
+ '@parcel/utils': 2.13.3
+ '@parcel/watcher': 2.5.1
+ '@parcel/workers': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+
+ '@parcel/graph@3.3.3':
+ dependencies:
+ '@parcel/feature-flags': 2.13.3
+ nullthrows: 1.1.1
+
+ '@parcel/logger@2.13.3':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/events': 2.13.3
+
+ '@parcel/markdown-ansi@2.13.3':
+ dependencies:
+ chalk: 4.1.2
+
+ '@parcel/namer-default@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/node-resolver-core@3.4.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@mischnic/json-sourcemap': 0.1.1
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/fs': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/rust': 2.13.3
+ '@parcel/utils': 2.13.3
+ nullthrows: 1.1.1
+ semver: 7.7.0
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/optimizer-css@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/source-map': 2.1.1
+ '@parcel/utils': 2.13.3
+ browserslist: 4.24.4
+ lightningcss: 1.29.1
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/optimizer-htmlnano@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(typescript@5.7.3)':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ htmlnano: 2.1.1(typescript@5.7.3)
+ nullthrows: 1.1.1
+ posthtml: 0.16.6
+ transitivePeerDependencies:
+ - '@parcel/core'
+ - cssnano
+ - postcss
+ - purgecss
+ - relateurl
+ - srcset
+ - svgo
+ - terser
+ - typescript
+ - uncss
+
+ '@parcel/optimizer-image@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/core': 2.13.3(@swc/helpers@0.5.15)
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/rust': 2.13.3
+ '@parcel/utils': 2.13.3
+ '@parcel/workers': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+
+ '@parcel/optimizer-svgo@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/optimizer-swc@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/source-map': 2.1.1
+ '@parcel/utils': 2.13.3
+ '@swc/core': 1.10.12(@swc/helpers@0.5.15)
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+ - '@swc/helpers'
+
+ '@parcel/package-manager@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)':
+ dependencies:
+ '@parcel/core': 2.13.3(@swc/helpers@0.5.15)
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/fs': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/logger': 2.13.3
+ '@parcel/node-resolver-core': 3.4.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/types': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ '@parcel/workers': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@swc/core': 1.10.12(@swc/helpers@0.5.15)
+ semver: 7.7.0
+ transitivePeerDependencies:
+ - '@swc/helpers'
+
+ '@parcel/packager-css@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/source-map': 2.1.1
+ '@parcel/utils': 2.13.3
+ lightningcss: 1.29.1
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/packager-html@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/types': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ nullthrows: 1.1.1
+ posthtml: 0.16.6
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/packager-js@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/rust': 2.13.3
+ '@parcel/source-map': 2.1.1
+ '@parcel/types': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ globals: 13.24.0
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/packager-raw@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/packager-svg@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/types': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ posthtml: 0.16.6
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/packager-wasm@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/plugin@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/types': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/profiler@2.13.3':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/events': 2.13.3
+ '@parcel/types-internal': 2.13.3
+ chrome-trace-event: 1.0.4
+
+ '@parcel/reporter-cli@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/types': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ chalk: 4.1.2
+ term-size: 2.2.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/reporter-dev-server@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/reporter-tracer@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ chrome-trace-event: 1.0.4
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/resolver-default@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/node-resolver-core': 3.4.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/runtime-browser-hmr@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/runtime-js@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/runtime-react-refresh@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ react-error-overlay: 6.0.9
+ react-refresh: 0.14.2
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/runtime-service-worker@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/rust@2.13.3': {}
+
+ '@parcel/source-map@2.1.1':
+ dependencies:
+ detect-libc: 1.0.3
+
+ '@parcel/transformer-babel@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/source-map': 2.1.1
+ '@parcel/utils': 2.13.3
+ browserslist: 4.24.4
+ json5: 2.2.3
+ nullthrows: 1.1.1
+ semver: 7.7.0
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/transformer-css@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/source-map': 2.1.1
+ '@parcel/utils': 2.13.3
+ browserslist: 4.24.4
+ lightningcss: 1.29.1
+ nullthrows: 1.1.1
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/transformer-html@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/rust': 2.13.3
+ nullthrows: 1.1.1
+ posthtml: 0.16.6
+ posthtml-parser: 0.12.1
+ posthtml-render: 3.0.0
+ semver: 7.7.0
+ srcset: 4.0.0
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/transformer-image@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/core': 2.13.3(@swc/helpers@0.5.15)
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ '@parcel/workers': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ nullthrows: 1.1.1
+
+ '@parcel/transformer-js@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/core': 2.13.3(@swc/helpers@0.5.15)
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/rust': 2.13.3
+ '@parcel/source-map': 2.1.1
+ '@parcel/utils': 2.13.3
+ '@parcel/workers': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@swc/helpers': 0.5.15
+ browserslist: 4.24.4
+ nullthrows: 1.1.1
+ regenerator-runtime: 0.14.1
+ semver: 7.7.0
+
+ '@parcel/transformer-json@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ json5: 2.2.3
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/transformer-postcss@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/rust': 2.13.3
+ '@parcel/utils': 2.13.3
+ clone: 2.1.2
+ nullthrows: 1.1.1
+ postcss-value-parser: 4.2.0
+ semver: 7.7.0
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/transformer-posthtml@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ nullthrows: 1.1.1
+ posthtml: 0.16.6
+ posthtml-parser: 0.12.1
+ posthtml-render: 3.0.0
+ semver: 7.7.0
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/transformer-raw@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/transformer-react-refresh-wrap@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ react-refresh: 0.14.2
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/transformer-svg@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/plugin': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/rust': 2.13.3
+ nullthrows: 1.1.1
+ posthtml: 0.16.6
+ posthtml-parser: 0.12.1
+ posthtml-render: 3.0.0
+ semver: 7.7.0
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/types-internal@2.13.3':
+ dependencies:
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/feature-flags': 2.13.3
+ '@parcel/source-map': 2.1.1
+ utility-types: 3.11.0
+
+ '@parcel/types@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/types-internal': 2.13.3
+ '@parcel/workers': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ transitivePeerDependencies:
+ - '@parcel/core'
+
+ '@parcel/utils@2.13.3':
+ dependencies:
+ '@parcel/codeframe': 2.13.3
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/logger': 2.13.3
+ '@parcel/markdown-ansi': 2.13.3
+ '@parcel/rust': 2.13.3
+ '@parcel/source-map': 2.1.1
+ chalk: 4.1.2
+ nullthrows: 1.1.1
+
+ '@parcel/watcher-android-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-darwin-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-freebsd-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-arm64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-glibc@2.5.1':
+ optional: true
+
+ '@parcel/watcher-linux-x64-musl@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-arm64@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-ia32@2.5.1':
+ optional: true
+
+ '@parcel/watcher-win32-x64@2.5.1':
+ optional: true
+
+ '@parcel/watcher@2.5.1':
+ dependencies:
+ detect-libc: 1.0.3
+ is-glob: 4.0.3
+ micromatch: 4.0.8
+ node-addon-api: 7.1.1
+ optionalDependencies:
+ '@parcel/watcher-android-arm64': 2.5.1
+ '@parcel/watcher-darwin-arm64': 2.5.1
+ '@parcel/watcher-darwin-x64': 2.5.1
+ '@parcel/watcher-freebsd-x64': 2.5.1
+ '@parcel/watcher-linux-arm-glibc': 2.5.1
+ '@parcel/watcher-linux-arm-musl': 2.5.1
+ '@parcel/watcher-linux-arm64-glibc': 2.5.1
+ '@parcel/watcher-linux-arm64-musl': 2.5.1
+ '@parcel/watcher-linux-x64-glibc': 2.5.1
+ '@parcel/watcher-linux-x64-musl': 2.5.1
+ '@parcel/watcher-win32-arm64': 2.5.1
+ '@parcel/watcher-win32-ia32': 2.5.1
+ '@parcel/watcher-win32-x64': 2.5.1
+
+ '@parcel/workers@2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))':
+ dependencies:
+ '@parcel/core': 2.13.3(@swc/helpers@0.5.15)
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/logger': 2.13.3
+ '@parcel/profiler': 2.13.3
+ '@parcel/types-internal': 2.13.3
+ '@parcel/utils': 2.13.3
+ nullthrows: 1.1.1
+
+ '@swc/core-darwin-arm64@1.10.12':
+ optional: true
+
+ '@swc/core-darwin-x64@1.10.12':
+ optional: true
+
+ '@swc/core-linux-arm-gnueabihf@1.10.12':
+ optional: true
+
+ '@swc/core-linux-arm64-gnu@1.10.12':
+ optional: true
+
+ '@swc/core-linux-arm64-musl@1.10.12':
+ optional: true
+
+ '@swc/core-linux-x64-gnu@1.10.12':
+ optional: true
+
+ '@swc/core-linux-x64-musl@1.10.12':
+ optional: true
+
+ '@swc/core-win32-arm64-msvc@1.10.12':
+ optional: true
+
+ '@swc/core-win32-ia32-msvc@1.10.12':
+ optional: true
+
+ '@swc/core-win32-x64-msvc@1.10.12':
+ optional: true
+
+ '@swc/core@1.10.12(@swc/helpers@0.5.15)':
+ dependencies:
+ '@swc/counter': 0.1.3
+ '@swc/types': 0.1.17
+ optionalDependencies:
+ '@swc/core-darwin-arm64': 1.10.12
+ '@swc/core-darwin-x64': 1.10.12
+ '@swc/core-linux-arm-gnueabihf': 1.10.12
+ '@swc/core-linux-arm64-gnu': 1.10.12
+ '@swc/core-linux-arm64-musl': 1.10.12
+ '@swc/core-linux-x64-gnu': 1.10.12
+ '@swc/core-linux-x64-musl': 1.10.12
+ '@swc/core-win32-arm64-msvc': 1.10.12
+ '@swc/core-win32-ia32-msvc': 1.10.12
+ '@swc/core-win32-x64-msvc': 1.10.12
+ '@swc/helpers': 0.5.15
+
+ '@swc/counter@0.1.3': {}
+
+ '@swc/helpers@0.5.15':
+ dependencies:
+ tslib: 2.8.1
+
+ '@swc/types@0.1.17':
+ dependencies:
+ '@swc/counter': 0.1.3
+
+ '@tsconfig/recommended@1.0.8': {}
+
+ '@types/parcel-env@0.0.8': {}
+
+ ansi-styles@4.3.0:
+ dependencies:
+ color-convert: 2.0.1
+
+ argparse@2.0.1: {}
+
+ base-x@3.0.10:
+ dependencies:
+ safe-buffer: 5.2.1
+
+ braces@3.0.3:
+ dependencies:
+ fill-range: 7.1.1
+
+ browserslist@4.24.4:
+ dependencies:
+ caniuse-lite: 1.0.30001696
+ electron-to-chromium: 1.5.90
+ node-releases: 2.0.19
+ update-browserslist-db: 1.1.2(browserslist@4.24.4)
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001696: {}
+
+ chalk@4.1.2:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
+ chrome-trace-event@1.0.4: {}
+
+ clone@2.1.2: {}
+
+ color-convert@2.0.1:
+ dependencies:
+ color-name: 1.1.4
+
+ color-name@1.1.4: {}
+
+ commander@12.1.0: {}
+
+ cosmiconfig@9.0.0(typescript@5.7.3):
+ dependencies:
+ env-paths: 2.2.1
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ parse-json: 5.2.0
+ optionalDependencies:
+ typescript: 5.7.3
+
+ detect-libc@1.0.3: {}
+
+ detect-libc@2.0.3: {}
+
+ dom-serializer@1.4.1:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 4.3.1
+ entities: 2.2.0
+
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@4.3.1:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@2.8.0:
+ dependencies:
+ dom-serializer: 1.4.1
+ domelementtype: 2.3.0
+ domhandler: 4.3.1
+
+ domutils@3.2.2:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
+ dotenv-expand@11.0.7:
+ dependencies:
+ dotenv: 16.4.7
+
+ dotenv@16.4.7: {}
+
+ electron-to-chromium@1.5.90: {}
+
+ entities@2.2.0: {}
+
+ entities@3.0.1: {}
+
+ entities@4.5.0: {}
+
+ env-paths@2.2.1: {}
+
+ error-ex@1.3.2:
+ dependencies:
+ is-arrayish: 0.2.1
+
+ escalade@3.2.0: {}
+
+ fill-range@7.1.1:
+ dependencies:
+ to-regex-range: 5.0.1
+
+ get-port@4.2.0: {}
+
+ globals@13.24.0:
+ dependencies:
+ type-fest: 0.20.2
+
+ has-flag@4.0.0: {}
+
+ htmlnano@2.1.1(typescript@5.7.3):
+ dependencies:
+ cosmiconfig: 9.0.0(typescript@5.7.3)
+ posthtml: 0.16.6
+ timsort: 0.3.0
+ transitivePeerDependencies:
+ - typescript
+
+ htmlparser2@7.2.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 4.3.1
+ domutils: 2.8.0
+ entities: 3.0.1
+
+ htmlparser2@9.1.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ domutils: 3.2.2
+ entities: 4.5.0
+
+ import-fresh@3.3.0:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ is-arrayish@0.2.1: {}
+
+ is-extglob@2.1.1: {}
+
+ is-glob@4.0.3:
+ dependencies:
+ is-extglob: 2.1.1
+
+ is-json@2.0.1: {}
+
+ is-number@7.0.0: {}
+
+ js-tokens@4.0.0: {}
+
+ js-yaml@4.1.0:
+ dependencies:
+ argparse: 2.0.1
+
+ json-parse-even-better-errors@2.3.1: {}
+
+ json5@2.2.3: {}
+
+ lightningcss-darwin-arm64@1.29.1:
+ optional: true
+
+ lightningcss-darwin-x64@1.29.1:
+ optional: true
+
+ lightningcss-freebsd-x64@1.29.1:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.29.1:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.29.1:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.29.1:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.29.1:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.29.1:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.29.1:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.29.1:
+ optional: true
+
+ lightningcss@1.29.1:
+ dependencies:
+ detect-libc: 1.0.3
+ optionalDependencies:
+ lightningcss-darwin-arm64: 1.29.1
+ lightningcss-darwin-x64: 1.29.1
+ lightningcss-freebsd-x64: 1.29.1
+ lightningcss-linux-arm-gnueabihf: 1.29.1
+ lightningcss-linux-arm64-gnu: 1.29.1
+ lightningcss-linux-arm64-musl: 1.29.1
+ lightningcss-linux-x64-gnu: 1.29.1
+ lightningcss-linux-x64-musl: 1.29.1
+ lightningcss-win32-arm64-msvc: 1.29.1
+ lightningcss-win32-x64-msvc: 1.29.1
+
+ lines-and-columns@1.2.4: {}
+
+ lmdb@2.8.5:
+ dependencies:
+ msgpackr: 1.11.2
+ node-addon-api: 6.1.0
+ node-gyp-build-optional-packages: 5.1.1
+ ordered-binary: 1.5.3
+ weak-lru-cache: 1.2.2
+ optionalDependencies:
+ '@lmdb/lmdb-darwin-arm64': 2.8.5
+ '@lmdb/lmdb-darwin-x64': 2.8.5
+ '@lmdb/lmdb-linux-arm': 2.8.5
+ '@lmdb/lmdb-linux-arm64': 2.8.5
+ '@lmdb/lmdb-linux-x64': 2.8.5
+ '@lmdb/lmdb-win32-x64': 2.8.5
+
+ micromatch@4.0.8:
+ dependencies:
+ braces: 3.0.3
+ picomatch: 2.3.1
+
+ msgpackr-extract@3.0.3:
+ dependencies:
+ node-gyp-build-optional-packages: 5.2.2
+ optionalDependencies:
+ '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3
+ '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3
+ optional: true
+
+ msgpackr@1.11.2:
+ optionalDependencies:
+ msgpackr-extract: 3.0.3
+
+ node-addon-api@6.1.0: {}
+
+ node-addon-api@7.1.1: {}
+
+ node-gyp-build-optional-packages@5.1.1:
+ dependencies:
+ detect-libc: 2.0.3
+
+ node-gyp-build-optional-packages@5.2.2:
+ dependencies:
+ detect-libc: 2.0.3
+ optional: true
+
+ node-releases@2.0.19: {}
+
+ nullthrows@1.1.1: {}
+
+ ordered-binary@1.5.3: {}
+
+ parcel@2.13.3(@swc/helpers@0.5.15)(typescript@5.7.3):
+ dependencies:
+ '@parcel/config-default': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)(typescript@5.7.3)
+ '@parcel/core': 2.13.3(@swc/helpers@0.5.15)
+ '@parcel/diagnostic': 2.13.3
+ '@parcel/events': 2.13.3
+ '@parcel/feature-flags': 2.13.3
+ '@parcel/fs': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/logger': 2.13.3
+ '@parcel/package-manager': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))(@swc/helpers@0.5.15)
+ '@parcel/reporter-cli': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/reporter-dev-server': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/reporter-tracer': 2.13.3(@parcel/core@2.13.3(@swc/helpers@0.5.15))
+ '@parcel/utils': 2.13.3
+ chalk: 4.1.2
+ commander: 12.1.0
+ get-port: 4.2.0
+ transitivePeerDependencies:
+ - '@swc/helpers'
+ - cssnano
+ - postcss
+ - purgecss
+ - relateurl
+ - srcset
+ - svgo
+ - terser
+ - typescript
+ - uncss
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ parse-json@5.2.0:
+ dependencies:
+ '@babel/code-frame': 7.26.2
+ error-ex: 1.3.2
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+
+ picocolors@1.1.1: {}
+
+ picomatch@2.3.1: {}
+
+ postcss-value-parser@4.2.0: {}
+
+ posthtml-parser@0.11.0:
+ dependencies:
+ htmlparser2: 7.2.0
+
+ posthtml-parser@0.12.1:
+ dependencies:
+ htmlparser2: 9.1.0
+
+ posthtml-render@3.0.0:
+ dependencies:
+ is-json: 2.0.1
+
+ posthtml@0.16.6:
+ dependencies:
+ posthtml-parser: 0.11.0
+ posthtml-render: 3.0.0
+
+ prettier@3.4.2: {}
+
+ react-error-overlay@6.0.9: {}
+
+ react-refresh@0.14.2: {}
+
+ regenerator-runtime@0.14.1: {}
+
+ resolve-from@4.0.0: {}
+
+ safe-buffer@5.2.1: {}
+
+ semver@7.7.0: {}
+
+ srcset@4.0.0: {}
+
+ supports-color@7.2.0:
+ dependencies:
+ has-flag: 4.0.0
+
+ term-size@2.2.1: {}
+
+ timsort@0.3.0: {}
+
+ to-regex-range@5.0.1:
+ dependencies:
+ is-number: 7.0.0
+
+ tslib@2.8.1: {}
+
+ type-fest@0.20.2: {}
+
+ typescript@5.7.3: {}
+
+ update-browserslist-db@1.1.2(browserslist@4.24.4):
+ dependencies:
+ browserslist: 4.24.4
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ utility-types@3.11.0: {}
+
+ weak-lru-cache@1.2.2: {}
diff --git a/docker/nginx/sites/www/src/main.ts b/docker/nginx/sites/www/src/main.ts
new file mode 100644
index 0000000..09e8661
--- /dev/null
+++ b/docker/nginx/sites/www/src/main.ts
@@ -0,0 +1,47 @@
+import "./style.css";
+
+class Emotion {
+ static opposite_map = new Map<Emotion, Emotion>();
+
+ constructor(public readonly name: string) {
+ }
+
+ get opposite(): Emotion {
+ return Emotion.opposite_map.get(this)!;
+ }
+
+ get element(): HTMLDivElement {
+ return document.querySelector<HTMLDivElement>(`.slogan.${this.name}`)!
+ }
+
+ get elementHeight(): number {
+ return this.element.clientHeight;
+ }
+
+ apply() {
+ localStorage.setItem(emotionKey, this.name);
+ document.body.dataset.emotion = this.name;
+ document.body.style.paddingTop = `${this.elementHeight}px`;
+ }
+}
+
+const happy = new Emotion("happy")
+const angry = new Emotion("angry")
+Emotion.opposite_map.set(happy, angry)
+Emotion.opposite_map.set(angry, happy)
+
+const emotionKey = "emotion";
+const savedEmotionName = localStorage.getItem(emotionKey) ?? happy.name;
+
+for (const emotion of [happy, angry]) {
+ if (emotion.name == savedEmotionName) {
+ emotion.apply();
+ }
+ emotion.element.addEventListener("click", () => {
+ emotion.opposite.apply();
+ });
+}
+
+setTimeout(() => {
+ document.body.style.transition = "padding-top 0.8s";
+});
diff --git a/docker/nginx/sites/www/src/style.css b/docker/nginx/sites/www/src/style.css
new file mode 100644
index 0000000..05c98a0
--- /dev/null
+++ b/docker/nginx/sites/www/src/style.css
@@ -0,0 +1,148 @@
+html {
+ width: 100%;
+}
+
+body {
+ width: 100%;
+ margin: 0;
+ display: flex;
+ flex-direction: column;
+}
+
+a {
+ font-family: monospace;
+}
+
+.fake-link {
+ font-family: monospace;
+}
+
+#main-article {
+ max-width: 880px;
+ margin-top: 1em;
+ padding: 0 1em;
+ align-self: center;
+}
+
+#title-name {
+ font-family: monospace;
+ background-color: black;
+ color: white;
+}
+
+@keyframes content-enter {
+ from {
+ opacity: 0;
+ transform: translateY(100px);
+ }
+
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes avatar-enter {
+ from {
+ opacity: 0;
+ transform: translateX(100%);
+ }
+
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+#main-article > * {
+ animation: content-enter 0.8s;
+}
+
+#avatar {
+ float: right;
+ animation: avatar-enter 0.8s;
+}
+
+.slogan-container {
+ width: 100vw;
+ top: 0;
+ position: fixed;
+}
+
+.slogan {
+ width: 100%;
+ padding: 0.5em 1em;
+ text-align: center;
+ box-sizing: border-box;
+ color: white;
+ position: absolute;
+ transform: translateY(-100%);
+ transition: transform 0.8s;
+}
+
+.slogan.happy {
+ background-color: dodgerblue;
+}
+
+.slogan.angry {
+ background-color: orangered;
+}
+
+body[data-emotion="happy"] .slogan.happy {
+ transform: translateY(0);
+}
+
+body[data-emotion="angry"] .slogan.angry {
+ transform: translateY(0);
+}
+
+#friends-container {
+ display: flex;
+ gap: 1em;
+}
+
+.friend {
+ flex-grow: 0;
+ text-align: center;
+}
+
+.friend a {
+ font-family: unset;
+}
+
+.friend-avatar {
+ object-fit: cover;
+}
+
+.friend-github {
+ width: 1em;
+ vertical-align: middle;
+ margin-right: -0.5em;
+}
+
+.friend-tag {
+ font-size: 0.8em;
+}
+
+.citation {
+ margin: auto;
+}
+
+.citation figcaption {
+ text-align: right;
+}
+
+#license a {
+ font-family: initial;
+ text-decoration: none;
+}
+
+#license-text {
+ font-family: monospace;
+ text-decoration: initial;
+}
+
+#license-img-container img {
+ height: 1em;
+ vertical-align: middle;
+}
diff --git a/docker/nginx/sites/www/tsconfig.json b/docker/nginx/sites/www/tsconfig.json
new file mode 100644
index 0000000..9d1434c
--- /dev/null
+++ b/docker/nginx/sites/www/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "extends": "@tsconfig/recommended/tsconfig.json",
+ "compilerOptions": {
+ "lib": [
+ "ESNext",
+ "DOM",
+ "DOM.Iterable"
+ ],
+ "types": [
+ "parcel-env"
+ ],
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true
+ }
+} \ No newline at end of file
diff --git a/docker/v2ray/Dockerfile b/docker/v2ray/Dockerfile
new file mode 100644
index 0000000..250a6b8
--- /dev/null
+++ b/docker/v2ray/Dockerfile
@@ -0,0 +1,5 @@
+FROM alpine:edge
+
+RUN apk add --no-cache v2ray
+
+ENTRYPOINT [ "/usr/bin/v2ray" ]