diff --git a/Cargo.lock b/Cargo.lock index 9f28bae..329cd4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,16 +44,16 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.4.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" +checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", "ahash 0.8.3", - "base64", + "base64 0.21.4", "bitflags 2.4.1", "brotli", "bytes", @@ -61,10 +61,10 @@ dependencies = [ "derive_more", "encoding_rs", "futures-core", - "http", + "http 0.2.9", "httparse", "httpdate", - "itoa 1.0.9", + "itoa 1.0.11", "language-tags", "local-channel", "mime", @@ -95,7 +95,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" dependencies = [ "bytestring", - "http", + "http 0.2.9", "regex", "serde", "tracing", @@ -123,7 +123,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "socket2 0.5.5", + "socket2", "tokio", "tracing", ] @@ -151,9 +151,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.4.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" +checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984" dependencies = [ "actix-codec", "actix-http", @@ -172,7 +172,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "itoa 1.0.9", + "itoa 1.0.11", "language-tags", "log", "mime", @@ -183,7 +183,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.5.5", + "socket2", "time", "url", ] @@ -294,9 +294,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.4" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -308,9 +308,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -327,7 +327,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -337,9 +337,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] +[[package]] +name = "anyhow" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" + [[package]] name = "arrayvec" version = "0.7.4" @@ -416,6 +422,12 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "base64-simd" version = "0.7.0" @@ -618,7 +630,7 @@ dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -645,9 +657,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -655,24 +667,24 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.0", "terminal_size", ] [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.48", @@ -680,9 +692,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -692,9 +704,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "comrak" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6751998a48e2327773c95f6f8e03c6e77c0156ce539d74c17d2199ff3d05e197" +checksum = "d0436149c9f6a1935b13306206c739b1ba84fa81f551b5eb87fc2ca7a13700af" dependencies = [ "clap", "derive_builder", @@ -710,6 +722,19 @@ dependencies = [ "xdg", ] +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + [[package]] name = "const-str" version = "0.3.2" @@ -830,7 +855,7 @@ checksum = "9be934d936a0fbed5bcdc01042b770de1398bf79d0e192f49fa7faea0e99281e" dependencies = [ "cssparser-macros", "dtoa-short", - "itoa 1.0.9", + "itoa 1.0.11", "phf 0.11.2", "smallvec", ] @@ -874,7 +899,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 1.0.109", ] @@ -985,6 +1010,19 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a1abaf4d861455be59f64fd2b55606cb151fce304ede7165f410243ce96bde6" +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console", + "shell-words", + "tempfile", + "thiserror", + "zeroize", +] + [[package]] name = "digest" version = "0.10.7" @@ -1019,12 +1057,41 @@ dependencies = [ "dtoa", ] +[[package]] +name = "dtt" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b2dd9ee2d76888dc4c17d6da74629fa11b3cb1e8094fdc159b7f8ff259fc88" +dependencies = [ + "regex", + "serde", + "time", +] + +[[package]] +name = "duct" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c" +dependencies = [ + "libc", + "once_cell", + "os_pipe", + "shared_child", +] + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -1040,6 +1107,29 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -1053,7 +1143,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1062,20 +1152,25 @@ version = "0.1.0" dependencies = [ "actix-files", "actix-web", + "base64 0.22.0", "cached", "chrono", "chrono-tz", "comrak", "glob", "lol_html", + "mime_guess", "minify-html", "minify-js 0.6.0", "ramhorns", + "regex", "reqwest", "rss", "serde", - "serde_yaml", + "serde_json", + "serde_yml", "toml", + "urlencoding", ] [[package]] @@ -1094,6 +1189,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "figlet-rs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4742a071cd9694fc86f9fa1a08fa3e53d40cc899d7ee532295da2d085639fbc5" + [[package]] name = "flate2" version = "1.0.28" @@ -1134,6 +1235,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "funty" version = "2.0.0" @@ -1256,17 +1363,17 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.21" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", - "http", - "indexmap 1.9.3", + "http 1.1.0", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -1317,6 +1424,29 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.9" @@ -1325,17 +1455,40 @@ checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", - "itoa 1.0.9", + "itoa 1.0.11", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.11", ] [[package]] name = "http-body" -version = "0.4.5" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" dependencies = [ "bytes", - "http", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body", "pin-project-lite", ] @@ -1358,40 +1511,65 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "hyper" -version = "0.14.27" +name = "humantime" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" dependencies = [ "bytes", "futures-channel", - "futures-core", "futures-util", "h2", - "http", + "http 1.1.0", "http-body", "httparse", - "httpdate", - "itoa 1.0.9", + "itoa 1.0.11", "pin-project-lite", - "socket2 0.4.10", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-tls" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", + "http-body-util", "hyper", + "hyper-util", "native-tls", "tokio", "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -1445,9 +1623,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.2", @@ -1494,9 +1672,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" @@ -1605,31 +1783,41 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "logos" -version = "0.12.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1" +checksum = "161971eb88a0da7ae0c333e1063467c5b5727e7fb6b710b8db4814eade3a42e8" dependencies = [ "logos-derive", ] [[package]] -name = "logos-derive" -version = "0.12.1" +name = "logos-codegen" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c" +checksum = "8e31badd9de5131fdf4921f6473d457e3dd85b11b7f091ceb50e4df7c3eeb12a" dependencies = [ "beef", "fnv", + "lazy_static", "proc-macro2", "quote", - "regex-syntax 0.6.29", - "syn 1.0.109", + "regex-syntax 0.8.2", + "syn 2.0.48", +] + +[[package]] +name = "logos-derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c2a69b3eb68d5bd595107c9ee58d7e07fe2bb5e360cc85b0f084dedac80de0a" +dependencies = [ + "logos-codegen", ] [[package]] @@ -1652,6 +1840,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matches" version = "0.1.10" @@ -1743,14 +1937,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1792,6 +1986,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "object" version = "0.32.1" @@ -1831,9 +2035,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.57" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ "bitflags 2.4.1", "cfg-if", @@ -1862,17 +2066,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] -name = "openssl-sys" -version = "0.9.93" +name = "openssl-src" +version = "300.2.3+3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "5cff92b6f71555b61bb9315f7c64da3ca43d87531622120fea0195fc761b4843" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] +[[package]] +name = "os_pipe" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "outref" version = "0.1.0" @@ -1929,7 +2153,7 @@ dependencies = [ "libc", "redox_syscall 0.4.1", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -2129,6 +2353,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2153,7 +2397,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a4a0cfc5fb21a09dc6af4bf834cf10d4a32fccd9e2ea468c4b1751a097487aa" dependencies = [ - "base64", + "base64 0.21.4", "indexmap 1.9.3", "line-wrap", "quick-xml", @@ -2240,15 +2484,22 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" +checksum = "dce76ce678ffc8e5675b22aa1405de0b7037e2fdf8913fea40d1926c6fe1e6e7" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.1", "memchr", + "pulldown-cmark-escape", "unicase", ] +[[package]] +name = "pulldown-cmark-escape" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d8f9aa0e3cbcfaf8bf00300004ee3b72f74770f9cbac93f6928771f613276b" + [[package]] name = "quick-xml" version = "0.30.0" @@ -2276,9 +2527,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "ramhorns" -version = "0.14.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47008ae2e2a9085a3f658203609d79f8a027829cf88a088d0c0084e18ba8f0b9" +checksum = "8adbbcd308f58fe5348325adcb6646b6e04ce53eca4bb1188ea7952aa435c31c" dependencies = [ "arrayvec", "beef", @@ -2290,12 +2541,13 @@ dependencies = [ [[package]] name = "ramhorns-derive" -version = "0.14.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ada9bbdd21adf426f932bf76b3db7d553538dffc16afd5fb8ce2ce2110a75536" +checksum = "74ead572d301d184a2789e9b7460b08aefd70472a448e9e5e54e4124e598c355" dependencies = [ "bae", "fnv", + "heck 0.4.1", "proc-macro2", "quote", "syn 1.0.109", @@ -2443,12 +2695,6 @@ dependencies = [ "regex-syntax 0.8.2", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.7.5" @@ -2472,20 +2718,22 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.22" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "2d66674f2b6fb864665eea7a3c1ac4e3dfacd2fda83cf6f935a612e01b0e3338" dependencies = [ - "base64", + "base64 0.21.4", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", - "http", + "http 1.1.0", "http-body", + "http-body-util", "hyper", "hyper-tls", + "hyper-util", "ipnet", "js-sys", "log", @@ -2494,9 +2742,11 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -2537,6 +2787,30 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rlg" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6ccf670238310d5c31a52fed1a3314620d037a64f1e5fbdc71b2c50909134dc" +dependencies = [ + "dtt", + "tokio", + "vrd 0.0.4", +] + +[[package]] +name = "rlg" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e02c717e23f67b23032a4acb01cf63534d6259938d592e6d2451c02f09fc368" +dependencies = [ + "dtt", + "hostname", + "serde_json", + "tokio", + "vrd 0.0.5", +] + [[package]] name = "rss" version = "2.0.6" @@ -2580,14 +2854,23 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.4", ] [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "safemem" @@ -2610,7 +2893,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2676,18 +2959,18 @@ checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -2696,11 +2979,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ - "itoa 1.0.9", + "itoa 1.0.11", "ryu", "serde", ] @@ -2721,22 +3004,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.9", + "itoa 1.0.11", "ryu", "serde", ] [[package]] -name = "serde_yaml" -version = "0.9.25" +name = "serde_yml" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +checksum = "cb4738d7e493b43ddd39b3d070d65f8110722b1039b3242ae3c2fad1c7053bd7" dependencies = [ - "indexmap 2.0.2", - "itoa 1.0.9", + "dtt", + "env_logger", + "figlet-rs", + "indexmap 2.2.6", + "itoa 1.0.11", + "log", + "openssl", + "rlg 0.0.3", "ryu", "serde", "unsafe-libyaml", + "uuid", + "xtasks", ] [[package]] @@ -2760,6 +3051,16 @@ dependencies = [ "digest", ] +[[package]] +name = "shared_child" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "shell-words" version = "1.1.0" @@ -2816,19 +3117,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -2837,7 +3128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2852,6 +3143,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "syn" version = "1.0.109" @@ -2874,6 +3171,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "syntect" version = "5.1.0" @@ -2933,7 +3236,7 @@ dependencies = [ "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2943,7 +3246,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2979,7 +3282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", - "itoa 1.0.9", + "itoa 1.0.11", "powerfmt", "serde", "time-core", @@ -3018,27 +3321,28 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", "libc", "mio", + "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.5", + "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", @@ -3096,13 +3400,35 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", "winnow", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -3183,6 +3509,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + [[package]] name = "unicode_categories" version = "0.1.1" @@ -3191,9 +3523,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "unsafe-libyaml" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "url" @@ -3206,6 +3538,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf8parse" version = "0.2.1" @@ -3214,9 +3552,12 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "getrandom 0.2.10", +] [[package]] name = "vcpkg" @@ -3236,6 +3577,25 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff" +[[package]] +name = "vrd" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a81b8b5b404f3d7afa1b8142a6bc980c20cd68556c634c3db517871aa0402521" +dependencies = [ + "rand 0.8.5", +] + +[[package]] +name = "vrd" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1067b8d17481f5be71b59d11c329e955ffe36348907e0a4a41b619682bb4af" +dependencies = [ + "rand 0.8.5", + "serde", +] + [[package]] name = "walkdir" version = "2.4.0" @@ -3380,7 +3740,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -3389,7 +3749,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", ] [[package]] @@ -3398,13 +3767,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -3413,42 +3797,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + [[package]] name = "winnow" version = "0.5.17" @@ -3465,7 +3891,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3483,6 +3909,26 @@ version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" +[[package]] +name = "xtasks" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940db5674e301470e6cd91098b2c68a1fad751a1623575d1133f7456146e6d2f" +dependencies = [ + "anyhow", + "clap", + "derive_builder", + "dialoguer", + "dtt", + "duct", + "fs_extra", + "glob", + "rlg 0.0.2", + "serde", + "serde_json", + "vrd 0.0.5", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -3491,3 +3937,9 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 87e8d2e..6a3d875 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,19 +10,24 @@ publish = false license = "AGPL-3.0-or-later" [dependencies] -actix-web = { version = "4.4", default-features = false, features = ["macros", "compress-brotli"] } +actix-web = { version = "4.5", default-features = false, features = ["macros", "compress-brotli"] } actix-files = "0.6" -cached = { version = "0.49", features = ["async"] } -ramhorns = "0.14" +cached = { version = "0.49", features = ["async", "ahash"] } +ramhorns = "1.0" toml = "0.8" serde = { version = "1.0", features = ["derive"] } -serde_yaml = "0.9" +serde_yml = "0.0.2" +serde_json = "1.0" minify-html = "0.15" minify-js = "0.6" glob = "0.3" -comrak = "0.21" -reqwest = { version = "0.11", features = ["json"] } -chrono = { version = "0.4.30", default-features = false, features = ["clock"]} +comrak = "0.22" +reqwest = { version = "0.12", features = ["json"] } +chrono = { version = "0.4", default-features = false, features = ["clock"]} chrono-tz = "0.8" rss = { version = "2.0", features = ["atom"] } lol_html = "1.2" +base64 = "0.22" +mime_guess = "2.0" +urlencoding = "2.1" +regex = "1.10" diff --git a/Documentation.md b/Documentation.md index f0be113..b527524 100644 --- a/Documentation.md +++ b/Documentation.md @@ -14,6 +14,7 @@ - [Blog](#blog) - [Projects](#projects) - [Contacts](#contacts) + - [Courses](#courses) # Installation @@ -105,6 +106,7 @@ onion = "http://youraddress.onion/" app_name = "Nickname" # fallback to 'EWP' if none name = "Firstname" fullname = "Fullname" +exclude_courses = [] ``` ## Link shortener for contacts @@ -248,3 +250,7 @@ For example, `socials` contact files are stored in `/app/data/contacts/socials/` ### About The file is stored at `/app/data/contacts/about.md`. + +## Courses + +Markdown files are stored in `/app/data/cours/` diff --git a/src/config.rs b/src/config.rs index d1edb9e..2a5e74a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,7 @@ use std::{fs::File, io::Write, path::Path}; use crate::template::Template; /// Store the configuration of config/config.toml -#[derive(Deserialize, Clone, Default, Debug)] +#[derive(Clone, Debug, Default, Deserialize)] pub struct FileConfig { /// http/https pub scheme: Option, @@ -27,6 +27,8 @@ pub struct FileConfig { pub name: Option, /// Fullname of website owner pub fullname: Option, + /// List exclusion for courses + pub exclude_courses: Option>, } impl FileConfig { @@ -37,6 +39,7 @@ impl FileConfig { domain: Some("localhost".into()), port: Some(8080), app_name: Some("EWP".into()), + exclude_courses: Some([].into()), ..FileConfig::default() } } @@ -65,6 +68,7 @@ impl FileConfig { app_name: test(a.app_name, d.app_name), name: test(a.name, d.name), fullname: test(a.fullname, d.fullname), + exclude_courses: test(a.exclude_courses, d.exclude_courses), } } } diff --git a/src/misc/github.rs b/src/misc/github.rs index 07d40a8..89c01c8 100644 --- a/src/misc/github.rs +++ b/src/misc/github.rs @@ -5,12 +5,12 @@ use serde::Deserialize; use crate::misc::utils::get_reqwest_client; -#[derive(Deserialize, Debug)] +#[derive(Debug, Deserialize)] struct GithubResponse { items: Vec, } -#[derive(Deserialize, Debug)] +#[derive(Debug, Deserialize)] struct GithubProject { repository_url: String, number: u32, @@ -19,7 +19,7 @@ struct GithubProject { pull_request: GithubPullRequest, } -#[derive(Deserialize, Debug)] +#[derive(Debug, Deserialize)] struct GithubPullRequest { html_url: String, merged_at: Option, diff --git a/src/misc/markdown.rs b/src/misc/markdown.rs index 51aea8c..69b3c3c 100644 --- a/src/misc/markdown.rs +++ b/src/misc/markdown.rs @@ -1,13 +1,19 @@ use crate::misc::date::Date; +use base64::engine::general_purpose; +use base64::Engine; use comrak::nodes::{AstNode, NodeValue}; -use comrak::{format_html, parse_document, Arena, ComrakOptions, ListStyleType}; -use lol_html::{element, rewrite_str, RewriteStrSettings}; +use comrak::{format_html, parse_document, Arena, ComrakOptions, ListStyleType, Options}; +use lol_html::html_content::ContentType; +use lol_html::{element, rewrite_str, HtmlRewriter, RewriteStrSettings, Settings}; use ramhorns::Content; use serde::{Deserialize, Deserializer}; use std::fs; +use std::path::Path; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; /// Metadata for blog posts -#[derive(Default, Deserialize, Content, Debug)] +#[derive(Content, Debug, Default, Deserialize)] pub struct FileMetadataBlog { pub title: Option, pub date: Option, @@ -29,7 +35,7 @@ impl<'de> Deserialize<'de> for Tag { D: Deserializer<'de>, { match <&str>::deserialize(deserializer) { - Ok(s) => match serde_yaml::from_str(s) { + Ok(s) => match serde_yml::from_str(s) { Ok(tag) => Ok(Self { name: tag }), Err(e) => Err(serde::de::Error::custom(e)), }, @@ -39,7 +45,7 @@ impl<'de> Deserialize<'de> for Tag { } /// Metadata for contact entry -#[derive(Default, Deserialize, Content, Debug)] +#[derive(Content, Debug, Default, Deserialize)] pub struct FileMetadataContact { pub title: String, pub custom: Option, @@ -50,7 +56,7 @@ pub struct FileMetadataContact { } /// Metadata for index page -#[derive(Default, Deserialize, Content, Debug)] +#[derive(Content, Debug, Default, Deserialize)] pub struct FileMetadataIndex { pub name: Option, pub pronouns: Option, @@ -60,7 +66,7 @@ pub struct FileMetadataIndex { } /// Metadata for portfolio cards -#[derive(Default, Deserialize, Content, Debug)] +#[derive(Content, Debug, Default, Deserialize)] pub struct FileMetadataPortfolio { pub title: Option, pub link: Option, @@ -79,7 +85,7 @@ pub enum TypeFileMetadata { /// Structure who holds all the metadata the file have /// Usually all fields are None except one -#[derive(Default, Deserialize, Content, Debug)] +#[derive(Content, Debug, Default, Deserialize)] pub struct FileMetadata { pub blog: Option, pub contact: Option, @@ -96,6 +102,15 @@ pub struct Metadata { pub syntax_highlight: bool, } +impl Metadata { + /// Update current metadata boolean fields, keeping true ones + fn merge(&mut self, other: Metadata) { + self.math = self.math || other.math; + self.mermaid = self.mermaid || other.mermaid; + self.syntax_highlight = self.syntax_highlight || other.syntax_highlight; + } +} + /// File description #[derive(Content, Debug)] pub struct File { @@ -118,6 +133,9 @@ pub fn get_options() -> ComrakOptions { options.extension.footnotes = true; options.extension.description_lists = true; options.extension.front_matter_delimiter = Some("---".into()); + options.extension.multiline_block_quotes = true; + options.extension.math_dollars = true; + options.extension.math_code = false; // Parser options.parse.smart = true; // could be boring @@ -134,6 +152,7 @@ pub fn get_options() -> ComrakOptions { options.render.escape = false; options.render.list_style = ListStyleType::Dash; options.render.sourcepos = false; + options.render.escaped_char_spans = false; options } @@ -186,12 +205,71 @@ fn custom_img_size(html: String) -> String { .unwrap() } +/// Fix local images to base64 and integration of markdown files +fn fix_images_and_integration(path: &str, html: String) -> (String, Metadata) { + let mut metadata = Metadata { + info: FileMetadata::default(), + math: false, + mermaid: false, + syntax_highlight: false, + }; + + ( + rewrite_str( + &html, + RewriteStrSettings { + element_content_handlers: vec![element!("img", |el| { + if let Some(src) = el.get_attribute("src") { + let img_src = Path::new(path).parent().unwrap(); + let img_path = urlencoding::decode(img_src.join(src).to_str().unwrap()) + .unwrap() + .to_string(); + if let Ok(file) = fs::read_to_string(&img_path) { + let mime = mime_guess::from_path(&img_path).first_or_octet_stream(); + if mime == "text/markdown" { + let mut options = get_options(); + options.extension.footnotes = false; + let data = read_md( + &img_path, + &file, + TypeFileMetadata::Generic, + Some(options), + ); + el.replace(&data.content, ContentType::Html); + metadata.merge(data.metadata); + } else { + let image = general_purpose::STANDARD.encode(file); + + el.set_attribute("src", &format!("data:{};base64,{}", mime, image)) + .unwrap(); + } + } + } + + Ok(()) + })], + ..RewriteStrSettings::default() + }, + ) + .unwrap(), + metadata, + ) +} + /// Transform markdown string to File structure -fn read(raw_text: &str, metadata_type: TypeFileMetadata) -> File { +pub fn read_md( + path: &str, + raw_text: &str, + metadata_type: TypeFileMetadata, + options: Option, +) -> File { let arena = Arena::new(); - let options = get_options(); - let root = parse_document(&arena, raw_text, &options); + let opt = match options { + Some(specific_opt) => specific_opt, + None => get_options(), + }; + let root = parse_document(&arena, raw_text, &opt); // Find metadata let metadata = get_metadata(root, metadata_type); @@ -201,34 +279,31 @@ fn read(raw_text: &str, metadata_type: TypeFileMetadata) -> File { // Convert to HTML let mut html = vec![]; - format_html(root, &options, &mut html).unwrap(); + format_html(root, &opt, &mut html).unwrap(); let mut html_content = String::from_utf8(html).unwrap(); + let children_metadata; + (html_content, children_metadata) = fix_images_and_integration(path, html_content); html_content = custom_img_size(html_content); - File { - metadata: Metadata { - info: metadata, - mermaid: check_mermaid(root, mermaid_name), - syntax_highlight: check_code(root, &[mermaid_name.into()]), - math: check_math(&html_content), - }, - content: html_content, - } -} + let mut final_metadata = Metadata { + info: metadata, + mermaid: check_mermaid(root, mermaid_name), + syntax_highlight: check_code(root, &[mermaid_name.into()]), + math: check_math(&html_content), + }; + final_metadata.merge(children_metadata); -/// Read markdown file -pub fn read_file(filename: &str, expected_file: TypeFileMetadata) -> Option { - match fs::read_to_string(filename) { - Ok(text) => Some(read(&text, expected_file)), - _ => None, + File { + metadata: final_metadata, + content: html_content, } } /// Deserialize metadata based on a type fn deserialize_metadata(text: &str) -> T { - serde_yaml::from_str(text.trim().trim_matches(&['-'] as &[_])).unwrap_or_default() + serde_yml::from_str(text.trim().trim_matches(&['-'] as &[_])).unwrap_or_default() } /// Fetch metadata from AST @@ -318,9 +393,25 @@ fn check_code<'a>(root: &'a AstNode<'a>, blacklist: &[String]) -> bool { }) } -/// Check if html can contains maths +/// Check if html contains maths fn check_math(html: &str) -> bool { - html.contains('$') + let math_detected = Arc::new(AtomicBool::new(false)); + + let mut output = vec![]; + let _ = HtmlRewriter::new( + Settings { + element_content_handlers: vec![element!("span[data-math-style]", |_| { + math_detected.store(true, Ordering::SeqCst); + + Ok(()) + })], + ..Settings::default() + }, + |c: &[u8]| output.extend_from_slice(c), + ) + .write(html.as_bytes()); + + math_detected.load(Ordering::SeqCst) } /// Change class of languages for hljs detection diff --git a/src/misc/utils.rs b/src/misc/utils.rs index 418ce6b..da27dec 100644 --- a/src/misc/utils.rs +++ b/src/misc/utils.rs @@ -1,12 +1,18 @@ +use std::{fs, path::Path}; + use actix_web::{ http::header::{self, ContentType, TryIntoHeaderValue}, + http::StatusCode, HttpRequest, HttpResponse, Responder, }; +use base64::{engine::general_purpose, Engine}; use cached::proc_macro::cached; -use reqwest::{Client, StatusCode}; +use reqwest::Client; use crate::config::FileConfig; +use super::markdown::{read_md, File, FileMetadata, Metadata, TypeFileMetadata}; + #[cached] pub fn get_reqwest_client() -> Client { Client::builder() @@ -45,3 +51,40 @@ impl Responder for Html { res } } + +/// Read a file +pub fn read_file(filename: &str, expected_file: TypeFileMetadata) -> Option { + match Path::new(filename).extension() { + Some(ext) => match ext.to_str().unwrap() { + "pdf" => match fs::read(filename) { + Ok(bytes) => Some(read_pdf(bytes)), + Err(_) => None, + }, + _ => match fs::read_to_string(filename) { + Ok(text) => Some(read_md(filename, &text, expected_file, None)), + Err(_) => None, + }, + }, + None => None, + } +} + +fn read_pdf(data: Vec) -> File { + let pdf = general_purpose::STANDARD.encode(data); + + File { + metadata: Metadata { + info: FileMetadata::default(), + mermaid: false, + syntax_highlight: false, + math: false, + }, + content: format!( + r#""#, + pdf + ), + } +} diff --git a/src/routes/blog.rs b/src/routes/blog.rs index aec3019..36b38a0 100644 --- a/src/routes/blog.rs +++ b/src/routes/blog.rs @@ -18,10 +18,8 @@ use crate::{ config::Config, misc::{ date::Date, - markdown::{ - get_metadata, get_options, read_file, File, FileMetadataBlog, TypeFileMetadata, - }, - utils::{get_url, make_kw, Html}, + markdown::{get_metadata, get_options, File, FileMetadataBlog, TypeFileMetadata}, + utils::{get_url, make_kw, read_file, Html}, }, template::{Infos, NavBar}, }; diff --git a/src/routes/contact.rs b/src/routes/contact.rs index 5debdb9..142886b 100644 --- a/src/routes/contact.rs +++ b/src/routes/contact.rs @@ -7,8 +7,8 @@ use std::fs::read_to_string; use crate::{ config::Config, misc::{ - markdown::{read_file, File, TypeFileMetadata}, - utils::{make_kw, Html}, + markdown::{File, TypeFileMetadata}, + utils::{make_kw, read_file, Html}, }, template::{Infos, NavBar}, }; diff --git a/src/routes/contrib.rs b/src/routes/contrib.rs index ad51fd9..f87e538 100644 --- a/src/routes/contrib.rs +++ b/src/routes/contrib.rs @@ -26,7 +26,7 @@ struct PortfolioTemplate { closed: Option>, } -#[derive(Content, Clone, Debug)] +#[derive(Clone, Content, Debug)] struct Project { name: String, url: String, @@ -35,7 +35,7 @@ struct Project { pulls_closed: Vec, } -#[derive(Content, Clone, Debug)] +#[derive(Clone, Content, Debug)] struct Pull { url: String, id: u32, diff --git a/src/routes/cours.rs b/src/routes/cours.rs index 2691aef..ff9d300 100644 --- a/src/routes/cours.rs +++ b/src/routes/cours.rs @@ -1,9 +1,148 @@ -use actix_web::{get, Responder}; +use std::path::Path; + +use actix_web::{get, web, Responder}; +use cached::proc_macro::cached; +use ramhorns::Content; +use regex::Regex; +use serde::{Deserialize, Serialize}; + +use crate::{ + config::Config, + misc::{ + markdown::{File, TypeFileMetadata}, + utils::{make_kw, read_file, Html}, + }, + template::{Infos, NavBar}, +}; + +#[derive(Debug, Deserialize)] +pub struct PathRequest { + q: Option, +} #[get("/cours")] -async fn page() -> impl Responder { - // Page de notes de cours - // Cf. https://univ.mylloon.fr/ - // Cf. https://github.com/xy2z/PineDocs - actix_web::web::Redirect::to("/") +async fn page(info: web::Query, config: web::Data) -> impl Responder { + Html(build_page(info, config.get_ref().to_owned())) +} + +#[derive(Content, Debug)] +struct CoursTemplate { + navbar: NavBar, + filetree: String, + content: Option, +} + +#[derive(Clone, Debug, Serialize)] +struct FileNode { + name: String, + is_dir: bool, + children: Vec, +} + +#[cached] +fn compile_patterns(exclusion_list: Vec) -> Vec { + exclusion_list + .iter() + .map(|pattern| Regex::new(pattern).unwrap()) + .collect() +} + +fn get_filetree(dir_path: &str, exclusion_patterns: &Vec) -> FileNode { + let children = std::fs::read_dir(dir_path) + .unwrap() + .filter_map(Result::ok) + .filter_map(|entry| { + let entry_path = entry.path(); + let entry_name = entry_path.file_name()?.to_string_lossy().to_string(); + + // Exclude element with the exclusion_list + if exclusion_patterns.iter().any(|re| re.is_match(&entry_name)) { + return None; + } + + if entry_path.is_file() { + Some(FileNode { + name: entry_name, + is_dir: false, + children: vec![], + }) + } else { + // Exclude empty directories + let children_of_children = + get_filetree(entry_path.to_str().unwrap(), exclusion_patterns); + if children_of_children.is_dir && children_of_children.children.is_empty() { + None + } else { + Some(children_of_children) + } + } + }) + .collect(); + + FileNode { + name: Path::new(dir_path) + .file_name() + .unwrap() + .to_string_lossy() + .to_string(), + is_dir: true, + children, + } +} + +/// Get a page content +fn get_content( + cours_dir: &str, + path: &web::Query, + exclusion_list: Vec, +) -> Option { + let filename = match &path.q { + Some(q) => q, + None => "index.md", + }; + + // We should support regex? + if exclusion_list + .iter() + .any(|excluded_term| filename.contains(excluded_term.as_str())) + { + return None; + } + + read_file( + &format!("{cours_dir}/{filename}"), + TypeFileMetadata::Generic, + ) +} + +fn build_page(info: web::Query, config: Config) -> String { + let cours_dir = "data/cours"; + let exclusion_list = config.fc.exclude_courses.unwrap(); + let exclusion_patterns = compile_patterns(exclusion_list.to_owned()); + let filetree = get_filetree(cours_dir, &exclusion_patterns); + + config.tmpl.render( + "cours.html", + CoursTemplate { + navbar: NavBar { + cours: true, + ..NavBar::default() + }, + filetree: serde_json::to_string(&filetree).unwrap(), + content: get_content(cours_dir, &info, exclusion_list), + }, + Infos { + page_title: Some("Cours".into()), + page_desc: Some("Cours à l'univ".into()), + page_kw: make_kw(&[ + "cours", + "études", + "université", + "licence", + "master", + "notes", + "digital garden", + ]), + }, + ) } diff --git a/src/routes/index.rs b/src/routes/index.rs index cb23ad1..4322953 100644 --- a/src/routes/index.rs +++ b/src/routes/index.rs @@ -5,8 +5,8 @@ use ramhorns::Content; use crate::{ config::Config, misc::{ - markdown::{read_file, File, TypeFileMetadata}, - utils::{make_kw, Html}, + markdown::{File, TypeFileMetadata}, + utils::{make_kw, read_file, Html}, }, template::{Infos, NavBar}, }; diff --git a/src/routes/portfolio.rs b/src/routes/portfolio.rs index b528002..170b9fd 100644 --- a/src/routes/portfolio.rs +++ b/src/routes/portfolio.rs @@ -6,8 +6,8 @@ use ramhorns::Content; use crate::{ config::Config, misc::{ - markdown::{read_file, File, TypeFileMetadata}, - utils::{make_kw, Html}, + markdown::{File, TypeFileMetadata}, + utils::{make_kw, read_file, Html}, }, template::{Infos, NavBar}, }; diff --git a/src/template.rs b/src/template.rs index fcff2d7..673a8f1 100644 --- a/src/template.rs +++ b/src/template.rs @@ -14,7 +14,7 @@ pub struct Template { } /// Structure used by /routes/*.rs -#[derive(Default, Debug)] +#[derive(Debug, Default)] pub struct Infos { /// Title pub page_title: Option, diff --git a/static/css/cours.css b/static/css/cours.css new file mode 100644 index 0000000..1cd0239 --- /dev/null +++ b/static/css/cours.css @@ -0,0 +1,53 @@ +/* Filetree */ +aside { + float: left; + margin-left: 20px; + position: sticky; + top: 0; +} + +aside ul { + list-style: none; + padding-left: 0.6em; +} + +aside li { + position: relative; +} + +/* Element */ +aside li:before { + content: ""; + position: absolute; + top: -0.2em; + left: -1em; + height: 1em; +} + +aside li.collapsed > ul { + display: none; +} + +aside li.directory::before { + content: "+"; +} + +aside li:not(.collapsed).directory::before { + content: "-"; +} + +aside li.directory { + cursor: pointer; +} + +@media print { + aside { + visibility: hidden; + } +} + +main img { + max-width: 100%; + display: block; + margin: auto; +} diff --git a/static/css/fonts/Luciole-Bold-Italic.ttf b/static/css/fonts/Luciole-Bold-Italic.ttf deleted file mode 100644 index 7926c7b..0000000 Binary files a/static/css/fonts/Luciole-Bold-Italic.ttf and /dev/null differ diff --git a/static/css/fonts/Luciole-Bold.ttf b/static/css/fonts/Luciole-Bold.ttf deleted file mode 100644 index 2a0f075..0000000 Binary files a/static/css/fonts/Luciole-Bold.ttf and /dev/null differ diff --git a/static/css/fonts/Luciole-Regular-Italic.ttf b/static/css/fonts/Luciole-Regular-Italic.ttf deleted file mode 100644 index 4f95be0..0000000 Binary files a/static/css/fonts/Luciole-Regular-Italic.ttf and /dev/null differ diff --git a/static/css/fonts/Luciole-Regular.ttf b/static/css/fonts/Luciole-Regular.ttf deleted file mode 100644 index 2055e8a..0000000 Binary files a/static/css/fonts/Luciole-Regular.ttf and /dev/null differ diff --git a/static/css/fonts/Read Me.txt b/static/css/fonts/Read Me.txt deleted file mode 100644 index d829bec..0000000 --- a/static/css/fonts/Read Me.txt +++ /dev/null @@ -1,14 +0,0 @@ - - - -Ces fontes sont distribuées gratuitement sous Licence publique Creative Commons Attribution 4.0 International : -https://creativecommons.org/licenses/by/4.0/legalcode.fr - - - -These fonts are freely available under Creative Commons Attribution 4.0 International Public License: -https://creativecommons.org/licenses/by/4.0/legalcode - - - -Luciole © Laurent Bourcellier & Jonathan Perez diff --git a/static/css/style.css b/static/css/style.css index e355e15..4aa7d99 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -65,3 +65,9 @@ header nav a:hover { .bold { font-weight: bold; } + +@media print { + header nav { + visibility: hidden; + } +} diff --git a/static/js/cours.js b/static/js/cours.js new file mode 100644 index 0000000..7da4a7e --- /dev/null +++ b/static/js/cours.js @@ -0,0 +1,167 @@ +/** + * Build the filetree + * @param {HTMLElement} parent Root element of the filetree + * @param {{name: string, is_dir: boolean, children: any[]}} data FileNode + * @param {string} location Current location, used for links creation + */ +const buildFileTree = (parent, data, location) => { + const ul = document.createElement("ul"); + data.forEach((item) => { + const li = document.createElement("li"); + li.classList.add(item.is_dir ? "directory" : "file"); + + if (item.is_dir) { + // Directory + li.textContent = item.name; + li.classList.add("collapsed"); + + // Toggle collapsing on click + li.addEventListener("click", function (e) { + if (e.target === li) { + li.classList.toggle("collapsed"); + } + }); + } else { + // File + const url = window.location.href.split("?")[0]; + const a = document.createElement("a"); + a.text = item.name; + a.href = `${url}?q=${location}${item.name}`; + li.appendChild(a); + } + + ul.appendChild(li); + + if (item.children && item.children.length > 0) { + buildFileTree( + li, + item.children, + item.is_dir ? location + `${item.name}/` : location + ); + } + }); + + parent.appendChild(ul); +}; + +/** + * Uncollapse elements from the deepest element + * @param {HTMLLIElement} element Element to uncollapse + */ +const uncollapse = (element) => { + if (element) { + element.classList.remove("collapsed"); + uncollapse(element.parentElement.closest("li")); + } +}; + +/** + * Find the deepest opened directory + * @param {string[]} path Current path we are looking at, init with fullpath + * @param {NodeListOf} options Options we have, init with list root + * @returns + */ +const deepestNodeOpened = (path, options) => { + // Iterate over possible options + for (let i = 0; i < options.length; ++i) { + // If the directory and the current path match + if (decodeURI(path[0]) === options[i].firstChild.nodeValue) { + if (path.length === 1) { + // We found it + return options[i]; + } + + // Continue the search + return deepestNodeOpened( + path.slice(1), + options[i].querySelector("ul").childNodes + ); + } + } +}; + +const svgDarkTheme = () => { + for (const item of document.getElementsByTagName("img")) { + if (!item.src.startsWith("data:image/svg+xml;base64,")) { + // Exclude image who aren't SVG and base64 encoded + break; + } + + /** Convert to grayscale */ + const colorToGrayscale = (color) => { + return 0.3 * color.r + 0.59 * color.g + 0.11 * color.b; + }; + + /** Extract color using canvas2d */ + const extractColors = (image) => { + const canvas = document.createElement("canvas"); + canvas.width = image.width; + canvas.height = image.height; + const ctx = canvas.getContext("2d"); + ctx.drawImage(image, 0, 0); + const imageData = ctx.getImageData( + 0, + 0, + Math.max(1, canvas.width), + Math.max(1, canvas.height) + ); + const pixelData = imageData.data; + + const colors = []; + for (let i = 0; i < pixelData.length; i += 4) { + if (pixelData[i + 3] > 0) { + colors.push({ + r: pixelData[i], + g: pixelData[i + 1], + b: pixelData[i + 2], + }); + } + } + + return colors; + }; + + // Extract colors + const colors = extractColors(item); + + // Calculate the average grayscale value + const grayscaleValues = colors.map(colorToGrayscale); + const totalGrayscale = grayscaleValues.reduce((acc, val) => acc + val, 0); + const averageGrayscale = totalGrayscale / grayscaleValues.length; + + if (averageGrayscale < 128) { + item.style = "filter: invert(1);"; + } + } +}; + +window.addEventListener("load", () => { + // Build the filetree + const fileTreeElement = document.getElementsByTagName("aside")[0]; + const dataElement = fileTreeElement.getElementsByTagName("span")[0]; + + buildFileTree( + fileTreeElement, + JSON.parse(dataElement.getAttribute("data-json")).children, + "" + ); + dataElement.remove(); + + // Open nested openeded directories + const infoURL = window.location.href.split("?"); + if (infoURL.length > 1) { + const fullpath = infoURL[1].substring(2); + const path = fullpath.substring(0, fullpath.lastIndexOf("/")); + const last_openeded = deepestNodeOpened( + path.split("/"), + fileTreeElement.querySelector("ul").childNodes + ); + + uncollapse(last_openeded); + } + + // Fix SVG images in dark mode + if (window.matchMedia("(prefers-color-scheme: dark)").matches) { + svgDarkTheme(); + } +}); diff --git a/static/js/index.js b/static/js/index.js index bfa9afb..0c27d13 100644 --- a/static/js/index.js +++ b/static/js/index.js @@ -24,6 +24,7 @@ window.addEventListener("load", () => { ` ), new Tag("Nul en CSS", "font-family: 'Comic Sans MS', cursive"), + new Tag("Mention poufiasse"), new Tag("anri k... caterpillar 🐛☝️"), ]; diff --git a/static/js/libs/hljs-languages/julia.js b/static/js/libs/hljs-languages/julia.js new file mode 100644 index 0000000..5947689 --- /dev/null +++ b/static/js/libs/hljs-languages/julia.js @@ -0,0 +1,452 @@ +/*! `julia` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: Julia + Description: Julia is a high-level, high-performance, dynamic programming language. + Author: Kenta Sato + Contributors: Alex Arslan , Fredrik Ekre + Website: https://julialang.org + Category: scientific + */ + + function julia(hljs) { + // Since there are numerous special names in Julia, it is too much trouble + // to maintain them by hand. Hence these names (i.e. keywords, literals and + // built-ins) are automatically generated from Julia 1.5.2 itself through + // the following scripts for each. + + // ref: https://docs.julialang.org/en/v1/manual/variables/#Allowed-Variable-Names + const VARIABLE_NAME_RE = '[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*'; + + // # keyword generator, multi-word keywords handled manually below (Julia 1.5.2) + // import REPL.REPLCompletions + // res = String["in", "isa", "where"] + // for kw in collect(x.keyword for x in REPLCompletions.complete_keyword("")) + // if !(contains(kw, " ") || kw == "struct") + // push!(res, kw) + // end + // end + // sort!(unique!(res)) + // foreach(x -> println("\'", x, "\',"), res) + const KEYWORD_LIST = [ + 'baremodule', + 'begin', + 'break', + 'catch', + 'ccall', + 'const', + 'continue', + 'do', + 'else', + 'elseif', + 'end', + 'export', + 'false', + 'finally', + 'for', + 'function', + 'global', + 'if', + 'import', + 'in', + 'isa', + 'let', + 'local', + 'macro', + 'module', + 'quote', + 'return', + 'true', + 'try', + 'using', + 'where', + 'while', + ]; + + // # literal generator (Julia 1.5.2) + // import REPL.REPLCompletions + // res = String["true", "false"] + // for compl in filter!(x -> isa(x, REPLCompletions.ModuleCompletion) && (x.parent === Base || x.parent === Core), + // REPLCompletions.completions("", 0)[1]) + // try + // v = eval(Symbol(compl.mod)) + // if !(v isa Function || v isa Type || v isa TypeVar || v isa Module || v isa Colon) + // push!(res, compl.mod) + // end + // catch e + // end + // end + // sort!(unique!(res)) + // foreach(x -> println("\'", x, "\',"), res) + const LITERAL_LIST = [ + 'ARGS', + 'C_NULL', + 'DEPOT_PATH', + 'ENDIAN_BOM', + 'ENV', + 'Inf', + 'Inf16', + 'Inf32', + 'Inf64', + 'InsertionSort', + 'LOAD_PATH', + 'MergeSort', + 'NaN', + 'NaN16', + 'NaN32', + 'NaN64', + 'PROGRAM_FILE', + 'QuickSort', + 'RoundDown', + 'RoundFromZero', + 'RoundNearest', + 'RoundNearestTiesAway', + 'RoundNearestTiesUp', + 'RoundToZero', + 'RoundUp', + 'VERSION|0', + 'devnull', + 'false', + 'im', + 'missing', + 'nothing', + 'pi', + 'stderr', + 'stdin', + 'stdout', + 'true', + 'undef', + 'π', + 'ℯ', + ]; + + // # built_in generator (Julia 1.5.2) + // import REPL.REPLCompletions + // res = String[] + // for compl in filter!(x -> isa(x, REPLCompletions.ModuleCompletion) && (x.parent === Base || x.parent === Core), + // REPLCompletions.completions("", 0)[1]) + // try + // v = eval(Symbol(compl.mod)) + // if (v isa Type || v isa TypeVar) && (compl.mod != "=>") + // push!(res, compl.mod) + // end + // catch e + // end + // end + // sort!(unique!(res)) + // foreach(x -> println("\'", x, "\',"), res) + const BUILT_IN_LIST = [ + 'AbstractArray', + 'AbstractChannel', + 'AbstractChar', + 'AbstractDict', + 'AbstractDisplay', + 'AbstractFloat', + 'AbstractIrrational', + 'AbstractMatrix', + 'AbstractRange', + 'AbstractSet', + 'AbstractString', + 'AbstractUnitRange', + 'AbstractVecOrMat', + 'AbstractVector', + 'Any', + 'ArgumentError', + 'Array', + 'AssertionError', + 'BigFloat', + 'BigInt', + 'BitArray', + 'BitMatrix', + 'BitSet', + 'BitVector', + 'Bool', + 'BoundsError', + 'CapturedException', + 'CartesianIndex', + 'CartesianIndices', + 'Cchar', + 'Cdouble', + 'Cfloat', + 'Channel', + 'Char', + 'Cint', + 'Cintmax_t', + 'Clong', + 'Clonglong', + 'Cmd', + 'Colon', + 'Complex', + 'ComplexF16', + 'ComplexF32', + 'ComplexF64', + 'CompositeException', + 'Condition', + 'Cptrdiff_t', + 'Cshort', + 'Csize_t', + 'Cssize_t', + 'Cstring', + 'Cuchar', + 'Cuint', + 'Cuintmax_t', + 'Culong', + 'Culonglong', + 'Cushort', + 'Cvoid', + 'Cwchar_t', + 'Cwstring', + 'DataType', + 'DenseArray', + 'DenseMatrix', + 'DenseVecOrMat', + 'DenseVector', + 'Dict', + 'DimensionMismatch', + 'Dims', + 'DivideError', + 'DomainError', + 'EOFError', + 'Enum', + 'ErrorException', + 'Exception', + 'ExponentialBackOff', + 'Expr', + 'Float16', + 'Float32', + 'Float64', + 'Function', + 'GlobalRef', + 'HTML', + 'IO', + 'IOBuffer', + 'IOContext', + 'IOStream', + 'IdDict', + 'IndexCartesian', + 'IndexLinear', + 'IndexStyle', + 'InexactError', + 'InitError', + 'Int', + 'Int128', + 'Int16', + 'Int32', + 'Int64', + 'Int8', + 'Integer', + 'InterruptException', + 'InvalidStateException', + 'Irrational', + 'KeyError', + 'LinRange', + 'LineNumberNode', + 'LinearIndices', + 'LoadError', + 'MIME', + 'Matrix', + 'Method', + 'MethodError', + 'Missing', + 'MissingException', + 'Module', + 'NTuple', + 'NamedTuple', + 'Nothing', + 'Number', + 'OrdinalRange', + 'OutOfMemoryError', + 'OverflowError', + 'Pair', + 'PartialQuickSort', + 'PermutedDimsArray', + 'Pipe', + 'ProcessFailedException', + 'Ptr', + 'QuoteNode', + 'Rational', + 'RawFD', + 'ReadOnlyMemoryError', + 'Real', + 'ReentrantLock', + 'Ref', + 'Regex', + 'RegexMatch', + 'RoundingMode', + 'SegmentationFault', + 'Set', + 'Signed', + 'Some', + 'StackOverflowError', + 'StepRange', + 'StepRangeLen', + 'StridedArray', + 'StridedMatrix', + 'StridedVecOrMat', + 'StridedVector', + 'String', + 'StringIndexError', + 'SubArray', + 'SubString', + 'SubstitutionString', + 'Symbol', + 'SystemError', + 'Task', + 'TaskFailedException', + 'Text', + 'TextDisplay', + 'Timer', + 'Tuple', + 'Type', + 'TypeError', + 'TypeVar', + 'UInt', + 'UInt128', + 'UInt16', + 'UInt32', + 'UInt64', + 'UInt8', + 'UndefInitializer', + 'UndefKeywordError', + 'UndefRefError', + 'UndefVarError', + 'Union', + 'UnionAll', + 'UnitRange', + 'Unsigned', + 'Val', + 'Vararg', + 'VecElement', + 'VecOrMat', + 'Vector', + 'VersionNumber', + 'WeakKeyDict', + 'WeakRef', + ]; + + const KEYWORDS = { + $pattern: VARIABLE_NAME_RE, + keyword: KEYWORD_LIST, + literal: LITERAL_LIST, + built_in: BUILT_IN_LIST, + }; + + // placeholder for recursive self-reference + const DEFAULT = { + keywords: KEYWORDS, + illegal: /<\// + }; + + // ref: https://docs.julialang.org/en/v1/manual/integers-and-floating-point-numbers/ + const NUMBER = { + className: 'number', + // supported numeric literals: + // * binary literal (e.g. 0x10) + // * octal literal (e.g. 0o76543210) + // * hexadecimal literal (e.g. 0xfedcba876543210) + // * hexadecimal floating point literal (e.g. 0x1p0, 0x1.2p2) + // * decimal literal (e.g. 9876543210, 100_000_000) + // * floating pointe literal (e.g. 1.2, 1.2f, .2, 1., 1.2e10, 1.2e-10) + begin: /(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/, + relevance: 0 + }; + + const CHAR = { + className: 'string', + begin: /'(.|\\[xXuU][a-zA-Z0-9]+)'/ + }; + + const INTERPOLATION = { + className: 'subst', + begin: /\$\(/, + end: /\)/, + keywords: KEYWORDS + }; + + const INTERPOLATED_VARIABLE = { + className: 'variable', + begin: '\\$' + VARIABLE_NAME_RE + }; + + // TODO: neatly escape normal code in string literal + const STRING = { + className: 'string', + contains: [ + hljs.BACKSLASH_ESCAPE, + INTERPOLATION, + INTERPOLATED_VARIABLE + ], + variants: [ + { + begin: /\w*"""/, + end: /"""\w*/, + relevance: 10 + }, + { + begin: /\w*"/, + end: /"\w*/ + } + ] + }; + + const COMMAND = { + className: 'string', + contains: [ + hljs.BACKSLASH_ESCAPE, + INTERPOLATION, + INTERPOLATED_VARIABLE + ], + begin: '`', + end: '`' + }; + + const MACROCALL = { + className: 'meta', + begin: '@' + VARIABLE_NAME_RE + }; + + const COMMENT = { + className: 'comment', + variants: [ + { + begin: '#=', + end: '=#', + relevance: 10 + }, + { + begin: '#', + end: '$' + } + ] + }; + + DEFAULT.name = 'Julia'; + DEFAULT.contains = [ + NUMBER, + CHAR, + STRING, + COMMAND, + MACROCALL, + COMMENT, + hljs.HASH_COMMENT_MODE, + { + className: 'keyword', + begin: + '\\b(((abstract|primitive)\\s+)type|(mutable\\s+)?struct)\\b' + }, + { begin: /<:/ } // relevance booster + ]; + INTERPOLATION.contains = DEFAULT.contains; + + return DEFAULT; + } + + return julia; + +})(); + + hljs.registerLanguage('julia', hljsGrammar); + })(); \ No newline at end of file diff --git a/static/js/libs/hljs-languages/ocaml.js b/static/js/libs/hljs-languages/ocaml.js new file mode 100644 index 0000000..eb9335c --- /dev/null +++ b/static/js/libs/hljs-languages/ocaml.js @@ -0,0 +1,93 @@ +/*! `ocaml` grammar compiled for Highlight.js 11.9.0 */ + (function(){ + var hljsGrammar = (function () { + 'use strict'; + + /* + Language: OCaml + Author: Mehdi Dogguy + Contributors: Nicolas Braud-Santoni , Mickael Delahaye + Description: OCaml language definition. + Website: https://ocaml.org + Category: functional + */ + + function ocaml(hljs) { + /* missing support for heredoc-like string (OCaml 4.0.2+) */ + return { + name: 'OCaml', + aliases: [ 'ml' ], + keywords: { + $pattern: '[a-z_]\\w*!?', + keyword: + 'and as assert asr begin class constraint do done downto else end ' + + 'exception external for fun function functor if in include ' + + 'inherit! inherit initializer land lazy let lor lsl lsr lxor match method!|10 method ' + + 'mod module mutable new object of open! open or private rec sig struct ' + + 'then to try type val! val virtual when while with ' + /* camlp4 */ + + 'parser value', + built_in: + /* built-in types */ + 'array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 string unit ' + /* (some) types in Pervasives */ + + 'in_channel out_channel ref', + literal: + 'true false' + }, + illegal: /\/\/|>>/, + contains: [ + { + className: 'literal', + begin: '\\[(\\|\\|)?\\]|\\(\\)', + relevance: 0 + }, + hljs.COMMENT( + '\\(\\*', + '\\*\\)', + { contains: [ 'self' ] } + ), + { /* type variable */ + className: 'symbol', + begin: '\'[A-Za-z_](?!\')[\\w\']*' + /* the grammar is ambiguous on how 'a'b should be interpreted but not the compiler */ + }, + { /* polymorphic variant */ + className: 'type', + begin: '`[A-Z][\\w\']*' + }, + { /* module or constructor */ + className: 'type', + begin: '\\b[A-Z][\\w\']*', + relevance: 0 + }, + { /* don't color identifiers, but safely catch all identifiers with ' */ + begin: '[a-z_]\\w*\'[\\w\']*', + relevance: 0 + }, + hljs.inherit(hljs.APOS_STRING_MODE, { + className: 'string', + relevance: 0 + }), + hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }), + { + className: 'number', + begin: + '\\b(0[xX][a-fA-F0-9_]+[Lln]?|' + + '0[oO][0-7_]+[Lln]?|' + + '0[bB][01_]+[Lln]?|' + + '[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)', + relevance: 0 + }, + { begin: /->/ // relevance booster + } + ] + }; + } + + return ocaml; + +})(); + + hljs.registerLanguage('ocaml', hljsGrammar); + })(); \ No newline at end of file diff --git a/static/js/libs/hljs.js b/static/js/libs/hljs.js index ba5372e..bd06cb8 100644 --- a/static/js/libs/hljs.js +++ b/static/js/libs/hljs.js @@ -9,7 +9,7 @@ window.addEventListener("load", () => { /* Aliases of langs */ const aliases = { bash: ["fish"], - pascal: ["pseudocode"], + julia: ["pseudocode"], }; for (const lang in aliases) { hljs.registerAliases(aliases[lang], { languageName: lang }); diff --git a/static/js/libs/jspdf.js b/static/js/libs/jspdf.js deleted file mode 100644 index 439f65e..0000000 --- a/static/js/libs/jspdf.js +++ /dev/null @@ -1,14 +0,0 @@ -window.addEventListener("load", () => { - const { jsPDF } = window.jspdf; - - const doc = new jsPDF(); - - doc.html(document.body, { - width: doc.internal.pageSize.getWidth() - 20, - windowWidth: 800, - margin: [15, 10, 10, 10], - callback: function (doc) { - doc.save(`${document.title}.pdf`); - }, - }); -}); diff --git a/static/js/libs/katex.js b/static/js/libs/katex.js index 9eb5541..d28ce0f 100644 --- a/static/js/libs/katex.js +++ b/static/js/libs/katex.js @@ -10,17 +10,20 @@ window.addEventListener("load", () => { la: "leftarrow", RA: "Rightarrow", LA: "Leftarrow", + u: "mu", }) )[Symbol.iterator]()) { - macros[`\\${item[0]}`] = `\\${item[1]}`; + const bs = "\\"; + macros[`${bs}${item[0]}`] = `${bs}${item[1]}`; } - renderMathInElement(document.body, { - delimiters: [ - { left: "$$", right: "$$", display: true }, - { left: "$", right: "$", display: false }, - ], - throwOnError: false, - macros, - }); + const attribute = "data-math-style"; + for (const element of document.querySelectorAll(`span[${attribute}]`)) { + katex.render(element.textContent, element, { + throwOnError: false, + displayMode: element.getAttribute(attribute) === "display", + macros: macros, + output: "mathml", + }); + } }); diff --git a/templates/cours.html b/templates/cours.html new file mode 100644 index 0000000..a898b23 --- /dev/null +++ b/templates/cours.html @@ -0,0 +1,30 @@ + + + + {{>head.html}} + + {{#data}} {{#content}} {{#metadata}} + {{#math}}{{>libs/katex_head.html}}{{/math}} + {{#syntax_highlight}}{{>libs/hljs_head.html}}{{/syntax_highlight}} + {{/metadata}} {{/content}} + + +
{{>navbar.html}}
+ + +
+ {{^content}} +

Fichier introuvable

+ {{/content}} {{#content}} +
{{&content}}
+
+ + {{#metadata}} {{#mermaid}}{{>libs/mermaid_footer.html}}{{/mermaid}} + {{#math}}{{>libs/katex_footer.html}}{{/math}} + {{#syntax_highlight}}{{>libs/hljs_footer.html}}{{/syntax_highlight}} + {{/metadata}} {{/content}} {{/data}} + + + diff --git a/templates/libs/hljs_footer.html b/templates/libs/hljs_footer.html index 84f5398..f1e6b0f 100644 --- a/templates/libs/hljs_footer.html +++ b/templates/libs/hljs_footer.html @@ -1,4 +1,6 @@ - + + + diff --git a/templates/libs/hljs_head.html b/templates/libs/hljs_head.html index 6dfd659..14a3918 100644 --- a/templates/libs/hljs_head.html +++ b/templates/libs/hljs_head.html @@ -1,12 +1,12 @@ - -