diff --git a/.envrc b/.envrc
index 3550a30..7feb5af 100644
--- a/.envrc
+++ b/.envrc
@@ -1 +1,3 @@
use flake
+
+PATH_add ./scripts
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 21cf35b..3835608 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
**/input.txt
-.direnv
\ No newline at end of file
+.direnv
+node_modules
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..862f40d
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..a1aae2a
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..c224ad5
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_apiguardian_apiguardian_api_1_1_2.xml b/.idea/libraries/Gradle__org_apiguardian_apiguardian_api_1_1_2.xml
new file mode 100644
index 0000000..31fbc18
--- /dev/null
+++ b/.idea/libraries/Gradle__org_apiguardian_apiguardian_api_1_1_2.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_annotations_13_0.xml b/.idea/libraries/Gradle__org_jetbrains_annotations_13_0.xml
new file mode 100644
index 0000000..800e9c0
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_annotations_13_0.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_2_0_21.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_2_0_21.xml
new file mode 100644
index 0000000..812193a
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_2_0_21.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_test_2_0_21.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_test_2_0_21.xml
new file mode 100644
index 0000000..1fde2ee
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_test_2_0_21.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_test_junit5_2_0_21.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_test_junit5_2_0_21.xml
new file mode 100644
index 0000000..cf1c621
--- /dev/null
+++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_test_junit5_2_0_21.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_api_5_10_1.xml b/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_api_5_10_1.xml
new file mode 100644
index 0000000..22631d0
--- /dev/null
+++ b/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_api_5_10_1.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_engine_5_10_1.xml b/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_engine_5_10_1.xml
new file mode 100644
index 0000000..e491279
--- /dev/null
+++ b/.idea/libraries/Gradle__org_junit_jupiter_junit_jupiter_engine_5_10_1.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_junit_platform_junit_platform_commons_1_10_1.xml b/.idea/libraries/Gradle__org_junit_platform_junit_platform_commons_1_10_1.xml
new file mode 100644
index 0000000..c06e468
--- /dev/null
+++ b/.idea/libraries/Gradle__org_junit_platform_junit_platform_commons_1_10_1.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_junit_platform_junit_platform_engine_1_10_1.xml b/.idea/libraries/Gradle__org_junit_platform_junit_platform_engine_1_10_1.xml
new file mode 100644
index 0000000..260d145
--- /dev/null
+++ b/.idea/libraries/Gradle__org_junit_platform_junit_platform_engine_1_10_1.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_junit_platform_junit_platform_launcher_1_10_1.xml b/.idea/libraries/Gradle__org_junit_platform_junit_platform_launcher_1_10_1.xml
new file mode 100644
index 0000000..5d96d77
--- /dev/null
+++ b/.idea/libraries/Gradle__org_junit_platform_junit_platform_launcher_1_10_1.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Gradle__org_opentest4j_opentest4j_1_3_0.xml b/.idea/libraries/Gradle__org_opentest4j_opentest4j_1_3_0.xml
new file mode 100644
index 0000000..2306b2b
--- /dev/null
+++ b/.idea/libraries/Gradle__org_opentest4j_opentest4j_1_3_0.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 6f29fee..dc3b735 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,8 @@
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 5e7a8ca..07afe0b 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -4,6 +4,9 @@
+
+
+
diff --git a/.idea/modules/kotlin.iml b/.idea/modules/kotlin.iml
new file mode 100644
index 0000000..0d6a483
--- /dev/null
+++ b/.idea/modules/kotlin.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin.main.iml b/.idea/modules/kotlin.main.iml
new file mode 100644
index 0000000..932feaf
--- /dev/null
+++ b/.idea/modules/kotlin.main.iml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/2.0.21/939d8b644308f8d97c60317df76ee40299475831/kotlin-scripting-jvm-2.0.21.jar
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/2.0.21/2aeb50e2df2ef94f6b90b7ab2c56d5e18d3687c1/kotlin-scripting-common-2.0.21.jar
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/2.0.21/618b539767b4899b4660a83006e052b63f1db551/kotlin-stdlib-2.0.21.jar
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/2.0.21/c9b044380ad41f89aa89aa896c2d32a8c0b2129d/kotlin-script-runtime-2.0.21.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules/kotlin.test.iml b/.idea/modules/kotlin.test.iml
new file mode 100644
index 0000000..b62f5c8
--- /dev/null
+++ b/.idea/modules/kotlin.test.iml
@@ -0,0 +1,61 @@
+
+
+
+
+
+ kotlin:main
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-jvm/2.0.21/939d8b644308f8d97c60317df76ee40299475831/kotlin-scripting-jvm-2.0.21.jar
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-scripting-common/2.0.21/2aeb50e2df2ef94f6b90b7ab2c56d5e18d3687c1/kotlin-scripting-common-2.0.21.jar
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/2.0.21/618b539767b4899b4660a83006e052b63f1db551/kotlin-stdlib-2.0.21.jar
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar
+ $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/2.0.21/c9b044380ad41f89aa89aa896c2d32a8c0b2129d/kotlin-script-runtime-2.0.21.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aoc b/aoc
deleted file mode 100755
index 9392077..0000000
--- a/aoc
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env zsh
-setopt extendedglob
-
-cd "day$1"
-
-# Handle deno days
-if [[ -n *.ts(#qN) ]]; then
- deno eval --ext=ts "await import('./part$2.ts').then(m => m.solve()).then(s => console.log('The solution is', s))"
-fi
\ No newline at end of file
diff --git a/cli/secrets.ts b/cli/secrets.ts
new file mode 100644
index 0000000..cd1a0a4
--- /dev/null
+++ b/cli/secrets.ts
@@ -0,0 +1,31 @@
+export async function saveToken(token: string) {
+ const process = new Deno.Command("secret-tool", {
+ args: [
+ "store",
+ "--label",
+ "Advent Of Code Session Token",
+ "aoc-deno",
+ "token"
+ ],
+ stdin: "piped"
+ }).spawn();
+ const stdin = process.stdin.getWriter();
+ await stdin.write(new TextEncoder().encode(token));
+ await stdin.close();
+}
+
+export async function readToken() {
+ const process = new Deno.Command("secret-tool", {
+ args: [
+ "lookup",
+ "aoc-deno",
+ "token"
+ ],
+ stdout: "piped"
+ }).spawn();
+ const decoderStream = new TextDecoderStream();
+ const stdout = process.stdout.pipeTo(decoderStream.writable);
+ for await (const v of decoderStream.readable.values()) {
+ console.log(v);
+ }
+}
\ No newline at end of file
diff --git a/day1/part1.ts b/day1/part1.ts
index d91ca53..443be1b 100644
--- a/day1/part1.ts
+++ b/day1/part1.ts
@@ -1,5 +1,5 @@
export async function solve() {
- return await Deno.readTextFile("./input.txt").then(
+ return await Deno.readTextFile(import.meta.dirname + "/input.txt").then(
(f) =>
f.split("\n").reduce<[number[], number[]]>(
(
diff --git a/day1/part2.ts b/day1/part2.ts
index cd21658..b193629 100644
--- a/day1/part2.ts
+++ b/day1/part2.ts
@@ -1,5 +1,5 @@
export async function solve() {
- return await Deno.readTextFile("./input.txt").then(
+ return await Deno.readTextFile(import.meta.dirname + "/input.txt").then(
(f) =>
f.split("\n").reduce<[number[], number[]]>(
(
diff --git a/day2/part1.ts b/day2/part1.ts
index 43251a7..e8102f2 100644
--- a/day2/part1.ts
+++ b/day2/part1.ts
@@ -1,5 +1,5 @@
export async function solve() {
- return await Deno.readTextFile("./input.txt").then((f) =>
+ return await Deno.readTextFile(import.meta.dirname + "/input.txt").then((f) =>
f.split("\n").filter((l) => {
const report = l.split(" ").map((s) => +s);
const increasing = report[0] < report[1];
diff --git a/day2/part2.ts b/day2/part2.ts
index c8d8563..e61b3d8 100644
--- a/day2/part2.ts
+++ b/day2/part2.ts
@@ -1,5 +1,5 @@
export async function solve() {
- return await Deno.readTextFile("./input.txt").then((f) =>
+ return await Deno.readTextFile(import.meta.dirname + "/input.txt").then((f) =>
f.split("\n").filter((l) => {
const report = l.split(" ").map((s) => +s);
for (let i = 0; i < report.length; i++) {
diff --git a/day3/part1.ts b/day3/part1.ts
index 279a0bc..86859da 100644
--- a/day3/part1.ts
+++ b/day3/part1.ts
@@ -1,5 +1,5 @@
export async function solve() {
- const input = await Deno.readTextFile("./input.txt");
+ const input = await Deno.readTextFile(import.meta.dirname + "/input.txt");
let sum = 0;
for (const match of input.matchAll(/mul\((\d{1,3}),(\d{1,3})\)/g)) {
sum += +match[1] * +match[2];
diff --git a/day3/part2.ts b/day3/part2.ts
index 698a37a..83a2eee 100644
--- a/day3/part2.ts
+++ b/day3/part2.ts
@@ -1,5 +1,5 @@
export async function solve() {
- const input = await Deno.readTextFile("./input.txt");
+ const input = await Deno.readTextFile(import.meta.dirname + "/input.txt");
let sum = 0;
for (const part of input.split("do()").slice(1).map(e => e.split("don't()")[0])) {
for (const match of part.matchAll(/mul\((\d{1,3}),(\d{1,3})\)/g)) {
diff --git a/day4/part1.ts b/day4/part1.ts
index 912213f..aadf3f7 100644
--- a/day4/part1.ts
+++ b/day4/part1.ts
@@ -1,5 +1,5 @@
export async function solve() {
- const grid = await Deno.readTextFile("./input.txt").then(i => i.split("\n").map(l => l.split("")));
+ const grid = await Deno.readTextFile(import.meta.dirname + "/input.txt").then(i => i.split("\n").map(l => l.split("")));
let sum = 0;
for (const [y, line] of grid.map((e, i) => [i, e] as const)) {
diff --git a/day4/part2.ts b/day4/part2.ts
index c8ae6f5..64e19b4 100644
--- a/day4/part2.ts
+++ b/day4/part2.ts
@@ -1,5 +1,5 @@
export async function solve() {
- const grid = await Deno.readTextFile("./input.txt").then(i => i.split("\n").map(l => l.split("")));
+ const grid = await Deno.readTextFile(import.meta.dirname + "/input.txt").then(i => i.split("\n").map(l => l.split("")));
let sum = 0;
for (const [y, line] of grid.map((e, i) => [i, e] as const)) {
diff --git a/day5/part1.ts b/day5/part1.ts
index b16e050..67b1eff 100644
--- a/day5/part1.ts
+++ b/day5/part1.ts
@@ -1,5 +1,5 @@
export async function solve() {
- const [rules, pages] = await Deno.readTextFile("./input.txt")
+ const [rules, pages] = await Deno.readTextFile(import.meta.dirname + "/input.txt")
.then(i => i
.split("\n\n")
).then(([rules, pages]) => [
diff --git a/day5/part2.ts b/day5/part2.ts
index 81e59c3..dd0756c 100644
--- a/day5/part2.ts
+++ b/day5/part2.ts
@@ -22,7 +22,7 @@ function validate(rules: [string, string][], pageGroup: string[]): [boolean, nul
}
export async function solve() {
- const [rules, pages] = await Deno.readTextFile("./input.txt")
+ const [rules, pages] = await Deno.readTextFile(import.meta.dirname + "/input.txt")
.then(i => i
.split("\n\n")
).then(([rules, pages]) => [
diff --git a/deno.json b/deno.json
new file mode 100644
index 0000000..6250651
--- /dev/null
+++ b/deno.json
@@ -0,0 +1,10 @@
+{
+ "imports": {
+ "@cliffy/command": "jsr:@cliffy/command@^1.0.0-rc.7",
+ "@cliffy/prompt": "jsr:@cliffy/prompt@^1.0.0-rc.7",
+ "@cross/dir": "jsr:@cross/dir@^1.1.0",
+ "@db/sqlite": "jsr:@db/sqlite@^0.12.0",
+ "@std/ini": "jsr:@std/ini@^0.225.2",
+ "@std/path": "jsr:@std/path@^1.0.8"
+ }
+}
\ No newline at end of file
diff --git a/deno.lock b/deno.lock
new file mode 100644
index 0000000..d506f6f
--- /dev/null
+++ b/deno.lock
@@ -0,0 +1,195 @@
+{
+ "version": "4",
+ "specifiers": {
+ "jsr:@cliffy/ansi@1.0.0-rc.7": "1.0.0-rc.7",
+ "jsr:@cliffy/command@^1.0.0-rc.7": "1.0.0-rc.7",
+ "jsr:@cliffy/flags@1.0.0-rc.7": "1.0.0-rc.7",
+ "jsr:@cliffy/internal@1.0.0-rc.7": "1.0.0-rc.7",
+ "jsr:@cliffy/keycode@1.0.0-rc.7": "1.0.0-rc.7",
+ "jsr:@cliffy/prompt@^1.0.0-rc.7": "1.0.0-rc.7",
+ "jsr:@cliffy/table@1.0.0-rc.7": "1.0.0-rc.7",
+ "jsr:@cross/deepmerge@1": "1.0.0",
+ "jsr:@cross/dir@^1.1.0": "1.1.0",
+ "jsr:@cross/env@1": "1.0.2",
+ "jsr:@cross/runtime@1": "1.1.0",
+ "jsr:@cross/utils@0.7": "0.7.1",
+ "jsr:@db/sqlite@0.12": "0.12.0",
+ "jsr:@denosaurs/plug@1": "1.0.6",
+ "jsr:@std/assert@0.217": "0.217.0",
+ "jsr:@std/assert@0.221": "0.221.0",
+ "jsr:@std/assert@~1.0.6": "1.0.9",
+ "jsr:@std/encoding@0.221": "0.221.0",
+ "jsr:@std/encoding@~1.0.5": "1.0.5",
+ "jsr:@std/fmt@0.221": "0.221.0",
+ "jsr:@std/fmt@~1.0.2": "1.0.3",
+ "jsr:@std/fs@0.221": "0.221.0",
+ "jsr:@std/ini@~0.225.2": "0.225.2",
+ "jsr:@std/path@0.217": "0.217.0",
+ "jsr:@std/path@0.221": "0.221.0",
+ "jsr:@std/path@^1.0.8": "1.0.8",
+ "jsr:@std/path@~1.0.6": "1.0.8",
+ "jsr:@std/text@~1.0.7": "1.0.8"
+ },
+ "jsr": {
+ "@cliffy/ansi@1.0.0-rc.7": {
+ "integrity": "f71c921cce224c13d322e5cedba4f38e8f7354c7d855c9cb22729362a53f25aa",
+ "dependencies": [
+ "jsr:@cliffy/internal",
+ "jsr:@std/encoding@~1.0.5"
+ ]
+ },
+ "@cliffy/command@1.0.0-rc.7": {
+ "integrity": "1288808d7a3cd18b86c24c2f920e47a6d954b7e23cadc35c8cbd78f8be41f0cd",
+ "dependencies": [
+ "jsr:@cliffy/flags",
+ "jsr:@cliffy/internal",
+ "jsr:@cliffy/table",
+ "jsr:@std/fmt@~1.0.2",
+ "jsr:@std/text"
+ ]
+ },
+ "@cliffy/flags@1.0.0-rc.7": {
+ "integrity": "318d9be98f6a6417b108e03dec427dea96cdd41a15beb21d2554ae6da450a781",
+ "dependencies": [
+ "jsr:@std/text"
+ ]
+ },
+ "@cliffy/internal@1.0.0-rc.7": {
+ "integrity": "10412636ab3e67517d448be9eaab1b70c88eba9be22617b5d146257a11cc9b17"
+ },
+ "@cliffy/keycode@1.0.0-rc.7": {
+ "integrity": "5b3f6c33994e81a76b79f108b1989642ac22705840da33781f7972d7dff05503"
+ },
+ "@cliffy/prompt@1.0.0-rc.7": {
+ "integrity": "a9cbd13acd8073558447cae8ca4cf593c09d23bcbe429cc63346920c21187b83",
+ "dependencies": [
+ "jsr:@cliffy/ansi",
+ "jsr:@cliffy/internal",
+ "jsr:@cliffy/keycode",
+ "jsr:@std/assert@~1.0.6",
+ "jsr:@std/fmt@~1.0.2",
+ "jsr:@std/path@~1.0.6",
+ "jsr:@std/text"
+ ]
+ },
+ "@cliffy/table@1.0.0-rc.7": {
+ "integrity": "9fdd9776eda28a0b397981c400eeb1aa36da2371b43eefe12e6ff555290e3180",
+ "dependencies": [
+ "jsr:@std/fmt@~1.0.2"
+ ]
+ },
+ "@cross/deepmerge@1.0.0": {
+ "integrity": "1e1318a74e31ba1959b9aa0acae8bd417b806f74ffd25ac07c90e12f83ad6b1d"
+ },
+ "@cross/dir@1.1.0": {
+ "integrity": "41eb779daf160f53bc33ef91f593f332fffc52ec9b81f87178db564718534e59",
+ "dependencies": [
+ "jsr:@cross/env",
+ "jsr:@cross/runtime",
+ "jsr:@cross/utils"
+ ]
+ },
+ "@cross/env@1.0.2": {
+ "integrity": "28501ad1043c218a5b00fe5db27ec62c01ab16371bbe1b9d738496f0a7c5eeb8",
+ "dependencies": [
+ "jsr:@cross/deepmerge",
+ "jsr:@cross/runtime"
+ ]
+ },
+ "@cross/runtime@1.1.0": {
+ "integrity": "f35a3b768a9de125277329483b684062ffc9ee86f4449cb8b3d614adcad64ffb"
+ },
+ "@cross/utils@0.7.1": {
+ "integrity": "6cc50ad31b0904364188c43d10e3d4888d817a3d415528b014c27deb8a35564e",
+ "dependencies": [
+ "jsr:@cross/runtime"
+ ]
+ },
+ "@db/sqlite@0.12.0": {
+ "integrity": "dd1ef7f621ad50fc1e073a1c3609c4470bd51edc0994139c5bf9851de7a6d85f",
+ "dependencies": [
+ "jsr:@denosaurs/plug",
+ "jsr:@std/path@0.217"
+ ]
+ },
+ "@denosaurs/plug@1.0.6": {
+ "integrity": "6cf5b9daba7799837b9ffbe89f3450510f588fafef8115ddab1ff0be9cb7c1a7",
+ "dependencies": [
+ "jsr:@std/encoding@0.221",
+ "jsr:@std/fmt@0.221",
+ "jsr:@std/fs",
+ "jsr:@std/path@0.221"
+ ]
+ },
+ "@std/assert@0.217.0": {
+ "integrity": "c98e279362ca6982d5285c3b89517b757c1e3477ee9f14eb2fdf80a45aaa9642"
+ },
+ "@std/assert@0.221.0": {
+ "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a"
+ },
+ "@std/assert@1.0.9": {
+ "integrity": "a9f0c611a869cc791b26f523eec54c7e187aab7932c2c8e8bea0622d13680dcd"
+ },
+ "@std/encoding@0.221.0": {
+ "integrity": "d1dd76ef0dc5d14088411e6dc1dede53bf8308c95d1537df1214c97137208e45"
+ },
+ "@std/encoding@1.0.5": {
+ "integrity": "ecf363d4fc25bd85bd915ff6733a7e79b67e0e7806334af15f4645c569fefc04"
+ },
+ "@std/fmt@0.221.0": {
+ "integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a"
+ },
+ "@std/fmt@1.0.3": {
+ "integrity": "97765c16aa32245ff4e2204ecf7d8562496a3cb8592340a80e7e554e0bb9149f"
+ },
+ "@std/fs@0.221.0": {
+ "integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286",
+ "dependencies": [
+ "jsr:@std/assert@0.221",
+ "jsr:@std/path@0.221"
+ ]
+ },
+ "@std/ini@0.225.2": {
+ "integrity": "c70f6560dacb7e333c2f868aa09aaa4117e6618cc66c60d0b4ca716c135c8e67"
+ },
+ "@std/path@0.217.0": {
+ "integrity": "1217cc25534bca9a2f672d7fe7c6f356e4027df400c0e85c0ef3e4343bc67d11",
+ "dependencies": [
+ "jsr:@std/assert@0.217"
+ ]
+ },
+ "@std/path@0.221.0": {
+ "integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095",
+ "dependencies": [
+ "jsr:@std/assert@0.221"
+ ]
+ },
+ "@std/path@1.0.8": {
+ "integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be"
+ },
+ "@std/text@1.0.8": {
+ "integrity": "40ba34caa095f393e78796e5eda37b8b4e2cc6cfd6f51f34658ad7487b1451e4"
+ }
+ },
+ "remote": {
+ "https://deno.land/x/sqlite@v3.9.1/build/sqlite.js": "2afc7875c7b9c85d89730c4a311ab3a304e5d1bf761fbadd8c07bbdf130f5f9b",
+ "https://deno.land/x/sqlite@v3.9.1/build/vfs.js": "7f7778a9fe499cd10738d6e43867340b50b67d3e39142b0065acd51a84cd2e03",
+ "https://deno.land/x/sqlite@v3.9.1/mod.ts": "e09fc79d8065fe222578114b109b1fd60077bff1bb75448532077f784f4d6a83",
+ "https://deno.land/x/sqlite@v3.9.1/src/constants.ts": "90f3be047ec0a89bcb5d6fc30db121685fc82cb00b1c476124ff47a4b0472aa9",
+ "https://deno.land/x/sqlite@v3.9.1/src/db.ts": "03d0c860957496eadedd86e51a6e650670764630e64f56df0092e86c90752401",
+ "https://deno.land/x/sqlite@v3.9.1/src/error.ts": "f7a15cb00d7c3797da1aefee3cf86d23e0ae92e73f0ba3165496c3816ab9503a",
+ "https://deno.land/x/sqlite@v3.9.1/src/function.ts": "bc778cab7a6d771f690afa27264c524d22fcb96f1bb61959ade7922c15a4ab8d",
+ "https://deno.land/x/sqlite@v3.9.1/src/query.ts": "d58abda928f6582d77bad685ecf551b1be8a15e8e38403e293ec38522e030cad",
+ "https://deno.land/x/sqlite@v3.9.1/src/wasm.ts": "e79d0baa6e42423257fb3c7cc98091c54399254867e0f34a09b5bdef37bd9487"
+ },
+ "workspace": {
+ "dependencies": [
+ "jsr:@cliffy/command@^1.0.0-rc.7",
+ "jsr:@cliffy/prompt@^1.0.0-rc.7",
+ "jsr:@cross/dir@^1.1.0",
+ "jsr:@db/sqlite@0.12",
+ "jsr:@std/ini@~0.225.2",
+ "jsr:@std/path@^1.0.8"
+ ]
+ }
+}
diff --git a/entrypoints/deno.bench.ts b/entrypoints/deno.bench.ts
new file mode 100644
index 0000000..76192bf
--- /dev/null
+++ b/entrypoints/deno.bench.ts
@@ -0,0 +1,2 @@
+// Redirect `deno bench` to the main entrypoint file
+import "./deno.ts"
diff --git a/entrypoints/deno.ts b/entrypoints/deno.ts
new file mode 100644
index 0000000..a16c890
--- /dev/null
+++ b/entrypoints/deno.ts
@@ -0,0 +1,34 @@
+import * as path from "@std/path"
+
+// Parse all modules
+const parentDir = path.resolve(path.join(import.meta.dirname!, ".."));
+const dayFolderRegex = /^day(\d{1,2})$/;
+const days: { day: number, part: 1|2, solve: () => Promise }[] = [];
+for await (const folder of Deno.readDir(parentDir)) {
+ const regex = folder.name.match(dayFolderRegex);
+ if (!regex) {
+ continue;
+ }
+ const dayNum = regex[1];
+
+ for (let i = 1; i <= 2; i++) {
+ if (await Deno.stat(path.join(parentDir, "day" + dayNum, `part${i}.ts`)).then(s => s.isFile).catch(_ => false)) {
+ const module = await import(path.join(parentDir, "day" + dayNum, `part${i}.ts`));
+ days.push({
+ day: +dayNum,
+ part: i as 1|2,
+ solve: module.solve
+ })
+ }
+ }
+}
+
+// Create deno benchmark entries
+for (const { day, part, solve } of days) {
+ Deno.bench(
+ `Day ${day} Part ${part}`,
+ // Group each day and say how much faster p1 is than p2
+ { group: `Day ${day}`, baseline: part == 1, permissions: { "read": true } },
+ () => solve().then(_ => undefined)
+ )
+}
\ No newline at end of file
diff --git a/entrypoints/kotlin/.gradle/8.10/checksums/checksums.lock b/entrypoints/kotlin/.gradle/8.10/checksums/checksums.lock
new file mode 100644
index 0000000..e470a77
Binary files /dev/null and b/entrypoints/kotlin/.gradle/8.10/checksums/checksums.lock differ
diff --git a/entrypoints/kotlin/.gradle/8.10/checksums/md5-checksums.bin b/entrypoints/kotlin/.gradle/8.10/checksums/md5-checksums.bin
new file mode 100644
index 0000000..e714d59
Binary files /dev/null and b/entrypoints/kotlin/.gradle/8.10/checksums/md5-checksums.bin differ
diff --git a/entrypoints/kotlin/.gradle/8.10/checksums/sha1-checksums.bin b/entrypoints/kotlin/.gradle/8.10/checksums/sha1-checksums.bin
new file mode 100644
index 0000000..abc9bf4
Binary files /dev/null and b/entrypoints/kotlin/.gradle/8.10/checksums/sha1-checksums.bin differ
diff --git a/entrypoints/kotlin/.gradle/8.10/dependencies-accessors/gc.properties b/entrypoints/kotlin/.gradle/8.10/dependencies-accessors/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/entrypoints/kotlin/.gradle/8.10/executionHistory/executionHistory.bin b/entrypoints/kotlin/.gradle/8.10/executionHistory/executionHistory.bin
new file mode 100644
index 0000000..f793d0e
Binary files /dev/null and b/entrypoints/kotlin/.gradle/8.10/executionHistory/executionHistory.bin differ
diff --git a/entrypoints/kotlin/.gradle/8.10/executionHistory/executionHistory.lock b/entrypoints/kotlin/.gradle/8.10/executionHistory/executionHistory.lock
new file mode 100644
index 0000000..a3a2dd4
Binary files /dev/null and b/entrypoints/kotlin/.gradle/8.10/executionHistory/executionHistory.lock differ
diff --git a/entrypoints/kotlin/.gradle/8.10/fileChanges/last-build.bin b/entrypoints/kotlin/.gradle/8.10/fileChanges/last-build.bin
new file mode 100644
index 0000000..f76dd23
Binary files /dev/null and b/entrypoints/kotlin/.gradle/8.10/fileChanges/last-build.bin differ
diff --git a/entrypoints/kotlin/.gradle/8.10/fileHashes/fileHashes.bin b/entrypoints/kotlin/.gradle/8.10/fileHashes/fileHashes.bin
new file mode 100644
index 0000000..0076b94
Binary files /dev/null and b/entrypoints/kotlin/.gradle/8.10/fileHashes/fileHashes.bin differ
diff --git a/entrypoints/kotlin/.gradle/8.10/fileHashes/fileHashes.lock b/entrypoints/kotlin/.gradle/8.10/fileHashes/fileHashes.lock
new file mode 100644
index 0000000..80a11bb
Binary files /dev/null and b/entrypoints/kotlin/.gradle/8.10/fileHashes/fileHashes.lock differ
diff --git a/entrypoints/kotlin/.gradle/8.10/gc.properties b/entrypoints/kotlin/.gradle/8.10/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/entrypoints/kotlin/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/entrypoints/kotlin/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 0000000..c5f7897
Binary files /dev/null and b/entrypoints/kotlin/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/entrypoints/kotlin/.gradle/buildOutputCleanup/cache.properties b/entrypoints/kotlin/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 0000000..cc155f9
--- /dev/null
+++ b/entrypoints/kotlin/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Sat Dec 07 19:12:33 MST 2024
+gradle.version=8.10
diff --git a/entrypoints/kotlin/.gradle/buildOutputCleanup/outputFiles.bin b/entrypoints/kotlin/.gradle/buildOutputCleanup/outputFiles.bin
new file mode 100644
index 0000000..9570d46
Binary files /dev/null and b/entrypoints/kotlin/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/entrypoints/kotlin/.gradle/file-system.probe b/entrypoints/kotlin/.gradle/file-system.probe
new file mode 100644
index 0000000..cc96804
Binary files /dev/null and b/entrypoints/kotlin/.gradle/file-system.probe differ
diff --git a/entrypoints/kotlin/.gradle/vcs-1/gc.properties b/entrypoints/kotlin/.gradle/vcs-1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/entrypoints/kotlin/build.gradle.kts b/entrypoints/kotlin/build.gradle.kts
new file mode 100644
index 0000000..b94df96
--- /dev/null
+++ b/entrypoints/kotlin/build.gradle.kts
@@ -0,0 +1,21 @@
+plugins {
+ kotlin("jvm") version "2.0.21"
+}
+
+group = "xyz.myriation.aoc2024.entrypoints"
+version = "1.0-SNAPSHOT"
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation(kotlin("test"))
+}
+
+tasks.test {
+ useJUnitPlatform()
+}
+kotlin {
+ jvmToolchain(21)
+}
\ No newline at end of file
diff --git a/entrypoints/kotlin/gradle/wrapper/gradle-wrapper.jar b/entrypoints/kotlin/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..a4b76b9
Binary files /dev/null and b/entrypoints/kotlin/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/entrypoints/kotlin/gradle/wrapper/gradle-wrapper.properties b/entrypoints/kotlin/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..9355b41
--- /dev/null
+++ b/entrypoints/kotlin/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/entrypoints/kotlin/gradlew b/entrypoints/kotlin/gradlew
new file mode 100755
index 0000000..f5feea6
--- /dev/null
+++ b/entrypoints/kotlin/gradlew
@@ -0,0 +1,252 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/entrypoints/kotlin/gradlew.bat b/entrypoints/kotlin/gradlew.bat
new file mode 100644
index 0000000..9b42019
--- /dev/null
+++ b/entrypoints/kotlin/gradlew.bat
@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/entrypoints/kotlin/settings.gradle.kts b/entrypoints/kotlin/settings.gradle.kts
new file mode 100644
index 0000000..d5b7cd1
--- /dev/null
+++ b/entrypoints/kotlin/settings.gradle.kts
@@ -0,0 +1,2 @@
+rootProject.name = "kotlin"
+
diff --git a/entrypoints/kotlin/src/main/kotlin/Main.kt b/entrypoints/kotlin/src/main/kotlin/Main.kt
new file mode 100644
index 0000000..2614238
--- /dev/null
+++ b/entrypoints/kotlin/src/main/kotlin/Main.kt
@@ -0,0 +1,5 @@
+package xyz.myriation.aoc2024.entrypoints
+
+fun main() {
+ println("Hello World!")
+}
\ No newline at end of file
diff --git a/flake.nix b/flake.nix
index c9b7961..a1546c3 100644
--- a/flake.nix
+++ b/flake.nix
@@ -10,6 +10,7 @@
packages = with pkgs; [
deno
kotlin
+ libsecret
];
};
});
diff --git a/main.ts b/main.ts
new file mode 100755
index 0000000..3558108
--- /dev/null
+++ b/main.ts
@@ -0,0 +1,226 @@
+#!/usr/bin/env deno
+import * as path from "@std/path";
+import * as ini from "@std/ini";
+
+import { Command } from "@cliffy/command";
+import { HelpCommand } from "@cliffy/command/help";
+import { Select } from "@cliffy/prompt";
+import { dir, DirectoryTypes } from "@cross/dir";
+
+import { Database } from "@db/sqlite";
+
+type ProfileData = {
+ Default: "0" | "1";
+ IsRelative: "0" | "1";
+ Name: string;
+ Path: string;
+};
+type ProfilesIni = {
+ General: {
+ StartWithLastProfile: string;
+ Verstion: string;
+ };
+} & Record;
+
+interface FirefoxContainer {
+ color: string;
+ icon: string;
+ name: string;
+ public: boolean;
+ userContextId: number;
+};
+interface ContainersJson {
+ identities: FirefoxContainer[];
+ lastUserContextId: number;
+ version: number;
+}
+
+if (import.meta.main) {
+ await new Command()
+ .name("aoc")
+ .version("0.1.0")
+ .description("My AoC utility command for 2024")
+ .help({
+ types: true,
+ hints: true,
+ colors: true
+ })
+ .default("help")
+ .command("help", new HelpCommand().global())
+ .command(
+ "login",
+ new Command()
+ .description("Stores your advent of code session token")
+ .default("help")
+ .command(
+ "firefox [profile:string] [container:string]",
+ "Imports an advent of code session token from firefox"
+ )
+ .action(async (_: unknown, profileArg: string | undefined, containerArg: string | undefined) => {
+ try {
+ // Discover firefox profiles
+ const firefoxProfilesPath = path.join(await dir(DirectoryTypes.home), ".mozilla", "firefox");
+
+ const profiles =
+ ini.parse(await Deno.readTextFile(path.join(firefoxProfilesPath, "profiles.ini"))) as ProfilesIni;
+
+ const parsedProfiles = Object.entries(profiles).reduce((acc, [k, v]) => ({
+ list: [
+ ...acc.list,
+ ...(
+ k !== "General"
+ ? [{
+ ...(v as ProfileData),
+ IsRelative: "0" as const,
+ Path: path.resolve(
+ path.join(...(
+ (v as ProfileData).IsRelative == "0"
+ ? [(v as ProfileData).Path]
+ : [firefoxProfilesPath, (v as ProfileData).Path]
+ ))
+ )
+ }]
+ : []
+ )
+ ],
+ default: k !== "General" && (v as ProfileData).Default == "1"
+ ? acc.list.length
+ : acc.default,
+ }), { default: undefined, list: [] } as { default: number | undefined; list: ProfileData[] });
+
+ // If the profile we need is ambigous, prompt the user for it
+ let profile: ProfileData;
+
+ if (profileArg !== undefined && parsedProfiles.list.find(d => d.Name == profileArg) !== undefined) {
+ profile = parsedProfiles.list.find(d => d.Name == profileArg)!;
+ } else {
+ let message: string
+ if (profileArg !== undefined) {
+ message = "Unable to find the specified profile name, please select the correct one";
+ } else {
+ message = "Please select the correct profile to import session token from";
+ }
+
+ const options = parsedProfiles.list.map(p =>
+ [
+ `${p.Name} (${path.resolve(
+ path.join(...(
+ p.IsRelative == "0"
+ ? [p.Path]
+ : [firefoxProfilesPath, p.Path]
+ ))
+ )})`,
+ p
+ ] as const
+ );
+
+ const selection = await Select.prompt({
+ message,
+ default: parsedProfiles.default !== undefined ? options[parsedProfiles.default][0] : undefined,
+ options: options.map(([e,]) => e)
+ });
+
+ profile = options.find(([e,]) => e == selection)![1];
+ }
+
+ // If necessary, differentiate between containers
+ let container: FirefoxContainer | null = null;
+ const containerFile = await Deno.readTextFile(
+ path.join(profile.Path, "containers.json")
+ ).then(t => JSON.parse(t) as ContainersJson).catch(_ => null);
+
+ if (containerFile === null && containerArg) {
+ console.error("Container was specified, but the selected profile has no containers");
+ Deno.exit(1);
+ } else if (containerFile !== null) {
+ const matchingContainer = containerArg === undefined
+ ? undefined
+ : containerFile.identities.find(
+ i => i.name.toLowerCase() == containerArg.toLowerCase()
+ );
+
+ if (matchingContainer === undefined) {
+ const message = containerArg === undefined
+ ? "Please select the container to import cookies from"
+ : "The specified container could not be found, please";
+
+ const choice = await Select.prompt({
+ message,
+ options: containerFile.identities.filter(c => c.public).map(c => c.name),
+ default: containerFile.identities.find(c => c.userContextId == containerFile.lastUserContextId)!.name
+ });
+
+ container = containerFile.identities.find(c => c.name == choice)!;
+ } else {
+ container = matchingContainer;
+ }
+ }
+
+ // Import the cookies
+ const tmpFile = await Deno.makeTempFile({ prefix: "aoc-firefox-cookies" });
+ await Deno.copyFile(path.join(profile.Path, "cookies.sqlite"), tmpFile);
+ const cookies = new Database(tmpFile, {
+ create: false,
+ readonly: true
+ });
+ let rows: { value: string }[];
+ try {
+ rows = container === null
+ ? cookies.sql`
+ SELECT value
+ FROM moz_cookies
+ WHERE name='session' AND host='.adventofcode.com';
+ `
+ : cookies.sql`
+ SELECT value
+ FROM moz_cookies
+ WHERE (
+ originAttributes LIKE ${`%userContextId=${container.userContextId}`}
+ OR originAttributes LIKE ${`%userContextId=${container.userContextId}&%`}
+ ) AND name='session' AND host='.adventofcode.com';
+ `;
+ } catch (_) {
+ rows = [];
+ }
+
+ if (rows.length < 1) {
+ console.error("No advent of code session cookie was found, make sure you are logged in!");
+ Deno.exit(1);
+ } else if (rows.length > 1) {
+ console.error("Multiple advent of code session cookies were found??");
+ Deno.exit(1);
+ } else {
+ const process = new Deno.Command("secret-tool", {
+ args: [
+ "store",
+ "--label",
+ "Advent Of Code Session Token",
+ "token",
+ "value"
+ ],
+ stdin: "piped"
+ }).spawn();
+ const stdin = process.stdin.getWriter();
+ await stdin.write(new TextEncoder().encode(rows[0].value));
+ await stdin.close();
+ console.log("Token saved!");
+ }
+
+ await Deno.remove(tmpFile);
+ } catch (e) {
+ console.log(e)
+ }
+ })
+ )
+ .reset()
+ .command(
+ "input [day:number]",
+ "Fetches the input for one day (or all if day # omitted) and writes to input.txt files"
+ )
+ .action((_: unknown, day: number | undefined) => {
+ if (day != undefined) {
+
+ }
+ })
+ .parse(Deno.args);
+}
diff --git a/scripts/aoc b/scripts/aoc
new file mode 100755
index 0000000..d08fd7c
--- /dev/null
+++ b/scripts/aoc
@@ -0,0 +1,4 @@
+#!/usr/bin/env sh
+
+cd "$(dirname "${BASH_SOURCE[0]}")/.."
+deno run -A ./main.ts $@