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 $@