pax_global_header00006660000000000000000000000064152115716400014514gustar00rootroot0000000000000052 comment=c3b864518a20c770e1a1d36576fdb1024287b5d9 disgreet-0.1.1/000077500000000000000000000000001521157164000133215ustar00rootroot00000000000000disgreet-0.1.1/.gitignore000066400000000000000000000003521521157164000153110ustar00rootroot00000000000000/target *.deb *.buildinfo *.changes *.dsc *.tar.xz *.tar.gz debian/.debhelper/ debian/debhelper-build-stamp debian/disgreet/ debian/disgreet-dbgsym/ debian/files debian/*.substvars debian/tmp/ debian/cargo_home .cargo-checksum.json disgreet-0.1.1/Cargo.lock000066400000000000000000001416521521157164000152370ustar00rootroot00000000000000# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "adler2" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aligned" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" dependencies = [ "as-slice", ] [[package]] name = "aligned-vec" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" dependencies = [ "equator", ] [[package]] name = "allocator-api2" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "anstream" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", "windows-sys 0.61.2", ] [[package]] name = "anyhow" version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "arbitrary" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" [[package]] name = "arg_enum_proc_macro" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "as-slice" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" dependencies = [ "stable_deref_trait", ] [[package]] name = "autocfg" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "av-scenechange" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" dependencies = [ "aligned", "anyhow", "arg_enum_proc_macro", "arrayvec", "log", "num-rational", "num-traits", "pastey", "rayon", "thiserror", "v_frame", "y4m", ] [[package]] name = "av1-grain" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" dependencies = [ "anyhow", "arrayvec", "log", "nom", "num-rational", "v_frame", ] [[package]] name = "avif-serialize" version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38" dependencies = [ "arrayvec", ] [[package]] name = "bit_field" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" [[package]] name = "bitflags" version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" [[package]] name = "bitstream-io" version = "4.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f" dependencies = [ "no_std_io2", ] [[package]] name = "built" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" [[package]] name = "bumpalo" version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "bytemuck" version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "byteorder-lite" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "cassowary" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] name = "castaway" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" dependencies = [ "rustversion", ] [[package]] name = "cc" version = "1.2.63" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" dependencies = [ "find-msvc-tools", "jobserver", "libc", "shlex", ] [[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "clap" version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_derive" version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", "quote", "syn", ] [[package]] name = "clap_lex" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "color_quant" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "compact_str" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fd622ebbb56a5b2ccb651b32b911cdeb2a9b4b11776b2473bf26a26a286244e" dependencies = [ "castaway", "cfg-if", "itoa", "rustversion", "ryu", "static_assertions", ] [[package]] name = "const-random" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ "const-random-macro", ] [[package]] name = "const-random-macro" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ "getrandom 0.2.17", "once_cell", "tiny-keccak", ] [[package]] name = "crc32fast" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-deque" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ "bitflags", "crossterm_winapi", "libc", "mio 0.8.11", "parking_lot", "signal-hook", "signal-hook-mio", "winapi", ] [[package]] name = "crossterm" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ "bitflags", "crossterm_winapi", "mio 1.2.1", "parking_lot", "rustix", "signal-hook", "signal-hook-mio", "winapi", ] [[package]] name = "crossterm_winapi" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] [[package]] name = "crunchy" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "darling" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ "darling_core", "darling_macro", ] [[package]] name = "darling_core" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", "syn", ] [[package]] name = "darling_macro" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", "syn", ] [[package]] name = "deranged" version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", ] [[package]] name = "disgreet" version = "0.1.1" dependencies = [ "anyhow", "clap", "crossterm 0.27.0", "image", "log", "ratatui", "rust-ini", "serde_json", "simplelog", "thiserror", ] [[package]] name = "dlv-list" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" dependencies = [ "const-random", ] [[package]] name = "either" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" [[package]] name = "equator" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" dependencies = [ "equator-macro", ] [[package]] name = "equator-macro" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys 0.61.2", ] [[package]] name = "exr" version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" dependencies = [ "bit_field", "half", "lebe", "miniz_oxide", "rayon-core", "smallvec", "zune-inflate", ] [[package]] name = "fax" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" [[package]] name = "fdeflate" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" dependencies = [ "simd-adler32", ] [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flate2" version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "getrandom" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "getrandom" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", "wasip2", ] [[package]] name = "gif" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" dependencies = [ "color_quant", "weezl", ] [[package]] name = "half" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", "zerocopy", ] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", "equivalent", "foldhash", ] [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "image" version = "0.25.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" dependencies = [ "bytemuck", "byteorder-lite", "color_quant", "exr", "gif", "image-webp", "moxcms", "num-traits", "png", "qoi", "ravif", "rayon", "rgb", "tiff", "zune-core 0.5.1", "zune-jpeg 0.5.15", ] [[package]] name = "image-webp" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" dependencies = [ "byteorder-lite", "quick-error", ] [[package]] name = "imgref" version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89194689a993ab15268672e99e7b0e19da2da3268ac682e8f02d29d4d1434cd7" [[package]] name = "indoc" version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" dependencies = [ "rustversion", ] [[package]] name = "instability" version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6778b0196eefee7df739db78758e5cf9b37412268bfa5650bfeed028aed20d9c" dependencies = [ "darling", "indoc", "proc-macro2", "quote", "syn", ] [[package]] name = "interpolate_name" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itertools" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jobserver" version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ "getrandom 0.3.4", "libc", ] [[package]] name = "lebe" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libfuzzer-sys" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" dependencies = [ "arbitrary", "cc", ] [[package]] name = "linux-raw-sys" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "lock_api" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ "scopeguard", ] [[package]] name = "log" version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f" [[package]] name = "loop9" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" dependencies = [ "imgref", ] [[package]] name = "lru" version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ "hashbrown 0.15.5", ] [[package]] name = "maybe-rayon" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ "cfg-if", "rayon", ] [[package]] name = "memchr" version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]] name = "miniz_oxide" version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", "simd-adler32", ] [[package]] name = "mio" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi", "windows-sys 0.48.0", ] [[package]] name = "mio" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "log", "wasi", "windows-sys 0.61.2", ] [[package]] name = "moxcms" version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" dependencies = [ "num-traits", "pxfm", ] [[package]] name = "new_debug_unreachable" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "no_std_io2" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "418abd1b6d34fbf6cae440dc874771b0525a604428704c76e48b29a5e67b8003" dependencies = [ "memchr", ] [[package]] name = "nom" version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" dependencies = [ "memchr", ] [[package]] name = "noop_proc_macro" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" [[package]] name = "num-bigint" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", ] [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-derive" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "num-integer" version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ "num-traits", ] [[package]] name = "num-rational" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ "num-bigint", "num-integer", "num-traits", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "num_threads" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] [[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "ordered-multimap" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" dependencies = [ "dlv-list", "hashbrown 0.14.5", ] [[package]] name = "parking_lot" version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-link", ] [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pastey" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" [[package]] name = "png" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ "bitflags", "crc32fast", "fdeflate", "flate2", "miniz_oxide", ] [[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.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro2" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" dependencies = [ "profiling-procmacros", ] [[package]] name = "profiling-procmacros" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" dependencies = [ "quote", "syn", ] [[package]] name = "pxfm" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" [[package]] name = "qoi" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" dependencies = [ "bytemuck", ] [[package]] name = "quick-error" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quote" version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] [[package]] name = "ratatui" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d" dependencies = [ "bitflags", "cassowary", "compact_str", "crossterm 0.28.1", "instability", "itertools 0.13.0", "lru", "paste", "strum", "strum_macros", "unicode-segmentation", "unicode-truncate", "unicode-width", ] [[package]] name = "rav1e" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" dependencies = [ "aligned-vec", "arbitrary", "arg_enum_proc_macro", "arrayvec", "av-scenechange", "av1-grain", "bitstream-io", "built", "cfg-if", "interpolate_name", "itertools 0.14.0", "libc", "libfuzzer-sys", "log", "maybe-rayon", "new_debug_unreachable", "noop_proc_macro", "num-derive", "num-traits", "paste", "profiling", "rand", "rand_chacha", "simd_helpers", "thiserror", "v_frame", "wasm-bindgen", ] [[package]] name = "ravif" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285" dependencies = [ "avif-serialize", "imgref", "loop9", "quick-error", "rav1e", "rayon", "rgb", ] [[package]] name = "rayon" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "redox_syscall" version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "rgb" version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" [[package]] name = "rust-ini" version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" dependencies = [ "cfg-if", "ordered-multimap", ] [[package]] name = "rustix" version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", "windows-sys 0.59.0", ] [[package]] name = "rustversion" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", ] [[package]] name = "serde_core" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", "serde", "serde_core", "zmij", ] [[package]] name = "shlex" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", ] [[package]] name = "signal-hook-mio" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" dependencies = [ "libc", "mio 0.8.11", "mio 1.2.1", "signal-hook", ] [[package]] name = "signal-hook-registry" version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ "errno", "libc", ] [[package]] name = "simd-adler32" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "simd_helpers" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" dependencies = [ "quote", ] [[package]] name = "simplelog" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" dependencies = [ "log", "termcolor", "time", ] [[package]] name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", "syn", ] [[package]] name = "syn" version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "thiserror" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tiff" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" dependencies = [ "fax", "flate2", "half", "quick-error", "weezl", "zune-jpeg 0.4.21", ] [[package]] name = "time" version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" dependencies = [ "deranged", "itoa", "libc", "num-conv", "num_threads", "powerfmt", "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" [[package]] name = "time-macros" version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" dependencies = [ "num-conv", "time-core", ] [[package]] name = "tiny-keccak" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" dependencies = [ "crunchy", ] [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-truncate" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ "itertools 0.13.0", "unicode-segmentation", "unicode-width", ] [[package]] name = "unicode-width" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "v_frame" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" dependencies = [ "aligned-vec", "num-traits", "wasm-bindgen", ] [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] [[package]] name = "weezl" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ "windows-sys 0.61.2", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ "windows-targets 0.52.6", ] [[package]] name = "windows-sys" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "y4m" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" [[package]] name = "zerocopy" version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" [[package]] name = "zune-core" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" [[package]] name = "zune-core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" [[package]] name = "zune-inflate" version = "0.2.54" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" dependencies = [ "simd-adler32", ] [[package]] name = "zune-jpeg" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ "zune-core 0.4.12", ] [[package]] name = "zune-jpeg" version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" dependencies = [ "zune-core 0.5.1", ] disgreet-0.1.1/Cargo.toml000066400000000000000000000005711521157164000152540ustar00rootroot00000000000000[package] name = "disgreet" version = "0.1.1" edition = "2024" [dependencies] anyhow = "1.0.95" clap = { version = "4.5.23", features = ["derive"] } crossterm = ">=0.27, < 0.30" image = "0.25.5" log = { version = "0.4.26", features = ["release_max_level_info"] } ratatui = ">= 0.28, < 0.31" rust-ini = "0.21.1" serde_json = "1.0.139" simplelog = "0.12.2" thiserror = "2.0.11" disgreet-0.1.1/LICENSE000066400000000000000000000261351521157164000143350ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. disgreet-0.1.1/README.md000066400000000000000000000041401521157164000145770ustar00rootroot00000000000000# Disgreet A sleek, keyboard-driven TUI greeter for [greetd](https://git.sr.ht/~kennylevinsen/greetd), written in Rust. Background images welcome. ![screenshot](screenshot.png) ## Usage ```bash # Show help disgreet -h # Launch with a background image (converted to terminal pixel art) disgreet -b /etc/greetd/background.png ``` > **Note:** The `_greetd` user must have read permission on the image file. Placing it under `/etc/greetd/` is recommended. ### Keyboard controls | Key | Action | | ----- | ------------------------------------------ | | Tab | Cycle focus (Session → Username → Password) | | ← / → | Switch between desktop sessions | | Enter | Log in | | Esc | Exit *(debug builds only)* | ## Prerequisites ### Core dependency - [greetd](https://git.sr.ht/~kennylevinsen/greetd) ### Recommended for TTY Without these, the TTY is limited to 16 colors: - [cage](https://github.com/cage-kiosk/cage) — minimal Wayland compositor (kiosk mode) - [alacritty](https://github.com/alacritty/alacritty) — GPU-accelerated terminal emulator `cage -s -- alacritty -e ./target/debug/disgreet -b /path/to/image.png` ### Directories Two directories must exist and be owned by the `_greetd` user: | Path | Purpose | | ----------------------- | ------------------------ | | `/var/cache/disgreet/` | Cached background images | | `/var/log/disgreet/` | Application logs | ```bash sudo mkdir -p /var/cache/disgreet /var/log/disgreet sudo chown _greetd:_greetd /var/cache/disgreet /var/log/disgreet ``` ## Installation ### Build from source ```bash git clone https://github.com/dvorakchen/disgreet.git cd disgreet cargo build --release sudo cp target/release/disgreet /usr/local/bin/ ``` ### Configure greetd In `/etc/greetd/config.toml`, set disgreet as the default session: ```toml [terminal] vt = 1 [default_session] command = "cage -s -- alacritty -e /usr/local/bin/disgreet -b path/to/your/image.png" user = "_greetd" ``` ## License [Apache 2.0](LICENSE) disgreet-0.1.1/screenshot.png000066400000000000000000002103241521157164000162060ustar00rootroot00000000000000PNG  IHDR @:ΌIDATxOϜ {X[VPJnE@;uu]ي03gfN]^:sT~I$I$I$IR(0@A P`0 a(0@A P`0 a(0@A "R}aR T_Tn,N r\'UH ߅Vu0ҳ$)}O{$?[J ӰJϢ/J ve0޿4ڿ$U_T_T* ',MZ;,ihxU҂E[% /:imVmwIW^~U%]tԑGq\;G1iꝒVl¨mvIZNI9iVK _wxYYg^t%xyIeԹ&eoNj'I:,?wR~iIN8墤9#M:昳=¤I;䤋/.S.I˓I:>洤O0/H:䈳+˕嫶On]vIzn+I7rw=_zwܟtoO滓<褷CIoׇ^%msV#ͤ&Ƿ$ 'JI'zGIc%-% &UIzޑtϞ'}&Ѥ~I=IeSvvkIo{Ւ=IqPWMIyǓ$ܝ^'X$\O˓^W$-XԟԮ$=E%MlNzϋ_tI%GI3J+;|04?;4לK8)|(ix`қ^Kk^ sͤmI/aUһvXR;ooys?>tm'>v4>5vƤvw~~>5ۇK815>4;>8SꔓNHRRJ6ڢ+fgIZ%g(0@A P`0 a(0@A P`0 a(0@A P`0 Ljw;In9Y<6:RRUm&5ۭZvͺLVKZ`0鵙鉩`p/Rm'k=In%ijz&R%'͵IkYTi$LL%%-lIO=>ibl2iNj %u:EIV')ʎsIr9R&mKZzERMI*IцM#IFopv:>:4955>tKͤv6iϽvOۺtݗTT&&JJԺZt%{QIwm&m)iFx/Z=Kz?MߚtaLsoK:vE#3?I9I?ae˖&wMjV&vn-I {ZKzGdR=tʻIڼi2ߟT'ƧFgƓvEI[7%q~ӟ&uIGIJ21ϷrI;.{Y|gA{=iYfq& 꽽IS3I|I͟~$_'&q㷒~Ѥ٤JTuTTLfhᢤfl3 a(0@A P`0 a(0@A P`0 a(0@A P`HNIL͊ůL _vTɔڥn jTτoVP_~;iO>&mꤙ &&*RROt'-_$ij5i23IcGz?azv:zIZ%-'ͤf)R&%ժը5YIn+LLMO&$enҺu6gzF5iph inf.ZMڰq]R\J _nTvS[-jJ.-ۥn'ibbXRxO:#?|))kˎəeK$Uդ)%=g?O[ʕ,J[|ѤgIO}GIk~ߤ*R$u;RTڭVү~ i_d_ʤgI/x]_Rџ$qϗ%MΌ&mْ̆I3ͤzy$i¤׽5I .L[ЛZyΎ;$mje[JjWZO$I{ݛ.JjuIZOT|RviYȄv4k};gޒe$MfGnRRKzd\|_E'ʣ?pᢤZ433޶cI|RӛTnwfR9nmns.g(0@A P`0 a(0@A P`0 a(0@A P`0 rR7StUON괓7!*JR9h$NIL'Ӛo&=~4٭$͵KIϬߒ7(i\\~hRTMN*{&'~μ3.>?K.L:N9 ,sJ:sι袤?T괓Q9J*wIV'֨%Uݤё N|R\N OcI0i璶Z* i5Iٰ>^%7gzlR^IvZIϬ_^դ餱j47N9'mᤙىs_xRMj4jIKj:IyVR\JZji̚IN9?&jd$9>qN4v2ij~*iEV.:i(3ycROoR;>&.IIy7N;$*ѹNIM\9//.M:sλ;II͹\7$ZLJ*KIR7驧KdRRx^o%&uzUKMLj6璺%'UJ夞z-[&MLM&e'f$-X0Y=Ir9ޓ4114;KMJTN43?䓏'5zISsIqm%_k:̆IOkQnTs>i.ӞOzO=xx8iƑz70419^3 &͆N;ٜOJÏ'mOZ$e&d槧^w璪n429TU$-K(גzդW?IJ5ۚN ML$ʝ,} Ia0U&UF7'pj*K?tl6i[߰, ڤӿyNҋ_5I;~ssakOZ1 ?I}}IK-McK:p}nIl}ҋvzq/7I~|劤6&դv+fRSI:;&7oNHVIcIN;i󦑤DRN ٤̦&7oL aʝfRNjeETE=0 a(0@A P`0 a(0@A P`0 a(0@A P`0 x~~.i&4=4;=5346!itd]ёI3ӣQSIN'&UKFTF=V;^&u+LR54ךOܔ4754;UjO'5JݹJ4?=4;i$Qs3I\lRNzޕ4ivΤ36&u GZ.~ˤ[&6lؘ4>>4=;T&MM%mٲ)iͺIV,M^luzf瓆$-tJvj4HjI3695rŋ%=yMZ:(̂ILc')*%OH3S'}NZtYo|ɤm?{[^ڤnfd/==I2VR[JLZzmM_/iyO#U$dGVfv~6Grn+N&/:IV+ۉ™g& 'W63IͤIRw~:T)%;zvT^tW$m34i@_ϤўIҤ^tMԓQI[ 'RQRir>ԣNz;'a,+O˓8k"oMII7Iꤟ緓.<缤]IILIO>4/I3%7ISIZ#i*ӪF\TYTm $jf4l%IZRRM{FoR^OzސKTN`_ juҒEKV,_mIz 440d񲤅CCIL%3ؿ ixxIK&f:f`h`aRћy󦤵k%m<4;34=5Ͷ'edžnVOj6g:nҺuk/Z0$mI477rՊf҂TҚu$UJILvrtIIW%IW.Oz=i8imJy;% 'կIZxImJόnI.Uo~~If;\&}O{ߗ>\ {?&%sILJvIJ5j%UʥRTKtI?8 JT[}8o~+iї~GgŸҤ+.:'iIwuS_$E$m\;ԚKzdIoyۓ'| I7>/ϭIJ-m'x}I?{"KW-Ƭ.`wv~YVynKV^Iz_RrTIԒkߤOtG$pQIg|j٧FvII'}B1G׽)`)ǝtOOk8ԤO=9cM:<ᤤ#lg?\R]NJj5z6lNzǒF7oI7:RRoO#\.%Mlٜ-z3͹V &jPٚMKIR9ixp@@MGGzzI0;;d銤znUz{jIӳIk׬IZx8ixxAI'idXҦMI==I3IR'9l~(i``(iɲ%I[FjzRZKJzǓfd /H$%C zzI.Ik'=&պFTԓ&&JJR\Jv:>uazKiT$uZn^EWI ,MZ%mw$u[I'qsR[Jڲe4ݙK*II5n!}lEmM*W*IIIŤaޭ+s7?ޞtO!隟^tݜג?fU%g}4 OJz;_ Ji&$m|U%-{IΨK:]*ޤ+/4iIvRP_Rxa6ۜOIѤNRRM&ZRo_R%sAM3._Kvkn_"Z&uJݤf'꡿)TDNQ5睓ͻߞߙ{ޓޕޓ4w&MN$=|׽IOIJ=)/JO~4<0SOM:IIr;)'uj}I5I?/ZtA$2Jg?BStJRxU_1鴒SSII=A;ޜTY04j'M&'r473V,Iůf>aIN)xyүIr=tW%:Z\7>'ULqI}o$o+ir얤r['O'L$VIy*Z%MLO$U+-IϣfJ4;?t%%egLR/,Z \$6rls>i򙧓(Rj%d.ޤ#/IjTKI3cIn3iw eMtR=l3 a(0@A P`0 a(0@A P`0 a(0@A P`HɱMI[6d=iMuQ#k7>ǒ6=x3O%mdO$*iӚ'6<5YO'mZX3&mZu&tR7SՓ'ƒfoZ\IOJIS33IL$=pI7I7z[Wj 7^t 'CIT):r+۩'ͯ$͕JI{I'2@RZt>ᴤO]yYR\J+In')t'ޙUW$}UoH{2]ao/s&I;,[t& $-JZ~6_.駿j'y_Ikh&=Țd#iݺZ~ƤHVH#_}hKƤ3uƧ$I<Ϥ}xW'w{O{F뻒>'掤MI[~{OzI5Isoԟ4$MI[Ix? ioOJݽIk~gs_ a(0@A P`0 a(0@A P`0 a(0@A P`0D:/\2ihpqRࢤVF-]4pyԒI ' .ZhIKNZd˶I^:ip%+KY$wg˓J ?HCW&-X:iɊ:iѪm,*i;F>E/}M)t$5IjVI']ss׏'>Ic8( oxSҧ?o҇?򡤝_sRf¤zi֒2 .LZHZha]h8I+I=}I[NRJv:I[2cICFROo-iUKV&-Y4iMj+IK-IjIr7iТz#iŲIC}I]ߛ{%yaI'lAV3yI}aܑt5$Mz'MIcǒzʤ?pg>xKIRړT5zR\MvJIVTޗtnwp҂F|3l%O2;t'$u˥3sIO>U[ߴ:i-Jyw^[]^Iozʤ?[o`ʤ%hVIWm4rMw}+KoH{Vz;iK?4'g҂ߟO*o֤ޔ47&-{ᛒW/H]>{MI 80@A P`0 a(0@A P`0 a(0@A P`0 a(t.IZ9Z%53sN4ߜIJIZ5n%u˕ri'j3Z-/=vO:sG%u)IppGt%}CN=Ĥ>6#H:c9Z'T$ݓ &-]$wARIIR7 ?O$kIa/R&+NJJLRJIO8%i|r"izz*S.'5jr?84?4p(iٲIK/J֫I٤FRLɾ j=i4^K%K$5ޑIsfRZI*n7kK: %-_m)'IIcOoNZ80MfAffr&inn695ی&uf4]ꔣNRRNHjI{Rڗ.'}IZxiRH궺If+).+IV)S$z=h6$5I;*ZRv7*b'uGR;s_4g%M.Τ)Hҗn)i,#$ugI@R54ۗ4514im|{&i|t%N<ɤ/ݐ$Iٱ& /JZ4Izk&ǷnT&{4Xs󭤭^T*Ւ?]Ij'\4w?ipxa@R_o5$?NT&v'Xl3 a(0@A P`0 a(0@A P`0 a(0@A P`Hv4?LjejZRRM*gzj=Ir9NIn;iEeZͨ٩Vm:n޻퓴j풖-Z4yKҲKz,L~ZnLRޓCzk 듎:ȤO;'i% $դj`PRo괣ͤc9:>ԚKLM -[$iv~6/&5J|3T)%_ &&'KݤHj%%%ML&mtݤnHMOZJj[Ij%[Jkf՚OZh8n&d%}r*JRk~.T2J) 97T,_UR@olL…Ij=Q&_&iHRoO@R^Iʬ[!iICj`p(GLv*IIlk>?Hj:I=gnT̈́-񱱤P-WsIL942>TWz{f2ϬۘtpW'JݤYR)uOȆu$Z%id|TTIN7in~6Ѩ%lؘT.֯[dҤn4$wF_+,$I|jWh']ٙVRIc+vLnՋ«˿pYRx/wI_/RRZ{+UIy{R,֞)'mmjR)9%=蔒.>IJ-^T+>kRZM|I+^^ƤO9&錛Nzld"ݷ4ilr2T$:ͤSIC>kI}6Tk$]|qI4Ԯԓ[>`$+%tHҥ49IO~A%pmy_t%U>yiR\KK Ϸ-Lj撲ܐtkZSIVYld㦤!̹T*-IڭnRTNη*R9G왴t٢zRxvfv<7V+%|R8εIF#g(0@A P`0 a(0@A P`0 a(0@A P`0 ى餱Mn{U&m^XҖI[6$KjN&M$͌Em\4=1ilG{-o#_rwޑt׿tWQzܛ|/{OtJt׾{;[Ϥ_I_wt]_Mo&]s;rҍݒ෾tWt%pMI]vYҕ\t'}K7%}'}./pCwߙtE%z-I^|qe]K󒲏EgwF5]tN:㒮. ꒨2;nNIw}g%W]M ᚤSO?=O:O%_XȺ'^~{$|IsI|Rғ_9+i+| Iߖ4_J=ؤ#?ic'y4Gc'yoIZ5Vk&:ʥjR\NqەI,[ԨtԾI_ڪF~ݤ{vRo'h$U3 {܁I+:VI/}nZ_I:˓ƤJyIs}W~[a]jI7{jII/&fꋣz&Nj~5C8:i{$}҃ؤzS]W#S~tM:%}⟓lܐyڨ $mYTҦuQ|fפ~R?颣>tᑟHKӏ6+I~yKK{>7$&{wOᅱOoJZےIz-i&=߷'=0 a(0@A P`0 a(0@A P`0 a(0@A P`0 =*SL:䳓N=嬤c=-ȣ>t%sI N[,ip񊤾ށEI},K\"ih8j$}rm};{~$}w>?_^}<Izޞ^&뇒>&קw&G>'}7:|w'-]oz}ҮH=4iḨMz;ޑ{'tI{}.tġ&}SJ:$!YGeN>Ĥ#;"L:>wȡI{Gҡtι&wIII|F9g^t%s֥I'rV1taG%{ItHetI?Ĥ=&âۥNr%]x IW~KIqEROIS$褥{p<)i^&-qI:5i`ÓνڤO=?iV;$~?7)i+Aҫ_JyRRKjuIn%[$M/M*O7s!IR9iNHz'37i8ktIH:'t N;EI⤥KV&-Y:j銤%6i`ʤ嫓&|짓.8봤ji&inz.[Mے}>I/`ߗ4/DM~5MIxXҒ4㻓IߚEI~q`0 a(0@A P`0 a(0@A P`0 a(0@A P\ג2sV\RNjG -LI[+ՓZͤJTWj=rn7f3_vmu6lKJg*}:ilr"ip-[F&5撞L@__DON%N$LEuդ̒eKZ:j' 'u˕2J-)5RR+3)%5ۭ/U{JJR֓4>%5IV*ISI\ҦѤz?'u3-MjTz=jTtfj֨$=ݼ%iѤ /2+/IJI'pjGTj.-IWm")X iUINEIr#-%-\4IIj5ITIn'>_Jo5jR[w~eRIzˋߔ,wF:Iv[Y夝&iݛweۤ$&>&׽9i5I~I_W~jRxQ*Iɹ[Ϥ5=$钵O0}w&_rʺÒ{I/פRu sDF_ҧ$i=H&m^)3',^i'kJ%MlN^(i|b]Ls6iCK:N\w"ivg$UEeOMݤRS&ʭV{>m%7f;՚Oy2阣:Li' %~خIW~pRu2ZOR^K^ _~%'~{БIxpRkn>錇6%_MjkICK& 'Ii`xaIqpnf>N:?hTRRNjԒJRIV=In5\$ϿIUIr=)X oXJ%w%ƑI_Rϓk~t'7kIf)i]V$ $KI[jz٤gs_ a(0@A P`0 a(0@A P`0 a(0@A P`0D:|Ip@t衇$O&â_tR7Ө$uKV''+JӜOjIx+JvRIo$U夅 :ၤqt'pII'VT6QR7ihpRQOkIIn'[&ZI=ɩ%VғO>TUzI}դRj%$jjRR'[&i'-Y4irt,ibrTV.֤ZIk߃>}*RRIJIr;)keJR4gIf|^LM$pI'oғ>C>tM:O'vIg٤gs_ a(0@A P`0 a(0@A P`0 a(0@A P`0D:qIg#/^/ߔt']yYIW]qfuI[6>4i$ir3Iӣ7IIې4?34;%g?v҅uI_Iws_mwޓ׿/?Uߑo~+e]uEI{jO8*جCLty&sIǟttit֙'']qՕI/|ኤϟzB҅tWL9笤ˮ6鎻J/'s}I_n5鼋.L:쳓:wI_k>ۿ2K.Kʫ8ܤ>1CH:C?젤c\1G~*钋NNݘ4>5tyg%tIǝvR҆O眤7.Nz &&ؤ7Ds'N9 7NĤ/ivf:$ & '5gf/MNzKJz6K*UIwIv'Mzߑ_5546)ijlKhTdƤɤɉѤpD۲9jtCRsv2jn6inj2g(0@A P`0 a(0@A P`0 a(0@A g,n iЛHQ@, ] ;z*b.( JH$gG~9X[Ϝ^ٙggJh`ah`ahŖ$!ImE!NL:}'LJ1jѤ1.K%R+$-2nɤK$5NI|xä>.i҉g$sIN8;OMwLqvI_~OmѤ~x-"i=HI:>I2|ICBuq҅^t)&]ruIza 'taG&]xIsA1'%AIO:5ON:Ӓ?!i}N/ot$uI'Lt)&MvIOtvҮI_҄I:cIsty真t>IK,rbKZiյ.֤λ:iI`&'i:w:! & iI_86iԮg%շ:ԲK'mٖIK4gܤ2-͕b4ןT*Uz{z==S/IF-T$F[+IjҦ[lt~8&49=}I#:%̙T$ZҐ֤3g%uKꚛ4fqIݽ=IIJ=TIz2'vj҅t&pII3M;wN҈Òuw'57'H*W_K&=g.ʤo~Irty$rI=+^MZRQjNMjmH*UI{6|TRTOjFTjmjnJ!Ò}j?sEF&͙7''際MNjd?jR9i'7I[%Ԝ/&IQ%RRS ?HZfI=cvbۤCR*7%KQᵅ?k^N -))| |Z$ QI[3Ia#d@>BZے$UJMI-R%iYIm|ҧy )癟$M}sJ6W<49,}յFnR[SfgZw$ tRR%&[\|RO)kp =RiN3jw3ʓL!I|!=VZ/i^4{n5iK' ts:IՓ蘤÷8",5ҔTN'?4?qyI-Kt/gh`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`}IMLӛʫSfI%͘:=i挮W_784~ɥ&utt& I;:%ZC37;/ivRnI*j9]IO=\RQ-Z[ښ2Isv%g6,gNRKKSR{g[RSݛTԪIӧOMii$&3=IgJ i^$K̔/"ᗚ .:?.O6#^EeM;8\$U{o҅^_~?iw^ăMZfu:i&MI׼<')ޔ1rhRې!I?X$ VI3gJOjimOjomK* IȤ֤aCjJR5j񎦤J%%3onR9i T%U3Qi4bbI?4k+IrR)u?4?iOl[O'==啤֑Iz+TIH\zHZV+>z<ؤo}ekTպjjRT)'m6I7Z/nJ**E=?Q_zIJK/KܷNv٥*QꋌL>jDRBn:w&j_Tܖ=7%$uvLjJMH:muۇ&fϞ4X-' 6<){VQ)`Ro_R`9o K*=ޝ4>'i`f_˯t' ԪIZԜTNZn:ޞ֕4sX/gh`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`wuKmߐtu%囒/'yMIw}椯|֤[.J_I ߸#[oJݟZ}UZz{JMIoeZ[2m֤DJZvI3gNONzsIL{k[Rǐ!ILTIzs괤S833NN+FTI32LS~L; M;/NM:N<&%mIW\sm+ڒ4v오Jtyg'qIo=9(Ւ8츤OJ:|d$?LMJgGROQOhKZ_KZ{V~՞ igMZ$Iz{I+?ͤ7+iU=՞VG^y oߒ{oN?އHޑt$UJR9UL UZuIއv?꒤9_ ;$o|AmN7;`>0@040@040@040@040@040@HSf=gjҜYo%u͎ m7g4{I&mԤyӧ$z{rt%?N9*KNK:ԉIwZ9睒tm7&=/I?I^xVҩMJN=Ĥ9-SOt']tQ_tg/n֤I-2"-i?4u[II;!鬳NH:^xŤSҟ~6WHzkԤ^y%i[o%xkjRZO鞓T $m瓆'VKIaI~Ro%JJ@te%ΟN|tjRKє4wԤ48gnR$OrXЧ}"i짷K/I֤JsK`t'M>Q;tN{$}ƯfRR$2Ƿ7iLjIo㤶rS%w^?M2lmCKI+vSI]K$U*z-mVMjo)ivܤg0i"jERޤ=I#[+I3iK:O&]ϓfj!OH:t풺%&ǒ:罒RKkICv&N:)ϾtsI՞rR9I:ڒ꽵'L#I`R10/i7i/'=f9OHz&զ=0`AAAAAAAAAAAAq'tyW$w)I|fǜ4c>Ԥ t)GpN'tY$|QD~I'r^]4鄳N:sλ:ȉg&sIǮ%m'}* 6I !eUWސt'yIwIҹ\t%r9Ig|fit'mI}@K%-2rLK-t'yI99i*嶤ZҸ>I+,\2#'3:iE/>&sxRK޹= F|qIX47/iJ% 7&u+?ByjL;~ɤR{{'9,cѤR_OZTTVjIF҇X'i}$i?QR9TDx!IET]ȤzyhRޖMjʬI-IZRiʟ|`9Lߛ_LږΌIOIb I=={NRQKjj/%I=ERexsҴ&uwHZvqIFҁL6|hiǬۊN46L*g[-tKZslnwH*<#k}sѰ/$M65Ojj$+ImC&'5䤃;LIMZ0 9`wn{/7Yo{_zB g·Z\eN_g[~f|G?Ï/.hYr,+c63[o]iۮ(ᚋ/ۯkZbKp5's}`H{lsʙXֶ}[o΃{|o޼yk~h֖{k+~%Wں6v?`ĭ_sZc'|? tC3Ç tM.=sN>cM7/= ?3Oޣ!Cc8k=w޼ǜdQxfΞƛo,?ᖫ?CW_eՅu(6fUgqW]p'k̚=x׿G9`ޣZv:g֣}y}OKu-o^Ygj--!nO;/r-ƌ9+ovoycO]xz /8n-7/9Wkomi]s58--sMW\;oOz|᧜sƏ 0 }pɓ~fw^aW\n:wK-gchQ~ߟw}_sڌo ,d/7_a]}/ҿsUS~ׅF.2qalM:d;һXs7νq`S~xJ~Oua>kE%^/kw0-.w ^‡~wiw:츉/y_w;|_}; AAsޚT-'M~sVR_[O?N/⋯&蚓4wNog' .TƍI5;i& ڔ40oFRIZ5eh[`HܞTn$u͝?TL,I=I}Qهt`9I3fLN9<=iqcKE[oMMJS9o?i^fM**Izzv%x{zRҔҜԚio4lĨ^z!cHkIG|T҈I?.;|MR=sM&]tI|b7@RGgguL,Փ&͞ӕI բIwET E?E=R*'ZR9TԒE/VK:kMy%i``RSkS=Ƕ'pYIB˰Iz=i>TM\Ik7LK*ժIrsF^F 4P &-ImC*-I-ڙ4j1MZb֛ZIg&M5#)|i`nՕK?؝TyfҴkOH:cӓ\Ҹbtܮ"ihǰYo43阇NHj7t'=p)?<)OHfETu6{&5WJI}IrsRդ9_ "5I~uW]tw&|5I__s_LwtoJZ$5gjޞI/jۯ4gvWb.TG53Z5'S-Z=9iHФjQKדTՓZZ34% & mOzkQcF'eޜF쮮G~hR-S*IRS%(Փ[Ό[l\RWmi$$5'͙=+i͵VO='TLjjZOm]:('I墔4kItW3KkCɓ.JҗΆ[$mIqܜT+I͕RGN 0ܫ'=%ۗ'W$|-IB$Ն%K]Ty5sФI{ ,ZMb"I%}{Iw-ҕ_^Hu' T~ԤC͙ZwI]3g%U륤]ԜY$-̢IŚI|QҰ]Tz[IG|db)k4{UR2&e?_]f'KN~ĤyIz-io$Ꞗ;7\N*Z2T $UZrRSԗ _1[0 ,w}9;>3{{uAqGO mW8n{n]7qמr w6rĈpWs˗\t;}^۽w}57Ev;\sx_o8/_wܽ%sߛk~n9Z[Z رM+|_w^'>17^~nʞ;vu'+\q%_+_zEx[eŕ?5ZCl\~w|]7y箹:.|Em_;G ΅ǟ|ǵ7~.:M>{($9ҳ/|YZm_a<`'?;u!~d[o>n{~녗^3g ˭0ayT*'_JV*)o5zԨ/}q|4cӻo}/_yc}Ó,]'(6ڤ\.Κ={%믳 G*V_xٳg/2n;> }Q#9SZr'zIx_}n϶=Svg|i'Ąs.:O]*>V.QO;ƍ{ ,}wg\pNVx_uvvE+//xÿ~?n򩍖X|9s^pgΘy?QQ~lږ?>ĭ_sZc'|c/'7MMMk,/$qWo|?x~tEQ(ޞ`ZզϘ^.{ 7޴mo_2{N{AS~W_nnj|M޹pe]b{zz_z=jt__]Y䦦7_(w-~'/:nGy]s`}ƛoE6[t wYcE‹=kŋw럿맞}f?vuuE1|wO7RsϾo,`x̝>_XjɥG!9 qꤓƌ_r5WX+/1b]:n>#(byw/عUEkk߾?SޚjQM;lf7]~{g6~5(;Z(ĵZ(v}C;4{޻.ޏ~߿RK3v%Zm(~9fX簢(yΜ5(Cη+1V-r[g=b2 AruyG(zE1]o8bȢ(uwGOS<}}߸^ڈ#8Pe0 *oË9k?zs.Z6tw~%(UV.9EQL>m ?cFy:u]x镗Xfpݵ><ˏ~y/1~٥^탫EӇ(X|w_(&==Zv ʪ;oO42 XwO!Cw.lϬ EQ<߼s;}i?n٭sϯO7G}q'5#n٭waԩEQUEQ^d{[Y]g:ȉƒ?aOoi_ѱ;݃glTc9ro=7#gLomm=ߙw~%?X|'?|N /o(oWYs``!߮j}ӷ]}\pWϟc9r8oO;Owfz~+fΜ*^vWw9'~| ;ǏO܅NWWטcsg'088-b_O;yU](~;nyǍ2N:+.?GgΜYEV{'?~دϻLKKˊ˯E^~n>ˮrƌ=}?a_}|O>]7~Þ~O?u9g~>;.qIg?ÒBrzk<͙;w'lN_~O4' \/'륤R_ITW2XL $筨֒nIIS33IMIcFI4KILQ&M{zT*Iez3s{{[j}IݽIIsf'zR%-lФ1'C_OOҸ1#J"i쮤k_INin)' t iO*e^IMMeST֓ZMɯNN:FT&u%YbqM;vѤK.!N*UIET5~wJw)InfRQL7I֤{׵IͭIZ5539Ғ}mIzRO_&/& f3+MICZJI|'uJ66xRsǐvpRuu$}IZrJ֤YS$MmISR_R9)}=I=KQT**IKMj.IR=^*r)2𭤡#&=fg?Y]T/Փ4UVyIL6'It'ԤDCtI|_+sߖ]W&~IS!iڽ_Nwf.tʷVM:m.{I)S_6\Iۮm[7MZzե52IcF Kk_IIIwjT.JMrH:g%UQrRܜT*ՓړZ=iI|I\դo&͙j/gh`ah``5_~7}Ko>Iˍ_y\m}b ? ,LSO{^}9.2bG^jk9300}=:]뼫.5}/ /o=(/K._?Xne'C~W{˽_+rf~ovV>ȓ|-߾pϝrѧ~luno[x%7>p}q~qgs߽{/ⓛm}EQη\xݷo7sz~zι[7~?\*~la:vݖ|>d)}9sV\n9x/:(^xW&Z\m^_:lE7oF=o?L~ڌi/ʢcmmS't'xxOEQמz<̓\qN~)<}=[j[la#ym7|[kۓi#x֤#8f~YO<=W^,bV7ck[*EQӞ-=os߸Ri>w O~wwK_(?=TQ\i(^{sr9 ^s}(e/wo^E/-xXwO?/V{n;xXN믽/-wvЉ5w3[q-uЖo?G75(w;^|#F}z]|Oo֛mmmk(V\v%]|EQ,bo1(9]z3f,b萡{g_yQ|^\? ,Lw:N<ӎ:ҳk;C+{uvt<_v_:tv=}!Αszċzɯ6Z&. 䰗_{(R;zQ\hO}`[o Q*ѝ^EQ{D+0̆U*'~k.?v#?{ oSs⾿ݣRi˿xaZv߃ߞ}pW[y;sػ|EQ/ӹE1bw]>s>0?N1m W[cGo8kNE7\V:v_ w~UՖ\|+pO=}n[~劢x/س}(%_ixW{/E,x\wo;XgQ=3Uꫬ>r؈]d=T*:r/Z-x[mW.̝3g_5w3jrK/E~3|UW`^{w}xڌ魭Gx=Wc]Zb?y_==[lmwɰݾ&qs섣:m舤$ >j6&i aZZ&MIs{z2su%DJIMͭIÓtJ9bl҈-2&s"IC:G&u4sLRv?(iK:㓎<⸤'4>#>4Ѓ&$IwqyF]|IhqG4#o}v+#&&I4!N:ij;Ͻ*[t%7&vIg0ʇY~c+%Q_=i6%}iIzIRyS.>>iqQcO1zlEKjIN8$' _M:m>O%}`U~'|ԾIyBR3'Z}0<'iOVt̄?1Io䚤.T T>vH{잴*+'4%~aJG6(i'uM4gμ&GI^I#vԹvKjrݞI[4fݒ?^o6'J%9K$IX'iK$ ܞ4|nsR[I<礣~v|Uݘe*֤LVM ֓3j-*MmIz-yQzRЎLK:g>Im$5 0`AAAAAAAAAAAA`^&ﴞeVIL\$UJI榤joRTI*;4CHovq/CK: t&M:t1&zIGtD҇?F1OZ$륤&URT*U$_-}IZR_=ijkK3{Nܮ)Ӧ%隑5{^R_=5^ &iOKjm'5eF4~%[zf&-IOrH,쇤Zu hjKz}rT褢Җ~עj՞z'9,֓t'-u6I7~r%I"T' kKRn[('8Iq]ic.<5VQO~Ҩ֎!I,2:R&T&rҋ~=iXۈZz&+-I=IEtʣ']uIj=^KMIITE5(jYBN}+>XJ*g:FHjmH [KKSLS[{ҬL`5Ԕ4mʴ7ߜ 6LI]w=}OxĤ%ƏM*JդZTf0T.*-Ij){^O֤ZQ$kEF/іT{+ޞZR[kgRuޚTגZm0_)o g^wRT$& ښ4oܤޤZU$UI[t颛'ᤡ-II Zm睒eKIOf)'դZ%KER('PUKդO:=imߛT-[ړo% i#Lj_f|RI3FTNTZH R=^+%=G;*idgkRόYI}s|)_&fV^eC_' & iTnN:3.}Ҥ`5\/։4=/ޖTIRTh~"3|҆8iܸ1IÇw&3.3lR5SW/уhړZ*p3:'-r`ah`ah`ah`ah`ah`h|q$ ȶ}'I;AAAAABjRuT &jդjm )W*I`RR$ՋjR9?XK OȒ-7/VJޖT*N՛4{JΤr=g^RQÆ% ҖK% ڑ~ $_|r%}hGR^K*WJII=&U{FTd_.3::"97ZH iyIJ=)JS鞓ޖT $ גjJRuqQMIWrksRgȤj4{ܤ᝝ILKې;z5jYIIY'q'EpҖ4e>اNؤ/l[t^G'm I/}|#})7!)|Zoy#OMzwO'wJI3ʤ;:nʬ⪤ۮ̺⚤OX,銓LImyRӒ>kotەW$~IZ҇HR}*R=Z˳IO6^L/HKIz=)'-:zTҊ+_HZbڇt&ERwR%(IJ)^+']pISߞ4-# )`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah<ߝTԫQRRS9^.%RQIfj"iڑӶ斤RnJ$뮤/}OҽV׾yowQWz׾y_OyC7XMZړV[yդar9iHR)%5@RQL*իIg|`ҩt1&-r`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ahڟHԧ6Ol˭6sI[l]bt!&txtȄN?IǞtg'xIIzht$5qbt衇'˗s/lOrmiҞ;.;%r:#9ĤC?>I:j1I{tҖoHy/$}n͓vnoYl$>ͤHҖ}&'-bIRIymƍY4iI24iE/xҰΤI}zys^/z좤63鳝+%}Io{ҙth:I6#i{'>i&$M(>tJ$Iu4qħh~ÓiKZi?;,;ToVm0?s?C]+gLƤi74clR:,}ؤrԟ/\rRT$UJ!M7Lj[lxҙ;H7$Rѻy8շ%[jRTOJ\IJsNW~LP)BrQOZ}>7ar_5)(\}I}}I/}'IxB}ߜ-w'=oYi)*P.jjRZ${VY~cjI%Y&gJ=7~tC$+IJsKRRI*75'UZ[tt&-1~=i>4zIZTi*%(;ڇ$4E+INMt-iXGG@_RZM ~x JJ9(7%II s࿜AAAAAAAAAAAAD:/RI+RҰ!I_,iܘQI;&KII?II~I_群K&.H:Ӓ馤yIӦ45 /$ՋYs%uԒ^}ers餞zQKN=3iHsSR_OoRVO.2*iH"IߜT*I]s&5&ͮnq&̼L4%3'iZZIiOIHjnjJ:㒊Z);sԑ%-IO;imMiIo̊ZdII`RYI|ҜJffKo37ޞ:9i%>󔤕Z,;E$ݹD+JZi$SIw$]|ҁI=I᷏z?5i1czﻵL\V Jzҋy,{ܤC~ǓJRxB.疤];){#?Kx]JZU*')ZT)꘣Ho-y E=)T.jI= FZ}㍓5' ՙ=h?T*WlZЎrF&}`M[m dOGTVHR5\4%=ǤR9)~դz nI}ff~mIR)ZK*zR@`Hj֑4|I3f&55I;gUV]#9SWI&ճ s࿜AAAAAAAAAAAAD:wI箯$KWoK=w$umI?w^{٤'Hs>Hz?%M}夙$w'͞9#iN׬^kRQL6#>0TO*ё4+i' &"gܤr%Rʔ*I]g' $ 'J1r(ՓjI=RbK$jR{{k[ֶ֖zQK*zRQ-mIsf&-I]sf&jI4鸓*zn cL\e%fzҜZ܁-T*IZq%:.i楓Zچ%U{J9g&qÅI%֤:OjLRfk&ݹIkIQsg'uEIwiRSK{RkSsҮTKI]sIWZU>TIm;II3-I+,RR^K%̞W& _dtR>T/Ig~CRT˄TJi)S*k+ղ{^}9^%4,S_*偤@`QJzၟ& դoR('ۓ>6I/tҎ'LL*)>JETVD$5iJ6卤sIg?{f˳TדW3I˖E0*E4}ƴuvM=;mDzY7iwI{'mݞImJSR[&Ѳ o& ֑N$-j[I+zz$M+tbRQ f-r`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah֛&͝73kV`wRޗ40PM*IETOUjIET4+IZ)j4PH*EIMIsI'3Cړ*GkXȤTOzW^jҐ!mIj=jܮɯ4jȤZ?}6V2Cۇ$̈́ ZstR>4[$+ZOz?JC%v$ ' u$ 4& IHCG&E-V*jk?r))}jH o[Xx-QsCTI]"i̶[%O&]wIϼ7Z$Æ%-&IO汤f]J 4&}EMZ5yg:IrTILNoJԔ_L:h‘I+FҨQÓZ*I3`m iI9flRVIjioI^.5-(2}l*{Λk%%67'+夅;N}j/gh`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ah`ZT,eՓwZʔ3Z-^4%JRxZ@RVKՊށ=I̜9s[MTW{j޹sz)i4nؤٳ$M1=k^o]ҐaI3f% '*夙f$-:n`-iƬIETijNz6&ISJ*7%eݽ}IC M,'Uo4zؤa#''4'e̝T.ՒfI;=MUz3g9g֌9IrKRwO5iΤGotIӫMI֤^#i#Z2֤rҜ޹Iz[ޚJ҈aC=I>&ҨEn两Z_5f%-I}}I?+I֤Zєtu'=ċI]unO_RIZӓVe[=%nL*kIg'"^%C&54'Ut&W:[zYMIc4ҚԜ/% 1&^)'}{J:ӓf~rItv&}%];ԧs *"(14*I(c1Ot(H&Cs%)2Jj'}Z}Uy^gN?mW%]y麤Ǥɤ/'ղ^tQŒI+V$`פ%K% $=λIׯO߲!kcҖO'MOlڒTIv;K#顟ޙtŧ'Ԥ]tMW'򁻓n[LzI_{AO~􃤛,ސ[OKk.;?+/HI{:9LĖP399izbTf9#ϤjR'&`ֽƞ[:iI椳.I|CҖFQI%IỰ>48PIZ28T4I''Y3t6oޒd`$ib|`$W$]ÝIbY/t>'$mܒ4ӫ%uIwВc;鿿Im"\dk6iࢤ<ھ&}w&/L/tڳ~R&yI%A:IETzͤk\t+VJZI'I|Lt}~$'zQIxtҾֿ'頃>G'{I;ؤ::FI7廓8⸤MI=蘤#X|8#I/%}>O]\'柒 $ %a( 0@IJ P`0$ %a( 0@IJ P`0$ %a( 0@IJ P`0D:ER3V*fR;ӯ:^RIIj?)T34JcϽ}8T-Ir!-}L*~TW~0iퟓ40T):Ig]FQKNtǓf]"S8*)˓NfTx| ?[=M?٣&`I~lxQҩg|-i|a>_>ifj65$-[(/xnYܚtW%=e"i5^b7I;㯽?)Bjԓ4߭~[?)JҒP{eRx}:qSO6Sxҹ'㿝oM:>CJp4J41?ԩ5&Z I)AuIǤs/^'ϷoN~.Oz"k' %U3*$B+i`V2N?ivv:9(it隤lRLo֬6)/˶vk6Vf4;JvVBRV$u[Iͼ%CIS9,g( 0@IJ P`0$ %a( 0@IJ P`0$ %a( 0@IJ P`0$ %@'-tZ^*"l$JRMդnT):I7|YYgt'']xɹIg}jigtII:N8[I=Ĥݤop|B7N9!iEkqע)W-'}3)};_O:G%LM'uڭB'i1xE#I?T@4<:?.ivn&i:IEZH ?!wV$,,$-_4I5I jxp i`x(idfIj׏J:SKh.k$}KL¿CWIEx`()<"6h ^Oo=)]H_^7遻LZh&wzjR֯^>$sIK'դMcI?wܓt=$kͤeG&VYCNvjzf2ihh$ilr&i$0_'fTIBRYKj$QQl$U348،HYH>2|QҿyI3IN%ionIy誤CҒIGMIz٢o]mW%-_2tM$u:Y FYhUZNRxޭ$J̱']|֗qI]Kf/\θ掤 n7t F]Je0*v޺ &:Ic3IiO ! ^jIQz40 ٤n}()|EU4O.VH /yt|៓#t'^u˃In{wRx_zeIǟze)ݘ+{vtō$M7+~/sp3(zI7<43%i~c[&6' fzE'۫$-d&")n7fI}*g2FƒtZ$IZ/ilr*Y4<5` %a( 0@IJ P`0$ %a( 0@IJ P`0$ %a( 0@IJ P`0$xvriL{I>1tٵ&ϴNROzgO&-IK?In~ .! ~7RD]u˽ItEYgt%7ܗԮTn|˿sb~RK ?H+W-Kf޷뒎>-I39bGIGkt6Q+W'-^2iIKIY,itʤ-Yf+|6IVoI >i嚝~mw-i$;(i]_W5食lҧI&m.I+!im-]jVmcG?I_'I^󓞻öI׽UI{f^%n/Lz^&=wm^' kI.J~UIS6+%-_6 }K:}'w\?cK6ӟLg?C1/$:靟MhN}&]w>w|aU%,^hiѥ-K:&}_Xy{-邯]ҙ_BRVMzzIۮYEIO:霳t剧%-83=5h $E-iɤJH֫IvR=HmZ ݤc6$U8iNLz%I{肤M|lҦ>/8<㿟\T>Z5*3?;t%דqג>v㗓6N$mKڼe<Ѭ%J҆cIOmLUIsxRD˖'f^_=^x>g o97>?},'ŏ>dRZ$5G|HjfjRZK+n/=i||6&]y˃[/Iڤɹ[ld5Íz@~ez-^$Ǧ*Zғ=4.jZRѫ$5Y:*}z$xr}>1oD}˒.oqRx9TW*")鄯}>iz|,iL#SIJ-)5u&LRI ;fF-)MIJ5^HwIәqnOIhRvѩzJRxjyf%I3^v'wk<J P`0$ %a( 0@IJ P`0$ %a( 0@IJ P`0$ %a( 0@I;=?镯zcR+,$uasI^+mO ͤj4L:cФC=2}t!L:Ó>xǓS_L:%Ò<=߽_{vy]6oHeIIF&IG5kV%=@BRZKHJ!ivv:if~.ithR5(^MՊNfI nl$ՊJRIښ0r`0$ %a( 0@IJ P`0$ %a( 0@IJ P`0$ %a( 0@IJ P Ij?#˒JTdjfR/3תQZH Zc`8iM7I+Nj4I 驨VIz'%CI#YLv۬LfI/Kzaf8ӬEoz[v}NI^'ivu$ipgZQI$I^?i' 4Ic7$vj%o؜hIK&6O&NM'2rժN'fO *TʤE59tڙ'&&}o%:Nw>i*7&iwIVkI%OxB[^-YXO:&u /ZRZ$^[vh$vIS3IVI_weE_tu'_o|sI˟ԫvviGsүdRxX3ٗej.Q+jNfhRIZ=)k˖Ht18iWW69n _bʤW%UZR5E5)~kQv'V'uj4;JvI4=; ԪICvtROjd:VtLLڴa,i'@#)|yB6TG 4Fj4534i'MMN'-,fuࢤHRZIzrӖ'~QKP%v%Iq~?3.H:#|~I<樤I[Im'Nz{'ըǒChk{+nV=pqoI2ԫQNRxN+VJeISS3ICIv/Ү$ Ԓ"_T*fn%O'uff[ICfGwvj>)<= NR^$M$"Lj͵jTԯTjJ` %a( 0@IJ P`0$ %a( 0@IJ P`0$ %a( 0@IJ P`0$'f:ݤfҦpRRMeu:Jt۝~TjFTR%+EtR#4VgZ ~U'-' 'o}YO,ʄ`5NW:I6'uZ I3sISIZ42HjuZI^TZ$gIK2̖g6&UtgƓ%-[&)<g: QC^iԒQ-zv@473ev>idx4i='i''MN$5덤Gy4iMfbf>ills_$mKL_$-}F_ZII~>hQ%B=;W^'iۍI  ×7|磿Um*[~Hw")| ~5֯$nR/bϞBKM&ݺ8/SIs+H#رI{ϝwARQ%{mUHդ#>Ťf+SˊEs%MlޒT+zJEES ߬c433Jj6&3+W.Oje«@#ifv>)ֲ^˞AsxxQR8jT除^^?ewMzNRLkI7nJj'5Io}h& 4_IE437ԯԓ $ %a( 0@IJ P`0$ %a( 0@IJ P`0$ %a( 0@IJ P`0D:׊~RWIZ4:TIs IZ3ivv>U2J5כIEenR;St{IF5i Sv}ዒvznvZU+'u擦'FISIZ4xQҲL^*N,$-i&oVIZdiR'uzQLo!+.4դeE-iLMGIv;QJR9~F2EHڰisd`6˓i6}~/-ifj碤y2_VҦ-I|I7ZTo};)=dj^RSo)mR;)|AP'[\wt?u'<I/OgCOH w%i.3?3UIEdhlDRN ϑ],~lRMZtq|R{n&).ۋ_5j?);X΅'n%ib/_dʤFc ){ExEٯjՁ~׳NLuuKu">n/W'u{N'nIʤ[_tӹQ7ua3&~ŽI)hx`fa*oI:o>/*I^Tuu!=l݃C&k[Aó]ڪϴlݷ%e^e㦤LRH:']IK>t%m24X'+驤QJ l|Ri:I Qu榦nҒ勒:텤N:٤LsTI=ǒ'6%UjnhIlR^M7*I[sY P`0$ %a( 0@IJ P`0$ %a( 0@IJ P`0$ %a( 0@IJ"k u']sEI_u &듦'͌oIɚؐw'yItyҍ^tW%%?M/L˒.;/OK:o Ig=1錳tڙQqbҹtg'vIvs=?Qݟ2OcoҕW^ty$]q٥I]pnu]t9g&uN=k<3NM ]uI]yqҙt's=I?'ܟ%=[n1/K{~romw [oIn֤2k.+.2iƍI_ҟgz2Ns.<䤇+i3OIzL'>t?t:O%vG^$}J'>>=镯}Mzs8u}cһ'COzސǞ{%Ó;#ᤷcߤc>ɤ=9(O:>K:&rQI?ؤ3}Û&mIoy绒w'aI/{w'Q/{Hz_+ozs{׽)i=HzϞQCCIYsGW$]}I`%,YlնINZbEeI+Vmj$j5MZfۤm{NRQ%3̒kVJZ|yp?49=tY%]k^tڨMƦ&gZISnl4n']nm&`aQI33ߛw=CNOIqm.$6OHaųOJ87̖6D=ȟnϿ=IÎh{{NZh4i~ԆMIcIV'%oLz_W' .I+쐴htihRc`$iҤF}$imᤑE+:CI{}D?=sDG~,iK7kk<J P`0$ %a( 0@IJ P`0$ %a( 0@IJ P`0$ %a( 0@I7_tm%]yIvEwݐt %_$/Ks˓~&]sڤ_ꞤDTk{I?I?;䤳n};w\tu=䤵g~/*.qIg;%OH:++|A=NFYg~/)< 󾟴n 9)sNN:o&xIݤ ?)NKnHs֮NytI']r)Ig>)W?i'%]ĤK/9-i64::Ԩ땤jTtjE/)|~w>ךMZtqRўʚI W-_|eʕ˓\RU';3Iqu׮>'W:'לO: uCԷ9?[Wt%w'=pI?vz֩I'ۇI|B|=NH'&εI+9;J]k~~9IK$}K}EI߼o\}nWZ΋ܤ\qN\6IriI謤/]|F?^pjߝrgM7K #t%I<7xA_.M \t&yIW\vfҝw^tk¹]5` %a( 0@IJ P`0$ %a( 0@IJ P`0$ %a(u\_IENDB`disgreet-0.1.1/src/000077500000000000000000000000001521157164000141105ustar00rootroot00000000000000disgreet-0.1.1/src/core.rs000066400000000000000000000061321521157164000154100ustar00rootroot00000000000000//! core.rs use std::{ env, io::{Read, Write}, os::unix::net::UnixStream, }; use log::debug; use serde_json::{Value, json}; use thiserror::Error; use crate::Session; pub(crate) fn authenticate( username: &str, password: &str, session: &Session, ) -> anyhow::Result<()> { debug!("start authentication: username: {username}, password: {password}"); let sock_path = env::var("GREETD_SOCK").map_err(|_| AuthError::EnvGreetdSock)?; let mut client = UnixStream::connect(sock_path)?; let res = login(&mut client, username, password, session); if res.is_err() { _ = send_msg( &mut client, &json!({ "type": "cancel_session" }), ); } res } fn login( client: &mut UnixStream, username: &str, password: &str, session: &Session, ) -> anyhow::Result<()> { let msg = json!({ "type": "create_session", "username": username }); send_msg(client, &msg)?; debug!("sent create_session: {:?}", msg); let resp = recv_msg(client)?; debug!("response: {:?}", resp); let msg_type = resp["type"].as_str().unwrap_or(""); if msg_type != "auth_message" { let e = resp["description"].as_str().unwrap_or("Unknow Error"); return Err(AuthError::Username(e.to_string()).into()); } let msg = json!({ "type": "post_auth_message_response", "response": password }); debug!("send post_auth_message_response: {:?}", msg); send_msg(client, &msg)?; let resp = recv_msg(client)?; debug!("response: {:?}", resp); let msg_type = resp["type"].as_str().unwrap_or(""); if msg_type != "success" { let e = resp["description"].as_str().unwrap_or("Unknow Error"); return Err(AuthError::Password(e.to_string()).into()); } debug!("auth success"); debug!("launch session: {:?}", session); // greetd 协议要求 cmd 是字符串数组,例如 ["/usr/bin/bash", "--login"] let cmd: Vec<&str> = session.exec.split_whitespace().collect(); let msg = json!({ "type": "start_session", "cmd": cmd }); debug!("send start_session: {:?}", msg); send_msg(client, &msg)?; Ok(()) } #[derive(Debug, Error)] pub(crate) enum AuthError { #[error("cannot found environment GREETD_SOCK")] EnvGreetdSock, #[error("wrong username: {0}")] Username(String), #[error("wrong password: {0}")] Password(String), // #[error("Launch session: {0}")] // LaunchSession(String), } fn send_msg(stream: &mut UnixStream, msg: &Value) -> anyhow::Result<()> { let json_bytes = serde_json::to_vec(msg)?; let len = json_bytes.len() as u32; stream.write_all(&len.to_ne_bytes())?; stream.write_all(&json_bytes)?; Ok(()) } fn recv_msg(stream: &mut UnixStream) -> anyhow::Result { let mut len_buf = [0u8; 4]; stream.read_exact(&mut len_buf)?; let len = u32::from_ne_bytes(len_buf) as usize; let mut json_buf = vec![0u8; len]; stream.read_exact(&mut json_buf)?; let val: Value = serde_json::from_slice(&json_buf)?; Ok(val) } disgreet-0.1.1/src/lib.rs000066400000000000000000000127111521157164000152260ustar00rootroot00000000000000//! disgreet lib use std::{ fs::{self, OpenOptions}, io, path::Path, }; use crate::ui::UI; use crossterm::{ event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}, execute, terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode}, }; use ini::Ini; use log::{debug, warn}; use ratatui::{ Terminal, backend::{Backend, CrosstermBackend}, }; use simplelog::{CombinedLogger, WriteLogger}; use thiserror::Error; mod core; mod ui; // i18n pub(crate) const CACHE_BG_DIR: &str = "/var/cache/disgreet/"; pub(crate) const DEFAULT_LOG_PATH: &str = "/var/log/disgreet/disgreet.log"; const DESKTOP_FILE_PATH: &str = "/usr/share/wayland-sessions/"; pub(crate) const PREVIOUS_USERNAME_FILE: &str = "/var/cache/disgreet/previous_username"; pub struct Disgreet { background: String, sessions: Vec, prev_username: String, } impl Disgreet { pub fn new(background: &str) -> Self { Self { background: background.into(), sessions: vec![], prev_username: String::new(), } } fn setup(&mut self) { if let Ok(log_file) = OpenOptions::new() .create(true) .append(true) .open(DEFAULT_LOG_PATH) { let level = if cfg!(debug_assertions) { simplelog::LevelFilter::Debug } else { simplelog::LevelFilter::Info }; _ = CombinedLogger::init(vec![WriteLogger::new( level, simplelog::Config::default(), log_file, )]); } debug!("new disgreet: \n{{ background: {} }}", self.background,); debug!("setup disgreet"); if !Path::new(DESKTOP_FILE_PATH).exists() { warn!("path {} not exists", DESKTOP_FILE_PATH); } debug!("path {} exists", DESKTOP_FILE_PATH); self.prev_username = fs::read_to_string(PREVIOUS_USERNAME_FILE).unwrap_or_default(); self.sessions = find_desktop_files(Path::new(DESKTOP_FILE_PATH)); append_bash_session(&mut self.sessions); } pub fn run(mut self) -> anyhow::Result<()> { self.setup(); enable_raw_mode()?; let mut stdout = io::stdout(); execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend)?; let res = run_app( &mut terminal, &self.background, &self.sessions, &self.prev_username, ); disable_raw_mode()?; execute!( terminal.backend_mut(), LeaveAlternateScreen, DisableMouseCapture )?; terminal.show_cursor()?; if let Err(err) = res { println!("{:?}", err); } Ok(()) } } fn run_app( terminal: &mut Terminal, background: &str, sessions: &[Session], username: &str, ) -> anyhow::Result<()> { let size = terminal.size().unwrap_or_default(); let mut ui = UI::new(background, sessions, username, size); loop { terminal.draw(|f| ui.draw(f)).expect("UI draw failed"); if let Event::Key(key) = event::read()? { match key.code { KeyCode::Esc => { if cfg!(debug_assertions) { return Ok(()); } } KeyCode::Tab => ui.next_focus(), KeyCode::Enter => { if ui.handle_enter() { return Ok(()); } } _ => ui.handle_input(key.code), } } } } fn append_bash_session(sessions: &mut Vec) { if !sessions.iter().any(|s| s.name.to_lowercase() == "bash") { sessions.push(Session { name: "bash".to_string(), exec: "/usr/bin/bash".to_string(), }); } } fn find_desktop_files(path: &Path) -> Vec { let mut sessions = vec![]; if let (true, Ok(entries)) = (path.is_dir(), fs::read_dir(path)) { for entry in entries.flatten() { let file_path = entry.path(); if file_path.is_file() { if let Some(ext) = file_path.extension() { if ext == "desktop" { if let Ok(session) = parser_desktop_file(&file_path) { sessions.push(session); } } } } } } sessions } fn parser_desktop_file(path: &Path) -> anyhow::Result { let conf = Ini::load_from_file(path)?; let section = conf .section(Some("Desktop Entry".to_string())) .ok_or(DesktopFile::NotExist)?; Ok(Session { name: section.get("Name").unwrap_or_default().to_string(), // comment: section.get("Comment").unwrap_or_default().to_string(), exec: section.get("Exec").unwrap_or_default().to_string(), // session_type: section.get("Type").unwrap_or_default().to_string(), // desktop_names: section.get("DesktopNames").unwrap_or_default().to_string(), }) } #[derive(Debug, Clone)] struct Session { name: String, // comment: String, exec: String, // session_type: String, // desktop_names: String, } #[derive(Debug, Error)] enum DesktopFile { #[error("Desktop Entry section not exists")] NotExist, } disgreet-0.1.1/src/main.rs000066400000000000000000000005411521157164000154020ustar00rootroot00000000000000use clap::Parser; use disgreet::Disgreet; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { /// path of the config file #[arg(short, long, default_value = "")] background: String, } fn main() -> anyhow::Result<()> { let args = Args::parse(); Disgreet::new(&args.background).run()?; Ok(()) } disgreet-0.1.1/src/ui.rs000066400000000000000000000274601521157164000151040ustar00rootroot00000000000000//! UI use std::{fs, path::PathBuf, str::FromStr}; use crossterm::event::KeyCode; use image::{DynamicImage, GenericImageView, RgbImage}; use log::{debug, error}; use ratatui::{ buffer::Buffer, layout::{Alignment, Constraint, Direction, Layout, Position, Rect, Size}, style::{Color, Modifier, Style}, text::Span, widgets::{Block, Borders, Padding, Paragraph}, }; use crate::{CACHE_BG_DIR, PREVIOUS_USERNAME_FILE, Session, core::authenticate}; #[derive(Clone, Copy, PartialEq, Eq)] enum Focus { Session, Username, Password, } pub(crate) struct UI<'a> { render_img: Option, focus: Focus, username: String, password: String, cursor_pos: usize, message: String, sessions: &'a [Session], session_idx: usize, handling: bool, } impl<'a> UI<'a> { pub(crate) fn new( background: &str, sessions: &'a [Session], prev_username: &str, size: Size, ) -> Self { let focus = if prev_username.is_empty() { Focus::Username } else { Focus::Password }; let cursor_pos = if prev_username.is_empty() { 0 } else { prev_username.chars().count() }; let mut render_img: Option = None; match PathBuf::from_str(background) { Ok(path) => { if path.exists() && path.is_file() { let file_name = path .file_name() .unwrap_or_default() .to_string_lossy() .to_string(); if render_img.is_none() { let cache_file = format!( "{}/{}_{}x{}.bin", CACHE_BG_DIR, file_name, size.width, size.height ); debug!("check cache file: {cache_file}"); let cache_path = PathBuf::from_str(&cache_file).unwrap(); if cache_path.exists() { if let Ok(raw_bytes) = fs::read(&cache_path) { if let Some(rgb_buf) = RgbImage::from_raw( size.width as u32, size.height as u32, raw_bytes, ) { debug!("cache file exists"); render_img = Some(DynamicImage::ImageRgb8(rgb_buf)); } } } if render_img.is_none() { debug!("has no cache"); let base_img = image::ImageReader::open(path) .unwrap() .with_guessed_format() .unwrap() .decode() .unwrap(); let resized_img = base_img.resize_exact( size.width as u32, size.height as u32, image::imageops::FilterType::Nearest, ); let rgb8 = resized_img.to_rgb8(); _ = fs::write(&cache_file, rgb8.as_raw()); debug!("cache new file"); render_img = Some(resized_img); } } } } Err(_) => { debug!("base_img is none, not draw background"); } } Self { render_img, focus, username: prev_username.to_string(), password: String::new(), cursor_pos, message: String::new(), sessions, session_idx: 0, handling: false, } } fn current_session(&mut self) -> Option<&Session> { let mut sessions = self.sessions.iter(); if let Some(session) = sessions.nth(self.session_idx) { Some(session) } else { self.session_idx = 0; sessions.nth(0) } } fn go_next_session(&mut self) -> Option<&Session> { let sessions = self.sessions.iter(); let count = sessions.count(); self.session_idx = (self.session_idx + 1) % count; self.current_session() } fn go_prev_session(&mut self) -> Option<&Session> { if self.session_idx > 0 { self.session_idx -= 1; } else { self.session_idx = self.sessions.len() - 1; } self.current_session() } pub(crate) fn draw(&mut self, f: &mut ratatui::Frame) { let area = f.area(); self.draw_background(area, f.buffer_mut()); let area = centered_rect(40, 10, area); self.draw_login_box(area, f); } fn draw_login_box(&mut self, area: Rect, f: &mut ratatui::Frame) { let message = if self.handling { "auth..." } else { &self.message.clone() }; let block = Block::default() .title(message) .title_alignment(Alignment::Center) .borders(Borders::ALL) .border_style(Style::default().fg(Color::White)) .style(Style::default().bg(Color::Black)) .padding(Padding::new(2, 2, 1, 0)); // 用布局切出内部区域 let inner = block.inner(area); let rows = Layout::default() .direction(Direction::Vertical) .constraints([ Constraint::Length(1), // 标题 Constraint::Length(1), // 空行 Constraint::Length(1), // username Constraint::Length(1), Constraint::Length(1), // password ]) .split(inner); let session_name = self .current_session() .map_or("".to_string(), |s| s.name.clone()); // 标题 let title_span = Span::styled( format!("< {session_name} >"), Style::default() .fg(Color::White) .add_modifier(if self.focus == Focus::Session { Modifier::UNDERLINED } else { Modifier::empty() }), ); let title = Paragraph::new(title_span).alignment(Alignment::Center); f.render_widget(title, rows[0]); // Username 行 let user_style = if self.focus == Focus::Username { Style::default().fg(Color::Cyan) // 获焦时高亮 } else { Style::default().fg(Color::Gray) }; let user_text = format!("{}: {}", "Username", self.username); f.render_widget(Paragraph::new(user_text.clone()).style(user_style), rows[2]); // cursor posinion if self.focus == Focus::Username { let x = rows[2].x + user_text.len() as u16; let y = rows[2].y; f.set_cursor_position(Position::new(x, y)); } // Password 行(类似,密码用 * 显示) let pass_style = if self.focus == Focus::Password { Style::default().fg(Color::Cyan) } else { Style::default().fg(Color::Gray) }; let pass_text = format!("{}: ", "Password",); if self.focus == Focus::Password { let x = rows[4].x + pass_text.len() as u16; let y = rows[4].y; f.set_cursor_position(Position::new(x, y)); } f.render_widget(Paragraph::new(pass_text).style(pass_style), rows[4]); // 最后画边框 f.render_widget(block, area); } fn draw_background(&mut self, area: Rect, buf: &mut Buffer) { if self.render_img.is_none() { return; } let render_img = self.render_img.as_ref().unwrap(); debug!("draw background start"); debug!("area height: {}", area.height); debug!("area width: {}", area.width); for y in 0..area.height { for x in 0..area.width { let pixel = render_img.get_pixel(x as u32, y as u32); let mut r = pixel[0]; let mut g = pixel[1]; let mut b = pixel[2]; if r > 230 && g > 230 && b > 230 { r = 255; g = 255; b = 255; } let bg_color = if r == 255 && g == 255 && b == 255 { Color::Indexed(15) } else { Color::Rgb(r, g, b) }; if let Some(cell) = buf.cell_mut((area.x + x, area.y + y)) { cell.set_char(' ').set_bg(bg_color); } } } debug!("draw background end"); } } impl UI<'_> { pub(crate) fn next_focus(&mut self) { self.focus = match self.focus { Focus::Session => Focus::Username, Focus::Username => Focus::Password, Focus::Password => Focus::Session, }; self.update_cursor_pos(); } pub(crate) fn update_cursor_pos(&mut self) { self.cursor_pos = match self.focus { Focus::Session => 0, Focus::Username => self.username.chars().count(), Focus::Password => self.password.len(), }; } pub(crate) fn handle_input(&mut self, key: KeyCode) { if self.handling { return; } match self.focus { Focus::Session => match key { KeyCode::Left => { self.go_prev_session(); } KeyCode::Right => { self.go_next_session(); } _ => {} }, Focus::Username => match key { KeyCode::Backspace => _ = self.username.pop(), KeyCode::Char(c) => self.username.push(c), _ => {} }, Focus::Password => match key { KeyCode::Backspace => _ = self.password.pop(), KeyCode::Char(c) => self.password.push(c), _ => {} }, } } /// Returns `true` if authentication succeeded and the session should be launched. pub(crate) fn handle_enter(&mut self) -> bool { if self.handling { return false; } self.handling = true; let username: &str = &(self.username.clone()); let password: &str = &(self.password.clone()); let session = self.current_session().unwrap(); let res = match authenticate(username, password, session) { Ok(()) => { debug!("auth success, exiting event loop to launch session"); _ = fs::write(PREVIOUS_USERNAME_FILE, username); true } Err(e) => { self.message = e.to_string(); error!("authenticate failed: {:?}", e); false } }; self.handling = false; res } } fn centered_rect(width: u16, height: u16, r: Rect) -> Rect { // 处理屏幕比组件还小的情况 if r.width < width || r.height < height { return r; } let popup_layout = Layout::default() .direction(Direction::Vertical) .constraints([ Constraint::Length((r.height - height) / 2), Constraint::Length(height), Constraint::Min(0), ]) .split(r); Layout::default() .direction(Direction::Horizontal) .constraints([ Constraint::Length((r.width - width) / 2), Constraint::Length(width), Constraint::Min(0), ]) .split(popup_layout[1])[1] }