From 8ea4edf133060adaf5978b9ee2f8a86056f84c24 Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Wed, 22 Nov 2023 23:34:55 -0300 Subject: [PATCH 01/18] Leyendo texto de pdf --- .env.example | 3 + .gitignore | 3 + Cargo.lock | 227 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/bin/indexer.rs | 75 +++++++++++++++ 5 files changed, 310 insertions(+) create mode 100644 src/bin/indexer.rs diff --git a/.env.example b/.env.example index fb2b744..de7d970 100644 --- a/.env.example +++ b/.env.example @@ -5,3 +5,6 @@ DATABASE_URL=sqlite:data.db # Donde escucha la API? HOST=127.0.0.1 PORT=8080 + +# Storage path +assets/ diff --git a/.gitignore b/.gitignore index df9d7e3..e3e8d2a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ # SQLite3 Databases *.db + +# Carpeta con documentos de trabajo. +assets diff --git a/Cargo.lock b/Cargo.lock index 3b05ebc..c614db4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,6 +188,23 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.7.6" @@ -357,6 +374,17 @@ version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9441c6b2fe128a7c2bf680a44c34d0df31ce09e5b7e401fcca3faa483dbc921" +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "atoi" version = "2.0.0" @@ -414,6 +442,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "blocking" version = "1.4.1" @@ -484,6 +521,15 @@ dependencies = [ "bytes", ] +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.0.79" @@ -514,6 +560,16 @@ dependencies = [ "windows-targets 0.48.0", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "concurrent-queue" version = "2.3.0" @@ -630,6 +686,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "datasize" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e65c07d59e45d77a8bda53458c24a828893a99ac6cdd9c84111e09176ab739a2" +dependencies = [ + "datasize_derive", +] + +[[package]] +name = "datasize_derive" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613e4ee15899913285b7612004bbd490abd605be7b11d35afada5902fb6b91d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "deflate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" +dependencies = [ + "adler32", +] + [[package]] name = "der" version = "0.7.8" @@ -666,6 +751,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "dotenv" version = "0.15.0" @@ -737,6 +828,7 @@ dependencies = [ "anyhow", "chrono", "dotenv", + "pdf", "prefixed-api-key", "rand", "serde", @@ -761,6 +853,26 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "fax" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2cec1797683c06c2f3de5edb3fde4d99c70e96f3204f6aaff944078353e5c55" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c1d7ffc9f2dc8316348c75281a99c8fdc60c1ddf4f82a366d117bf1b74d5a39" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "flate2" version = "1.0.26" @@ -905,6 +1017,15 @@ dependencies = [ "wasi", ] +[[package]] +name = "globalcache" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469dba5c15b33d67400508ff1f640e8906fa6c8d5ee80540203eb9029ce475df" +dependencies = [ + "async-trait", +] + [[package]] name = "gloo-timers" version = "0.2.6" @@ -1093,6 +1214,25 @@ dependencies = [ "hashbrown 0.14.1", ] +[[package]] +name = "inflate" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" +dependencies = [ + "adler32", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -1113,6 +1253,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "istring" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875cc6fb9aecbc1a9bd736f2d18b12e0756b4c80c5e35e28262154abcb077a39" +dependencies = [ + "datasize", +] + [[package]] name = "itertools" version = "0.10.5" @@ -1137,6 +1286,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" + [[package]] name = "js-sys" version = "0.3.62" @@ -1253,6 +1408,12 @@ dependencies = [ "digest", ] +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + [[package]] name = "memchr" version = "2.5.0" @@ -1401,6 +1562,44 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +[[package]] +name = "pdf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e375ec076445f61d4dbc4636e9e788f841d279c65d6fea8a3875caddd4f2dd82" +dependencies = [ + "aes", + "bitflags 1.3.2", + "cbc", + "datasize", + "deflate", + "fax", + "globalcache", + "inflate", + "istring", + "itertools", + "jpeg-decoder", + "log", + "md5", + "once_cell", + "pdf_derive", + "sha2", + "snafu", + "stringprep", + "weezl", +] + +[[package]] +name = "pdf_derive" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4007262775d0798de87b15cbc64cf1aed5f7ee87eec847e297b69d8ed4b4f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1760,6 +1959,28 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "snafu" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" +dependencies = [ + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "socket2" version = "0.4.9" @@ -2366,6 +2587,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + [[package]] name = "whoami" version = "1.4.1" diff --git a/Cargo.toml b/Cargo.toml index 1c89dd8..11bbb19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "exdev_api" version = "0.1.0" edition = "2021" +default-run = "exdev_api" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -17,3 +18,4 @@ prefixed-api-key = { version = "0.1.0", features = ["sha2"] } rand = { version = "0.8.5", features = ["std"] } sha2 = "0.10.8" anyhow = "1.0.75" +pdf = "0.8.1" diff --git a/src/bin/indexer.rs b/src/bin/indexer.rs new file mode 100644 index 0000000..67836f6 --- /dev/null +++ b/src/bin/indexer.rs @@ -0,0 +1,75 @@ +use std::ops::Deref; + +use pdf::content::Op; + +fn op_to_string(op: &Op) -> String { + match op { + Op::TextDraw { text } => { + let datos = text + .as_bytes() + .iter() + .map(|&c| c as char) + .collect::(); + + datos + } + Op::TextDrawAdjusted { array } => { + let text = array.iter().fold(String::new(), |mut acc, txt| { + use pdf::content::TextDrawAdjusted::Text; + match txt { + Text(texto) => { + let texto = texto + .as_bytes() + .iter() + .map(|&c| c as char) + .collect::(); + + acc.push_str(texto.as_str()); + } + _ => (), + } + acc + }); + + text + } + _ => String::new(), + } +} + +fn main() -> anyhow::Result<()> { + let input = String::from("assets/Trabajo asalariado y Capital.pdf"); + + let pdf = pdf::file::FileOptions::cached().open(input)?; + + for (i, page) in pdf.pages().enumerate() { + println!( + r#" + ------------------------------------------- + Página número {i} + ------------------------------------------- + "# + ); + + let page = page?; + let page = page.deref(); + + let content = match &page.contents { + Some(c) => c, + None => continue, + }; + + let parrafo = content + .operations(&pdf)? + .iter() + .map(|e| -> String { op_to_string(e) }) + .fold(String::new(), |mut acc, s| { + acc.push_str(s.as_str()); + acc + }); + + println!("{parrafo}"); + } + + Ok(()) +} From 1e57aa1105b4e55de718bfc5995dce80104b109d Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Thu, 23 Nov 2023 12:45:06 -0300 Subject: [PATCH 02/18] =?UTF-8?q?Reestructuraci=C3=B3n=20del=20proyecto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Estoy haciendo uso de los workspaces de cargo. La ventaja es que para compilar los binarios necesito menos dependencias para cada uno; - El servidor mantiene las 250~ que tenía en un inicio - El indexador ahora trabaja solo con 65 --- Cargo.lock | 1053 +++++++++-------- Cargo.toml | 24 +- indexer/Cargo.toml | 10 + src/bin/indexer.rs => indexer/src/main.rs | 4 +- server/Cargo.toml | 19 + .../migrations}/20230513034227_init.down.sql | 0 .../migrations}/20230513034227_init.up.sql | 0 .../20230914155010_create_app_model.down.sql | 0 .../20230914155010_create_app_model.up.sql | 0 ...9_Alter_project_involvement_table.down.sql | 0 ...649_Alter_project_involvement_table.up.sql | 0 {src => server/src}/main.rs | 0 {src => server/src}/v1/mod.rs | 0 {src => server/src}/v1/models/auth.rs | 0 {src => server/src}/v1/models/club_member.rs | 0 {src => server/src}/v1/models/mod.rs | 0 {src => server/src}/v1/models/project.rs | 0 {src => server/src}/v1/res/auth.rs | 0 {src => server/src}/v1/res/club_members.rs | 0 {src => server/src}/v1/res/mod.rs | 0 {src => server/src}/v1/res/projects.rs | 0 .../src}/v1/responders/basic_response.rs | 0 {src => server/src}/v1/responders/errors.rs | 0 {src => server/src}/v1/responders/mod.rs | 0 {src => server/src}/v1/schemas/auth.rs | 0 {src => server/src}/v1/schemas/club_member.rs | 0 {src => server/src}/v1/schemas/mod.rs | 0 {src => server/src}/v1/schemas/project.rs | 0 28 files changed, 619 insertions(+), 491 deletions(-) create mode 100644 indexer/Cargo.toml rename src/bin/indexer.rs => indexer/src/main.rs (93%) create mode 100644 server/Cargo.toml rename {migrations => server/migrations}/20230513034227_init.down.sql (100%) rename {migrations => server/migrations}/20230513034227_init.up.sql (100%) rename {migrations => server/migrations}/20230914155010_create_app_model.down.sql (100%) rename {migrations => server/migrations}/20230914155010_create_app_model.up.sql (100%) rename {migrations => server/migrations}/20231016014649_Alter_project_involvement_table.down.sql (100%) rename {migrations => server/migrations}/20231016014649_Alter_project_involvement_table.up.sql (100%) rename {src => server/src}/main.rs (100%) rename {src => server/src}/v1/mod.rs (100%) rename {src => server/src}/v1/models/auth.rs (100%) rename {src => server/src}/v1/models/club_member.rs (100%) rename {src => server/src}/v1/models/mod.rs (100%) rename {src => server/src}/v1/models/project.rs (100%) rename {src => server/src}/v1/res/auth.rs (100%) rename {src => server/src}/v1/res/club_members.rs (100%) rename {src => server/src}/v1/res/mod.rs (100%) rename {src => server/src}/v1/res/projects.rs (100%) rename {src => server/src}/v1/responders/basic_response.rs (100%) rename {src => server/src}/v1/responders/errors.rs (100%) rename {src => server/src}/v1/responders/mod.rs (100%) rename {src => server/src}/v1/schemas/auth.rs (100%) rename {src => server/src}/v1/schemas/club_member.rs (100%) rename {src => server/src}/v1/schemas/mod.rs (100%) rename {src => server/src}/v1/schemas/project.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index c614db4..47b0fd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,19 +4,19 @@ version = 3 [[package]] name = "actix-codec" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" dependencies = [ "bitflags 1.3.2", "bytes", "futures-core", "futures-sink", - "log", "memchr", "pin-project-lite", "tokio", "tokio-util", + "tracing", ] [[package]] @@ -29,9 +29,9 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.3", + "ahash", "base64", - "bitflags 2.4.0", + "bitflags 2.4.1", "brotli", "bytes", "bytestring", @@ -60,12 +60,12 @@ dependencies = [ [[package]] name = "actix-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.39", ] [[package]] @@ -83,9 +83,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" dependencies = [ "futures-core", "tokio", @@ -93,9 +93,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" dependencies = [ "actix-rt", "actix-service", @@ -103,8 +103,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "num_cpus", - "socket2 0.4.9", + "socket2 0.5.5", "tokio", "tracing", ] @@ -145,7 +144,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.3", + "ahash", "bytes", "bytestring", "cfg-if", @@ -165,21 +164,30 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.5.4", + "socket2 0.5.5", "time", "url", ] [[package]] name = "actix-web-codegen" -version = "4.2.0" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" +checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.39", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", ] [[package]] @@ -207,32 +215,22 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.3" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -252,6 +250,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -280,36 +284,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e" +dependencies = [ + "concurrent-queue", + "event-listener 3.1.0", + "event-listener-strategy", "futures-core", + "pin-project-lite", ] [[package]] name = "async-executor" -version = "1.5.4" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1da3ae8dabd9c00f453a329dfe1fb28da3c0a72e2478cdcd93171740c20499" +checksum = "fc5ea910c42e5ab19012bab31f53cb4d63d54c3a27730f9a833a88efcf4bb52d" dependencies = [ - "async-lock", + "async-lock 3.1.1", "async-task", "concurrent-queue", "fastrand 2.0.1", - "futures-lite", + "futures-lite 2.0.1", "slab", ] [[package]] name = "async-global-executor" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +checksum = "9b4353121d5644cdf2beb5726ab752e79a8db1ebb52031770ec47db31d245526" dependencies = [ - "async-channel", + "async-channel 2.1.0", "async-executor", - "async-io", - "async-lock", + "async-io 2.2.0", + "async-lock 3.1.1", "blocking", - "futures-lite", + "futures-lite 2.0.1", "once_cell", ] @@ -319,27 +336,58 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ - "async-lock", + "async-lock 2.8.0", "autocfg", "cfg-if", "concurrent-queue", - "futures-lite", + "futures-lite 1.13.0", "log", "parking", - "polling", - "rustix 0.37.25", + "polling 2.8.0", + "rustix 0.37.27", "slab", - "socket2 0.4.9", + "socket2 0.4.10", "waker-fn", ] +[[package]] +name = "async-io" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9d5715c2d329bf1b4da8d60455b99b187f27ba726df2883799af9af60997" +dependencies = [ + "async-lock 3.1.1", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.0.1", + "parking", + "polling 3.3.0", + "rustix 0.38.25", + "slab", + "tracing", + "waker-fn", + "windows-sys", +] + [[package]] name = "async-lock" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ - "event-listener", + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655b9c7fe787d3b25cc0f804a1a8401790f0c5bc395beb5a64dc77d8de079105" +dependencies = [ + "event-listener 3.1.0", + "event-listener-strategy", + "pin-project-lite", ] [[package]] @@ -348,15 +396,15 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-global-executor", - "async-io", - "async-lock", + "async-io 1.13.0", + "async-lock 2.8.0", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite", + "futures-lite 1.13.0", "gloo-timers", "kv-log-macro", "log", @@ -370,9 +418,9 @@ dependencies = [ [[package]] name = "async-task" -version = "4.4.1" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9441c6b2fe128a7c2bf680a44c34d0df31ce09e5b7e401fcca3faa483dbc921" +checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" [[package]] name = "async-trait" @@ -382,7 +430,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] @@ -400,17 +448,42 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atomic-write-file" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c232177ba50b16fe7a4588495bd474a62a9e45a8e4ca6fd7d0b7ac29d164631e" +dependencies = [ + "nix", + "rand", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" -version = "0.21.0" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -426,9 +499,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" dependencies = [ "serde", ] @@ -453,25 +526,25 @@ dependencies = [ [[package]] name = "blocking" -version = "1.4.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" dependencies = [ - "async-channel", - "async-lock", + "async-channel 2.1.0", + "async-lock 3.1.1", "async-task", "fastrand 2.0.1", "futures-io", - "futures-lite", + "futures-lite 2.0.1", "piper", "tracing", ] [[package]] name = "brotli" -version = "3.3.4" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -480,9 +553,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.4" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -496,27 +569,27 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bumpalo" -version = "3.12.2" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "bytestring" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" dependencies = [ "bytes", ] @@ -532,11 +605,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -557,7 +631,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.48.0", + "windows-targets", ] [[package]] @@ -616,9 +690,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] @@ -634,9 +708,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" @@ -659,9 +733,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -676,16 +750,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "datasize" version = "0.2.15" @@ -726,6 +790,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -771,18 +844,18 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" dependencies = [ "serde", ] [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] @@ -795,12 +868,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -811,7 +884,7 @@ checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ "cfg-if", "home", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -821,21 +894,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] -name = "exdev_api" -version = "0.1.0" +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" dependencies = [ - "actix-web", - "anyhow", - "chrono", - "dotenv", - "pdf", - "prefixed-api-key", - "rand", - "serde", - "serde_json", - "sha2", - "sqlx", - "uuid", + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +dependencies = [ + "event-listener 3.1.0", + "pin-project-lite", ] [[package]] @@ -873,11 +949,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", @@ -902,18 +984,18 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -921,15 +1003,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -949,9 +1031,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-lite" @@ -968,23 +1050,37 @@ dependencies = [ "waker-fn", ] +[[package]] +name = "futures-lite" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-core", "futures-io", @@ -1008,15 +1104,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + [[package]] name = "globalcache" version = "0.2.0" @@ -1040,9 +1142,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.18" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -1050,7 +1152,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap", "slab", "tokio", "tokio-util", @@ -1059,26 +1161,21 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" dependencies = [ - "ahash 0.7.6", + "ahash", + "allocator-api2", ] -[[package]] -name = "hashbrown" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" - [[package]] name = "hashlink" -version = "0.8.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.12.3", + "hashbrown", ] [[package]] @@ -1090,15 +1187,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.3" @@ -1135,14 +1223,14 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -1157,22 +1245,22 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -1186,32 +1274,30 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +name = "indexer" +version = "0.1.0" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "anyhow", + "pdf", ] [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown", ] [[package]] @@ -1248,9 +1334,9 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi", "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -1271,17 +1357,26 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" dependencies = [ "libc", ] @@ -1294,9 +1389,9 @@ checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" [[package]] name = "js-sys" -version = "0.3.62" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" dependencies = [ "wasm-bindgen", ] @@ -1327,9 +1422,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.149" +version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libm" @@ -1339,9 +1434,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libsqlite3-sys" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" dependencies = [ "cc", "pkg-config", @@ -1356,33 +1451,32 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "local-channel" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" dependencies = [ "futures-core", "futures-sink", - "futures-util", "local-waker", ] [[package]] name = "local-waker" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -1390,11 +1484,10 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" dependencies = [ - "cfg-if", "value-bag", ] @@ -1416,9 +1509,18 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] [[package]] name = "mime" @@ -1443,14 +1545,27 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.45.0", + "windows-sys", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset", + "pin-utils", ] [[package]] @@ -1503,35 +1618,34 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", "libm", ] [[package]] -name = "num_cpus" -version = "1.15.0" +name = "object" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ - "hermit-abi 0.2.6", - "libc", + "memchr", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "parking" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e52c774a4c39359c1d1c52e43f73dd91a75a614652c825408eec30c95a9b2067" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" @@ -1545,22 +1659,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", - "windows-sys 0.45.0", + "windows-targets", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pdf" @@ -1577,7 +1691,7 @@ dependencies = [ "globalcache", "inflate", "istring", - "itertools", + "itertools 0.10.5", "jpeg-decoder", "log", "md5", @@ -1611,15 +1725,15 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1678,9 +1792,29 @@ dependencies = [ "libc", "log", "pin-project-lite", - "windows-sys 0.48.0", + "windows-sys", +] + +[[package]] +name = "polling" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531" +dependencies = [ + "cfg-if", + "concurrent-queue", + "pin-project-lite", + "rustix 0.38.25", + "tracing", + "windows-sys", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1751,27 +1885,30 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] -name = "redox_syscall" -version = "0.3.5" +name = "regex" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ - "bitflags 1.3.2", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "regex" -version = "1.8.1" +name = "regex-automata" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -1780,22 +1917,20 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rsa" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +checksum = "6a3211b01eea83d80687da9eef70e39d65144a3894866a5153a2723e425a157f" dependencies = [ - "byteorder", "const-oid", "digest", "num-bigint-dig", "num-integer", - "num-iter", "num-traits", "pkcs1", "pkcs8", @@ -1806,6 +1941,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1817,74 +1958,74 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.25" +version = "0.37.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] name = "rustix" -version = "0.38.19" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745ecfa778e66b2b63c88a61cb36e0eea109e803b0b86bf9879fbc77c70e86ed" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys 0.4.10", - "windows-sys 0.48.0", + "linux-raw-sys 0.4.11", + "windows-sys", ] [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.17" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.189" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.189" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -1903,11 +2044,28 @@ dependencies = [ "serde", ] +[[package]] +name = "server" +version = "0.1.0" +dependencies = [ + "actix-web", + "anyhow", + "chrono", + "dotenv", + "prefixed-api-key", + "rand", + "serde", + "serde_json", + "sha2", + "sqlx", + "uuid", +] + [[package]] name = "sha1" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -1936,9 +2094,9 @@ dependencies = [ [[package]] name = "signature" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", "rand_core", @@ -1946,18 +2104,18 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "snafu" @@ -1983,9 +2141,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", @@ -1993,12 +2151,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -2028,20 +2186,20 @@ dependencies = [ [[package]] name = "sqlformat" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c12bc9199d1db8234678b7051747c07f517cdcf019262d1847b94ec8b1aee3e" +checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" dependencies = [ - "itertools", + "itertools 0.11.0", "nom", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e50c216e3624ec8e7ecd14c6a6a6370aad6ee5d8cfc3ab30b5162eeeef2ed33" +checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf" dependencies = [ "sqlx-core", "sqlx-macros", @@ -2052,12 +2210,12 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d" +checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" dependencies = [ - "ahash 0.8.3", - "async-io", + "ahash", + "async-io 1.13.0", "async-std", "atoi", "byteorder", @@ -2067,7 +2225,7 @@ dependencies = [ "crossbeam-queue", "dotenvy", "either", - "event-listener", + "event-listener 2.5.3", "futures-channel", "futures-core", "futures-intrusive", @@ -2075,7 +2233,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.0.2", + "indexmap", "log", "memchr", "once_cell", @@ -2094,9 +2252,9 @@ dependencies = [ [[package]] name = "sqlx-macros" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a793bb3ba331ec8359c1853bd39eed32cdd7baaf22c35ccf5c92a7e8d1189ec" +checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" dependencies = [ "proc-macro2", "quote", @@ -2107,11 +2265,12 @@ dependencies = [ [[package]] name = "sqlx-macros-core" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4ee1e104e00dedb6aa5ffdd1343107b0a4702e862a84320ee7cc74782d96fc" +checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841" dependencies = [ "async-std", + "atomic-write-file", "dotenvy", "either", "heck", @@ -2133,13 +2292,13 @@ dependencies = [ [[package]] name = "sqlx-mysql" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db" +checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" dependencies = [ "atoi", "base64", - "bitflags 2.4.0", + "bitflags 2.4.1", "byteorder", "bytes", "chrono", @@ -2177,13 +2336,13 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624" +checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" dependencies = [ "atoi", "base64", - "bitflags 2.4.0", + "bitflags 2.4.1", "byteorder", "chrono", "crc", @@ -2218,9 +2377,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59dc83cf45d89c555a577694534fcd1b55c545a816c816ce51f20bbe56a4f3f" +checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490" dependencies = [ "atoi", "chrono", @@ -2238,14 +2397,16 @@ dependencies = [ "time", "tracing", "url", + "urlencoding", ] [[package]] name = "stringprep" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" dependencies = [ + "finl_unicode", "unicode-bidi", "unicode-normalization", ] @@ -2269,9 +2430,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", @@ -2280,44 +2441,46 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand 2.0.1", - "redox_syscall 0.3.5", - "rustix 0.38.19", - "windows-sys 0.48.0", + "redox_syscall", + "rustix 0.38.25", + "windows-sys", ] [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "time" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ + "deranged", "itoa", + "powerfmt", "serde", "time-core", "time-macros", @@ -2325,15 +2488,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" dependencies = [ "time-core", ] @@ -2355,26 +2518,26 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.4.9", - "windows-sys 0.48.0", + "socket2 0.5.5", + "windows-sys", ] [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -2386,11 +2549,10 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -2405,23 +2567,23 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" @@ -2431,9 +2593,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -2458,20 +2620,26 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" [[package]] name = "url" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "uuid" -version = "1.4.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "getrandom", "serde", @@ -2479,13 +2647,9 @@ dependencies = [ [[package]] name = "value-bag" -version = "1.0.0-alpha.9" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" -dependencies = [ - "ctor", - "version_check", -] +checksum = "4a72e1902dde2bd6441347de2b70b7f5d59bf157c6c62f0c44572607a1d55bbe" [[package]] name = "vcpkg" @@ -2513,9 +2677,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.85" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2523,24 +2687,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.85" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.35" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "083abe15c5d88556b77bdf7aef403625be9e327ad37c62c4e4129af740168163" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" dependencies = [ "cfg-if", "js-sys", @@ -2550,9 +2714,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.85" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2560,28 +2724,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.85" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.85" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" [[package]] name = "web-sys" -version = "0.3.62" +version = "0.3.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" dependencies = [ "js-sys", "wasm-bindgen", @@ -2622,21 +2786,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" +name = "windows-core" +version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", + "windows-targets", ] [[package]] @@ -2645,143 +2800,106 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +name = "zerocopy" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0" +dependencies = [ + "zerocopy-derive", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" +name = "zerocopy-derive" +version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] [[package]] name = "zeroize" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" [[package]] name = "zstd" -version = "0.12.3+zstd.1.5.2" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "6.0.5+zstd.1.5.4" +version = "6.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" dependencies = [ "libc", "zstd-sys", @@ -2789,11 +2907,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.9+zstd.1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index 11bbb19..5985012 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,21 +1,3 @@ -[package] -name = "exdev_api" -version = "0.1.0" -edition = "2021" -default-run = "exdev_api" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -actix-web = "^4.4.0" -dotenv = "0.15.0" -serde = {version = "1.0.189", features = ["derive"]} -serde_json = "1.0.107" -sqlx = { version = "0.7", features = [ "sqlite", "runtime-async-std", "time", "chrono"] } -uuid = { version = "1.4.1", features = ["serde", "v4"] } -chrono = { version = "0.4.31", features = ["serde"] } -prefixed-api-key = { version = "0.1.0", features = ["sha2"] } -rand = { version = "0.8.5", features = ["std"] } -sha2 = "0.10.8" -anyhow = "1.0.75" -pdf = "0.8.1" +[workspace] +members = ["server", "indexer"] +resolver = "2" diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml new file mode 100644 index 0000000..a2b7355 --- /dev/null +++ b/indexer/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "indexer" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.75" +pdf = "0.8.1" diff --git a/src/bin/indexer.rs b/indexer/src/main.rs similarity index 93% rename from src/bin/indexer.rs rename to indexer/src/main.rs index 67836f6..189e7b4 100644 --- a/src/bin/indexer.rs +++ b/indexer/src/main.rs @@ -38,7 +38,7 @@ fn op_to_string(op: &Op) -> String { } fn main() -> anyhow::Result<()> { - let input = String::from("assets/Trabajo asalariado y Capital.pdf"); + let input = String::from("indexer/assets/Introduction_to_algorithms-3rd Edition.pdf"); let pdf = pdf::file::FileOptions::cached().open(input)?; @@ -46,7 +46,7 @@ fn main() -> anyhow::Result<()> { println!( r#" ------------------------------------------- - Página número {i} + Página número {i} ------------------------------------------- "# ); diff --git a/server/Cargo.toml b/server/Cargo.toml new file mode 100644 index 0000000..a6c48e7 --- /dev/null +++ b/server/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "server" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +actix-web = "^4.4.0" +dotenv = "0.15.0" +serde = {version = "1.0.189", features = ["derive"]} +serde_json = "1.0.107" +sqlx = { version = "0.7", features = [ "sqlite", "runtime-async-std", "time", "chrono"] } +uuid = { version = "1.4.1", features = ["serde", "v4"] } +chrono = { version = "0.4.31", features = ["serde"] } +prefixed-api-key = { version = "0.1.0", features = ["sha2"] } +rand = { version = "0.8.5", features = ["std"] } +sha2 = "0.10.8" +anyhow = "1.0.75" diff --git a/migrations/20230513034227_init.down.sql b/server/migrations/20230513034227_init.down.sql similarity index 100% rename from migrations/20230513034227_init.down.sql rename to server/migrations/20230513034227_init.down.sql diff --git a/migrations/20230513034227_init.up.sql b/server/migrations/20230513034227_init.up.sql similarity index 100% rename from migrations/20230513034227_init.up.sql rename to server/migrations/20230513034227_init.up.sql diff --git a/migrations/20230914155010_create_app_model.down.sql b/server/migrations/20230914155010_create_app_model.down.sql similarity index 100% rename from migrations/20230914155010_create_app_model.down.sql rename to server/migrations/20230914155010_create_app_model.down.sql diff --git a/migrations/20230914155010_create_app_model.up.sql b/server/migrations/20230914155010_create_app_model.up.sql similarity index 100% rename from migrations/20230914155010_create_app_model.up.sql rename to server/migrations/20230914155010_create_app_model.up.sql diff --git a/migrations/20231016014649_Alter_project_involvement_table.down.sql b/server/migrations/20231016014649_Alter_project_involvement_table.down.sql similarity index 100% rename from migrations/20231016014649_Alter_project_involvement_table.down.sql rename to server/migrations/20231016014649_Alter_project_involvement_table.down.sql diff --git a/migrations/20231016014649_Alter_project_involvement_table.up.sql b/server/migrations/20231016014649_Alter_project_involvement_table.up.sql similarity index 100% rename from migrations/20231016014649_Alter_project_involvement_table.up.sql rename to server/migrations/20231016014649_Alter_project_involvement_table.up.sql diff --git a/src/main.rs b/server/src/main.rs similarity index 100% rename from src/main.rs rename to server/src/main.rs diff --git a/src/v1/mod.rs b/server/src/v1/mod.rs similarity index 100% rename from src/v1/mod.rs rename to server/src/v1/mod.rs diff --git a/src/v1/models/auth.rs b/server/src/v1/models/auth.rs similarity index 100% rename from src/v1/models/auth.rs rename to server/src/v1/models/auth.rs diff --git a/src/v1/models/club_member.rs b/server/src/v1/models/club_member.rs similarity index 100% rename from src/v1/models/club_member.rs rename to server/src/v1/models/club_member.rs diff --git a/src/v1/models/mod.rs b/server/src/v1/models/mod.rs similarity index 100% rename from src/v1/models/mod.rs rename to server/src/v1/models/mod.rs diff --git a/src/v1/models/project.rs b/server/src/v1/models/project.rs similarity index 100% rename from src/v1/models/project.rs rename to server/src/v1/models/project.rs diff --git a/src/v1/res/auth.rs b/server/src/v1/res/auth.rs similarity index 100% rename from src/v1/res/auth.rs rename to server/src/v1/res/auth.rs diff --git a/src/v1/res/club_members.rs b/server/src/v1/res/club_members.rs similarity index 100% rename from src/v1/res/club_members.rs rename to server/src/v1/res/club_members.rs diff --git a/src/v1/res/mod.rs b/server/src/v1/res/mod.rs similarity index 100% rename from src/v1/res/mod.rs rename to server/src/v1/res/mod.rs diff --git a/src/v1/res/projects.rs b/server/src/v1/res/projects.rs similarity index 100% rename from src/v1/res/projects.rs rename to server/src/v1/res/projects.rs diff --git a/src/v1/responders/basic_response.rs b/server/src/v1/responders/basic_response.rs similarity index 100% rename from src/v1/responders/basic_response.rs rename to server/src/v1/responders/basic_response.rs diff --git a/src/v1/responders/errors.rs b/server/src/v1/responders/errors.rs similarity index 100% rename from src/v1/responders/errors.rs rename to server/src/v1/responders/errors.rs diff --git a/src/v1/responders/mod.rs b/server/src/v1/responders/mod.rs similarity index 100% rename from src/v1/responders/mod.rs rename to server/src/v1/responders/mod.rs diff --git a/src/v1/schemas/auth.rs b/server/src/v1/schemas/auth.rs similarity index 100% rename from src/v1/schemas/auth.rs rename to server/src/v1/schemas/auth.rs diff --git a/src/v1/schemas/club_member.rs b/server/src/v1/schemas/club_member.rs similarity index 100% rename from src/v1/schemas/club_member.rs rename to server/src/v1/schemas/club_member.rs diff --git a/src/v1/schemas/mod.rs b/server/src/v1/schemas/mod.rs similarity index 100% rename from src/v1/schemas/mod.rs rename to server/src/v1/schemas/mod.rs diff --git a/src/v1/schemas/project.rs b/server/src/v1/schemas/project.rs similarity index 100% rename from src/v1/schemas/project.rs rename to server/src/v1/schemas/project.rs From 89cd4d5616b70f3e5aa114a18187e4f9374ebb4d Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Fri, 24 Nov 2023 00:12:32 -0300 Subject: [PATCH 03/18] using clap --- Cargo.lock | 107 ++++++++++++++++++++++++++++++++++++++++++++ indexer/Cargo.toml | 1 + indexer/src/main.rs | 43 +++++++++--------- 3 files changed, 129 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47b0fd1..25ee4ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -271,6 +271,54 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +dependencies = [ + "anstyle", + "windows-sys", +] + [[package]] name = "anyhow" version = "1.0.75" @@ -644,6 +692,52 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "concurrent-queue" version = "2.3.0" @@ -1287,6 +1381,7 @@ name = "indexer" version = "0.1.0" dependencies = [ "anyhow", + "clap", "pdf", ] @@ -2411,6 +2506,12 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "subtle" version = "2.5.0" @@ -2635,6 +2736,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "uuid" version = "1.6.1" diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml index a2b7355..34e87e7 100644 --- a/indexer/Cargo.toml +++ b/indexer/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" [dependencies] anyhow = "1.0.75" +clap = { version = "4.4.8", features = ["derive"] } pdf = "0.8.1" diff --git a/indexer/src/main.rs b/indexer/src/main.rs index 189e7b4..ca55696 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -1,3 +1,6 @@ +//! Indexador de documentos para plataforma estudiantil, utilizando la estrategia TF-IDF + +use clap::Parser; use std::ops::Deref; use pdf::content::Op; @@ -16,18 +19,18 @@ fn op_to_string(op: &Op) -> String { Op::TextDrawAdjusted { array } => { let text = array.iter().fold(String::new(), |mut acc, txt| { use pdf::content::TextDrawAdjusted::Text; - match txt { - Text(texto) => { - let texto = texto - .as_bytes() - .iter() - .map(|&c| c as char) - .collect::(); + if let Text(texto) = txt { + let texto = texto + .as_bytes() + .iter() + .map(|&c| c as char) + .collect::(); - acc.push_str(texto.as_str()); - } - _ => (), + acc.push_str(texto.as_str()); + } else { + acc.push_str(" ") } + acc }); @@ -37,21 +40,17 @@ fn op_to_string(op: &Op) -> String { } } -fn main() -> anyhow::Result<()> { - let input = String::from("indexer/assets/Introduction_to_algorithms-3rd Edition.pdf"); +#[derive(Parser, Debug)] +struct Args { + path: std::path::PathBuf, +} - let pdf = pdf::file::FileOptions::cached().open(input)?; +fn main() -> anyhow::Result<()> { + let args = Args::parse(); - for (i, page) in pdf.pages().enumerate() { - println!( - r#" - ------------------------------------------- - Página número {i} - ------------------------------------------- - "# - ); + let pdf = pdf::file::FileOptions::cached().open(args.path)?; - let page = page?; + for page in pdf.pages().filter_map(Result::ok) { let page = page.deref(); let content = match &page.contents { From 700e90a812d8ea3191ff3afe933eaae8116c01db Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Wed, 29 Nov 2023 15:22:55 -0300 Subject: [PATCH 04/18] Aun no estoy convencido --- indexer/src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/indexer/src/main.rs b/indexer/src/main.rs index ca55696..75f3f27 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -14,7 +14,7 @@ fn op_to_string(op: &Op) -> String { .map(|&c| c as char) .collect::(); - datos + format!("{datos} ") } Op::TextDrawAdjusted { array } => { let text = array.iter().fold(String::new(), |mut acc, txt| { @@ -27,8 +27,6 @@ fn op_to_string(op: &Op) -> String { .collect::(); acc.push_str(texto.as_str()); - } else { - acc.push_str(" ") } acc From 04a09b3dc33d1e4bf0078587e51633010fa0e64c Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Sun, 24 Dec 2023 11:55:32 -0300 Subject: [PATCH 05/18] ejemplos para trabajar, aun no funca --- Cargo.lock | 78 ++++++++++++++++++++++------ indexer/Cargo.toml | 2 +- indexer/examples/stallman-latex.pdf | Bin 0 -> 21772 bytes indexer/examples/stallman-typ.pdf | Bin 0 -> 20184 bytes indexer/src/main.rs | 58 +++++++++------------ 5 files changed, 87 insertions(+), 51 deletions(-) create mode 100644 indexer/examples/stallman-latex.pdf create mode 100644 indexer/examples/stallman-typ.pdf diff --git a/Cargo.lock b/Cargo.lock index 25ee4ed..e7dcfff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -782,6 +782,15 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpufeatures" version = "0.2.11" @@ -844,6 +853,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "dary_heap" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" + [[package]] name = "datasize" version = "0.2.15" @@ -1253,6 +1268,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.14.2" @@ -1269,7 +1293,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown", + "hashbrown 0.14.2", ] [[package]] @@ -1392,16 +1416,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown", -] - -[[package]] -name = "inflate" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff" -dependencies = [ - "adler32", + "hashbrown 0.14.2", ] [[package]] @@ -1521,6 +1536,30 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libflate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7d5654ae1795afc7ff76f4365c2c8791b0feb18e8996a96adad8ffd7c3b2bf" +dependencies = [ + "adler32", + "core2", + "crc32fast", + "dary_heap", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5f52fb8c451576ec6b79d3f4deb327398bc05bbdbd99021a6e77a4c855d524" +dependencies = [ + "core2", + "hashbrown 0.13.2", + "rle-decode-fast", +] + [[package]] name = "libm" version = "0.2.8" @@ -1773,9 +1812,9 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pdf" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e375ec076445f61d4dbc4636e9e788f841d279c65d6fea8a3875caddd4f2dd82" +checksum = "3afc7e745846405d572daba57a429f30a198d955602aff8a1a9e437c2abfcaa2" dependencies = [ "aes", "bitflags 1.3.2", @@ -1784,10 +1823,11 @@ dependencies = [ "deflate", "fax", "globalcache", - "inflate", + "indexmap", "istring", "itertools 0.10.5", "jpeg-decoder", + "libflate", "log", "md5", "once_cell", @@ -1800,9 +1840,9 @@ dependencies = [ [[package]] name = "pdf_derive" -version = "0.1.22" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4007262775d0798de87b15cbc64cf1aed5f7ee87eec847e297b69d8ed4b4f8" +checksum = "1038b9cb38dec35eeee9f23eacfb2480087982f9b7e9221efa8034eea9ca2360" dependencies = [ "proc-macro2", "quote", @@ -2016,6 +2056,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rle-decode-fast" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" + [[package]] name = "rsa" version = "0.9.4" diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml index 34e87e7..bc0f5eb 100644 --- a/indexer/Cargo.toml +++ b/indexer/Cargo.toml @@ -8,4 +8,4 @@ edition = "2021" [dependencies] anyhow = "1.0.75" clap = { version = "4.4.8", features = ["derive"] } -pdf = "0.8.1" +pdf = "0.9" diff --git a/indexer/examples/stallman-latex.pdf b/indexer/examples/stallman-latex.pdf new file mode 100644 index 0000000000000000000000000000000000000000..95d59417e92c9cdb5df682172fd5c9353e82afbc GIT binary patch literal 21772 zcma%?Ly#y6%%z*RZQHhO+qP}nwr$(CZQHipJ#VJwU(IH+I@zRBS$vf`m5|5_i_$RA zvOto|FORH4GU3zX+ZkFya&tq{Nt@W3Ih*4%FfuUV|DS-Q6Sc5*HgUwK6SX#QHW4;4 zvNJY;iz7ARC&&Qk5CV8Oh;M07u-6_&QaV z)1Bq|?m<3sEa4}>r*8XrD;LhI3|XOuN1on_9ShoE&UDTHZVb>VH3cHR6lN215F$Dq znfM!;6#;C6qENK1Kl5BHddwGKi|T8YljU3tk4^<@uPWeXG#?D7`EjjY0(d0HB*T4G zpim$+uK?id3hGP4pMqBqf&J!!SD#8EQjPR-hzzw}r|fr^v_k>gwHLYE`}_XlU`|HZ zL!p;M;72A?0z(osAcmkmam&jbn zH$dP6)KC^ue8s8S)2+~m3_>j@;;XIeP9$vCu;N4ma)%h~M{imaR%4zWwvrpAYj*>I z_F*}RKams7oeNfzGZ94DDHIkQ>jfR14>?&-SJ@dYnbES7hH;!aDy>@)i>}9ZK`Cx- zN&au(O~j3Im1#cyEw;S>BjqV5m*$#xKb#*?Y{<9~n_r_h$Fd>dlMVcZS>vc}v@|D( z77vRiL6vyq!M3%KgSiv(!Uv9WGa9^9I^VqlY(n6Kg5a2D< z(Yl`vK5-tglulJ1B#dYkNp6whwB@jSmE;WN%&Cq$ z%SmM8C|{hEY>bHQiMewDI7S?Pl$wTcQBr%DR}yXaHbC8eD^tpGYg#9SnO=@K6fD%2 zyz0h~Ko|wu%RtU*9fQRi>cT2gLNThSNlv!W%7*sZQWs8{pI!z+Q0Anb8W)!*-jec8 z^#8hHs<;2mpsl*C1|AkHUT>&46;c#HWh@r$|u=30NaElJ8 zvpnGa1seLI_<;^B_G~hoAf4;O*rfG^hBbdYvfUPCqG`eiF9gK<@|a^T;ES+qgz1bwXarbBD=UiEVg(4cR=jMbRmJm zbF+iExvc>V?Cj_W#^a~;%zence(Y6swsl&*U@nb)pMIl~R77$Xm4_r{lq4q+g(sv$ zguvm~mXA&X=^GfB85$S}- zdu9H4fX=5c0jYauIwxV-J==!CsqWV^rbTp$OAE3TL=6l zR&i+ra7*jZ0Nw$4X*o%W?RSM`6@`>g?elQ(>!MVbBBo?qC5>Azk?m z{%n2K@wdkMab;y@adEI`ae8iWY64eV-_QU~Dnd%*%fSQpFE1R@2`PEyFLm`*bXC;! zRBUt&?4@J@6$`5XmfnH<$-tT4T3$f|F#_7${1uLWtEIouN^xq2|5s0)GteL0Z-va@ z%F^O@*Ol(nFXviJj0{dJ&kvYNOAM;2Ph7p7gUO0>v$I`eQu2H2SSR>i%+v+~$iA_@ z-u|f(m|6!QHTRTt+An17-m&#tYvMEQJtrV9t|^JB|1u}IB(EmrG|oS?6403h>EIza1|SbzNxv@Mfe@*N5|UYh3?z;y|y(Mz$f)>!w9tg`{ipc>)^{> zgPmj3>xbd*%RA#_7=_q`ZTHYgrS>{1>_d5Q;47<16Up&tv(| z_2Vz=zOV3mFZA0FjrhdW?yoKL)b8g`%;r+x>h8rZ=&is7xQEWaaOn$^{nt*(X3CGI zrm!TWCTr+#buv(T4^3csVe^;IrWsUn!&6hUd_8d5=9h)$FVX6^#pJa$HkDGAf2*$+ z1>opw;hS#f%QC~yyN}cVj_9Lp^3liXm#d_>s3U1ak7{&u0+imxh2=%io$uIf7~JT@Y|(OI~%}sp-Q?R%Hs zODW7xy&f>V=C{8u{)Vsl4tMp>{|>_Dx7d%&;^@TM=;9qN%58)1XOGL~4enj`^@wku zi|EU*->vhn{MzR!;}7BEr_#XnGwEyR^+)O%?#1h5)^GXFBWF)-@j{MneUC?bJA3!- z;I85C=zVtL1@Arw;9hQSFULO>w)L;-?vC02wUj^0uf2!t+iczqs_nnhg}49ppuqFH z@Z?sQ`=1o<`32mI@c4uIv(lR0(bn1HL-*S=yQ_NUd%vqoDk&)|;TU`jOyck>*U>Q_ z6N)(pgB$&U7|@vXxv6W8=AEj|v6UmQpJ-mm7|5#a6HXHQoL_Y%vA7jh71#Ba)xy#z z+C)^@^84b&8mp4IYa^nTIe?Zy&5m4!LmWV2v<%07?`?m#1oa8F2E9uyns#wG5>WUE z{n%%~ztP}RZ{Go!Y zN@VsJBTSo%J8(xG+A}X^7e({xu7wFqH$-cZh#{Ml zMzHZkVMi3JnbJ4g=s;T>{b5;!7$#A;93@O(5ax98$t6M%R_*-vYq%nwEKr}eLuALh z6rx&U`h_;@t+LqDWIp;(G@5VF5MK|ttA{Ga)i*gc5?vpc(~Mh3$wN3IYS_loF7(9f zQUQAU43M%^EK)=edFyuebucqN$1=Pvfs=V8-@*ct=Q`#UnahJdX-q<10hNXVb`l3l z=$!_WMhyA&UFmHp|Kq9@f9kYcrJ_6)S{i0P1ZiM1 zx*dOVx^a)5jLuBvcTOdu2nwuw^^OC3PG@Tq{x!X)fOu;6etk zN^3q}1SQ)*L4aN10mSEWKb?}zbVQL;cKP1(E#!&(n`^^zBB;oEamXA9goSQfZTo#;_q5bfP^zI?7#r&LJpSiT}X zKLzY^=!m56n9oRG>5FHZPN&@hek`D=^rOU6_5{WFgokKXlp!UiP>fo`GhWP|bjV%1 zLPX(RwHKJJ3`z=1rig%0Ci9&I(ipCxA?b6lxC^owheL~%iI>L6CTd;F>L|oU6$gBP ziDhNU7%X-#6KvO^BWvohm$UbRBw%#vPVA2LwS1Ms2n}g@nvswNJ4|o{S1t+?W8TbII;c!dPk7d$ZYC- zlCgUHAS-I_g<)SJcH$#VH1aZB+{A?t9?`98Azyf0G4!>OtYO-sSk-Qdo4tp=X-RMOTK}OJDw&t$WS)&#o*CrV{eiJTv?1ryAzXx{r<6qAbPZ1 z#PpCKM7Sn6!QV|%q;Dwlu{KyNUcj0~Hh~ZaRS`HMy>bgyru4_7N^?3lWEe=;!k0HI zp@Hb>@|4|;M=^_6cH0N02&?QW7pL!KZD-wt!I|=62UHoY7i?nVo8O6Z62YM@KCu7D z(pcC}Q=;CV0_)|l1NK&J4G>-&FD3YZjLorP$6YRoA!lY)*;LYlC+RMC4-!^^^lCn; z%W0fvlbnl*>iwF`06?y%L4dM7bB0r2V1pIqSsprpJSU6&PdKyXY>4Usk`iZinp`8b zPjHDRqd0F6_L#($lu>Kv#cab(u~NM8eO!6Y~xAo zfaY6>f}*T>v6LGE?0hlRFhe?52yj@Cno;gRdKj^bO(J_ zWlZmfB>G;&bxWE1^C*gXu9nrZhaKc3X#kRfDbI}2EKpJ>sf4BB8zHIO7K@mQvUYYN z?y{H0T9|XWyVXE=> zdC|Kf3~(7}S$&fZ$I3V+rJdU? zK}Q^TY7sQVY#kK{K`kI_gd9zTE&H0DAYaz}))##Lj#lL^oi_t&!{CV_S^S1FgG=7) z=oj#Uy31l}QR7GQ2j0Iey0}v8%IbC&qhEi=T^zKU!PLVBL4Kh5^P>;8d=cwVqDVJy zI&5o`Ujx8BpaQ{Gwq673Pn8TRL*;|EMtC=ph+1L7KI9m=W3_-qlf zjAxF=m9+I~?!@yM!2HEPC=w|kZY;rwhEA7ZfktLU!@nL!Ur$@JARst7Z|EHy3y>lg z*@?=BmLg$m=t1nGmR017(XX4TBYsRn1>!H$=?f^;Bos!!j%ATs4b9=k;sVF+lH6Oubv!%)Li z0U)nPcTmidqxcaLnZf4Rz71=aSZH~}DpFZ-6wV4~*lX#cFcA4M)obil@w;le;7ev=jZo*$RcaWzsnuH5jqF)K>e_JI(Y5?rJZ#aF5z6!;3YA zF5z%xbf3Ortb)g9Bm+T6ZKcPpjhm~pDvgi$To2`pxn-9a!F|t4LZtG>DJ}fT@1C~g zY1|(~&0E0A+B5Aeh%xG7&2J-}%MO*LUecIfD@&X;|Be}EQ!%44V{wiUZfs%pOk{-M z&Y^8Qr3>(s7)fE?N5z<|Dm76&rfJqsY`JfTSsCQYCzu0O87Stbel0McTq1^TH(C_d zwN2Pw2jXAjA4vrNi%a}ZS3v2}ORUZwhvlu{Vks*$>K;7MT^$Y+{fvnBVJ{l|!Gy@D zB;l|9%pnE~uyd9i9YnnPeNIB#4301jV3l4?d3sr_@5vng;wb)8XPW)62bI%T2rNZVGHs zb+Jkf?U4?_GCcBWl{^)&-0+=_iLNySl05R^89{RfRbpei}4 zkmwmRheFE?@zw$+VBY=r+)ItL2QA}?M6MlHkeLs2Ok*wiyzIxcCuchG<%rBhK#fL{ z&Xx4d5C38l9M&sYR0WItSZC$2{h}cpW|lo7y48nAQPNKMmF_SlT)d$IgN2%{+X2HDD74s zUOw{#e^6Hc{0^rQ!CzV*gM`uQkOW+Yj5M5>r#7$uOf-8p^^nk_h&9)Y7x5E@?89^t9RN)(?jS^iF_BAArqAoERkcR@+^;q(CNED_8KvEMrs7gBY>@bOOgP zh=vC^MJ2l)?Maw)(iWwd?Cy(>8c9UsWfgwJ5nhto0v);?Yi>WuUj{<2jU$k!8cfNn zRgBmK2eB`K2(CQnhHuXKEkEl<5vv}W43uT5GJ`N0mPGtZ7Yo7L;<5;0BVXJe9%v6_ zK})L3q?YBl{9LcetpC~+YDZGZXjYioJnIFqUP-)V<38J&seF#f{UG)UN~r$zq+ma= z_B0MgZ#H(S{6<(LuKFM}TKhPFs7M@}v5FadAvO77-GCXGoZBwR%WYbl%6m51vFE+I z7!sPph$IyvaYrLhd+kq^J0)$C;;`0FDV9q!KcNL}{jb@UcI4UcJ)P=8`GJBC~9|oMNJqQeY zMD2CXlW=oe7(Kq3hF>)ipB6`BDP4x)Mt8d$u!oaQUp}_t_C>romU`2ZD{6ttB`< zhY|YQUpbw*78-b7VGO@5f2{bhU_4=7s-pRe#%IPM9WeH`Bke)r0}9qtr_K$iqhjpnj zFo88IM?&|f!?2Bw{Y8jd_XFfx{uvPFLs1DQk_YZ8VVLv;{s#wq?i`MGPw25H-`GNN zm-Bj_9VK$g*lQZ=$J-{{i~O+XKWCqX?5o$k`D%3DtylT{K}H)FRvH!Bw9$2sc@vCU z>(%=m*7oofA4p&yO2t7mu%{l?V>zDJxOwp9Adq9r>a#84LIqcJf!;CM_eB^vb3%G8 z-PqMP4@`jWIfLQ>teE=_cnb@3NnRV8uWKQ52q9tbL*dIe2r#!CENxR}zTV<17NLK= zjyl$voR@s%b)IGDn=fN8TJaElpZjBW$oh9sqM+jxu@@xT&j+BzR?WZ;euFW^fgppWly z^731{ev)n`J9OJ4%lktnu0y++$U`+dkagO*QD&2AMNX8gt#USIv8hl>8%E3>#K)p7 zQd*d$iQ1DmOjyqseq(17Hmo6#z&))nxlL~1M7K;fzaZ*2!W*SdlHeuAsPO$zo*mda z@pEm%=g-I=xi%!Vc@PNrhX5A7OYpNre=5AAWVxgO&+-_pedbJHIdV*l=MeHvK0+}b z9Pz7%MATDsHsLTaJRYaUzcpqe*HEl@e(SI;f$h&`s>X>1qQhfvxs?@1x$nZzVXfR? zn;^zu;ebe(sv9l5?gK)C()W8_!MF+MvCnjZ?2yGVOQHBS4;mIi_crDfkstybAK_zZ z-^*KW836Gg@W42ut&_H0We}Z`UPY7gM%c_d&xDqt#JZit^4R<2_4NFl8if|W<3s(l zV3Eh99a@HPttOU$&wFktOAS4aU^7=5M^8*>z^g`Fe73BP`Dd7ilH#{Hw4^f0a(Zit z!oL>D%AQ6xMyDgbGI7sfmiJka)M8o(xRhOZgB2IgH4RHpO7kt7)@C&QKu(To%@X2F zn?u!%)Jqn8^O)s=GK`2JY@TmjbayL1MA zb4{R}zTQh)r_A94$qy_u_t(*2eoNCYQKc(lX5TpQ6jXr~ZT_P~5oUY|C?4%ElILl* zLX&SSLt*pY@HE-f5jeBf1^;O?2&~&g9j6hmbI)NLIm#tSN9zv!Ygv;f<7CxGDPlOw z`zBL^( zf}U3cMw5*bpJ@LWuWI6$W4Tt}qNgQWzz+0PEiTW=0rGhCDRE=X8;W?zZbLB)C=xnV zU#~pTAdy3r4mwL8qcq1O{pby1p&y0xn}PkEJg~m&`vh>jA|{j1@bj_Y63vG7wAW~r z_tYYA>kw&@N?|ejG1R>VYw|KNlDdtxG7}XJZbxcJdDnK9a1E-HFbCq5qxG1j@ld~- zlY{~QP2FciDe^Zx>yP{ZER33Ey1lqvRgvQVa=cHv;zSaf#+=C!(r=P(AR>^k>#Ppj zOXG^(;P_}=hO`7wj&_`~^W|bN{b5yL%vJ9?@=*4DJ9j{fE2moW#t^Ml6srR)ObhO-#H%f4YX)BfXgT7YhbE?CI+c&ZPQQG^$s zC+Q0!4so1&I3jy8qv;}Qr|dUJ5l2(7|0fdV>EiDa{a%((b-ul1 zv)J4iZ3VcOq)hl;G#Pf1oaz!yR;aUdpTCeu{e*Uj|5Ly?+h~`_m{#y@C}RyI>nb3&*j5&YPwT>W`*jgxiG zQN*47%;GWN!n&TZ<4AYT<|`E}_eDpYSNHh-jSb_0BSF5B>l`@stC7JClPQtHik3)r zmAAu7%%8k&GM z%eeiO5C=Bn?(wtHVf5wj>Cx5iLukjKf>tXc{lcZ}j((2_s|%(IWcW|;RG=#tRi0w1 zLR*_!Nt$udwSR!_$P!8JvEkeGu1d#~VOoCmpXq3OrMVC!Z+1~W7lJcO0%LQ(1`8GL zkuk+2@&ji;GFioKdnw1YCJg!$3$zvtg7gQJ)v!@1_iE&>sg=8k>+}u-fgr6 z7o#vwyc`hTbnS7`I7aS0%^|GnEt7i|sV?_znU`B0sI4)SL3clfo-!Z4Ff1+R%#>*} z>E*}_($xdF8!S(lxC#_mox3ws*~h7VJd3@I&yZDL6I7xe!(u z)j@wJ#A-Ohr2&Q=sm(2}L9<*wq%(J}9l4BF$g`0n zxTNOi8d7cvEguylFkVWG2zZ-O2ONfudsyM`zFR_nP5&5}N3lt-gsteIs^v2Xr z`GMXXFw;FbFKQUY>nJ}7d^TsJn?!WkGseDUXzq+-<;475duPSBPZ0M(RO}YhOmf-P zT)PuiHn&8n;NbJ=Ja0gnB^fyfa3|xJf`AeqW9zjo+Ls~RW3Wl{R8GQN#B;38JC`2WzR^ zw8NGYs8TC3Mw${t%41c=SvSuHC`gc?qzB1R&h?h>^HkP@Vk1zYHoaFJ>AI@d1NTTs zU~fRvl7GSYF@~YX!s8~e0#bQqWzx@*(8&AC<}Ksv%ALnCWuZOlg_8w|1!OAc`8POw zih3+R2ktq_a@pl#`YtoL=u7;Cp|kB$^Iguv9Kjct^;_U_@#qCR14+hwwwrbNX?RG2 zvJ~E_JCq-|lsJ*EMTXV=2f2?`CUI&a@Ju@@fK9u_nR>3xs}XL&)zVI6yZptrU_Ve| z8!4^~eALT`VvwUY;p{+a2t$nPZkx>SWr06H)PyJ@wh@?BT;r4|9yOe}dBz<#Jc(Vq z+J(BYWw=?Ak>e-q@9sTaHw^assvAF}ZjYfMQ>dHa2y!?VGhjs4YLi zjCja#-I!ohY+yyJkz6sIn$;VNxI_6xaB&{!5L$6V`ip8uo?=9$knCWg>!X8}rw+ca z=c*qpA<0?9ZhO_&F?dfyg*B(}Qwviy3T9z2Y{rx5uH^wamV=lGNtwk@Jet$CLG2-< zhQ$msL4! zCzqlNu!g@K&QKw&H)OgFu61zx*zYesN~}VG7caTbH<41N10nIQ(l($+$prDxx^p$K%_KKpvFbpba*mi%^ zGz9C*n$4%!v{M8S&?wxGJtUv7ku6UMLR@}=wO34n#~9aVR@@w^pl{v}Y=b$AS{jzf<}i=?I@kBK zl*esjJpX0gn)4&PAMD(U0LO^Ez8YUkjmP0}Z=$W43+JzsLa#8GkEUXk&LOqNzMJ>3!jd0(_{@UGx2|OPM6cEs_Igd2&2K)Y2 z<`kblbiv!0ikJ}7LK(@bRbKVqgT5M)!wA5f#M<+orNzU>HV*(yONbB1uW{e!S4rL!{eQ;#BSc-94MFTMp?ovW8@ zaFPxVE^%}n|E9lQe9}dqrIKDl+8YPV6hUYsz=vGw_Kj=8SIQ%^@h39k+S}x@Aww(m z3r7@edaO#!SMwA1fN|Gc?kANb&qZ*ZBd2Bsg0L4BltjUd~_p$WNDPcZdFM?A^ z0KEZM+w*s;z)v!C!Cw!iX_RL&+_>PVp)`gG}U!1GWb83utJVI9*O1nnC*y9M`S z$}YsO39)Oa4R~04LH;0SzzJrOqBl72R>PkUot%=y{8<0J9!*2;+lkifIE7%nu)lQJ zGKtzz<1kvj5xA+~)W~(-VYb-v^hmG*)vFQ|H+aWM526y`=oPic7&oscG5_zZ>m86MI!+x@*T zc~#cf{CNJ2r?JAv*uD)w7Wd?AT|F->ziF#)5Yb?Rut99As$M^RX#a_P)6{CsBA0ZC zZcv}#njaMDlq*)EYbxtEH#cKS=nr@@z@KevPKm>aUfry3i6sJMGt@DUAQSa?YQGRRcD-l8!m4+i zJiqD?Mh8$aX5y`wBXr{1QT;J6nKo^%=<`vH#TDL1s29cP-zBdY=(q!|OGJncmA~I~ z!9qP!+6)H{@!jgw%2dmM1lNE|NC})^r-^B1|9z)FS=na5* zG_g!(bEVZS88ikWjb!9g3hb_nzQ}0VdOYTf;6`J^JTAg{Kp)@U?~hM`e&04oZ)&UD zC4q3XIdxvdea;RED&*w36rr{N9cQqV>iZ6BZr+AkD)o7uc~jDAEW#++0w-O(jgXsl z!Yv|=m_H;>kEDIAQ{cB{hqz%!9c+dgge=A;Z&M88LVT7zI4;WJfHcMr!{kj|iC?XY zS0M3|z+nmG>XzFh#mj=v0mY=KL|Z+JSaU*M?BzfGTNu`LUxd4AGgIT5J>k(!JfAA8 zjH+g|Jo%5j0Q^N{8iH4#4`gS-9t~t#xOdfd#j7hWV~E27j;MfD_EOC~@N4wLWI!d} zcPS)f7uNo7IVd00`98eL zB#0P_q_nh5E2Gc{1P(3w^F+{x0!yz&nZ}|rtx@RrQ+1k+8O1Uk-(!;sfA-gbCxN8l zj2H0vVuzqJJ?e5yTqkY-#Eui___WPC8@V0U{oKQ=xQeaLl|b|no1hlV`{rEMVc`{E zx;W%~SZ769LzAh5k#xJ5iB4N~TfEUX^aSzWBXGk+;-p8ozD+xFh$-q1ufr=2rGv03 z8NO6Q?7d{lzZRL-ZrTo7L=`>61h~ae+Be+RZXL1fgHFn6Z$(fd)PH6jXv|~=Fw@A$wz+Il zC=Q*)L?osHNrysOVx2$|Tzxng9i3lp+Ao9eAQWj4$aV2#XHPiR^IvkwuV@92qkWFG#wxF$A+4|XCUhBw;R%2wF9iNG@b)BEhJ#Tb*w~~$(}f-c@K9Y|NsFe}Fl z%*$J>MwU_@eQgl~O?rubbz4Sb{&P?KQ+`REkSt(AtrVDEUmaW|%g5Gpgr|aEVkDD* zeyE33V+U_G8N~$F?e+^+>Ux&+%hf{bJp&I+CpR z-`Cd1!!7SJUOhfwg=~uO#fH?U!W5t8TgQZmz+~mT?`}C5o^EVh&J8%s;t_rfZ%*Ph zx?!P7E}YU?$5m1L(yb^4>_b-yKz$^8VHd}ZTW4z!v4w!6KTiPcL`P?FRTtTk;v>Wk zs7+3Q3CH=@{QlW*4^>kjg6r>to4*)!Y^UFMA19^lqxiws9mIf#^?@87`N?v1fX^6_ z$>5vNuzKR+J@Du#GAaaQpHa$jDuF zNwQ<={UglOgNNkZpEX^dNL@wWJaH51TD=8)%rgfRJ&v+A( zi`bzuyb`zr=1;-IYRKege~{HPu$VOrQPp}{7v{CarFp_!8S(5)S`lpN1l$Tv%?Cq= zH+xwpl}eVrH>FDp4)~e;1rAd_stk!-emSCd=%mN_s|6t$=?wOU@%-$ZCbjy;vm@Pa zRDdCFmrMGw2CgH=9bT>&uj0jphlNwq<#JnDjYcYIOWpYTN!c8?YjnDGM@9slL~?II zO#GxvG?HL!P*eR70JIt)`!Owo2UQ7h!`FyB09&w8gc^u`YD&0h2+-3S?$c-q>!e)~ zUsl!=VO}G6+5?RWBa&WXblHjR3&O0^}ax<{hAbe)g=6RYR7&zGzUl zn@J4|Dx-VWhmFT4Lu1ZXz1a4;cBrzMlm@jKlR!6=k=NF|OY zaL+aNa^xB7`=eV0MRDX%feuI>>|4W~8Exh%-g4Nj)e!Q5l7FYT?6zMRfh_$mC z?0%GlrOE|XbsNX+Q5DTaFC2mP#cb<(#-812A@D_ybe^M@u1qCB8Ih(%IKf!PU;Vcl zmnH-$!ib7)qOp=|Lr#oC2gpi`ZC1^2_6!1Oskps&g7-qa^L8fCZ%$7tJ0j#=UrL_M zId5ndM(`2Ob09essxX1Sm*mWiGSA5V~@SvhBfe#bLKS>^5pYukyOcmp-_iS?NRXmEWR+EvhvU(<6YcyRwAM~SjNNVw2{**^w zpi}*ngwmD>?@<#G@6c@`)0iqKUeV^u&$uN~1}1qE(5_Seb0;_SYaie|bhLFTmBq~g zK<77fn&$KS_;?X%gpJ9B{B<0wAT;er!jCU4dbNUq$%9ltFUzD{0^7JU<_q$Nqkve? z!LFg`#kCRGe_{!u2-AY@m_aSJ@#LBJp-B=!wuc7423a*{kUw3n;4P@1l2dB-6-73)to%$E_hHlxG^DB8~_^?Q8E}SO=&}FgYDiQ=uVUK9JCqCCw zn=Pjpy*pNQyu?>i9v~?&(KGuPx|hOA$fs{V)9}h(-B+Ir8^PZP4=IYH`juNwl~OxVz5)`yHAa+e92(8-5OLC{=l=lhrR zB)(~1I(Rwc5$M!7S=c66HqnA>Ce%U|=uu`A36`_G&^O=_A?-0?R}U`}DVVAvwbUfm zm9;aE4dz|)$%+S}B&Q9yP65Im3!9YLTcQVXEb^4xEYKE&VL*Vb{O`YUx5%H}RXhZT zX1`9{5daYWiTu>OtsB0)iMeTbpD@OIka$Bn%%NHS=Kb>Z=92YF{ACc8Au$C2w01AF5xpe%Z#>ps} zet|qZmWO(HRar9f(y351_kDkPGRZVQ$+NpSxOtSqJSK*}xCtZCdxRfQHr8t`pCH#0 zDGrFQBbOHuz@4kt*ui2up!EQgU#5%I`{!WOcH)$jBp;O4?nP(w6jLK7&o4kw+pl|w-p)my!-S-?6xe4BJ@m#Jw0DOR%gTVVzIYD6RG*bF+mg|F zvLzOY`y51zL0u*9SA>zN{P0}yBtc*)3!{^j^UJ$*mzdiVy=#Ui7|CWLn}`fu^;*^~ z$^7MWC{?VW#77=vSfbp+HW@dGyGcw7u~-;aoJ!rVS@QAL%v}agwt@Cn#W*p9jL@`X zkou$l$*m1P=fp8-Zb0elZJUI#D_6P8gHb_fQVSW_q#-+{`;HqTC6;V)^@CScFOdb$ zoDF>8hLA@Lr#|(rgji||zd~{_?xlHg2>p_hM4xPC*qqZx-1p0D(6bbczsZOOobIr6 z3NG7}&xL+S5Qb5u`vxgQ#S(RAXP_m$Fp!@nt~*|d>m;He>4p~d@(?Y^x~Gq&cI+v5 zk*BU)IsWPd9A>xnOlZkX_pJ*Cmi#E>U|fgY>xArGlmo~rv+mb{CR8hgzB}y)P)gw_ zmgUTtfD9S4IeuB=VfHHa2!YgA#+Zt6`SP`)5MVaOgZnk6K`#&z;0<%k!1S*<{1xLg zI3|1(OR3yIh3*Vouv5rsEtx3ZYv_kV^10n*UG##wAX2kB76a}pSLsAw<7~G1KCst? zNV>IvkNGlrOKJaE8Y@dH;@YOrhXYffdl&C%q;pzvhFffprr4)74ZxuG4g!YQ_%MsP@2J0wCB)iKdjejDRe9Xi`;j3RP2u0Wz0-co8$mx{_OmpI(LLiZCBKh1U+m0xu$A zP$OcX24_IWgvqujqk{J9a1j-}4jd_RQRrl%OgG8XKUhLgzgarCVsu+tmL%x_XK(0f zy(2MuA>cv_u;D7I%d~?f8%#9cmGpn2q~4Ql@4rD&gfW9RRe|mQJ&P%9)YWU@&8z^~ zhO*Arskvd+w57lMmIRPVjU=5K_Fd7|10plPv z{Paam_yiV4m}d|xt+!4d$lfE^2E0QaGymy4d(zI(wq?9pTkT#fsK*b0)m_FZzR8OW zE2)`<4v!3}g#T;KD54ePj8^~G^*$kWcc>TO2i_6tO?ZEj6qPhgKs@%I^N(s+ENEb# zOgUU*L>w-9hwWzmj$RqCukk4O{njQDV63Ko%@oCqJ9sf{^U7?1ym{F(MFrUCYZQ;^ zvsiagDSSi2CRkb6L$ZGvZOvfB1??;xVvAQADx~4;1JoLev479q^a@H8T(0&@OYu?> zhYbZ`@6C{^8n`O}c(%WDDw57$JITLNWNRPl|+>>mobwwVjwkQ=4tK_dLdH~oD!?m+*wX$6_Y z4$4tFA!S7{TT~T_C=$tARdx%tv61Xip|LY3uPc{eliu2(*(LpSE~#;qY-8=7E5b6@ zd+1B61DqU5y0mCoy;YvIl5onCa$~$~<%(h=K=rOB7<9h&5C~}`^`rxHPI(iCfvCG< z)IwRH(faA#s~)kMA1#OJ1OV&6n%l^B2cW$x>{vl)x~(PxOtx#sV2)a5ZP11c|L zjvUX|2;201El?(-t-r5+k=~fyZI#D2&k5vF6~+X3^3f~~`*s~tGW<`*V$P6_KX7$LpvSUZUXWTT7M zcHUx-&;3yimY?|iYG|fcdr+K5k=gYp4-AXlj72)fEuwdNHK^$KYMNGV$gC8RtDj(+ z66F+T*LuFV4(l^-ep+g99}$4XCOO4S{MJl9W=W27YQMS{8gZmwRIff*h>@J2JkpjC zeaQDT5`!kHm|U7hvO|#Fo~1-%F{G9EOvk9U80*Bt(dtrvL#-%H`i$6FD1{OkDpQ&% zw8`XhcVxa;HiYo@-AB>gVcc@DlEf>LE{R!FmpC_Ck=^J=eZb5kd{6Q$HK_XMBGuL1 zNR1+prF)yOXquvh`F7R(Kw>t*^2JKc%cX$4@#4dFf8_fT>3Zs0IPcTPu4nf1LJpfD zfY9JK4qG&A(*5paJIpJOpSygQ8*F~$v-gs!q;=eSl*n;E(Qu06+1ApR)T9JqzH8=E z+9!u`B^**#1;7;rrm;{&?!}|K?U3UR{dC)^sMpDakHeU>x2j{ikvK0E+n-OseY^Fx zm5EgmFF4d)KT#)`LOsHsRLh2s{tW+z({}0{kpPAFBUkIR;Zwj@PWd3_-``?Tev!7N z()bVC$Cw6QS54^$r2mK>p%pgv99Y{;mgsImwyxjwMkT86r-RtxaT?3FGQw(e8&(Ax zj0&vqz1hqR8sYhmD5mg8>W6J!pZDhzv-&w!W{=IGxSQ-A}kh(az!H%s&&>Md2t8y?GR}3qS zMe2O~!I)6-N3QR-m)b>@CIfk*TXB8mZ%(*(aA>Bso7ZkTU2sufC%+;sGZ~l;9LaiabmYz zqJ}BC1@OW&V^mUiKRgbL?nuITCvKROuS#!anZ8$*%dnJdOBee;JJ8GbHLbA(Y9+gVP4hUo`Yv zMUDKr(A+sY+H5?ipxcQ7o^AE56?QL0j=giuSG}91NtF@`nQrevHtoMt8A*8Q6VK;C z`fhDBMq6;U$o4>E$gXBaEBeK&c>(9DJF$xLZ5i9%x}3Gcf%~N8tysC4A$GRc&(|mu zTVMm9o!xhu8Rg2F@FA)LDjC2foWj^T!9WsqQhCvba|kjGqy7RVzoL zML9i|2FfiM&8P*UruchJp0!KwWHb#wD^11u5*5@R~iuLgdwA=qxq*0O8VzlQfgU~;XC4G4``IDH`}ch zQ3Y%_Z%eBJU7l|4J0&R(6?663EBb6w)i%8DGFHHA66#gypBBNY!gsdf)-u(GJI62MaWnm^M@h@#|1S-=k*{R-iC{?wY)RLQ&K(+M0i$ z+yCtS0T%~mg|bzP1(A)Z8au4cu*T_3SyCmB>03HX;1WheY}JfwFbL3eJq9jO-sGgP zlRcqw(dbmu&i>a+kqT#ivO&{jZ+nuN<(HAP>QRrWv{|~ zyecux(wR$n&Qc^l)fl|uWHw-x8ly8( zAguh3)cyfaCKp1M!|UCwalhQviEy@eFVwMYSS#{0wt4tC0zVHiv2WzROPAPdIWM1H zSv@>#alAj0m(qhOdUv8tzEPGowcuwLgRMg#pd9fdsTU)tVD`#CTF#Ra?BdN&8dZkc*tn310 zuT|uNnU`}?K;(c?Cw>1{kcB~C49+XxUzB>Suuy^=tCXFn6GN|yrNJiSk_F0Na9ZVK zvmz(Jw^Z=Du{A2;36Xv1SULB)5jF`q?w&$N3}bNur)eiOE^vxlmuvr#w3ufV50^AG zf84a;_oJ8HF9+ZQ7=iQ&v0r7@9h z+uNI?fCDaSaeLie-RCf%W*94x+xmw5o$eJR_*p}ua@zsb(U5BX#|{}DA{T1rzAz;& zPMC}^74fsxC3Tmist;d3JrWY(CU~bT6C6I-pJnnT47JcPmK5Vw9-HCYpCFM9Bp1ry zuj`#PM{yBx&q&#Zm3Zv4V|eb=yc-uDo^?x98%!tf8GpAiS-G3IBoZ*O>x4^Zu;HMc zQNj{^k)PPp5I3|5j}U9`%2E}2`#QLt=-JVxE^afe5k-nJMa8n{+l4KTA?`@hExSN$ zx8&(Nb0eHO%%yDnOqa4ZiwD)8Etfg%p4k}kNHxvnd6BJtkWXb-`MDpp**Sc2Y9qcy zsAX5A^LuC4Ez@YKatt{hu;s!Jr{42&*Y@svtJX3#Z!*%e(liq)cCZCx4P zFSB8%p*56|hXbmANtn)N>(JMc%_IMsOmse-ewL;11FbbOZcv=Av=Lf}udG>!Pz@ba z6(g-OY+HbH=&lP|u`;EHaz!hrzH=YFx+Lt5r8xQ4j@<_)&*_cPhb55Sbk$;3#UvT! zhO(?~MskJ{bJYsk!`*iB=m$O9RM>;fJo`@rf46^^J%T3xo@@=HF-x_P*O%D-cK{Da z;NJ*501=4TKVW2l|4t)w)m3%h7NA5R_5DdxSFna)ikP}lHc04povUu;Co^Wyx?=JN zGLpNSZ|AK3%hwNRrIYgQkNei{{7uz$)?KHb2JIeC<#c$PXDVHLdlQ|WUer8eQW2M+ z)6Ndek(8`o>aO~1XK}O4ZQeX}W-(UPvXbu%Y3Sx~yqs&wiwOR5*ZEVjf~0FR<)nR? zR8@Ryvs+}~t5mhGR>MbJV3^#z5t|uS{0MVRo(r@m-nrEt!frYUN7xSKq1od-T)K zpZ;rfAv#FqvlShF(jwJEOB5manK!Bup%xys+j9AmXhc!I60SG2A|ia1##O>;+ja zAsZTv33Ig+mr_&)K~gmKA&6eln;oK^ZKnHCE_dh6he(+yQ9=yT>!%bJN+t&s(^yLo z3#5$Qn;nT!dLtau$bRPds3QV@HD`vAfSvZ8Sq928mK+iCz8-*i$xceyq$k0)qQ%A5 zb!vng9jc_*c`}@$|BOLP9Y;-366zuQjFnh&jtx^Z1ujZ1swopvz|1{H9XOnGJDa?# zgD1@#@zn z)63$xRf&oVVfCzyeWm!?fcXpOJfDNhVtXm|XBPqU^)o4IL3vkeNG1NDye70@1*!Dc z)J?#A^h^pcI1hY!`Tk*knF>n6w((nTyLtDok{#E6@xb68mEIexcyp31rv(EPOHKPI zMy5_yz4oM6qa!`U31;J){O6bD8vh|=!2c358eZ-;zSd}7AE$?nosO*mn)4?p00awi z5%5FNz&;;$^bA`3&!MBcn;aVJ2jG-@1{MHAKwz*S2qYi^hVThMI0OVZ(0Z!wHvdgU z$IH^g!`24P2()zZwk6=#(2+L)D)_p%SXsKc{bh@egQGV9-Tq+{FF?=M%NxBl00IOF zf`r7t!a@)}Fi`lP#{RE~02N1=EgHTB2J_3=S~*&}aRHn?EPWijZ7l(?zt;-`Awcxe z&^W@s`CUT);tHJr4_g4gx|Nf*k1GMc8bIW)?BV6@0}zD#AGAwY82tZEExtO2>Z{Mm zLT+j^M)V%%Nd~Te6{2UTVf$;B4zwOeLmIB8io=3 zG@8aA5OyzzwaNRI41-!06M2;+>n?cVagERnTUve@AnJCc_9+)viAIF+E9bh)s)-|J zQ-X3cZ{va;p0`2*oDi;Ee>RF>6ORxv8X2MTm$eX}#ZZ%bey@c2wC`KXn7b~Xw^yJr zMoxt(9-*}$>A-AK@0{FA^J|^K`us2(z40&E{3K7XWj66n*`v^p+3CF1Ge1z+o1h$L zsIZ)LanQbQ4NR?8 zx(JYv>=FGV(2dwixYcc$Clig<7XSVNBa+pUXFyAvA`3;4yIP^H9!1W1aW&t<510H%YHK0_WK?FxTby>H`{0nSEQ0J zo9%v0m?3vmq@`T5%J=ZOZ|WhY_}VuA??mySVd?Lt4D4+3`9$Wo-R18WuIn512a0Xf zAl1jX{-!IDRI{*#SGHO$9gv?3W)~h=T_y)Gb6}?|`ZsJ=<97F=r_^xtZ2}tFx(Euid{j^kt{oN&YlErXMH6-(@PVSj`1Ko7-#L@9pmj|>E+|^ Tg?0rPBq%IKz{V!8u0ZfVFYM=Y literal 0 HcmV?d00001 diff --git a/indexer/examples/stallman-typ.pdf b/indexer/examples/stallman-typ.pdf new file mode 100644 index 0000000000000000000000000000000000000000..fd4abf8df6b173fa58254352c0971167ba29850d GIT binary patch literal 20184 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 String { match op { Op::TextDraw { text } => { - let datos = text - .as_bytes() - .iter() - .map(|&c| c as char) - .collect::(); - - format!("{datos} ") + format!("{datos} ", datos = text.to_string_lossy()) } Op::TextDrawAdjusted { array } => { let text = array.iter().fold(String::new(), |mut acc, txt| { use pdf::content::TextDrawAdjusted::Text; + if let Text(texto) = txt { - let texto = texto - .as_bytes() - .iter() - .map(|&c| c as char) - .collect::(); + let texto = texto.to_string_lossy(); acc.push_str(texto.as_str()); } @@ -46,27 +36,27 @@ struct Args { fn main() -> anyhow::Result<()> { let args = Args::parse(); - let pdf = pdf::file::FileOptions::cached().open(args.path)?; - - for page in pdf.pages().filter_map(Result::ok) { - let page = page.deref(); - - let content = match &page.contents { - Some(c) => c, - None => continue, - }; - - let parrafo = content - .operations(&pdf)? - .iter() - .map(|e| -> String { op_to_string(e) }) - .fold(String::new(), |mut acc, s| { - acc.push_str(s.as_str()); - acc - }); - - println!("{parrafo}"); - } + let file = pdf::file::FileOptions::cached().open(args.path)?; + let resolver = file.resolver(); + + let text = file + .pages() + .filter_map(Result::ok) + .filter_map(|page| page.contents.clone()) + .map(|content| { + content + .operations(&resolver) + .unwrap() + .iter() + .map(|e| -> String { op_to_string(e) }) + .fold(String::new(), |mut acc, s| { + acc.push_str(s.as_str()); + acc + }) + }) + .collect::(); + + println!("{text}"); Ok(()) } From 7e8e557f2e208be6296deef2fd620308f711d15a Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Sun, 24 Dec 2023 15:17:10 -0300 Subject: [PATCH 06/18] Por fin una wea que si funciona --- Cargo.lock | 544 ++++++++++++++++++++++---------------------- indexer/Cargo.toml | 2 +- indexer/src/main.rs | 53 +---- 3 files changed, 278 insertions(+), 321 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7dcfff..2fb49bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -196,23 +196,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - -[[package]] -name = "aes" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "ahash" version = "0.8.6" @@ -470,17 +453,6 @@ version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" -[[package]] -name = "async-trait" -version = "0.1.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - [[package]] name = "atoi" version = "2.0.0" @@ -563,15 +535,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" -dependencies = [ - "generic-array", -] - [[package]] name = "blocking" version = "1.5.1" @@ -643,12 +606,28 @@ dependencies = [ ] [[package]] -name = "cbc" -version = "0.1.2" +name = "cairo-rs" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +checksum = "f33613627f0dea6a731b0605101fad59ba4f193a52c96c4687728d822605a8a1" dependencies = [ - "cipher", + "bitflags 2.4.1", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", ] [[package]] @@ -661,6 +640,16 @@ dependencies = [ "libc", ] +[[package]] +name = "cfg-expr" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03915af431787e6ffdcc74c645077518c6b6e01f80b761e0fbbfa288536311b3" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -682,16 +671,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clap" version = "4.4.8" @@ -782,15 +761,6 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" -[[package]] -name = "core2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" -dependencies = [ - "memchr", -] - [[package]] name = "cpufeatures" version = "0.2.11" @@ -853,41 +823,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "dary_heap" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" - -[[package]] -name = "datasize" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e65c07d59e45d77a8bda53458c24a828893a99ac6cdd9c84111e09176ab739a2" -dependencies = [ - "datasize_derive", -] - -[[package]] -name = "datasize_derive" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613e4ee15899913285b7612004bbd490abd605be7b11d35afada5902fb6b91d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "deflate" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" -dependencies = [ - "adler32", -] - [[package]] name = "der" version = "0.7.8" @@ -933,12 +868,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "dotenv" version = "0.15.0" @@ -1038,26 +967,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" -[[package]] -name = "fax" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cec1797683c06c2f3de5edb3fde4d99c70e96f3204f6aaff944078353e5c55" -dependencies = [ - "fax_derive", -] - -[[package]] -name = "fax_derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c1d7ffc9f2dc8316348c75281a99c8fdc60c1ddf4f82a366d117bf1b74d5a39" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "finl_unicode" version = "1.2.0" @@ -1173,6 +1082,17 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "futures-sink" version = "0.3.29" @@ -1193,6 +1113,7 @@ checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1229,12 +1150,82 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] -name = "globalcache" -version = "0.2.0" +name = "gio" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469dba5c15b33d67400508ff1f640e8906fa6c8d5ee80540203eb9029ce475df" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" dependencies = [ - "async-trait", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "951bbd7fdc5c044ede9f05170f05a3ae9479239c3afdfe2d22d537a3add15c4e" +dependencies = [ + "bitflags 2.4.1", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72793962ceece3863c2965d7f10c8786323b17c7adea75a515809fa20ab799a5" +dependencies = [ + "heck", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.39", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", ] [[package]] @@ -1249,6 +1240,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "h2" version = "0.3.22" @@ -1268,15 +1270,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.14.2" @@ -1293,7 +1286,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.2", + "hashbrown", ] [[package]] @@ -1406,7 +1399,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", - "pdf", + "poppler-rs", ] [[package]] @@ -1416,17 +1409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.2", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "block-padding", - "generic-array", + "hashbrown", ] [[package]] @@ -1449,24 +1432,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "istring" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875cc6fb9aecbc1a9bd736f2d18b12e0756b4c80c5e35e28262154abcb077a39" -dependencies = [ - "datasize", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.11.0" @@ -1491,12 +1456,6 @@ dependencies = [ "libc", ] -[[package]] -name = "jpeg-decoder" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" - [[package]] name = "js-sys" version = "0.3.65" @@ -1536,30 +1495,6 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" -[[package]] -name = "libflate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7d5654ae1795afc7ff76f4365c2c8791b0feb18e8996a96adad8ffd7c3b2bf" -dependencies = [ - "adler32", - "core2", - "crc32fast", - "dary_heap", - "libflate_lz77", -] - -[[package]] -name = "libflate_lz77" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5f52fb8c451576ec6b79d3f4deb327398bc05bbdbd99021a6e77a4c855d524" -dependencies = [ - "core2", - "hashbrown 0.13.2", - "rle-decode-fast", -] - [[package]] name = "libm" version = "0.2.8" @@ -1635,12 +1570,6 @@ dependencies = [ "digest", ] -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - [[package]] name = "memchr" version = "2.6.4" @@ -1810,45 +1739,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" -[[package]] -name = "pdf" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afc7e745846405d572daba57a429f30a198d955602aff8a1a9e437c2abfcaa2" -dependencies = [ - "aes", - "bitflags 1.3.2", - "cbc", - "datasize", - "deflate", - "fax", - "globalcache", - "indexmap", - "istring", - "itertools 0.10.5", - "jpeg-decoder", - "libflate", - "log", - "md5", - "once_cell", - "pdf_derive", - "sha2", - "snafu", - "stringprep", - "weezl", -] - -[[package]] -name = "pdf_derive" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1038b9cb38dec35eeee9f23eacfb2480087982f9b7e9221efa8034eea9ca2360" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -1944,6 +1834,33 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "poppler-rs" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eeee26af64d7c1bfdb436d831fb78e65a325ade17f380e6bee7af2bc9859b8e" +dependencies = [ + "cairo-rs", + "gio", + "glib", + "libc", + "poppler-sys-rs", +] + +[[package]] +name = "poppler-sys-rs" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568f80975a5d4270c97bbfd6283f873b2204c92b67b803237c2e705fde4362a1" +dependencies = [ + "cairo-sys-rs", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1970,6 +1887,40 @@ dependencies = [ "sha2", ] +[[package]] +name = "proc-macro-crate" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" +dependencies = [ + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.69" @@ -2056,12 +2007,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" -[[package]] -name = "rle-decode-fast" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" - [[package]] name = "rsa" version = "0.9.4" @@ -2173,6 +2118,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2258,28 +2212,6 @@ version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" -[[package]] -name = "snafu" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" -dependencies = [ - "doc-comment", - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "socket2" version = "0.4.10" @@ -2331,7 +2263,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" dependencies = [ - "itertools 0.11.0", + "itertools", "nom", "unicode_categories", ] @@ -2586,6 +2518,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-deps" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" + [[package]] name = "tempfile" version = "3.8.1" @@ -2694,6 +2645,40 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tracing" version = "0.1.40" @@ -2810,6 +2795,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + [[package]] name = "version_check" version = "0.9.4" @@ -2904,12 +2895,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "weezl" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" - [[package]] name = "whoami" version = "1.4.1" @@ -3013,6 +2998,15 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "winnow" +version = "0.5.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" +dependencies = [ + "memchr", +] + [[package]] name = "zerocopy" version = "0.7.26" diff --git a/indexer/Cargo.toml b/indexer/Cargo.toml index bc0f5eb..27bad23 100644 --- a/indexer/Cargo.toml +++ b/indexer/Cargo.toml @@ -8,4 +8,4 @@ edition = "2021" [dependencies] anyhow = "1.0.75" clap = { version = "4.4.8", features = ["derive"] } -pdf = "0.9" +poppler-rs = "^0.22" diff --git a/indexer/src/main.rs b/indexer/src/main.rs index 40ea367..d9a417e 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -2,32 +2,6 @@ use clap::Parser; -use pdf::content::Op; - -fn op_to_string(op: &Op) -> String { - match op { - Op::TextDraw { text } => { - format!("{datos} ", datos = text.to_string_lossy()) - } - Op::TextDrawAdjusted { array } => { - let text = array.iter().fold(String::new(), |mut acc, txt| { - use pdf::content::TextDrawAdjusted::Text; - - if let Text(texto) = txt { - let texto = texto.to_string_lossy(); - - acc.push_str(texto.as_str()); - } - - acc - }); - - text - } - _ => String::new(), - } -} - #[derive(Parser, Debug)] struct Args { path: std::path::PathBuf, @@ -36,27 +10,16 @@ struct Args { fn main() -> anyhow::Result<()> { let args = Args::parse(); - let file = pdf::file::FileOptions::cached().open(args.path)?; - let resolver = file.resolver(); + let file = std::fs::read(args.path).unwrap(); - let text = file - .pages() - .filter_map(Result::ok) - .filter_map(|page| page.contents.clone()) - .map(|content| { - content - .operations(&resolver) - .unwrap() - .iter() - .map(|e| -> String { op_to_string(e) }) - .fold(String::new(), |mut acc, s| { - acc.push_str(s.as_str()); - acc - }) - }) - .collect::(); + let file = poppler::Document::from_data(file.as_slice(), None).unwrap(); - println!("{text}"); + for index in 0..file.n_pages() { + println!( + "{out}", + out = file.page(index).unwrap().text().unwrap().to_string() + ); + } Ok(()) } From b08abfbf3ce6ddae1783331eb266216c329c7398 Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Sun, 24 Dec 2023 20:54:53 -0300 Subject: [PATCH 07/18] WIP --- indexer/src/main.rs | 20 ++++++++++---------- indexer/src/pdf.rs | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 indexer/src/pdf.rs diff --git a/indexer/src/main.rs b/indexer/src/main.rs index d9a417e..fa05b16 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -1,5 +1,8 @@ //! Indexador de documentos para plataforma estudiantil, utilizando la estrategia TF-IDF +mod pdf; +use std::collections::HashMap; + use clap::Parser; #[derive(Parser, Debug)] @@ -7,19 +10,16 @@ struct Args { path: std::path::PathBuf, } -fn main() -> anyhow::Result<()> { - let args = Args::parse(); +fn process_buf(buf: String) -> HashMap { + let mut terms = HashMap::::new(); - let file = std::fs::read(args.path).unwrap(); + terms +} - let file = poppler::Document::from_data(file.as_slice(), None).unwrap(); +fn main() -> anyhow::Result<()> { + let args = Args::parse(); - for index in 0..file.n_pages() { - println!( - "{out}", - out = file.page(index).unwrap().text().unwrap().to_string() - ); - } + println!("{}", pdf::read_file(&args.path)?); Ok(()) } diff --git a/indexer/src/pdf.rs b/indexer/src/pdf.rs new file mode 100644 index 0000000..0591707 --- /dev/null +++ b/indexer/src/pdf.rs @@ -0,0 +1,23 @@ +use std::path::PathBuf; + +use anyhow::{anyhow, Result}; + +pub fn read_file(path: &PathBuf) -> Result { + let file = std::fs::read(path)?; + + let file = poppler::Document::from_data(file.as_slice(), None).unwrap(); + + let mut out = Vec::::new(); + + for index in 0..file.n_pages() { + out.push( + file.page(index) + .ok_or(anyhow!("Couldn't retrieve page {index}"))? + .text() + .ok_or(anyhow!("Couldn't retrieve text from page {index}"))? + .to_string(), + ) + } + + Ok(out.join(" ")) +} From a9cfdbd2818130fdb036b5abf75e13feab073f0c Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Sun, 24 Dec 2023 23:15:50 -0300 Subject: [PATCH 08/18] indexando documentos por fin???? --- indexer/README.md | 9 +++++++++ indexer/src/main.rs | 14 +++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 indexer/README.md diff --git a/indexer/README.md b/indexer/README.md new file mode 100644 index 0000000..e46413c --- /dev/null +++ b/indexer/README.md @@ -0,0 +1,9 @@ +# Indexer + +## Dependencias + +Esta wea requiere algunas librerias de sistema debido a que depende de Poppler. + +```shell +sudo apt install libcairo2-dev libpoppler-dev libpoppler-glib-dev +``` diff --git a/indexer/src/main.rs b/indexer/src/main.rs index fa05b16..05c744b 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -13,13 +13,25 @@ struct Args { fn process_buf(buf: String) -> HashMap { let mut terms = HashMap::::new(); + buf.split(|c: char| c.is_whitespace()) + .map(|w| w.to_lowercase()) + .for_each(|word| { + if let Some(counter) = terms.get(&word) { + terms.insert(String::from(word), counter + 1); + } else { + terms.insert(String::from(word), 1); + } + }); + terms } fn main() -> anyhow::Result<()> { let args = Args::parse(); - println!("{}", pdf::read_file(&args.path)?); + let map = process_buf(pdf::read_file(&args.path)?); + + println!("{map:?}"); Ok(()) } From 984170f425d424e93497e1a29d51009c55617a9e Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Mon, 25 Dec 2023 10:36:10 -0300 Subject: [PATCH 09/18] Terminos mas frecuentes por documento --- indexer/src/main.rs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/indexer/src/main.rs b/indexer/src/main.rs index 05c744b..4e4a6d2 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -15,23 +15,39 @@ fn process_buf(buf: String) -> HashMap { buf.split(|c: char| c.is_whitespace()) .map(|w| w.to_lowercase()) - .for_each(|word| { - if let Some(counter) = terms.get(&word) { - terms.insert(String::from(word), counter + 1); - } else { - terms.insert(String::from(word), 1); - } + // TODO: Reemplazar el map de abajo por un Lexer + .map(|w| w.chars().filter(|c| c.is_alphanumeric()).collect()) + .for_each(|word: String| { + let counter = terms.get(&word).unwrap_or(&0) + 1; + terms.insert(String::from(word), counter); }); terms } +#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] +struct Term { + frecuency: u32, + word: String, +} + fn main() -> anyhow::Result<()> { let args = Args::parse(); let map = process_buf(pdf::read_file(&args.path)?); - println!("{map:?}"); + let mut top = map + .iter() + .map(|(k, v)| Term { + word: k.clone(), + frecuency: *v, + }) + .collect::>(); + + top.sort_unstable(); + top.reverse(); + + top.iter().take(10).for_each(|t| println!("{t:?}")); Ok(()) } From b62dbbc5e690b244c5a609f3238f72fbbc746e27 Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Mon, 25 Dec 2023 23:09:41 -0300 Subject: [PATCH 10/18] Lexer terminado --- indexer/src/lexer.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++ indexer/src/main.rs | 21 +++++++------ 2 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 indexer/src/lexer.rs diff --git a/indexer/src/lexer.rs b/indexer/src/lexer.rs new file mode 100644 index 0000000..f2b90b4 --- /dev/null +++ b/indexer/src/lexer.rs @@ -0,0 +1,74 @@ +#[derive(Debug)] +pub struct Lexer<'a>(pub &'a str); + +impl<'a> Iterator for Lexer<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option { + self.0 = self.0.trim(); + + let chars = self.0.chars().collect::>(); + + match chars.first() { + None => None, + Some(c) if c.is_alphabetic() => { + let mut n = 0; + while chars.get(n).is_some() && chars.get(n).unwrap().is_alphanumeric() { + n += 1; + } + + let res = &self.0[0..n]; + self.0 = &self.0[n..]; + + Some(res) + } + Some(c) if c.is_numeric() => { + let mut n = 0; + while chars.get(n).is_some() && chars.get(n).unwrap().is_numeric() { + n += 1; + } + + let res = &self.0[0..n]; + self.0 = &self.0[n..]; + + Some(res) + } + Some(_) => { + let Some(n) = self.0.char_indices().map(|(i, _)| i).nth(1) else { + // Este es un edge case. En caso de que el ultimo caracter sea un caracter no + // alfanumerico, retorno lo que queda de string nomas. + let res = self.0; + self.0 = ""; + return Some(res); + }; + + let res = &self.0[0..n]; + self.0 = &self.0[n..]; + + Some(res) + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn gets_basic_lex() { + let string = "Hello, world."; + let tokens = Lexer(string).collect::>(); + + assert_eq!(tokens, vec!["Hello", ",", "world", "."]); + } + + #[test] + fn working_with_numbers() { + let string = "1234, alfa12 CR7 Ho-18"; + + let tokens = Lexer(string).collect::>(); + + assert_eq!(tokens, vec!["1234", ",", "alfa12", "CR7", "Ho", "-", "18"]); + } +} diff --git a/indexer/src/main.rs b/indexer/src/main.rs index 4e4a6d2..7162363 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -1,9 +1,11 @@ //! Indexador de documentos para plataforma estudiantil, utilizando la estrategia TF-IDF +mod lexer; mod pdf; use std::collections::HashMap; use clap::Parser; +use lexer::Lexer; #[derive(Parser, Debug)] struct Args { @@ -13,14 +15,12 @@ struct Args { fn process_buf(buf: String) -> HashMap { let mut terms = HashMap::::new(); - buf.split(|c: char| c.is_whitespace()) - .map(|w| w.to_lowercase()) - // TODO: Reemplazar el map de abajo por un Lexer - .map(|w| w.chars().filter(|c| c.is_alphanumeric()).collect()) - .for_each(|word: String| { - let counter = terms.get(&word).unwrap_or(&0) + 1; - terms.insert(String::from(word), counter); - }); + Lexer(&buf).for_each(|word| { + let counter = terms.get(&String::from(word)).unwrap_or(&0) + 1; + terms.insert(word.to_owned(), counter); + }); + + println!("{:?}", Lexer(&buf).collect::>()); terms } @@ -47,7 +47,10 @@ fn main() -> anyhow::Result<()> { top.sort_unstable(); top.reverse(); - top.iter().take(10).for_each(|t| println!("{t:?}")); + println!("-------- Hottest words -----------"); + top.iter() + .take(10) + .for_each(|t| println!("{t:?} - {:?}", t.word.bytes())); Ok(()) } From a1b5afa2acdce43cd3c8e756c8273766f0181fe3 Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Mon, 25 Dec 2023 23:46:58 -0300 Subject: [PATCH 11/18] Modificado pdfs de prueba --- indexer/examples/goblin.pdf | Bin 0 -> 22581 bytes indexer/examples/stallman-latex.pdf | Bin 21772 -> 0 bytes .../examples/{stallman-typ.pdf => stallman.pdf} | Bin indexer/examples/vaporeon.pdf | Bin 0 -> 22980 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 indexer/examples/goblin.pdf delete mode 100644 indexer/examples/stallman-latex.pdf rename indexer/examples/{stallman-typ.pdf => stallman.pdf} (100%) create mode 100644 indexer/examples/vaporeon.pdf diff --git a/indexer/examples/goblin.pdf b/indexer/examples/goblin.pdf new file mode 100644 index 0000000000000000000000000000000000000000..62b5e0b27158d8b8c2d250361116bbaba6e11d29 GIT binary patch literal 22581 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 Tg?0rPBq%IKz{V!8u0ZfVFYM=Y diff --git a/indexer/examples/stallman-typ.pdf b/indexer/examples/stallman.pdf similarity index 100% rename from indexer/examples/stallman-typ.pdf rename to indexer/examples/stallman.pdf diff --git a/indexer/examples/vaporeon.pdf b/indexer/examples/vaporeon.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5a74689bd7ff81be2efb1405dbc2e285625e0ed9 GIT binary patch literal 22980 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 Date: Tue, 26 Dec 2023 00:23:03 -0300 Subject: [PATCH 12/18] Upgrading lexer --- indexer/src/lexer.rs | 42 ++++++++++++++++++++++++------------------ indexer/src/main.rs | 10 +++++----- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/indexer/src/lexer.rs b/indexer/src/lexer.rs index f2b90b4..c65280b 100644 --- a/indexer/src/lexer.rs +++ b/indexer/src/lexer.rs @@ -7,31 +7,37 @@ impl<'a> Iterator for Lexer<'a> { fn next(&mut self) -> Option { self.0 = self.0.trim(); - let chars = self.0.chars().collect::>(); + let mut chars = self.0.char_indices(); - match chars.first() { + match chars.next() { None => None, - Some(c) if c.is_alphabetic() => { - let mut n = 0; - while chars.get(n).is_some() && chars.get(n).unwrap().is_alphanumeric() { - n += 1; + Some((_, c)) if c.is_alphabetic() => { + while let Some((n, c)) = chars.next() { + if !c.is_alphanumeric() { + let res = &self.0[0..n]; + self.0 = &self.0[n..]; + + return Some(res); + } } - let res = &self.0[0..n]; - self.0 = &self.0[n..]; - - Some(res) + let res = self.0; + self.0 = ""; + return Some(res); } - Some(c) if c.is_numeric() => { - let mut n = 0; - while chars.get(n).is_some() && chars.get(n).unwrap().is_numeric() { - n += 1; + Some((_, c)) if c.is_numeric() => { + while let Some((n, c)) = chars.next() { + if !c.is_numeric() { + let res = &self.0[0..n]; + self.0 = &self.0[n..]; + + return Some(res); + } } - let res = &self.0[0..n]; - self.0 = &self.0[n..]; - - Some(res) + let res = self.0; + self.0 = ""; + return Some(res); } Some(_) => { let Some(n) = self.0.char_indices().map(|(i, _)| i).nth(1) else { diff --git a/indexer/src/main.rs b/indexer/src/main.rs index 7162363..8cfb195 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -12,25 +12,25 @@ struct Args { path: std::path::PathBuf, } -fn process_buf(buf: String) -> HashMap { - let mut terms = HashMap::::new(); +fn process_buf(buf: String) -> Index { + let mut terms = Index::new(); Lexer(&buf).for_each(|word| { let counter = terms.get(&String::from(word)).unwrap_or(&0) + 1; terms.insert(word.to_owned(), counter); }); - println!("{:?}", Lexer(&buf).collect::>()); - terms } #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] struct Term { - frecuency: u32, + frecuency: usize, word: String, } +type Index = HashMap; + fn main() -> anyhow::Result<()> { let args = Args::parse(); From 66dc7b52fa7dc4cd2c1339c9899076dcac744371 Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Tue, 26 Dec 2023 23:37:29 -0300 Subject: [PATCH 13/18] Procesar carpetas --- indexer/src/main.rs | 52 ++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/indexer/src/main.rs b/indexer/src/main.rs index 8cfb195..243edaf 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -2,8 +2,9 @@ mod lexer; mod pdf; -use std::collections::HashMap; +use std::{collections::HashMap, path::PathBuf}; +use anyhow::anyhow; use clap::Parser; use lexer::Lexer; @@ -23,6 +24,17 @@ fn process_buf(buf: String) -> Index { terms } +fn read_file(p: &PathBuf) -> anyhow::Result { + if let Some(ext) = p.extension() { + match ext.to_str() { + Some("pdf") => pdf::read_file(p), + _ => unimplemented!(), + } + } else { + Err(anyhow!("Couldn't get file extension of {p:?}")) + } +} + #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] struct Term { frecuency: usize, @@ -34,23 +46,33 @@ type Index = HashMap; fn main() -> anyhow::Result<()> { let args = Args::parse(); - let map = process_buf(pdf::read_file(&args.path)?); + let mut indexes = HashMap::new(); - let mut top = map - .iter() - .map(|(k, v)| Term { - word: k.clone(), - frecuency: *v, - }) - .collect::>(); + match args.path { + p if p.is_dir() => { + std::fs::read_dir(p)? + .filter_map(Result::ok) + .for_each(|file| { + if let Ok(content) = read_file(&file.path()) { + let map = process_buf(content); - top.sort_unstable(); - top.reverse(); + indexes.insert(file.path(), map); + } + }); + } + p if p.is_file() => { + if let Ok(content) = read_file(&p) { + let map = process_buf(content); - println!("-------- Hottest words -----------"); - top.iter() - .take(10) - .for_each(|t| println!("{t:?} - {:?}", t.word.bytes())); + indexes.insert(p, map); + } + } + _ => unreachable!(), + } + + indexes.iter().for_each(|(a, b)| { + println!("{a:?} : {b:?}\n"); + }); Ok(()) } From 3bfc304a965656c96f9f1a9d3d3fd23868cc4999 Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Sat, 30 Dec 2023 23:56:51 -0300 Subject: [PATCH 14/18] Agregada prueba a superar --- indexer/src/lexer.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/indexer/src/lexer.rs b/indexer/src/lexer.rs index c65280b..8027487 100644 --- a/indexer/src/lexer.rs +++ b/indexer/src/lexer.rs @@ -77,4 +77,21 @@ mod test { assert_eq!(tokens, vec!["1234", ",", "alfa12", "CR7", "Ho", "-", "18"]); } + + #[test] + fn multiple_paragraphs() { + let input = r#"Este es un parrafo. + Este es otro parra- + fo, que es acortado."#; + + let tokens = Lexer(input).collect::>(); + + assert_eq!( + tokens, + vec![ + "Este", "es", "un", "parrafo", ".", "Este", "es", "otro", "parrafo", ",", "que", + "es", "acortado", "." + ] + ); + } } From d1253cf7aa966da176cb64f43f2cffcaf8235d90 Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Mon, 1 Jan 2024 11:53:30 -0300 Subject: [PATCH 15/18] =?UTF-8?q?Este=20si=20es=20el=20lexer=20que=20so?= =?UTF-8?q?=C3=B1=C3=A9=20ctm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- indexer/src/lexer.rs | 99 +++++++++++++++++--------------------------- indexer/src/main.rs | 4 +- 2 files changed, 40 insertions(+), 63 deletions(-) diff --git a/indexer/src/lexer.rs b/indexer/src/lexer.rs index 8027487..b68f472 100644 --- a/indexer/src/lexer.rs +++ b/indexer/src/lexer.rs @@ -1,59 +1,36 @@ -#[derive(Debug)] -pub struct Lexer<'a>(pub &'a str); +pub struct Lexer { + input: String, +} + +impl<'a> Lexer { + pub fn new(input: &'a str) -> Self { + let input = input.replace("-\n", "").replace("\n", " "); + + Lexer { input } + } +} -impl<'a> Iterator for Lexer<'a> { - type Item = &'a str; +impl<'a> Iterator for Lexer { + type Item = String; fn next(&mut self) -> Option { - self.0 = self.0.trim(); - - let mut chars = self.0.char_indices(); - - match chars.next() { - None => None, - Some((_, c)) if c.is_alphabetic() => { - while let Some((n, c)) = chars.next() { - if !c.is_alphanumeric() { - let res = &self.0[0..n]; - self.0 = &self.0[n..]; - - return Some(res); - } - } - - let res = self.0; - self.0 = ""; - return Some(res); - } - Some((_, c)) if c.is_numeric() => { - while let Some((n, c)) = chars.next() { - if !c.is_numeric() { - let res = &self.0[0..n]; - self.0 = &self.0[n..]; - - return Some(res); - } - } - - let res = self.0; - self.0 = ""; - return Some(res); - } - Some(_) => { - let Some(n) = self.0.char_indices().map(|(i, _)| i).nth(1) else { - // Este es un edge case. En caso de que el ultimo caracter sea un caracter no - // alfanumerico, retorno lo que queda de string nomas. - let res = self.0; - self.0 = ""; - return Some(res); - }; - - let res = &self.0[0..n]; - self.0 = &self.0[n..]; - - Some(res) - } + let (word, new) = self + .input + .split_once(" ") + .unwrap_or((self.input.as_str(), "")); + + if word == "" { + return None; } + + let word = word + .chars() + .filter(|c| c.is_alphabetic()) + .collect::(); + + self.input = new.trim().to_owned(); + + Some(word.to_lowercase()) } } @@ -64,33 +41,33 @@ mod test { #[test] fn gets_basic_lex() { let string = "Hello, world."; - let tokens = Lexer(string).collect::>(); + let tokens = Lexer::new(string).filter(|s| s.ne("")).collect::>(); - assert_eq!(tokens, vec!["Hello", ",", "world", "."]); + assert_eq!(tokens, vec!["Hello", "world"]); } #[test] fn working_with_numbers() { let string = "1234, alfa12 CR7 Ho-18"; - let tokens = Lexer(string).collect::>(); + let tokens = Lexer::new(string).filter(|s| s.ne("")).collect::>(); - assert_eq!(tokens, vec!["1234", ",", "alfa12", "CR7", "Ho", "-", "18"]); + assert_eq!(tokens, vec!["alfa", "CR", "Ho"]); } #[test] fn multiple_paragraphs() { let input = r#"Este es un parrafo. - Este es otro parra- - fo, que es acortado."#; +Este es otro parra- +fo, que es acortado."#; - let tokens = Lexer(input).collect::>(); + let tokens = Lexer::new(input).filter(|s| s.ne("")).collect::>(); assert_eq!( tokens, vec![ - "Este", "es", "un", "parrafo", ".", "Este", "es", "otro", "parrafo", ",", "que", - "es", "acortado", "." + "Este", "es", "un", "parrafo", "Este", "es", "otro", "parrafo", "que", "es", + "acortado", ] ); } diff --git a/indexer/src/main.rs b/indexer/src/main.rs index 243edaf..659d808 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -16,8 +16,8 @@ struct Args { fn process_buf(buf: String) -> Index { let mut terms = Index::new(); - Lexer(&buf).for_each(|word| { - let counter = terms.get(&String::from(word)).unwrap_or(&0) + 1; + Lexer::new(&buf).for_each(|word| { + let counter = terms.get(&String::from(&word)).unwrap_or(&0) + 1; terms.insert(word.to_owned(), counter); }); From 0b162d99da851491b4ef80ba3c4f3726abb57c3e Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Mon, 1 Jan 2024 21:48:25 -0300 Subject: [PATCH 16/18] Ya, no webeo mas con el lexer. --- indexer/src/lexer.rs | 49 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/indexer/src/lexer.rs b/indexer/src/lexer.rs index b68f472..c0c9ddb 100644 --- a/indexer/src/lexer.rs +++ b/indexer/src/lexer.rs @@ -1,3 +1,11 @@ +//! Lexeador de palabras naturales. +//! +//! A partir de un string, extrae todas las palabras naturales de este. Se toma como palabra +//! natural cualquier conjunto de caracteres alfabeticos. Debido a esto, nos interesa +//! principalmente filtrar cualquier numero de estos tokens. +//! +//! Se recomienda mirar las pruebas para entender el funcionamiento de este lexer. + pub struct Lexer { input: String, } @@ -14,22 +22,33 @@ impl<'a> Iterator for Lexer { type Item = String; fn next(&mut self) -> Option { + // Separo por el siguiente espacio. let (word, new) = self .input .split_once(" ") .unwrap_or((self.input.as_str(), "")); + // El input estaba vacio, no quedan palabras. if word == "" { return None; } + // Filtro y obtengo las letras. let word = word .chars() .filter(|c| c.is_alphabetic()) .collect::(); + // Quito espacios que existieran al inicio, por si acaso. self.input = new.trim().to_owned(); + // Tokens que solo contienen numeros quedan vacios con el filtro anterior, + // por lo que retorno la siguiente palabra. + if word == "" { + return self.next(); + } + + // Si salio todo bien, retorno el token. Some(word.to_lowercase()) } } @@ -41,18 +60,18 @@ mod test { #[test] fn gets_basic_lex() { let string = "Hello, world."; - let tokens = Lexer::new(string).filter(|s| s.ne("")).collect::>(); + let tokens = Lexer::new(string).collect::>(); - assert_eq!(tokens, vec!["Hello", "world"]); + assert_eq!(tokens, vec!["hello", "world"]); } #[test] fn working_with_numbers() { let string = "1234, alfa12 CR7 Ho-18"; - let tokens = Lexer::new(string).filter(|s| s.ne("")).collect::>(); + let tokens = Lexer::new(string).collect::>(); - assert_eq!(tokens, vec!["alfa", "CR", "Ho"]); + assert_eq!(tokens, vec!["alfa", "cr", "ho"]); } #[test] @@ -61,14 +80,32 @@ mod test { Este es otro parra- fo, que es acortado."#; - let tokens = Lexer::new(input).filter(|s| s.ne("")).collect::>(); + let tokens = Lexer::new(input).collect::>(); assert_eq!( tokens, vec![ - "Este", "es", "un", "parrafo", "Este", "es", "otro", "parrafo", "que", "es", + "este", "es", "un", "parrafo", "este", "es", "otro", "parrafo", "que", "es", "acortado", ] ); } + + #[test] + fn none_on_numbers() { + let input = "11 13 69 420"; + + let tokens = Lexer::new(input).collect::>(); + + assert_eq!(tokens, Vec::::new()); + } + + #[test] + fn splitted_words() { + let input = "hol-12492835a"; + + let tokens = Lexer::new(input).collect::>(); + + assert_eq!(tokens, vec!["hola"]); + } } From 90060ee47cc62392c11b01e20ca3c23d7b9a1ae0 Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Wed, 14 Feb 2024 10:46:38 -0300 Subject: [PATCH 17/18] IDF Implemented as in, Inverse Document Frequency. --- indexer/src/main.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/indexer/src/main.rs b/indexer/src/main.rs index 659d808..b8fbcf5 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -70,9 +70,25 @@ fn main() -> anyhow::Result<()> { _ => unreachable!(), } - indexes.iter().for_each(|(a, b)| { - println!("{a:?} : {b:?}\n"); + let mut idf = indexes.iter().fold(HashMap::new(), |mut acc, (_, e)| { + for (term, _) in e.iter() { + let found = acc.get(term).unwrap_or(&0.0) + 1.0; + acc.insert(term.clone(), found); + } + acc }); + let docs = indexes.len(); + + println!("{idf:?}"); + println!("'Linux' term: {linux:?}", linux = idf.get("linux")); + + for (_, i) in idf.iter_mut() { + *i = (docs as f64 / *i as f64).ln(); + } + + println!("{idf:?}"); + println!("'Linux' term: {linux:?}", linux = idf.get("linux")); + Ok(()) } From 069ce104eb933d6df88b0ff5d1f2925850fcc1ab Mon Sep 17 00:00:00 2001 From: Rafael Morales Date: Sat, 9 Mar 2024 21:06:30 -0300 Subject: [PATCH 18/18] TF-IDF implementado --- indexer/src/main.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/indexer/src/main.rs b/indexer/src/main.rs index b8fbcf5..96439ba 100644 --- a/indexer/src/main.rs +++ b/indexer/src/main.rs @@ -10,7 +10,11 @@ use lexer::Lexer; #[derive(Parser, Debug)] struct Args { + #[arg(help = "Archivo o directorio por el cual buscar.")] path: std::path::PathBuf, + + #[arg(short, long, help = "Termino por el que hacer la busqueda.")] + term: Option, } fn process_buf(buf: String) -> Index { @@ -28,7 +32,7 @@ fn read_file(p: &PathBuf) -> anyhow::Result { if let Some(ext) = p.extension() { match ext.to_str() { Some("pdf") => pdf::read_file(p), - _ => unimplemented!(), + _ => Err(anyhow!("Not implemented or invalid file")), } } else { Err(anyhow!("Couldn't get file extension of {p:?}")) @@ -70,6 +74,7 @@ fn main() -> anyhow::Result<()> { _ => unreachable!(), } + let docs = indexes.len(); let mut idf = indexes.iter().fold(HashMap::new(), |mut acc, (_, e)| { for (term, _) in e.iter() { let found = acc.get(term).unwrap_or(&0.0) + 1.0; @@ -78,17 +83,21 @@ fn main() -> anyhow::Result<()> { acc }); - let docs = indexes.len(); - - println!("{idf:?}"); - println!("'Linux' term: {linux:?}", linux = idf.get("linux")); - for (_, i) in idf.iter_mut() { *i = (docs as f64 / *i as f64).ln(); } - println!("{idf:?}"); - println!("'Linux' term: {linux:?}", linux = idf.get("linux")); + // Si se introdujo un termino de busca, imprimo + // cuales son los documentos mas relevantes. + if let Some(search) = args.term { + let search = search.to_lowercase(); + indexes.iter().for_each(|(path, index)| { + println!( + "{path:?} - {}", + *index.get(&search).unwrap_or(&0) as f64 * idf.get(&search).unwrap_or(&0.0) + ); + }); + } Ok(()) }