├── .ecrc ├── .gitattributes ├── Cargo.lock ├── Cargo.toml ├── LICENSE.txt ├── README.md ├── results └── .gitignore └── src ├── bin ├── cleanup.rs └── hacktoberfest.rs └── main.rs /.ecrc: -------------------------------------------------------------------------------- 1 | { 2 | "Exclude": ["target", ".git", "node_modules", "results"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /.github export-ignore 2 | /.gitignore export-ignore 3 | /CONTRIBUTING.md export-ignore 4 | /.markdownlint.json export-ignore 5 | /.editorconfig export-ignore 6 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.16.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "aho-corasick" 22 | version = "0.7.18" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 25 | dependencies = [ 26 | "memchr", 27 | ] 28 | 29 | [[package]] 30 | name = "anyhow" 31 | version = "1.0.93" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" 34 | 35 | [[package]] 36 | name = "atty" 37 | version = "0.2.14" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 40 | dependencies = [ 41 | "hermit-abi", 42 | "libc", 43 | "winapi", 44 | ] 45 | 46 | [[package]] 47 | name = "autocfg" 48 | version = "1.0.1" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 51 | 52 | [[package]] 53 | name = "awesome-rust" 54 | version = "0.1.0" 55 | dependencies = [ 56 | "anyhow", 57 | "chrono", 58 | "chrono-humanize", 59 | "diffy", 60 | "env_logger", 61 | "futures", 62 | "hyper 0.14.27", 63 | "lazy_static", 64 | "log", 65 | "pulldown-cmark", 66 | "regex", 67 | "reqwest", 68 | "scraper", 69 | "serde", 70 | "serde_json", 71 | "serde_yaml", 72 | "thiserror", 73 | "tokio", 74 | ] 75 | 76 | [[package]] 77 | name = "backtrace" 78 | version = "0.3.61" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01" 81 | dependencies = [ 82 | "addr2line", 83 | "cc", 84 | "cfg-if", 85 | "libc", 86 | "miniz_oxide", 87 | "object", 88 | "rustc-demangle", 89 | ] 90 | 91 | [[package]] 92 | name = "base64" 93 | version = "0.22.1" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 96 | 97 | [[package]] 98 | name = "bitflags" 99 | version = "1.2.1" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 102 | 103 | [[package]] 104 | name = "bumpalo" 105 | version = "3.12.0" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" 108 | 109 | [[package]] 110 | name = "byteorder" 111 | version = "1.4.3" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 114 | 115 | [[package]] 116 | name = "bytes" 117 | version = "1.9.0" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" 120 | 121 | [[package]] 122 | name = "cc" 123 | version = "1.2.16" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" 126 | dependencies = [ 127 | "shlex", 128 | ] 129 | 130 | [[package]] 131 | name = "cfg-if" 132 | version = "1.0.0" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 135 | 136 | [[package]] 137 | name = "cfg_aliases" 138 | version = "0.2.1" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 141 | 142 | [[package]] 143 | name = "chrono" 144 | version = "0.4.19" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 147 | dependencies = [ 148 | "libc", 149 | "num-integer", 150 | "num-traits", 151 | "serde", 152 | "time", 153 | "winapi", 154 | ] 155 | 156 | [[package]] 157 | name = "chrono-humanize" 158 | version = "0.2.1" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "2eddc119501d583fd930cb92144e605f44e0252c38dd89d9247fffa1993375cb" 161 | dependencies = [ 162 | "chrono", 163 | ] 164 | 165 | [[package]] 166 | name = "convert_case" 167 | version = "0.4.0" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 170 | 171 | [[package]] 172 | name = "cssparser" 173 | version = "0.27.2" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" 176 | dependencies = [ 177 | "cssparser-macros", 178 | "dtoa-short", 179 | "itoa 0.4.7", 180 | "matches", 181 | "phf", 182 | "proc-macro2", 183 | "quote", 184 | "smallvec", 185 | "syn 1.0.109", 186 | ] 187 | 188 | [[package]] 189 | name = "cssparser-macros" 190 | version = "0.6.0" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e" 193 | dependencies = [ 194 | "quote", 195 | "syn 1.0.109", 196 | ] 197 | 198 | [[package]] 199 | name = "derive_more" 200 | version = "0.99.17" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" 203 | dependencies = [ 204 | "convert_case", 205 | "proc-macro2", 206 | "quote", 207 | "rustc_version", 208 | "syn 1.0.109", 209 | ] 210 | 211 | [[package]] 212 | name = "diffy" 213 | version = "0.3.0" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "e616e59155c92257e84970156f506287853355f58cd4a6eb167385722c32b790" 216 | dependencies = [ 217 | "nu-ansi-term", 218 | ] 219 | 220 | [[package]] 221 | name = "displaydoc" 222 | version = "0.2.5" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 225 | dependencies = [ 226 | "proc-macro2", 227 | "quote", 228 | "syn 2.0.90", 229 | ] 230 | 231 | [[package]] 232 | name = "dtoa" 233 | version = "0.4.8" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" 236 | 237 | [[package]] 238 | name = "dtoa-short" 239 | version = "0.3.3" 240 | source = "registry+https://github.com/rust-lang/crates.io-index" 241 | checksum = "bde03329ae10e79ede66c9ce4dc930aa8599043b0743008548680f25b91502d6" 242 | dependencies = [ 243 | "dtoa", 244 | ] 245 | 246 | [[package]] 247 | name = "ego-tree" 248 | version = "0.6.2" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" 251 | 252 | [[package]] 253 | name = "env_logger" 254 | version = "0.8.3" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" 257 | dependencies = [ 258 | "atty", 259 | "humantime", 260 | "log", 261 | "regex", 262 | "termcolor", 263 | ] 264 | 265 | [[package]] 266 | name = "fnv" 267 | version = "1.0.7" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 270 | 271 | [[package]] 272 | name = "form_urlencoded" 273 | version = "1.2.1" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 276 | dependencies = [ 277 | "percent-encoding", 278 | ] 279 | 280 | [[package]] 281 | name = "futf" 282 | version = "0.1.4" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" 285 | dependencies = [ 286 | "mac", 287 | "new_debug_unreachable", 288 | ] 289 | 290 | [[package]] 291 | name = "futures" 292 | version = "0.3.14" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253" 295 | dependencies = [ 296 | "futures-channel", 297 | "futures-core", 298 | "futures-executor", 299 | "futures-io", 300 | "futures-sink", 301 | "futures-task", 302 | "futures-util", 303 | ] 304 | 305 | [[package]] 306 | name = "futures-channel" 307 | version = "0.3.31" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 310 | dependencies = [ 311 | "futures-core", 312 | "futures-sink", 313 | ] 314 | 315 | [[package]] 316 | name = "futures-core" 317 | version = "0.3.31" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 320 | 321 | [[package]] 322 | name = "futures-executor" 323 | version = "0.3.14" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d" 326 | dependencies = [ 327 | "futures-core", 328 | "futures-task", 329 | "futures-util", 330 | ] 331 | 332 | [[package]] 333 | name = "futures-io" 334 | version = "0.3.31" 335 | source = "registry+https://github.com/rust-lang/crates.io-index" 336 | checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" 337 | 338 | [[package]] 339 | name = "futures-macro" 340 | version = "0.3.31" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 343 | dependencies = [ 344 | "proc-macro2", 345 | "quote", 346 | "syn 2.0.90", 347 | ] 348 | 349 | [[package]] 350 | name = "futures-sink" 351 | version = "0.3.31" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 354 | 355 | [[package]] 356 | name = "futures-task" 357 | version = "0.3.31" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 360 | 361 | [[package]] 362 | name = "futures-util" 363 | version = "0.3.31" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 366 | dependencies = [ 367 | "futures-channel", 368 | "futures-core", 369 | "futures-io", 370 | "futures-macro", 371 | "futures-sink", 372 | "futures-task", 373 | "memchr", 374 | "pin-project-lite", 375 | "pin-utils", 376 | "slab", 377 | ] 378 | 379 | [[package]] 380 | name = "fxhash" 381 | version = "0.2.1" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" 384 | dependencies = [ 385 | "byteorder", 386 | ] 387 | 388 | [[package]] 389 | name = "getopts" 390 | version = "0.2.21" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" 393 | dependencies = [ 394 | "unicode-width", 395 | ] 396 | 397 | [[package]] 398 | name = "getrandom" 399 | version = "0.1.16" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 402 | dependencies = [ 403 | "cfg-if", 404 | "libc", 405 | "wasi 0.9.0+wasi-snapshot-preview1", 406 | ] 407 | 408 | [[package]] 409 | name = "getrandom" 410 | version = "0.2.14" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" 413 | dependencies = [ 414 | "cfg-if", 415 | "js-sys", 416 | "libc", 417 | "wasi 0.11.0+wasi-snapshot-preview1", 418 | "wasm-bindgen", 419 | ] 420 | 421 | [[package]] 422 | name = "gimli" 423 | version = "0.25.0" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" 426 | 427 | [[package]] 428 | name = "hermit-abi" 429 | version = "0.1.18" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" 432 | dependencies = [ 433 | "libc", 434 | ] 435 | 436 | [[package]] 437 | name = "html5ever" 438 | version = "0.25.2" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "e5c13fb08e5d4dfc151ee5e88bae63f7773d61852f3bdc73c9f4b9e1bde03148" 441 | dependencies = [ 442 | "log", 443 | "mac", 444 | "markup5ever", 445 | "proc-macro2", 446 | "quote", 447 | "syn 1.0.109", 448 | ] 449 | 450 | [[package]] 451 | name = "http" 452 | version = "0.2.4" 453 | source = "registry+https://github.com/rust-lang/crates.io-index" 454 | checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" 455 | dependencies = [ 456 | "bytes", 457 | "fnv", 458 | "itoa 0.4.7", 459 | ] 460 | 461 | [[package]] 462 | name = "http" 463 | version = "1.2.0" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" 466 | dependencies = [ 467 | "bytes", 468 | "fnv", 469 | "itoa 1.0.9", 470 | ] 471 | 472 | [[package]] 473 | name = "http-body" 474 | version = "0.4.1" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "5dfb77c123b4e2f72a2069aeae0b4b4949cc7e966df277813fc16347e7549737" 477 | dependencies = [ 478 | "bytes", 479 | "http 0.2.4", 480 | "pin-project-lite", 481 | ] 482 | 483 | [[package]] 484 | name = "http-body" 485 | version = "1.0.1" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 488 | dependencies = [ 489 | "bytes", 490 | "http 1.2.0", 491 | ] 492 | 493 | [[package]] 494 | name = "http-body-util" 495 | version = "0.1.2" 496 | source = "registry+https://github.com/rust-lang/crates.io-index" 497 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 498 | dependencies = [ 499 | "bytes", 500 | "futures-util", 501 | "http 1.2.0", 502 | "http-body 1.0.1", 503 | "pin-project-lite", 504 | ] 505 | 506 | [[package]] 507 | name = "httparse" 508 | version = "1.8.0" 509 | source = "registry+https://github.com/rust-lang/crates.io-index" 510 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 511 | 512 | [[package]] 513 | name = "httpdate" 514 | version = "1.0.0" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "05842d0d43232b23ccb7060ecb0f0626922c21f30012e97b767b30afd4a5d4b9" 517 | 518 | [[package]] 519 | name = "humantime" 520 | version = "2.1.0" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" 523 | 524 | [[package]] 525 | name = "hyper" 526 | version = "0.14.27" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" 529 | dependencies = [ 530 | "bytes", 531 | "futures-channel", 532 | "futures-core", 533 | "futures-util", 534 | "http 0.2.4", 535 | "http-body 0.4.1", 536 | "httparse", 537 | "httpdate", 538 | "itoa 1.0.9", 539 | "pin-project-lite", 540 | "tokio", 541 | "tower-service", 542 | "tracing", 543 | "want", 544 | ] 545 | 546 | [[package]] 547 | name = "hyper" 548 | version = "1.5.2" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" 551 | dependencies = [ 552 | "bytes", 553 | "futures-channel", 554 | "futures-util", 555 | "http 1.2.0", 556 | "http-body 1.0.1", 557 | "httparse", 558 | "itoa 1.0.9", 559 | "pin-project-lite", 560 | "smallvec", 561 | "tokio", 562 | "want", 563 | ] 564 | 565 | [[package]] 566 | name = "hyper-rustls" 567 | version = "0.27.3" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" 570 | dependencies = [ 571 | "futures-util", 572 | "http 1.2.0", 573 | "hyper 1.5.2", 574 | "hyper-util", 575 | "rustls", 576 | "rustls-pki-types", 577 | "tokio", 578 | "tokio-rustls", 579 | "tower-service", 580 | "webpki-roots", 581 | ] 582 | 583 | [[package]] 584 | name = "hyper-util" 585 | version = "0.1.10" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" 588 | dependencies = [ 589 | "bytes", 590 | "futures-channel", 591 | "futures-util", 592 | "http 1.2.0", 593 | "http-body 1.0.1", 594 | "hyper 1.5.2", 595 | "pin-project-lite", 596 | "socket2", 597 | "tokio", 598 | "tower-service", 599 | "tracing", 600 | ] 601 | 602 | [[package]] 603 | name = "icu_collections" 604 | version = "1.5.0" 605 | source = "registry+https://github.com/rust-lang/crates.io-index" 606 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 607 | dependencies = [ 608 | "displaydoc", 609 | "yoke", 610 | "zerofrom", 611 | "zerovec", 612 | ] 613 | 614 | [[package]] 615 | name = "icu_locid" 616 | version = "1.5.0" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 619 | dependencies = [ 620 | "displaydoc", 621 | "litemap", 622 | "tinystr", 623 | "writeable", 624 | "zerovec", 625 | ] 626 | 627 | [[package]] 628 | name = "icu_locid_transform" 629 | version = "1.5.0" 630 | source = "registry+https://github.com/rust-lang/crates.io-index" 631 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 632 | dependencies = [ 633 | "displaydoc", 634 | "icu_locid", 635 | "icu_locid_transform_data", 636 | "icu_provider", 637 | "tinystr", 638 | "zerovec", 639 | ] 640 | 641 | [[package]] 642 | name = "icu_locid_transform_data" 643 | version = "1.5.0" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 646 | 647 | [[package]] 648 | name = "icu_normalizer" 649 | version = "1.5.0" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 652 | dependencies = [ 653 | "displaydoc", 654 | "icu_collections", 655 | "icu_normalizer_data", 656 | "icu_properties", 657 | "icu_provider", 658 | "smallvec", 659 | "utf16_iter", 660 | "utf8_iter", 661 | "write16", 662 | "zerovec", 663 | ] 664 | 665 | [[package]] 666 | name = "icu_normalizer_data" 667 | version = "1.5.0" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 670 | 671 | [[package]] 672 | name = "icu_properties" 673 | version = "1.5.1" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 676 | dependencies = [ 677 | "displaydoc", 678 | "icu_collections", 679 | "icu_locid_transform", 680 | "icu_properties_data", 681 | "icu_provider", 682 | "tinystr", 683 | "zerovec", 684 | ] 685 | 686 | [[package]] 687 | name = "icu_properties_data" 688 | version = "1.5.0" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 691 | 692 | [[package]] 693 | name = "icu_provider" 694 | version = "1.5.0" 695 | source = "registry+https://github.com/rust-lang/crates.io-index" 696 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 697 | dependencies = [ 698 | "displaydoc", 699 | "icu_locid", 700 | "icu_provider_macros", 701 | "stable_deref_trait", 702 | "tinystr", 703 | "writeable", 704 | "yoke", 705 | "zerofrom", 706 | "zerovec", 707 | ] 708 | 709 | [[package]] 710 | name = "icu_provider_macros" 711 | version = "1.5.0" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 714 | dependencies = [ 715 | "proc-macro2", 716 | "quote", 717 | "syn 2.0.90", 718 | ] 719 | 720 | [[package]] 721 | name = "idna" 722 | version = "1.0.3" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 725 | dependencies = [ 726 | "idna_adapter", 727 | "smallvec", 728 | "utf8_iter", 729 | ] 730 | 731 | [[package]] 732 | name = "idna_adapter" 733 | version = "1.2.0" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 736 | dependencies = [ 737 | "icu_normalizer", 738 | "icu_properties", 739 | ] 740 | 741 | [[package]] 742 | name = "instant" 743 | version = "0.1.12" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 746 | dependencies = [ 747 | "cfg-if", 748 | ] 749 | 750 | [[package]] 751 | name = "ipnet" 752 | version = "2.3.0" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" 755 | 756 | [[package]] 757 | name = "itoa" 758 | version = "0.4.7" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" 761 | 762 | [[package]] 763 | name = "itoa" 764 | version = "1.0.9" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 767 | 768 | [[package]] 769 | name = "js-sys" 770 | version = "0.3.50" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" 773 | dependencies = [ 774 | "wasm-bindgen", 775 | ] 776 | 777 | [[package]] 778 | name = "lazy_static" 779 | version = "1.4.0" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 782 | 783 | [[package]] 784 | name = "libc" 785 | version = "0.2.168" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" 788 | 789 | [[package]] 790 | name = "linked-hash-map" 791 | version = "0.5.4" 792 | source = "registry+https://github.com/rust-lang/crates.io-index" 793 | checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" 794 | 795 | [[package]] 796 | name = "litemap" 797 | version = "0.7.4" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" 800 | 801 | [[package]] 802 | name = "lock_api" 803 | version = "0.4.6" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" 806 | dependencies = [ 807 | "scopeguard", 808 | ] 809 | 810 | [[package]] 811 | name = "log" 812 | version = "0.4.22" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 815 | 816 | [[package]] 817 | name = "mac" 818 | version = "0.1.1" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" 821 | 822 | [[package]] 823 | name = "markup5ever" 824 | version = "0.10.1" 825 | source = "registry+https://github.com/rust-lang/crates.io-index" 826 | checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd" 827 | dependencies = [ 828 | "log", 829 | "phf", 830 | "phf_codegen", 831 | "string_cache", 832 | "string_cache_codegen", 833 | "tendril", 834 | ] 835 | 836 | [[package]] 837 | name = "matches" 838 | version = "0.1.8" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 841 | 842 | [[package]] 843 | name = "memchr" 844 | version = "2.4.0" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" 847 | 848 | [[package]] 849 | name = "mime" 850 | version = "0.3.16" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 853 | 854 | [[package]] 855 | name = "miniz_oxide" 856 | version = "0.4.4" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" 859 | dependencies = [ 860 | "adler", 861 | "autocfg", 862 | ] 863 | 864 | [[package]] 865 | name = "mio" 866 | version = "1.0.3" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 869 | dependencies = [ 870 | "libc", 871 | "wasi 0.11.0+wasi-snapshot-preview1", 872 | "windows-sys", 873 | ] 874 | 875 | [[package]] 876 | name = "new_debug_unreachable" 877 | version = "1.0.4" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" 880 | 881 | [[package]] 882 | name = "nodrop" 883 | version = "0.1.14" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" 886 | 887 | [[package]] 888 | name = "nu-ansi-term" 889 | version = "0.46.0" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 892 | dependencies = [ 893 | "overload", 894 | "winapi", 895 | ] 896 | 897 | [[package]] 898 | name = "num-integer" 899 | version = "0.1.44" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 902 | dependencies = [ 903 | "autocfg", 904 | "num-traits", 905 | ] 906 | 907 | [[package]] 908 | name = "num-traits" 909 | version = "0.2.14" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 912 | dependencies = [ 913 | "autocfg", 914 | ] 915 | 916 | [[package]] 917 | name = "object" 918 | version = "0.26.0" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386" 921 | dependencies = [ 922 | "memchr", 923 | ] 924 | 925 | [[package]] 926 | name = "once_cell" 927 | version = "1.19.0" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 930 | 931 | [[package]] 932 | name = "overload" 933 | version = "0.1.1" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 936 | 937 | [[package]] 938 | name = "parking_lot" 939 | version = "0.11.2" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 942 | dependencies = [ 943 | "instant", 944 | "lock_api", 945 | "parking_lot_core", 946 | ] 947 | 948 | [[package]] 949 | name = "parking_lot_core" 950 | version = "0.8.5" 951 | source = "registry+https://github.com/rust-lang/crates.io-index" 952 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 953 | dependencies = [ 954 | "cfg-if", 955 | "instant", 956 | "libc", 957 | "redox_syscall", 958 | "smallvec", 959 | "winapi", 960 | ] 961 | 962 | [[package]] 963 | name = "percent-encoding" 964 | version = "2.3.1" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 967 | 968 | [[package]] 969 | name = "phf" 970 | version = "0.8.0" 971 | source = "registry+https://github.com/rust-lang/crates.io-index" 972 | checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" 973 | dependencies = [ 974 | "phf_macros", 975 | "phf_shared 0.8.0", 976 | "proc-macro-hack", 977 | ] 978 | 979 | [[package]] 980 | name = "phf_codegen" 981 | version = "0.8.0" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" 984 | dependencies = [ 985 | "phf_generator", 986 | "phf_shared 0.8.0", 987 | ] 988 | 989 | [[package]] 990 | name = "phf_generator" 991 | version = "0.8.0" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" 994 | dependencies = [ 995 | "phf_shared 0.8.0", 996 | "rand 0.7.3", 997 | ] 998 | 999 | [[package]] 1000 | name = "phf_macros" 1001 | version = "0.8.0" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" 1004 | dependencies = [ 1005 | "phf_generator", 1006 | "phf_shared 0.8.0", 1007 | "proc-macro-hack", 1008 | "proc-macro2", 1009 | "quote", 1010 | "syn 1.0.109", 1011 | ] 1012 | 1013 | [[package]] 1014 | name = "phf_shared" 1015 | version = "0.8.0" 1016 | source = "registry+https://github.com/rust-lang/crates.io-index" 1017 | checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" 1018 | dependencies = [ 1019 | "siphasher", 1020 | ] 1021 | 1022 | [[package]] 1023 | name = "phf_shared" 1024 | version = "0.10.0" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" 1027 | dependencies = [ 1028 | "siphasher", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "pin-project-lite" 1033 | version = "0.2.13" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 1036 | 1037 | [[package]] 1038 | name = "pin-utils" 1039 | version = "0.1.0" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1042 | 1043 | [[package]] 1044 | name = "ppv-lite86" 1045 | version = "0.2.16" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 1048 | 1049 | [[package]] 1050 | name = "precomputed-hash" 1051 | version = "0.1.1" 1052 | source = "registry+https://github.com/rust-lang/crates.io-index" 1053 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 1054 | 1055 | [[package]] 1056 | name = "proc-macro-hack" 1057 | version = "0.5.19" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 1060 | 1061 | [[package]] 1062 | name = "proc-macro2" 1063 | version = "1.0.92" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 1066 | dependencies = [ 1067 | "unicode-ident", 1068 | ] 1069 | 1070 | [[package]] 1071 | name = "pulldown-cmark" 1072 | version = "0.8.0" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" 1075 | dependencies = [ 1076 | "bitflags", 1077 | "getopts", 1078 | "memchr", 1079 | "unicase", 1080 | ] 1081 | 1082 | [[package]] 1083 | name = "quinn" 1084 | version = "0.11.6" 1085 | source = "registry+https://github.com/rust-lang/crates.io-index" 1086 | checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" 1087 | dependencies = [ 1088 | "bytes", 1089 | "pin-project-lite", 1090 | "quinn-proto", 1091 | "quinn-udp", 1092 | "rustc-hash", 1093 | "rustls", 1094 | "socket2", 1095 | "thiserror", 1096 | "tokio", 1097 | "tracing", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "quinn-proto" 1102 | version = "0.11.9" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" 1105 | dependencies = [ 1106 | "bytes", 1107 | "getrandom 0.2.14", 1108 | "rand 0.8.5", 1109 | "ring", 1110 | "rustc-hash", 1111 | "rustls", 1112 | "rustls-pki-types", 1113 | "slab", 1114 | "thiserror", 1115 | "tinyvec", 1116 | "tracing", 1117 | "web-time", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "quinn-udp" 1122 | version = "0.5.8" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" 1125 | dependencies = [ 1126 | "cfg_aliases", 1127 | "libc", 1128 | "once_cell", 1129 | "socket2", 1130 | "tracing", 1131 | "windows-sys", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "quote" 1136 | version = "1.0.35" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" 1139 | dependencies = [ 1140 | "proc-macro2", 1141 | ] 1142 | 1143 | [[package]] 1144 | name = "rand" 1145 | version = "0.7.3" 1146 | source = "registry+https://github.com/rust-lang/crates.io-index" 1147 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1148 | dependencies = [ 1149 | "getrandom 0.1.16", 1150 | "libc", 1151 | "rand_chacha 0.2.2", 1152 | "rand_core 0.5.1", 1153 | "rand_hc", 1154 | "rand_pcg", 1155 | ] 1156 | 1157 | [[package]] 1158 | name = "rand" 1159 | version = "0.8.5" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1162 | dependencies = [ 1163 | "libc", 1164 | "rand_chacha 0.3.1", 1165 | "rand_core 0.6.4", 1166 | ] 1167 | 1168 | [[package]] 1169 | name = "rand_chacha" 1170 | version = "0.2.2" 1171 | source = "registry+https://github.com/rust-lang/crates.io-index" 1172 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 1173 | dependencies = [ 1174 | "ppv-lite86", 1175 | "rand_core 0.5.1", 1176 | ] 1177 | 1178 | [[package]] 1179 | name = "rand_chacha" 1180 | version = "0.3.1" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1183 | dependencies = [ 1184 | "ppv-lite86", 1185 | "rand_core 0.6.4", 1186 | ] 1187 | 1188 | [[package]] 1189 | name = "rand_core" 1190 | version = "0.5.1" 1191 | source = "registry+https://github.com/rust-lang/crates.io-index" 1192 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1193 | dependencies = [ 1194 | "getrandom 0.1.16", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "rand_core" 1199 | version = "0.6.4" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1202 | dependencies = [ 1203 | "getrandom 0.2.14", 1204 | ] 1205 | 1206 | [[package]] 1207 | name = "rand_hc" 1208 | version = "0.2.0" 1209 | source = "registry+https://github.com/rust-lang/crates.io-index" 1210 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1211 | dependencies = [ 1212 | "rand_core 0.5.1", 1213 | ] 1214 | 1215 | [[package]] 1216 | name = "rand_pcg" 1217 | version = "0.2.1" 1218 | source = "registry+https://github.com/rust-lang/crates.io-index" 1219 | checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" 1220 | dependencies = [ 1221 | "rand_core 0.5.1", 1222 | ] 1223 | 1224 | [[package]] 1225 | name = "redox_syscall" 1226 | version = "0.2.10" 1227 | source = "registry+https://github.com/rust-lang/crates.io-index" 1228 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 1229 | dependencies = [ 1230 | "bitflags", 1231 | ] 1232 | 1233 | [[package]] 1234 | name = "regex" 1235 | version = "1.5.5" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" 1238 | dependencies = [ 1239 | "aho-corasick", 1240 | "memchr", 1241 | "regex-syntax", 1242 | ] 1243 | 1244 | [[package]] 1245 | name = "regex-syntax" 1246 | version = "0.6.25" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 1249 | 1250 | [[package]] 1251 | name = "reqwest" 1252 | version = "0.12.9" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" 1255 | dependencies = [ 1256 | "base64", 1257 | "bytes", 1258 | "futures-core", 1259 | "futures-util", 1260 | "http 1.2.0", 1261 | "http-body 1.0.1", 1262 | "http-body-util", 1263 | "hyper 1.5.2", 1264 | "hyper-rustls", 1265 | "hyper-util", 1266 | "ipnet", 1267 | "js-sys", 1268 | "log", 1269 | "mime", 1270 | "once_cell", 1271 | "percent-encoding", 1272 | "pin-project-lite", 1273 | "quinn", 1274 | "rustls", 1275 | "rustls-pemfile", 1276 | "rustls-pki-types", 1277 | "serde", 1278 | "serde_json", 1279 | "serde_urlencoded", 1280 | "sync_wrapper", 1281 | "tokio", 1282 | "tokio-rustls", 1283 | "tower-service", 1284 | "url", 1285 | "wasm-bindgen", 1286 | "wasm-bindgen-futures", 1287 | "web-sys", 1288 | "webpki-roots", 1289 | "windows-registry", 1290 | ] 1291 | 1292 | [[package]] 1293 | name = "ring" 1294 | version = "0.17.13" 1295 | source = "registry+https://github.com/rust-lang/crates.io-index" 1296 | checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee" 1297 | dependencies = [ 1298 | "cc", 1299 | "cfg-if", 1300 | "getrandom 0.2.14", 1301 | "libc", 1302 | "untrusted", 1303 | "windows-sys", 1304 | ] 1305 | 1306 | [[package]] 1307 | name = "rustc-demangle" 1308 | version = "0.1.24" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1311 | 1312 | [[package]] 1313 | name = "rustc-hash" 1314 | version = "2.1.0" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" 1317 | 1318 | [[package]] 1319 | name = "rustc_version" 1320 | version = "0.4.0" 1321 | source = "registry+https://github.com/rust-lang/crates.io-index" 1322 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1323 | dependencies = [ 1324 | "semver", 1325 | ] 1326 | 1327 | [[package]] 1328 | name = "rustls" 1329 | version = "0.23.20" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" 1332 | dependencies = [ 1333 | "once_cell", 1334 | "ring", 1335 | "rustls-pki-types", 1336 | "rustls-webpki", 1337 | "subtle", 1338 | "zeroize", 1339 | ] 1340 | 1341 | [[package]] 1342 | name = "rustls-pemfile" 1343 | version = "2.2.0" 1344 | source = "registry+https://github.com/rust-lang/crates.io-index" 1345 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 1346 | dependencies = [ 1347 | "rustls-pki-types", 1348 | ] 1349 | 1350 | [[package]] 1351 | name = "rustls-pki-types" 1352 | version = "1.10.1" 1353 | source = "registry+https://github.com/rust-lang/crates.io-index" 1354 | checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" 1355 | dependencies = [ 1356 | "web-time", 1357 | ] 1358 | 1359 | [[package]] 1360 | name = "rustls-webpki" 1361 | version = "0.102.8" 1362 | source = "registry+https://github.com/rust-lang/crates.io-index" 1363 | checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 1364 | dependencies = [ 1365 | "ring", 1366 | "rustls-pki-types", 1367 | "untrusted", 1368 | ] 1369 | 1370 | [[package]] 1371 | name = "ryu" 1372 | version = "1.0.5" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1375 | 1376 | [[package]] 1377 | name = "scopeguard" 1378 | version = "1.1.0" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1381 | 1382 | [[package]] 1383 | name = "scraper" 1384 | version = "0.12.0" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "48e02aa790c80c2e494130dec6a522033b6a23603ffc06360e9fe6c611ea2c12" 1387 | dependencies = [ 1388 | "cssparser", 1389 | "ego-tree", 1390 | "getopts", 1391 | "html5ever", 1392 | "matches", 1393 | "selectors", 1394 | "smallvec", 1395 | "tendril", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "selectors" 1400 | version = "0.22.0" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" 1403 | dependencies = [ 1404 | "bitflags", 1405 | "cssparser", 1406 | "derive_more", 1407 | "fxhash", 1408 | "log", 1409 | "matches", 1410 | "phf", 1411 | "phf_codegen", 1412 | "precomputed-hash", 1413 | "servo_arc", 1414 | "smallvec", 1415 | "thin-slice", 1416 | ] 1417 | 1418 | [[package]] 1419 | name = "semver" 1420 | version = "1.0.6" 1421 | source = "registry+https://github.com/rust-lang/crates.io-index" 1422 | checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" 1423 | 1424 | [[package]] 1425 | name = "serde" 1426 | version = "1.0.125" 1427 | source = "registry+https://github.com/rust-lang/crates.io-index" 1428 | checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" 1429 | dependencies = [ 1430 | "serde_derive", 1431 | ] 1432 | 1433 | [[package]] 1434 | name = "serde_derive" 1435 | version = "1.0.125" 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" 1437 | checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" 1438 | dependencies = [ 1439 | "proc-macro2", 1440 | "quote", 1441 | "syn 1.0.109", 1442 | ] 1443 | 1444 | [[package]] 1445 | name = "serde_json" 1446 | version = "1.0.64" 1447 | source = "registry+https://github.com/rust-lang/crates.io-index" 1448 | checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" 1449 | dependencies = [ 1450 | "itoa 0.4.7", 1451 | "ryu", 1452 | "serde", 1453 | ] 1454 | 1455 | [[package]] 1456 | name = "serde_urlencoded" 1457 | version = "0.7.1" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1460 | dependencies = [ 1461 | "form_urlencoded", 1462 | "itoa 1.0.9", 1463 | "ryu", 1464 | "serde", 1465 | ] 1466 | 1467 | [[package]] 1468 | name = "serde_yaml" 1469 | version = "0.8.17" 1470 | source = "registry+https://github.com/rust-lang/crates.io-index" 1471 | checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" 1472 | dependencies = [ 1473 | "dtoa", 1474 | "linked-hash-map", 1475 | "serde", 1476 | "yaml-rust", 1477 | ] 1478 | 1479 | [[package]] 1480 | name = "servo_arc" 1481 | version = "0.1.1" 1482 | source = "registry+https://github.com/rust-lang/crates.io-index" 1483 | checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" 1484 | dependencies = [ 1485 | "nodrop", 1486 | "stable_deref_trait", 1487 | ] 1488 | 1489 | [[package]] 1490 | name = "shlex" 1491 | version = "1.3.0" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1494 | 1495 | [[package]] 1496 | name = "siphasher" 1497 | version = "0.3.9" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e" 1500 | 1501 | [[package]] 1502 | name = "slab" 1503 | version = "0.4.9" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1506 | dependencies = [ 1507 | "autocfg", 1508 | ] 1509 | 1510 | [[package]] 1511 | name = "smallvec" 1512 | version = "1.13.2" 1513 | source = "registry+https://github.com/rust-lang/crates.io-index" 1514 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1515 | 1516 | [[package]] 1517 | name = "socket2" 1518 | version = "0.5.8" 1519 | source = "registry+https://github.com/rust-lang/crates.io-index" 1520 | checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" 1521 | dependencies = [ 1522 | "libc", 1523 | "windows-sys", 1524 | ] 1525 | 1526 | [[package]] 1527 | name = "stable_deref_trait" 1528 | version = "1.2.0" 1529 | source = "registry+https://github.com/rust-lang/crates.io-index" 1530 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1531 | 1532 | [[package]] 1533 | name = "string_cache" 1534 | version = "0.8.3" 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" 1536 | checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26" 1537 | dependencies = [ 1538 | "lazy_static", 1539 | "new_debug_unreachable", 1540 | "parking_lot", 1541 | "phf_shared 0.10.0", 1542 | "precomputed-hash", 1543 | "serde", 1544 | ] 1545 | 1546 | [[package]] 1547 | name = "string_cache_codegen" 1548 | version = "0.5.1" 1549 | source = "registry+https://github.com/rust-lang/crates.io-index" 1550 | checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" 1551 | dependencies = [ 1552 | "phf_generator", 1553 | "phf_shared 0.8.0", 1554 | "proc-macro2", 1555 | "quote", 1556 | ] 1557 | 1558 | [[package]] 1559 | name = "subtle" 1560 | version = "2.6.1" 1561 | source = "registry+https://github.com/rust-lang/crates.io-index" 1562 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1563 | 1564 | [[package]] 1565 | name = "syn" 1566 | version = "1.0.109" 1567 | source = "registry+https://github.com/rust-lang/crates.io-index" 1568 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1569 | dependencies = [ 1570 | "proc-macro2", 1571 | "quote", 1572 | "unicode-ident", 1573 | ] 1574 | 1575 | [[package]] 1576 | name = "syn" 1577 | version = "2.0.90" 1578 | source = "registry+https://github.com/rust-lang/crates.io-index" 1579 | checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" 1580 | dependencies = [ 1581 | "proc-macro2", 1582 | "quote", 1583 | "unicode-ident", 1584 | ] 1585 | 1586 | [[package]] 1587 | name = "sync_wrapper" 1588 | version = "1.0.2" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1591 | dependencies = [ 1592 | "futures-core", 1593 | ] 1594 | 1595 | [[package]] 1596 | name = "synstructure" 1597 | version = "0.13.1" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1600 | dependencies = [ 1601 | "proc-macro2", 1602 | "quote", 1603 | "syn 2.0.90", 1604 | ] 1605 | 1606 | [[package]] 1607 | name = "tendril" 1608 | version = "0.4.2" 1609 | source = "registry+https://github.com/rust-lang/crates.io-index" 1610 | checksum = "a9ef557cb397a4f0a5a3a628f06515f78563f2209e64d47055d9dc6052bf5e33" 1611 | dependencies = [ 1612 | "futf", 1613 | "mac", 1614 | "utf-8", 1615 | ] 1616 | 1617 | [[package]] 1618 | name = "termcolor" 1619 | version = "1.1.2" 1620 | source = "registry+https://github.com/rust-lang/crates.io-index" 1621 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1622 | dependencies = [ 1623 | "winapi-util", 1624 | ] 1625 | 1626 | [[package]] 1627 | name = "thin-slice" 1628 | version = "0.1.1" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" 1631 | 1632 | [[package]] 1633 | name = "thiserror" 1634 | version = "2.0.3" 1635 | source = "registry+https://github.com/rust-lang/crates.io-index" 1636 | checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" 1637 | dependencies = [ 1638 | "thiserror-impl", 1639 | ] 1640 | 1641 | [[package]] 1642 | name = "thiserror-impl" 1643 | version = "2.0.3" 1644 | source = "registry+https://github.com/rust-lang/crates.io-index" 1645 | checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" 1646 | dependencies = [ 1647 | "proc-macro2", 1648 | "quote", 1649 | "syn 2.0.90", 1650 | ] 1651 | 1652 | [[package]] 1653 | name = "time" 1654 | version = "0.1.44" 1655 | source = "registry+https://github.com/rust-lang/crates.io-index" 1656 | checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" 1657 | dependencies = [ 1658 | "libc", 1659 | "wasi 0.10.0+wasi-snapshot-preview1", 1660 | "winapi", 1661 | ] 1662 | 1663 | [[package]] 1664 | name = "tinystr" 1665 | version = "0.7.6" 1666 | source = "registry+https://github.com/rust-lang/crates.io-index" 1667 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 1668 | dependencies = [ 1669 | "displaydoc", 1670 | "zerovec", 1671 | ] 1672 | 1673 | [[package]] 1674 | name = "tinyvec" 1675 | version = "1.2.0" 1676 | source = "registry+https://github.com/rust-lang/crates.io-index" 1677 | checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" 1678 | dependencies = [ 1679 | "tinyvec_macros", 1680 | ] 1681 | 1682 | [[package]] 1683 | name = "tinyvec_macros" 1684 | version = "0.1.0" 1685 | source = "registry+https://github.com/rust-lang/crates.io-index" 1686 | checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" 1687 | 1688 | [[package]] 1689 | name = "tokio" 1690 | version = "1.43.1" 1691 | source = "registry+https://github.com/rust-lang/crates.io-index" 1692 | checksum = "492a604e2fd7f814268a378409e6c92b5525d747d10db9a229723f55a417958c" 1693 | dependencies = [ 1694 | "backtrace", 1695 | "bytes", 1696 | "libc", 1697 | "mio", 1698 | "pin-project-lite", 1699 | "socket2", 1700 | "tokio-macros", 1701 | "windows-sys", 1702 | ] 1703 | 1704 | [[package]] 1705 | name = "tokio-macros" 1706 | version = "2.5.0" 1707 | source = "registry+https://github.com/rust-lang/crates.io-index" 1708 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 1709 | dependencies = [ 1710 | "proc-macro2", 1711 | "quote", 1712 | "syn 2.0.90", 1713 | ] 1714 | 1715 | [[package]] 1716 | name = "tokio-rustls" 1717 | version = "0.26.1" 1718 | source = "registry+https://github.com/rust-lang/crates.io-index" 1719 | checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" 1720 | dependencies = [ 1721 | "rustls", 1722 | "tokio", 1723 | ] 1724 | 1725 | [[package]] 1726 | name = "tower-service" 1727 | version = "0.3.1" 1728 | source = "registry+https://github.com/rust-lang/crates.io-index" 1729 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 1730 | 1731 | [[package]] 1732 | name = "tracing" 1733 | version = "0.1.40" 1734 | source = "registry+https://github.com/rust-lang/crates.io-index" 1735 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 1736 | dependencies = [ 1737 | "pin-project-lite", 1738 | "tracing-core", 1739 | ] 1740 | 1741 | [[package]] 1742 | name = "tracing-core" 1743 | version = "0.1.32" 1744 | source = "registry+https://github.com/rust-lang/crates.io-index" 1745 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 1746 | dependencies = [ 1747 | "once_cell", 1748 | ] 1749 | 1750 | [[package]] 1751 | name = "try-lock" 1752 | version = "0.2.3" 1753 | source = "registry+https://github.com/rust-lang/crates.io-index" 1754 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1755 | 1756 | [[package]] 1757 | name = "unicase" 1758 | version = "2.6.0" 1759 | source = "registry+https://github.com/rust-lang/crates.io-index" 1760 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 1761 | dependencies = [ 1762 | "version_check", 1763 | ] 1764 | 1765 | [[package]] 1766 | name = "unicode-ident" 1767 | version = "1.0.8" 1768 | source = "registry+https://github.com/rust-lang/crates.io-index" 1769 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" 1770 | 1771 | [[package]] 1772 | name = "unicode-width" 1773 | version = "0.1.8" 1774 | source = "registry+https://github.com/rust-lang/crates.io-index" 1775 | checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" 1776 | 1777 | [[package]] 1778 | name = "untrusted" 1779 | version = "0.9.0" 1780 | source = "registry+https://github.com/rust-lang/crates.io-index" 1781 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1782 | 1783 | [[package]] 1784 | name = "url" 1785 | version = "2.5.4" 1786 | source = "registry+https://github.com/rust-lang/crates.io-index" 1787 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 1788 | dependencies = [ 1789 | "form_urlencoded", 1790 | "idna", 1791 | "percent-encoding", 1792 | ] 1793 | 1794 | [[package]] 1795 | name = "utf-8" 1796 | version = "0.7.6" 1797 | source = "registry+https://github.com/rust-lang/crates.io-index" 1798 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" 1799 | 1800 | [[package]] 1801 | name = "utf16_iter" 1802 | version = "1.0.5" 1803 | source = "registry+https://github.com/rust-lang/crates.io-index" 1804 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 1805 | 1806 | [[package]] 1807 | name = "utf8_iter" 1808 | version = "1.0.4" 1809 | source = "registry+https://github.com/rust-lang/crates.io-index" 1810 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1811 | 1812 | [[package]] 1813 | name = "version_check" 1814 | version = "0.9.3" 1815 | source = "registry+https://github.com/rust-lang/crates.io-index" 1816 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1817 | 1818 | [[package]] 1819 | name = "want" 1820 | version = "0.3.0" 1821 | source = "registry+https://github.com/rust-lang/crates.io-index" 1822 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1823 | dependencies = [ 1824 | "log", 1825 | "try-lock", 1826 | ] 1827 | 1828 | [[package]] 1829 | name = "wasi" 1830 | version = "0.9.0+wasi-snapshot-preview1" 1831 | source = "registry+https://github.com/rust-lang/crates.io-index" 1832 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 1833 | 1834 | [[package]] 1835 | name = "wasi" 1836 | version = "0.10.0+wasi-snapshot-preview1" 1837 | source = "registry+https://github.com/rust-lang/crates.io-index" 1838 | checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" 1839 | 1840 | [[package]] 1841 | name = "wasi" 1842 | version = "0.11.0+wasi-snapshot-preview1" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1845 | 1846 | [[package]] 1847 | name = "wasm-bindgen" 1848 | version = "0.2.99" 1849 | source = "registry+https://github.com/rust-lang/crates.io-index" 1850 | checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" 1851 | dependencies = [ 1852 | "cfg-if", 1853 | "once_cell", 1854 | "wasm-bindgen-macro", 1855 | ] 1856 | 1857 | [[package]] 1858 | name = "wasm-bindgen-backend" 1859 | version = "0.2.99" 1860 | source = "registry+https://github.com/rust-lang/crates.io-index" 1861 | checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" 1862 | dependencies = [ 1863 | "bumpalo", 1864 | "log", 1865 | "proc-macro2", 1866 | "quote", 1867 | "syn 2.0.90", 1868 | "wasm-bindgen-shared", 1869 | ] 1870 | 1871 | [[package]] 1872 | name = "wasm-bindgen-futures" 1873 | version = "0.4.23" 1874 | source = "registry+https://github.com/rust-lang/crates.io-index" 1875 | checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" 1876 | dependencies = [ 1877 | "cfg-if", 1878 | "js-sys", 1879 | "wasm-bindgen", 1880 | "web-sys", 1881 | ] 1882 | 1883 | [[package]] 1884 | name = "wasm-bindgen-macro" 1885 | version = "0.2.99" 1886 | source = "registry+https://github.com/rust-lang/crates.io-index" 1887 | checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" 1888 | dependencies = [ 1889 | "quote", 1890 | "wasm-bindgen-macro-support", 1891 | ] 1892 | 1893 | [[package]] 1894 | name = "wasm-bindgen-macro-support" 1895 | version = "0.2.99" 1896 | source = "registry+https://github.com/rust-lang/crates.io-index" 1897 | checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" 1898 | dependencies = [ 1899 | "proc-macro2", 1900 | "quote", 1901 | "syn 2.0.90", 1902 | "wasm-bindgen-backend", 1903 | "wasm-bindgen-shared", 1904 | ] 1905 | 1906 | [[package]] 1907 | name = "wasm-bindgen-shared" 1908 | version = "0.2.99" 1909 | source = "registry+https://github.com/rust-lang/crates.io-index" 1910 | checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" 1911 | 1912 | [[package]] 1913 | name = "web-sys" 1914 | version = "0.3.50" 1915 | source = "registry+https://github.com/rust-lang/crates.io-index" 1916 | checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" 1917 | dependencies = [ 1918 | "js-sys", 1919 | "wasm-bindgen", 1920 | ] 1921 | 1922 | [[package]] 1923 | name = "web-time" 1924 | version = "1.1.0" 1925 | source = "registry+https://github.com/rust-lang/crates.io-index" 1926 | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 1927 | dependencies = [ 1928 | "js-sys", 1929 | "wasm-bindgen", 1930 | ] 1931 | 1932 | [[package]] 1933 | name = "webpki-roots" 1934 | version = "0.26.7" 1935 | source = "registry+https://github.com/rust-lang/crates.io-index" 1936 | checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" 1937 | dependencies = [ 1938 | "rustls-pki-types", 1939 | ] 1940 | 1941 | [[package]] 1942 | name = "winapi" 1943 | version = "0.3.9" 1944 | source = "registry+https://github.com/rust-lang/crates.io-index" 1945 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1946 | dependencies = [ 1947 | "winapi-i686-pc-windows-gnu", 1948 | "winapi-x86_64-pc-windows-gnu", 1949 | ] 1950 | 1951 | [[package]] 1952 | name = "winapi-i686-pc-windows-gnu" 1953 | version = "0.4.0" 1954 | source = "registry+https://github.com/rust-lang/crates.io-index" 1955 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1956 | 1957 | [[package]] 1958 | name = "winapi-util" 1959 | version = "0.1.5" 1960 | source = "registry+https://github.com/rust-lang/crates.io-index" 1961 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1962 | dependencies = [ 1963 | "winapi", 1964 | ] 1965 | 1966 | [[package]] 1967 | name = "winapi-x86_64-pc-windows-gnu" 1968 | version = "0.4.0" 1969 | source = "registry+https://github.com/rust-lang/crates.io-index" 1970 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1971 | 1972 | [[package]] 1973 | name = "windows-registry" 1974 | version = "0.2.0" 1975 | source = "registry+https://github.com/rust-lang/crates.io-index" 1976 | checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" 1977 | dependencies = [ 1978 | "windows-result", 1979 | "windows-strings", 1980 | "windows-targets", 1981 | ] 1982 | 1983 | [[package]] 1984 | name = "windows-result" 1985 | version = "0.2.0" 1986 | source = "registry+https://github.com/rust-lang/crates.io-index" 1987 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 1988 | dependencies = [ 1989 | "windows-targets", 1990 | ] 1991 | 1992 | [[package]] 1993 | name = "windows-strings" 1994 | version = "0.1.0" 1995 | source = "registry+https://github.com/rust-lang/crates.io-index" 1996 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 1997 | dependencies = [ 1998 | "windows-result", 1999 | "windows-targets", 2000 | ] 2001 | 2002 | [[package]] 2003 | name = "windows-sys" 2004 | version = "0.52.0" 2005 | source = "registry+https://github.com/rust-lang/crates.io-index" 2006 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2007 | dependencies = [ 2008 | "windows-targets", 2009 | ] 2010 | 2011 | [[package]] 2012 | name = "windows-targets" 2013 | version = "0.52.6" 2014 | source = "registry+https://github.com/rust-lang/crates.io-index" 2015 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2016 | dependencies = [ 2017 | "windows_aarch64_gnullvm", 2018 | "windows_aarch64_msvc", 2019 | "windows_i686_gnu", 2020 | "windows_i686_gnullvm", 2021 | "windows_i686_msvc", 2022 | "windows_x86_64_gnu", 2023 | "windows_x86_64_gnullvm", 2024 | "windows_x86_64_msvc", 2025 | ] 2026 | 2027 | [[package]] 2028 | name = "windows_aarch64_gnullvm" 2029 | version = "0.52.6" 2030 | source = "registry+https://github.com/rust-lang/crates.io-index" 2031 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2032 | 2033 | [[package]] 2034 | name = "windows_aarch64_msvc" 2035 | version = "0.52.6" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2038 | 2039 | [[package]] 2040 | name = "windows_i686_gnu" 2041 | version = "0.52.6" 2042 | source = "registry+https://github.com/rust-lang/crates.io-index" 2043 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2044 | 2045 | [[package]] 2046 | name = "windows_i686_gnullvm" 2047 | version = "0.52.6" 2048 | source = "registry+https://github.com/rust-lang/crates.io-index" 2049 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2050 | 2051 | [[package]] 2052 | name = "windows_i686_msvc" 2053 | version = "0.52.6" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2056 | 2057 | [[package]] 2058 | name = "windows_x86_64_gnu" 2059 | version = "0.52.6" 2060 | source = "registry+https://github.com/rust-lang/crates.io-index" 2061 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2062 | 2063 | [[package]] 2064 | name = "windows_x86_64_gnullvm" 2065 | version = "0.52.6" 2066 | source = "registry+https://github.com/rust-lang/crates.io-index" 2067 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2068 | 2069 | [[package]] 2070 | name = "windows_x86_64_msvc" 2071 | version = "0.52.6" 2072 | source = "registry+https://github.com/rust-lang/crates.io-index" 2073 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2074 | 2075 | [[package]] 2076 | name = "write16" 2077 | version = "1.0.0" 2078 | source = "registry+https://github.com/rust-lang/crates.io-index" 2079 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 2080 | 2081 | [[package]] 2082 | name = "writeable" 2083 | version = "0.5.5" 2084 | source = "registry+https://github.com/rust-lang/crates.io-index" 2085 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 2086 | 2087 | [[package]] 2088 | name = "yaml-rust" 2089 | version = "0.4.5" 2090 | source = "registry+https://github.com/rust-lang/crates.io-index" 2091 | checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" 2092 | dependencies = [ 2093 | "linked-hash-map", 2094 | ] 2095 | 2096 | [[package]] 2097 | name = "yoke" 2098 | version = "0.7.5" 2099 | source = "registry+https://github.com/rust-lang/crates.io-index" 2100 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 2101 | dependencies = [ 2102 | "serde", 2103 | "stable_deref_trait", 2104 | "yoke-derive", 2105 | "zerofrom", 2106 | ] 2107 | 2108 | [[package]] 2109 | name = "yoke-derive" 2110 | version = "0.7.5" 2111 | source = "registry+https://github.com/rust-lang/crates.io-index" 2112 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 2113 | dependencies = [ 2114 | "proc-macro2", 2115 | "quote", 2116 | "syn 2.0.90", 2117 | "synstructure", 2118 | ] 2119 | 2120 | [[package]] 2121 | name = "zerofrom" 2122 | version = "0.1.5" 2123 | source = "registry+https://github.com/rust-lang/crates.io-index" 2124 | checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" 2125 | dependencies = [ 2126 | "zerofrom-derive", 2127 | ] 2128 | 2129 | [[package]] 2130 | name = "zerofrom-derive" 2131 | version = "0.1.5" 2132 | source = "registry+https://github.com/rust-lang/crates.io-index" 2133 | checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" 2134 | dependencies = [ 2135 | "proc-macro2", 2136 | "quote", 2137 | "syn 2.0.90", 2138 | "synstructure", 2139 | ] 2140 | 2141 | [[package]] 2142 | name = "zeroize" 2143 | version = "1.8.1" 2144 | source = "registry+https://github.com/rust-lang/crates.io-index" 2145 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2146 | 2147 | [[package]] 2148 | name = "zerovec" 2149 | version = "0.10.4" 2150 | source = "registry+https://github.com/rust-lang/crates.io-index" 2151 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 2152 | dependencies = [ 2153 | "yoke", 2154 | "zerofrom", 2155 | "zerovec-derive", 2156 | ] 2157 | 2158 | [[package]] 2159 | name = "zerovec-derive" 2160 | version = "0.10.3" 2161 | source = "registry+https://github.com/rust-lang/crates.io-index" 2162 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 2163 | dependencies = [ 2164 | "proc-macro2", 2165 | "quote", 2166 | "syn 2.0.90", 2167 | ] 2168 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "awesome-rust" 3 | version = "0.1.0" 4 | authors = [] 5 | homepage = "https://github.com/rust-unofficial/awesome-rust" 6 | repository = "https://github.com/rust-unofficial/awesome-rust" 7 | edition = "2018" 8 | default-run = "awesome-rust" 9 | 10 | [dependencies] 11 | pulldown-cmark = "0.8" 12 | futures = "0.3" 13 | reqwest = { version="0.12", default-features=false, features=["rustls-tls", "json"] } 14 | tokio = {version = "1", features = ["macros", "rt", "rt-multi-thread", "time"] } 15 | serde = { version = "1.0", features = ["derive"] } 16 | serde_yaml = "0.8" 17 | hyper = "0.14" 18 | anyhow = "1" 19 | thiserror = "2" 20 | lazy_static = "1" 21 | env_logger = "0.8" 22 | log = "0.4" 23 | regex = "1" 24 | scraper = "0.12" 25 | chrono = { version = "0.4", features = ["serde"] } 26 | chrono-humanize = "0.2" 27 | diffy = "0.3" 28 | serde_json = "*" 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /results/.gitignore: -------------------------------------------------------------------------------- 1 | # Note that this is in a directory so we can cache it with Travis 2 | *.yaml 3 | -------------------------------------------------------------------------------- /src/bin/cleanup.rs: -------------------------------------------------------------------------------- 1 | // Cleans up `README.md` 2 | // Usage: cargo run --bin cleanup 3 | 4 | use std::fs; 5 | use std::fs::File; 6 | use std::io::Read; 7 | 8 | fn fix_dashes(lines: Vec) -> Vec { 9 | let mut fixed_lines: Vec = Vec::with_capacity(lines.len()); 10 | 11 | let mut within_content = false; 12 | 13 | for line in lines { 14 | if within_content { 15 | fixed_lines.push(line.replace(" — ", " - ")); 16 | } else { 17 | if line.starts_with("## Applications") { 18 | within_content = true; 19 | } 20 | 21 | fixed_lines.push(line.to_string()); 22 | } 23 | } 24 | 25 | fixed_lines 26 | } 27 | 28 | fn main() { 29 | // Read the awesome file. 30 | let mut file = File::open("README.md").expect("Failed to read the file"); 31 | 32 | let mut contents = String::new(); 33 | file.read_to_string(&mut contents) 34 | .expect("Failed to read file contents"); 35 | 36 | // Split contents into lines. 37 | let lines: Vec = contents.lines().map(|l| l.to_string()).collect(); 38 | 39 | // Fix the dashes. 40 | let fixed_contents = fix_dashes(lines); 41 | 42 | // Write the awesome file. 43 | fs::write("README.md", fixed_contents.join("\n").as_bytes()) 44 | .expect("Failed to write to the file"); 45 | } 46 | -------------------------------------------------------------------------------- /src/bin/hacktoberfest.rs: -------------------------------------------------------------------------------- 1 | // Helper tool to dump all repos in awesome-rust that are tagged with "hacktoberfest" 2 | 3 | use anyhow::{format_err, Result}; 4 | use chrono::{DateTime, Duration, Local}; 5 | use futures::future::{select_all, BoxFuture, FutureExt}; 6 | use lazy_static::lazy_static; 7 | use log::{debug, warn}; 8 | use pulldown_cmark::{Event, Parser, Tag}; 9 | use regex::Regex; 10 | use reqwest::redirect::Policy; 11 | use reqwest::Client; 12 | use serde::{Deserialize, Serialize}; 13 | use std::collections::{BTreeMap, BTreeSet}; 14 | use std::env; 15 | use std::fs; 16 | use std::io::Write; 17 | use std::time; 18 | use std::u8; 19 | use thiserror::Error; 20 | use tokio::sync::Semaphore; 21 | use tokio::sync::SemaphorePermit; 22 | 23 | #[derive(Debug, Error, Serialize, Deserialize)] 24 | enum CheckerError { 25 | #[error("http error: {}", status)] 26 | HttpError { 27 | status: u16, 28 | location: Option, 29 | }, 30 | } 31 | 32 | struct MaxHandles { 33 | remaining: Semaphore, 34 | } 35 | 36 | struct Handle<'a> { 37 | _permit: SemaphorePermit<'a>, 38 | } 39 | 40 | impl MaxHandles { 41 | fn new(max: usize) -> MaxHandles { 42 | MaxHandles { 43 | remaining: Semaphore::new(max), 44 | } 45 | } 46 | 47 | async fn get(&self) -> Handle { 48 | let permit = self.remaining.acquire().await.unwrap(); 49 | Handle { _permit: permit } 50 | } 51 | } 52 | 53 | impl<'a> Drop for Handle<'a> { 54 | fn drop(&mut self) { 55 | debug!("Dropping"); 56 | } 57 | } 58 | 59 | lazy_static! { 60 | static ref CLIENT: Client = Client::builder() 61 | .danger_accept_invalid_certs(true) // because some certs are out of date 62 | .user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0") // so some sites (e.g. sciter.com) don't reject us 63 | .redirect(Policy::none()) 64 | .pool_max_idle_per_host(0) 65 | .timeout(time::Duration::from_secs(20)) 66 | .build().unwrap(); 67 | 68 | // This is to avoid errors with running out of file handles, so we only do 20 requests at a time 69 | static ref HANDLES: MaxHandles = MaxHandles::new(20); 70 | } 71 | 72 | lazy_static! { 73 | static ref GITHUB_REPO_REGEX: Regex = 74 | Regex::new(r"^https://github.com/(?P[^/]+)/(?P[^/]+)/?$").unwrap(); 75 | static ref GITHUB_API_REGEX: Regex = Regex::new(r"https://api.github.com/").unwrap(); 76 | } 77 | 78 | #[derive(Deserialize, Debug)] 79 | struct RepoInfo { 80 | full_name: String, 81 | description: Option, 82 | topics: Vec, 83 | } 84 | 85 | async fn get_hacktoberfest_core(github_url: String) -> Result { 86 | warn!("Downloading Hacktoberfest label for {}", github_url); 87 | let rewritten = GITHUB_REPO_REGEX 88 | .replace_all(&github_url, "https://api.github.com/repos/$org/$repo") 89 | .to_string(); 90 | let mut req = CLIENT.get(&rewritten); 91 | if let Ok(username) = env::var("USERNAME_FOR_GITHUB") { 92 | if let Ok(password) = env::var("TOKEN_FOR_GITHUB") { 93 | // needs a token with at least public_repo scope 94 | req = req.basic_auth(username, Some(password)); 95 | } 96 | } 97 | 98 | let resp = req.send().await; 99 | match resp { 100 | Err(err) => { 101 | warn!("Error while getting {}: {}", github_url, err); 102 | Err(CheckerError::HttpError { 103 | status: err.status().unwrap().as_u16(), 104 | location: Some(github_url.to_string()), 105 | }) 106 | } 107 | Ok(ok) => { 108 | if !ok.status().is_success() { 109 | return Err(CheckerError::HttpError { 110 | status: ok.status().as_u16(), 111 | location: None, 112 | }); 113 | } 114 | let raw = ok.text().await.unwrap(); 115 | match serde_json::from_str::(&raw) { 116 | Ok(val) => Ok(Info { 117 | name: val.full_name, 118 | description: val.description.unwrap_or_default(), 119 | hacktoberfest: val.topics.iter().any(|t| *t == "hacktoberfest"), 120 | }), 121 | Err(_) => { 122 | panic!("{}", raw); 123 | } 124 | } 125 | } 126 | } 127 | } 128 | 129 | fn get_hacktoberfest(url: String) -> BoxFuture<'static, (String, Result)> { 130 | debug!("Need handle for {}", url); 131 | async move { 132 | let _handle = HANDLES.get().await; 133 | (url.clone(), get_hacktoberfest_core(url).await) 134 | } 135 | .boxed() 136 | } 137 | 138 | #[derive(Debug, Serialize, Deserialize)] 139 | struct Info { 140 | hacktoberfest: bool, 141 | name: String, 142 | description: String, 143 | } 144 | 145 | #[derive(Debug, Serialize, Deserialize)] 146 | struct Link { 147 | updated_at: DateTime, 148 | info: Info, 149 | } 150 | 151 | type Results = BTreeMap; 152 | 153 | #[tokio::main] 154 | async fn main() -> Result<()> { 155 | env_logger::init(); 156 | let markdown_input = fs::read_to_string("README.md").expect("Can't read README.md"); 157 | let parser = Parser::new(&markdown_input); 158 | 159 | let mut used: BTreeSet = BTreeSet::new(); 160 | let mut results: Results = fs::read_to_string("results/hacktoberfest.yaml") 161 | .map_err(|e| format_err!("{}", e)) 162 | .and_then(|x| serde_yaml::from_str(&x).map_err(|e| format_err!("{}", e))) 163 | .unwrap_or_default(); 164 | 165 | let mut url_checks = vec![]; 166 | 167 | let mut do_check = |url: String| { 168 | if !url.starts_with("http") { 169 | return; 170 | } 171 | if used.contains(&url) { 172 | return; 173 | } 174 | used.insert(url.clone()); 175 | if results.contains_key(&url) { 176 | return; 177 | } 178 | let check = get_hacktoberfest(url).boxed(); 179 | url_checks.push(check); 180 | }; 181 | 182 | let mut to_check: Vec = vec![]; 183 | 184 | for (event, _) in parser.into_offset_iter() { 185 | if let Event::Start(tag) = event { 186 | if let Tag::Link(_link_type, url, _title) | Tag::Image(_link_type, url, _title) = tag { 187 | if GITHUB_REPO_REGEX.is_match(&url) { 188 | to_check.push(url.to_string()); 189 | } 190 | } 191 | } 192 | } 193 | 194 | for url in to_check { 195 | do_check(url) 196 | } 197 | 198 | let results_keys = results.keys().cloned().collect::>(); 199 | let old_links = results_keys.difference(&used); 200 | for link in old_links { 201 | results.remove(link).unwrap(); 202 | } 203 | fs::write("results/results.yaml", serde_yaml::to_string(&results)?)?; 204 | 205 | let mut not_written = 0; 206 | let mut last_written = Local::now(); 207 | 208 | let mut failed: u32 = 0; 209 | while !url_checks.is_empty() { 210 | debug!("Waiting for {}", url_checks.len()); 211 | let ((url, res), _index, remaining) = select_all(url_checks).await; 212 | url_checks = remaining; 213 | match res { 214 | Ok(info) => { 215 | print!("\u{2714} "); 216 | if let Some(link) = results.get_mut(&url) { 217 | link.updated_at = Local::now(); 218 | link.info = info 219 | } else { 220 | results.insert( 221 | url.clone(), 222 | Link { 223 | updated_at: Local::now(), 224 | info, 225 | }, 226 | ); 227 | } 228 | } 229 | Err(_) => { 230 | print!("\u{2718} "); 231 | println!("{}", url); 232 | failed += 1; 233 | } 234 | } 235 | std::io::stdout().flush().unwrap(); 236 | 237 | not_written += 1; 238 | let duration = Local::now() - last_written; 239 | if duration > Duration::seconds(5) || not_written > 20 { 240 | fs::write( 241 | "results/hacktoberfest.yaml", 242 | serde_yaml::to_string(&results)?, 243 | )?; 244 | not_written = 0; 245 | last_written = Local::now(); 246 | } 247 | } 248 | fs::write( 249 | "results/hacktoberfest.yaml", 250 | serde_yaml::to_string(&results)?, 251 | )?; 252 | println!(); 253 | 254 | if failed == 0 { 255 | println!("All awesome-rust repos tagged with 'hacktoberfest'"); 256 | let mut sorted_repos = results 257 | .keys() 258 | .map(|s| s.to_string()) 259 | .collect::>(); 260 | sorted_repos.sort_by_key(|a| a.to_lowercase()); 261 | for name in sorted_repos { 262 | let link = results.get(&name).unwrap(); 263 | if link.info.hacktoberfest { 264 | println!( 265 | "* [{}]({}) - {}", 266 | link.info.name, name, link.info.description 267 | ) 268 | } 269 | } 270 | Ok(()) 271 | } else { 272 | Err(format_err!("{} urls with errors", failed)) 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | 3 | use anyhow::{format_err, Result}; 4 | use chrono::{DateTime, Duration, Local}; 5 | use diffy::create_patch; 6 | use futures::future::{select_all, BoxFuture, FutureExt}; 7 | use lazy_static::lazy_static; 8 | use log::{debug, info, warn}; 9 | use pulldown_cmark::{Event, Parser, Tag}; 10 | use regex::Regex; 11 | use reqwest::{header, redirect::Policy, Client, StatusCode, Url}; 12 | use serde::{Deserialize, Serialize}; 13 | use std::collections::{BTreeMap, BTreeSet}; 14 | use std::env; 15 | use std::io::Write; 16 | use std::time; 17 | use std::u8; 18 | use std::{cmp::Ordering, fs}; 19 | use thiserror::Error; 20 | use tokio::sync::Semaphore; 21 | use tokio::sync::SemaphorePermit; 22 | 23 | const MINIMUM_GITHUB_STARS: u32 = 50; 24 | const MINIMUM_CARGO_DOWNLOADS: u32 = 2000; 25 | 26 | // Allow overriding the needed stars for a section. "level" is the header level in the markdown, default is MINIMUM_GITHUB_STARS 27 | // In general, we should just use the defaults. However, for some areas where there's not a lot of well-starred projects, but a 28 | // a few that are say just below the thresholds, then it's worth reducing the thresholds so we can get a few more projects. 29 | fn override_stars(level: u32, text: &str) -> Option { 30 | if level == 2 && text.contains("Resources") { 31 | // This is zero because a lot of the resources are non-github/non-cargo links and overriding for all would be annoying 32 | // These should be evaluated with more primitive means 33 | Some(0) 34 | } else if level == 3 && (text.contains("Games") || text.contains("Emulators")) { 35 | Some(40) 36 | } else { 37 | None // i.e. use defaults 38 | } 39 | } 40 | 41 | lazy_static! { 42 | // We don't explicitly check these, because they just bug out in GitHub. We're _hoping_ they don't go away! 43 | static ref ASSUME_WORKS: Vec = vec![ 44 | "https://www.reddit.com/r/rust/", 45 | "https://opcfoundation.org/about/opc-technologies/opc-ua/", 46 | "https://arangodb.com", 47 | "https://git.sr.ht/~lessa/pepper", 48 | "https://git.sr.ht/~pyrossh/rust-embed", 49 | "https://www.gnu.org/software/emacs/", 50 | "http://www.gnu.org/software/gsl/" 51 | ].iter().map(|s| s.to_string()).collect(); 52 | // Overrides for popularity count, each needs a good reason (i.e. downloads/stars we don't support automatic counting of) 53 | // Each is a URL that's "enough" for an item to pass the popularity checks 54 | static ref POPULARITY_OVERRIDES: Vec = vec![ 55 | "https://github.com/maidsafe", // Many repos of Rust code, collectively > 50 stars 56 | "https://pijul.org", // Uses it's own VCS at https://nest.pijul.com/pijul/pijul with 190 stars at last check 57 | "https://gitlab.com/veloren/veloren", // No direct gitlab support, but >1000 stars there 58 | "https://gitlab.redox-os.org/redox-os/redox", // 394 stars 59 | "https://amp.rs", // https://github.com/jmacdonald/amp has 2.9k stars 60 | "https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb", // > 350k downloads 61 | "https://gitpod.io", // https://github.com/gitpod-io/gitpod has 4.7k stars 62 | "https://wiki.gnome.org/Apps/Builder", // https://gitlab.gnome.org/GNOME/gnome-builder has 133 stars 63 | "https://www.jetbrains.com/rust/", // popular closed-source IDE, free for non-commercial use 64 | "https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml", // > 1M downloads 65 | "https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer", // > 260k downloads 66 | "https://marketplace.visualstudio.com/items?itemName=rust-lang.rust", // > 1M downloads 67 | "https://docs.rs", // https://github.com/rust-lang/docs.rs has >600 stars 68 | "https://github.com/rust-bio", // https://github.com/rust-bio/rust-bio on it's own has >900 stars 69 | "https://github.com/contain-rs", // Lots of repos with good star counts 70 | "https://github.com/georust", // Lots of repos with good star counts 71 | "http://kiss3d.org", // https://github.com/sebcrozet/kiss3d has >900 stars 72 | "https://github.com/rust-qt", // Various high-stars repositories 73 | "https://chromium.googlesource.com/chromiumos/platform/crosvm/", // Can't tell count directly, but various mirrors of it (e.g. https://github.com/dgreid/crosvm) have enough stars that it's got enough interest 74 | "https://crates.io", // This one gets a free pass :) 75 | "https://cloudsmith.com/product/formats/cargo-registry", // First private cargo registry (https://cloudsmith.com/blog/worlds-first-private-cargo-registry-w-cloudsmith-rust/) and not much in the way of other options yet. See also https://github.com/rust-unofficial/awesome-rust/pull/1141#discussion_r688711555 76 | "https://gitlab.com/ttyperacer/terminal-typeracer", // GitLab repo with >40 stars. 77 | "https://github.com/esp-rs", // Espressif Rust Organization (Organizations have no stars). 78 | "https://github.com/arkworks-rs", // Rust ecosystem for zkSNARK programming (Organizations have no stars) 79 | "https://marketplace.visualstudio.com/items?itemName=jinxdash.prettier-rust", // https://github.com/jinxdash/prettier-plugin-rust has >50 stars 80 | "https://github.com/andoriyu/uclicious", // FIXME: CI hack. the crate has a higher count, but we don't refresh. 81 | "https://marketplace.visualstudio.com/items?itemName=fill-labs.dependi", // marketplace link , but also has enough stars 82 | ].iter().map(|s| s.to_string()).collect(); 83 | } 84 | 85 | #[derive(Debug, Error, Serialize, Deserialize)] 86 | enum CheckerError { 87 | #[error("failed to try url")] 88 | NotTried, // Generally shouldn't happen, but useful to have 89 | 90 | #[error("http error: {status}")] 91 | HttpError { 92 | status: u16, 93 | location: Option, 94 | }, 95 | 96 | #[error("too many requests")] 97 | TooManyRequests, 98 | 99 | #[error("reqwest error: {error}")] 100 | ReqwestError { error: String }, 101 | 102 | #[error("travis build is unknown")] 103 | TravisBuildUnknown, 104 | 105 | #[error("travis build image with no branch")] 106 | TravisBuildNoBranch, 107 | } 108 | 109 | fn formatter(err: &CheckerError, url: &String) -> String { 110 | match err { 111 | CheckerError::HttpError { status, location } => match location { 112 | Some(loc) => { 113 | format!("[{}] {} -> {}", status, url, loc) 114 | } 115 | None => { 116 | format!("[{}] {}", status, url) 117 | } 118 | }, 119 | CheckerError::TravisBuildUnknown => { 120 | format!("[Unknown travis build] {}", url) 121 | } 122 | CheckerError::TravisBuildNoBranch => { 123 | format!("[Travis build image with no branch specified] {}", url) 124 | } 125 | _ => { 126 | format!("{:?}", err) 127 | } 128 | } 129 | } 130 | 131 | struct MaxHandles { 132 | remaining: Semaphore, 133 | } 134 | 135 | struct Handle<'a> { 136 | _permit: SemaphorePermit<'a>, 137 | } 138 | 139 | impl MaxHandles { 140 | fn new(max: usize) -> MaxHandles { 141 | MaxHandles { 142 | remaining: Semaphore::new(max), 143 | } 144 | } 145 | 146 | async fn get(&self) -> Handle { 147 | let permit = self.remaining.acquire().await.unwrap(); 148 | Handle { _permit: permit } 149 | } 150 | } 151 | 152 | impl<'a> Drop for Handle<'a> { 153 | fn drop(&mut self) { 154 | debug!("Dropping"); 155 | } 156 | } 157 | 158 | lazy_static! { 159 | static ref CLIENT: Client = Client::builder() 160 | .danger_accept_invalid_certs(true) // because some certs are out of date 161 | .user_agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:68.0) Gecko/20100101 Firefox/68.0") // so some sites (e.g. sciter.com) don't reject us 162 | .redirect(Policy::none()) 163 | .pool_max_idle_per_host(0) 164 | .timeout(time::Duration::from_secs(20)) 165 | .build().unwrap(); 166 | 167 | // This is to avoid errors with running out of file handles, so we only do 20 requests at a time 168 | static ref HANDLES: MaxHandles = MaxHandles::new(20); 169 | } 170 | 171 | fn get_url(url: String) -> BoxFuture<'static, (String, Result<(), CheckerError>)> { 172 | debug!("Need handle for {}", url); 173 | async move { 174 | let _handle = HANDLES.get().await; 175 | get_url_core(url).await 176 | } 177 | .boxed() 178 | } 179 | 180 | lazy_static! { 181 | static ref GITHUB_REPO_REGEX: Regex = 182 | Regex::new(r"^https://github.com/(?P[^/]+)/(?P[^/]+)(.*)").unwrap(); 183 | static ref GITHUB_API_REGEX: Regex = Regex::new(r"https://api.github.com/").unwrap(); 184 | static ref CRATE_REGEX: Regex = 185 | Regex::new(r"https://crates.io/crates/(?P[^/]+)/?$").unwrap(); 186 | static ref ITEM_REGEX: Regex = 187 | Regex::new(r"(?P(\S+)(/\S+)?)(?P \[\S*\])? - (?P\S.+)").unwrap(); 188 | } 189 | 190 | #[derive(Deserialize, Debug)] 191 | struct GitHubStars { 192 | stargazers_count: u32, 193 | archived: bool, 194 | } 195 | 196 | async fn get_stars(github_url: &str) -> Option { 197 | warn!("Downloading GitHub stars for {}", github_url); 198 | let rewritten = GITHUB_REPO_REGEX 199 | .replace_all(github_url, "https://api.github.com/repos/$org/$repo") 200 | .to_string(); 201 | let mut req = CLIENT.get(&rewritten); 202 | if let Ok(username) = env::var("USERNAME_FOR_GITHUB") { 203 | if let Ok(password) = env::var("TOKEN_FOR_GITHUB") { 204 | // needs a token with at least public_repo scope 205 | req = req.basic_auth(username, Some(password)); 206 | } 207 | } 208 | 209 | let resp = req.send().await; 210 | match resp { 211 | Err(err) => { 212 | warn!("Error while getting {}: {}", github_url, err); 213 | None 214 | } 215 | Ok(ok) => { 216 | let raw = ok.text().await.unwrap(); 217 | let data = match serde_json::from_str::(&raw) { 218 | Ok(val) => val, 219 | Err(_) => { 220 | panic!("{:?}", raw); 221 | } 222 | }; 223 | if data.archived { 224 | warn!("{} is archived, so ignoring stars", github_url); 225 | return Some(0); 226 | } 227 | Some(data.stargazers_count) 228 | } 229 | } 230 | } 231 | 232 | #[derive(Deserialize, Debug)] 233 | struct CrateInfo { 234 | downloads: u64, 235 | } 236 | 237 | #[derive(Deserialize, Debug)] 238 | struct Crate { 239 | #[serde(rename = "crate")] 240 | info: CrateInfo, 241 | } 242 | 243 | async fn get_downloads(github_url: &str) -> Option { 244 | warn!("Downloading Crates downloads for {}", github_url); 245 | let rewritten = CRATE_REGEX 246 | .replace_all(github_url, "https://crates.io/api/v1/crates/$crate") 247 | .to_string(); 248 | let req = CLIENT.get(&rewritten); 249 | 250 | let resp = req.send().await; 251 | match resp { 252 | Err(err) => { 253 | warn!("Error while getting {}: {}", github_url, err); 254 | None 255 | } 256 | Ok(ok) => { 257 | let data = ok.json::().await.unwrap(); 258 | Some(data.info.downloads) 259 | } 260 | } 261 | } 262 | 263 | fn get_url_core(url: String) -> BoxFuture<'static, (String, Result<(), CheckerError>)> { 264 | async move { 265 | if ASSUME_WORKS.contains(&url) { 266 | info!("We assume {} just works...", url); 267 | return (url, Ok(())); 268 | } 269 | if env::var("USERNAME_FOR_GITHUB").is_ok() && env::var("TOKEN_FOR_GITHUB").is_ok() && GITHUB_REPO_REGEX.is_match(&url) { 270 | let rewritten = GITHUB_REPO_REGEX.replace_all(&url, "https://api.github.com/repos/$org/$repo"); 271 | info!("Replacing {} with {} to workaround rate limits on GitHub", url, rewritten); 272 | let (_new_url, res) = get_url_core(rewritten.to_string()).await; 273 | return (url, res); 274 | } 275 | let mut res: Result<(), CheckerError> = Err(CheckerError::NotTried); 276 | for _ in 0..5u8 { 277 | debug!("Running {}", url); 278 | let mut req = CLIENT 279 | .get(&url) 280 | .header(header::ACCEPT, "image/svg+xml, text/html, */*;q=0.8"); 281 | 282 | if GITHUB_API_REGEX.is_match(&url) { 283 | if let Ok(username) = env::var("USERNAME_FOR_GITHUB") { 284 | if let Ok(password) = env::var("TOKEN_FOR_GITHUB") { 285 | // needs a token with at least public_repo scope 286 | info!("Using basic auth for {}", url); 287 | req = req.basic_auth(username, Some(password)); 288 | } 289 | } 290 | } 291 | 292 | let resp = req.send().await; 293 | match resp { 294 | Err(err) => { 295 | warn!("Error while getting {}, retrying: {}", url, err); 296 | res = Err(CheckerError::ReqwestError{error: err.to_string()}); 297 | continue; 298 | } 299 | Ok(ok) => { 300 | let status = ok.status(); 301 | if status != StatusCode::OK { 302 | lazy_static! { 303 | static ref ACTIONS_REGEX: Regex = Regex::new(r"https://github.com/(?P[^/]+)/(?P[^/]+)/actions(?:\?workflow=.+)?").unwrap(); 304 | static ref YOUTUBE_VIDEO_REGEX: Regex = Regex::new(r"https://www.youtube.com/watch\?v=(?P.+)").unwrap(); 305 | static ref YOUTUBE_PLAYLIST_REGEX: Regex = Regex::new(r"https://www.youtube.com/playlist\?list=(?P.+)").unwrap(); 306 | static ref YOUTUBE_CONSENT_REGEX: Regex = Regex::new(r"https://consent.youtube.com/m\?continue=.+").unwrap(); 307 | static ref AZURE_BUILD_REGEX: Regex = Regex::new(r"https://dev.azure.com/[^/]+/[^/]+/_build").unwrap(); 308 | } 309 | if status == StatusCode::NOT_FOUND && ACTIONS_REGEX.is_match(&url) { 310 | let rewritten = ACTIONS_REGEX.replace_all(&url, "https://github.com/$org/$repo"); 311 | warn!("Got 404 with GitHub actions, so replacing {} with {}", url, rewritten); 312 | let (_new_url, res) = get_url_core(rewritten.to_string()).await; 313 | return (url, res); 314 | } 315 | if status == StatusCode::FOUND && YOUTUBE_VIDEO_REGEX.is_match(&url) { 316 | // Based off of https://gist.github.com/tonY1883/a3b85925081688de569b779b4657439b 317 | // Guesswork is that the img feed will cause less 302's than the main url 318 | // See https://github.com/rust-unofficial/awesome-rust/issues/814 for original issue 319 | let rewritten = YOUTUBE_VIDEO_REGEX.replace_all(&url, "http://img.youtube.com/vi/$video_id/mqdefault.jpg"); 320 | warn!("Got 302 with Youtube, so replacing {} with {}", url, rewritten); 321 | let (_new_url, res) = get_url_core(rewritten.to_string()).await; 322 | return (url, res); 323 | }; 324 | if status == StatusCode::FOUND && YOUTUBE_PLAYLIST_REGEX.is_match(&url) { 325 | let location = ok.headers().get("LOCATION").map(|h| h.to_str().unwrap()).unwrap_or_default(); 326 | if YOUTUBE_CONSENT_REGEX.is_match(location) { 327 | warn!("Got Youtube consent link for {}, so assuming playlist is ok", url); 328 | return (url, Ok(())); 329 | } 330 | }; 331 | if status == StatusCode::FOUND && AZURE_BUILD_REGEX.is_match(&url) { 332 | // Azure build urls always redirect to a particular build id, so no stable url guarantees 333 | let redirect = ok.headers().get(header::LOCATION).unwrap().to_str().unwrap(); 334 | let merged_url = Url::parse(&url).unwrap().join(redirect).unwrap(); 335 | info!("Got 302 from Azure devops, so replacing {} with {}", url, merged_url); 336 | let (_new_url, res) = get_url_core(merged_url.into()).await; 337 | return (url, res); 338 | } 339 | 340 | if status == StatusCode::TOO_MANY_REQUESTS { 341 | // We get a lot of these, and we should not retry as they'll just fail again 342 | warn!("Error while getting {}: {}", url, status); 343 | return (url, Err(CheckerError::TooManyRequests)); 344 | } 345 | 346 | if status.is_redirection() { 347 | if status != StatusCode::TEMPORARY_REDIRECT && status != StatusCode::FOUND { // ignore temporary redirects 348 | res = Err(CheckerError::HttpError {status: status.as_u16(), location: ok.headers().get(header::LOCATION).and_then(|h| h.to_str().ok()).map(|x| x.to_string())}); 349 | warn!("Redirect while getting {} - {}", url, status); 350 | break; 351 | } 352 | } else { 353 | warn!("Error while getting {}, retrying: {}", url, status); 354 | res = Err(CheckerError::HttpError {status: status.as_u16(), location: None}); 355 | continue; 356 | } 357 | } 358 | lazy_static! { 359 | static ref TRAVIS_IMG_REGEX: Regex = Regex::new(r"https://api.travis-ci.(?:com|org)/[^/]+/.+\.svg(\?.+)?").unwrap(); 360 | static ref GITHUB_ACTIONS_REGEX: Regex = Regex::new(r"https://github.com/[^/]+/[^/]+/workflows/[^/]+/badge.svg(\?.+)?").unwrap(); 361 | } 362 | if let Some(matches) = TRAVIS_IMG_REGEX.captures(&url) { 363 | // Previously we checked the Content-Disposition headers, but sometimes that is incorrect 364 | // We're now looking for the explicit text "unknown" in the middle of the SVG 365 | let content = ok.text().await.unwrap(); 366 | if content.contains("unknown") { 367 | res = Err(CheckerError::TravisBuildUnknown); 368 | break; 369 | } 370 | let query = matches.get(1).map(|x| x.as_str()).unwrap_or(""); 371 | if !query.starts_with('?') || !query.contains("branch=") { 372 | res = Err(CheckerError::TravisBuildNoBranch); 373 | break; 374 | } 375 | } 376 | debug!("Finished {}", url); 377 | res = Ok(()); 378 | break; 379 | } 380 | } 381 | } 382 | (url, res) 383 | }.boxed() 384 | } 385 | 386 | #[derive(Debug, Serialize, Deserialize)] 387 | enum Working { 388 | Yes, 389 | No(CheckerError), 390 | } 391 | 392 | #[derive(Debug, Serialize, Deserialize)] 393 | struct Link { 394 | last_working: Option>, 395 | updated_at: DateTime, 396 | working: Working, 397 | } 398 | 399 | type Results = BTreeMap; 400 | 401 | #[derive(Debug, Serialize, Deserialize)] 402 | struct PopularityData { 403 | pub github_stars: BTreeMap, 404 | pub cargo_downloads: BTreeMap, 405 | } 406 | 407 | #[tokio::main] 408 | async fn main() -> Result<()> { 409 | env_logger::init(); 410 | let markdown_input = fs::read_to_string("README.md").expect("Can't read README.md"); 411 | let parser = Parser::new(&markdown_input); 412 | 413 | let mut used: BTreeSet = BTreeSet::new(); 414 | let mut results: Results = fs::read_to_string("results/results.yaml") 415 | .map_err(|e| format_err!("{}", e)) 416 | .and_then(|x| serde_yaml::from_str(&x).map_err(|e| format_err!("{}", e))) 417 | .unwrap_or_default(); 418 | 419 | let mut popularity_data: PopularityData = fs::read_to_string("results/popularity.yaml") 420 | .map_err(|e| format_err!("{}", e)) 421 | .and_then(|x| serde_yaml::from_str(&x).map_err(|e| format_err!("{}", e))) 422 | .unwrap_or(PopularityData { 423 | github_stars: BTreeMap::new(), 424 | cargo_downloads: BTreeMap::new(), 425 | }); 426 | 427 | let mut url_checks = vec![]; 428 | 429 | let min_between_checks: Duration = Duration::days(3); 430 | let max_allowed_failed: Duration = Duration::days(7); 431 | let mut do_check = |url: String| { 432 | if !url.starts_with("http") { 433 | return; 434 | } 435 | if used.contains(&url) { 436 | return; 437 | } 438 | used.insert(url.clone()); 439 | if let Some(link) = results.get(&url) { 440 | if let Working::Yes = link.working { 441 | let since = Local::now() - link.updated_at; 442 | if since < min_between_checks { 443 | return; 444 | } 445 | } 446 | } 447 | let check = get_url(url).boxed(); 448 | url_checks.push(check); 449 | }; 450 | 451 | let mut to_check: Vec = vec![]; 452 | 453 | #[derive(Debug)] 454 | struct ListInfo { 455 | data: Vec, 456 | } 457 | 458 | let mut list_items: Vec = Vec::new(); 459 | let mut in_list_item = false; 460 | let mut list_item: String = String::new(); 461 | 462 | let mut link_count: u8 = 0; 463 | let mut github_stars: Option = None; 464 | let mut cargo_downloads: Option = None; 465 | 466 | let mut required_stars: u32 = MINIMUM_GITHUB_STARS; 467 | let mut last_level: u32 = 0; 468 | let mut star_override_level: Option = None; 469 | 470 | for (event, _range) in parser.into_offset_iter() { 471 | debug!("Event {:?}", event); 472 | match event { 473 | Event::Start(tag) => { 474 | match tag { 475 | Tag::Link(_link_type, url, _title) | Tag::Image(_link_type, url, _title) => { 476 | if !url.starts_with('#') { 477 | let new_url = url.to_string(); 478 | if POPULARITY_OVERRIDES.contains(&new_url) { 479 | github_stars = Some(MINIMUM_GITHUB_STARS); 480 | } else if GITHUB_REPO_REGEX.is_match(&url) && github_stars.is_none() { 481 | let github_url = GITHUB_REPO_REGEX 482 | .replace_all(&url, "https://github.com/$org/$repo") 483 | .to_string(); 484 | let existing = popularity_data.github_stars.get(&github_url); 485 | if let Some(stars) = existing { 486 | // Use existing star data, but re-retrieve url to check aliveness 487 | // Some will have overrides, so don't check the regex yet 488 | github_stars = Some(*stars) 489 | } else { 490 | github_stars = get_stars(&github_url).await; 491 | if let Some(raw_stars) = github_stars { 492 | popularity_data.github_stars.insert(github_url, raw_stars); 493 | if raw_stars >= required_stars { 494 | fs::write( 495 | "results/popularity.yaml", 496 | serde_yaml::to_string(&popularity_data)?, 497 | )?; 498 | } 499 | link_count += 1; 500 | continue; 501 | } 502 | } 503 | } 504 | if CRATE_REGEX.is_match(&url) { 505 | let existing = popularity_data.cargo_downloads.get(&new_url); 506 | if let Some(downloads) = existing { 507 | cargo_downloads = Some(*downloads); 508 | } else { 509 | let raw_downloads = get_downloads(&url).await; 510 | if let Some(positive_downloads) = raw_downloads { 511 | cargo_downloads = Some( 512 | positive_downloads.clamp(0, u32::MAX as u64) as u32, 513 | ); 514 | popularity_data 515 | .cargo_downloads 516 | .insert(new_url, cargo_downloads.unwrap()); 517 | if cargo_downloads.unwrap_or(0) >= MINIMUM_CARGO_DOWNLOADS { 518 | fs::write( 519 | "results/popularity.yaml", 520 | serde_yaml::to_string(&popularity_data)?, 521 | )?; 522 | } 523 | } 524 | link_count += 1; 525 | continue; 526 | } 527 | } 528 | 529 | to_check.push(url.to_string()); 530 | link_count += 1; 531 | } 532 | } 533 | Tag::List(_) => { 534 | if in_list_item && !list_item.is_empty() { 535 | list_items.last_mut().unwrap().data.push(list_item.clone()); 536 | in_list_item = false; 537 | } 538 | list_items.push(ListInfo { data: Vec::new() }); 539 | } 540 | Tag::Item => { 541 | if in_list_item && !list_item.is_empty() { 542 | list_items.last_mut().unwrap().data.push(list_item.clone()); 543 | } 544 | in_list_item = true; 545 | list_item = String::new(); 546 | link_count = 0; 547 | github_stars = None; 548 | cargo_downloads = None; 549 | } 550 | Tag::Heading(level) => { 551 | last_level = level; 552 | if let Some(override_level) = star_override_level { 553 | if level == override_level { 554 | star_override_level = None; 555 | required_stars = MINIMUM_GITHUB_STARS; 556 | } 557 | } 558 | } 559 | Tag::Paragraph => {} 560 | _ => { 561 | if in_list_item { 562 | in_list_item = false; 563 | } 564 | } 565 | } 566 | } 567 | Event::Text(text) => { 568 | let possible_override = override_stars(last_level, &text); 569 | if let Some(override_value) = possible_override { 570 | star_override_level = Some(last_level); 571 | required_stars = override_value; 572 | } 573 | 574 | if in_list_item { 575 | list_item.push_str(&text); 576 | } 577 | } 578 | Event::End(tag) => { 579 | match tag { 580 | Tag::Item => { 581 | if !list_item.is_empty() { 582 | if link_count > 0 583 | && github_stars.unwrap_or(0) < required_stars 584 | && cargo_downloads.unwrap_or(0) < MINIMUM_CARGO_DOWNLOADS 585 | { 586 | if github_stars.is_none() { 587 | warn!("No valid github link for {list_item}"); 588 | } 589 | if cargo_downloads.is_none() { 590 | warn!("No valid crates link for {list_item}"); 591 | } 592 | return Err(format_err!("Not high enough metrics ({:?} stars < {}, and {:?} cargo downloads < {}): {}", github_stars, required_stars, cargo_downloads, MINIMUM_CARGO_DOWNLOADS, list_item)); 593 | } 594 | if link_count > 0 && !ITEM_REGEX.is_match(&list_item) { 595 | if list_item.contains("—") { 596 | warn!("\"{list_item}\" uses a '—' hyphen, not the '-' hyphen and we enforce the use of the latter one"); 597 | } 598 | return Err(format_err!("Item does not match the template: \"{list_item}\". See https://github.com/rust-unofficial/awesome-rust/blob/main/CONTRIBUTING.md#tldr")); 599 | } 600 | list_items.last_mut().unwrap().data.push(list_item.clone()); 601 | list_item = String::new(); 602 | } 603 | in_list_item = false 604 | } 605 | Tag::List(_) => { 606 | let list_info = list_items.pop().unwrap(); 607 | if list_info.data.iter().any(|s| *s == "License") 608 | && list_info.data.iter().any(|s| *s == "Resources") 609 | { 610 | // Ignore wrong ordering in top-level list 611 | continue; 612 | } 613 | let mut sorted_recent_list = list_info.data.to_vec(); 614 | sorted_recent_list.sort_by_key(|a| a.to_lowercase()); 615 | let joined_recent = list_info.data.join("\n"); 616 | let joined_sorted = sorted_recent_list.join("\n"); 617 | let patch = create_patch(&joined_recent, &joined_sorted); 618 | if !patch.hunks().is_empty() { 619 | println!("{}", patch); 620 | return Err(format_err!("Sorting error")); 621 | } 622 | } 623 | _ => {} 624 | } 625 | } 626 | Event::Html(content) => { 627 | // Allow ToC markers, nothing else 628 | if !content.contains("