Compare commits

...

237 Commits
dev ... master

Author SHA1 Message Date
277f03594c [+] release updated cli_bootstrap 2025-04-30 15:27:01 +03:00
7f5c9f4fdb [+] improve cli_bootstrap 2025-04-30 15:22:58 +03:00
e5af828867 [+] improve toml compatibility for python 3.10 2025-04-30 10:43:11 +03:00
1faa511d15 [+] update configs 2025-04-30 09:47:30 +03:00
5190d23f09 [+] fix pyright wrapper 2025-04-29 14:12:11 +03:00
908f0cbd20 [+] add pythonpath to pyright 2025-04-29 14:01:49 +03:00
548a8bcb7a [+] release merged version 2025-04-26 14:42:03 +03:00
56c2eb1671 [m] 27-fix-http-server
1. update http-server
2025-04-26 14:40:16 +03:00
2fef63a253 [+] update auto host, http-server 2025-04-21 18:07:42 +03:00
dc39583cc6 [+] add auto addr search for public, http-server 2025-04-21 17:45:53 +03:00
a912e1b6bf [+] update http_server
1. remove ping dependency;
2025-04-19 18:10:07 +03:00
fdcd67aae6 [+] implement interfaces_index 2025-04-18 16:38:36 +03:00
799280f074 [+] add interfaces_index 2025-04-18 16:30:10 +03:00
202bf85f55 [+] partially wrap ip addr 2025-04-17 12:11:18 +03:00
7ad8e4a781 [+] fix ruff execution in cli 2025-04-14 17:32:25 +03:00
8d43813c37 [+] add linters 2025-04-12 16:22:21 +03:00
ae4fcb16f2 [+] fix ninja tests 2025-04-08 16:42:47 +03:00
7fa2a8a83c [+] update platform
1. update udev for air 2012;
  2. update commands for air 2012;
2025-04-04 12:40:09 +03:00
fa732867c3 [+] tune power management for air 2018 2025-04-01 12:40:53 +03:00
61584fedac [+] fix intel_pstate cpufreq 2025-03-31 17:35:08 +03:00
42ce6ffbff [+] update pr34
1. update m.py;
  2. add intel_pstate profile for cpufreq;
  3. build 0.1.5.0;
2025-03-31 17:15:53 +03:00
385e82bab8 [+] add dotfiles for platform macbook air 2018 2025-03-31 17:04:57 +03:00
ccb0fb09c9 [+] ad platform dotfiles 2025-03-31 17:04:56 +03:00
6d184edec8 [+] update systemd 2025-03-25 14:52:31 +03:00
6374849014 [+] migrate to systemd 2025-03-20 19:20:55 +03:00
3d023047b4 [+] update cpanel
1. fix logging;
  2. refactor into a class;
2025-03-20 19:07:34 +03:00
43c711cb2c [+] add make
1. add venv_compile;
  2. add venv;
  3. add mypy;
  4. update d1/cpanel.py
    to aggregate .ssh/known_hosts files;
  5. add systemd service for a gateway;
2025-03-20 19:03:05 +03:00
dff3782834 [+] integrate with podman 2025-03-20 17:02:18 +03:00
b399c5546c [+] update pr34
1. update katerc;
  2. add mime.types to few some source code
    as plain text in firefox;
  3. update .whl release for pr34;
  4. update commands_typed/typing.py;
2025-03-18 10:02:27 +03:00
c1e598b3ab [+] update nginx multiplexing 2025-03-15 13:40:38 +03:00
7442368b03 [+] update gateway
1. add systemd units deployment recipie;
  2. add certbot periodic task;
  3. update nginx_config.py
    to user ssl_preread_server_name
    instead of protocol, since it seems
    to be broken;
2025-03-15 12:06:52 +03:00
4cf720ee17 [+] add .whl 2025-03-13 19:35:11 +03:00
93f023dda3 [+] fix percentage 2025-03-13 19:32:17 +03:00
e06a1f4007 [+] add env for meson_setup 2025-03-13 12:04:54 +03:00
9ac87fb3df [+] update cli_bootstrap
1. generate requirements with hashes;
2025-03-12 19:16:28 +03:00
c8b6d96b01 [+] add .lock generation, fix mypy 2025-03-12 11:02:20 +03:00
cc0acd6f13 [+] add .whl 2025-03-11 14:19:42 +03:00
acf1850d70 [+] add env for ninja 2025-03-11 14:14:13 +03:00
9e117048dc [+] add parse_args 2025-03-08 18:39:35 +03:00
723c5b6677 [+] pack .whl release 2025-03-04 18:49:12 +03:00
aaf8b12549 [+] check invalid password 2025-03-04 18:39:48 +03:00
06e79d0679 [+] fix secret_check 2025-03-04 18:38:52 +03:00
ff786e3ce6 [+] update pr34
1. add dotfiles deploy via .tar.xz;
  2. update .sway/config;
  3. update test_crypto.py;
2025-03-04 15:44:20 +03:00
add9d858d8 [+] improve crypto 2025-03-03 18:00:51 +03:00
731c507b95 [+] add tests for pr34 2025-03-03 17:57:14 +03:00
62063a1448 [+] update .p43
1. partially improve crypto;
  2. fix m.py;
2025-03-03 12:53:58 +03:00
1fb4e4efc5 [+] update pr34
1. partially add crypto logic;
  2. fetch updated commands from laptop;
  3. update Makefile;
2025-03-03 09:51:26 +03:00
b12395621d [+] update desktop-services 2025-02-22 18:54:10 +03:00
905241a068 [+] update cli 2025-02-18 18:29:48 +03:00
01aab0517a [+] improve pip_resolve
1. add -r flag
    that can parse complicated
    requirements
    and format into a temp file
    for uv pip compile;
2025-01-24 21:47:43 +03:00
6ddfc7d2d7 [+] update dotfiles
1. add kate editor config;
2025-01-24 21:25:13 +03:00
3245d6d7e5 [+] add uv_pip_freeze
1. uv_pip_compile
    just a raw wrapper
    around uv pip compile --generate-hashes;
  2. uv_pip_freeze
    does compile of frozen dependencies
    with generated hashes along the way;
2025-01-24 21:15:28 +03:00
a529db106a [+] fix mypy errors 2025-01-24 21:06:26 +03:00
57f74df865 [+] fix some mypy errors 2025-01-24 18:27:51 +03:00
528d9b1ce5 [+] integrate uv pip compile 2025-01-23 12:17:07 +03:00
ebbd1a2b5b [+] raise to 0.1.4.9 2025-01-18 21:22:56 +03:00
62cfbf36cb [+] fix --hash format 2025-01-18 21:13:26 +03:00
d643e8f97b [+] improve pip_resolve
1. do not download anything;
  2. provide hashes per dependency;
  3. test that works on numpy
2025-01-18 20:56:03 +03:00
9b5fff93c0 [+] add pip_resolve
1. add freezing packages based on pip resolver;
  1.1. the command
    should resolve final packages with versions,
    and provide constraints with file hashes;
    to act alike go mod tool;
2025-01-18 19:34:46 +03:00
ff22d9311b [+] update
1. fix python3.13 regression
    with class property;
  2. update books dependency;
2025-01-18 12:43:28 +03:00
759ce361e3 [+] fix .gitmodules 2025-01-12 18:23:47 +03:00
136b5709b0 [+] refactor book1
1. move book1 into a private repo;
2025-01-12 18:20:19 +03:00
584b4b652f [+] add submodule books 2025-01-12 11:02:29 +03:00
7d1d887692 [+] update keybindigs 2025-01-02 10:42:58 +03:00
212c8c8086 [+] improve deploy:wheel command 2025-01-01 02:19:40 +03:00
6599115a68 [+] 0.1.4.7, improve os module
1. add runtime initialization;
    works for .so files;
    linux platform only at the moment;
2024-12-30 15:03:45 +03:00
22f5f0fba3 [+] raise 0.1.4.1 2024-12-29 14:44:07 +03:00
c9382162de [+] update cli logic
1. add pip_sync method;
  1.1. rely on -f flag
    of pip to use a custom cache dir;
2024-12-29 14:36:30 +03:00
0cee9beaea [+] improve mypy step while deploy:wheel 2024-12-22 21:07:05 +03:00
93437359a8 [+] fix mypy errors 2024-12-22 21:02:35 +03:00
9c8b554acc [+] update pr34
1. update dependencies handling
    during venv creation;
  2. update cli and cli_boostrap modules;
2024-12-22 20:45:46 +03:00
adc3fd0205 [+] fix mypy errors 2024-12-22 19:18:06 +03:00
48ef23aa88 [+] update vscode dot files 2024-12-22 18:38:29 +03:00
1626974759 [+] update packaging
1. update cli and cli_bootstrap;
  1.1. use /meson and /pyproject
    build dirs to fix collision
    for install step;
2024-12-22 18:33:06 +03:00
ea63c67280 [+] update cli module; 2024-12-22 12:06:07 +03:00
34c65f7ba5 [+] update commands
1. add basic cli.py module;
  2. add stubs for debugpy;
2024-12-22 10:31:31 +03:00
dedff2aee5 [+] update repo 2024-12-12 17:03:33 +03:00
cb69309307 [+] update repo
1. add asyncio.handle_task_result;
  2. improve pass_ssh_osx;
  3. update vpn dependency;
2024-12-10 20:28:00 +03:00
0a50c26d1d [+] add qrcode mode for pass ssh osx 2024-12-05 09:03:22 +03:00
a6cdf03523 [+] fix exit status for commands
1. fix intercept_output when the process has died
    before select poll has been started;
2024-12-04 20:28:20 +03:00
eb457950d3 [+] add launch.json 2024-12-04 19:04:06 +03:00
4afe4048d9 [+] update debugging
1. disable telemtry in ms-python;
  1.1. TODO, use a forked version of the plugin;
  2. add debug module into pr34;
  3. enable show strack frame for all .py files;
2024-12-04 19:01:30 +03:00
74cc54ae85 [~] update vpn 2024-12-03 19:07:43 +03:00
fd0dbb0c4a [+] update vpn dependency 2024-12-03 09:25:42 +03:00
d0b696206c [r] update versions of pip packages 2024-12-03 09:21:45 +03:00
92966ca86d [~] Refactor 2024-12-03 09:17:16 +03:00
d38022b5a6 [+] update packaging 2024-12-01 18:49:12 +03:00
796fb51ad9 [~] Refactor 2024-12-01 09:04:58 +03:00
b32b058083 [~] Refactor 2024-12-01 08:49:34 +03:00
d3d5e3bcfb [~] Refactor 2024-11-30 18:59:22 +03:00
64706907ca [~] Refactor 2024-11-29 21:17:34 +03:00
8656b3b985 [~] Refactor 2024-11-28 12:24:38 +03:00
1cfc6c52f3 [~] Refactor 2024-11-25 16:56:28 +03:00
62f4d9f948 [~] Refactor 2024-11-25 12:41:06 +03:00
5c69e922a7 [~] Refactor 2024-11-24 22:47:42 +03:00
27af208437 [~] Refactor 2024-11-24 22:35:54 +03:00
fadd95cef3 [~] Refactor 2024-11-24 19:54:24 +03:00
bd9878335a [~] add host_deps command 2024-11-24 19:47:36 +03:00
cadec5376a [~] Refactor 2024-11-24 19:34:24 +03:00
0ef9268f48 [~] Refactor 2024-11-24 02:28:19 +03:00
60929176ef [~] Refactor 2024-11-24 00:26:23 +03:00
0d9e225a76 [~] Refactor 2024-11-23 23:56:23 +03:00
3321e4c165 [~] Refactor 2024-11-23 23:51:06 +03:00
dffcb96358 [~] Refactor 2024-11-22 23:13:18 +03:00
fc18a91f63 [~] Refactor 2024-11-22 23:11:57 +03:00
34c3ed74eb [~] Refactor 2024-11-22 23:08:18 +03:00
2522ed4ac4 [~] Refactor 2024-11-22 22:51:31 +03:00
6d1c845d74 [~] Refactor 2024-11-22 21:24:07 +03:00
83b1177f85 [~] Refactor 2024-11-21 10:17:37 +03:00
9620bb2b25 [~] Refactort 2024-11-15 20:57:06 +03:00
f9f18df737 [~] Refactor 2024-11-15 20:47:41 +03:00
14b499637b [~] Refactor 2024-11-15 20:47:41 +03:00
40350d128a [~] Refactor 2024-11-15 20:47:40 +03:00
1eecc616f5 [~] Refactor 2024-11-15 20:47:40 +03:00
c4944ede7f [~] Refactor 2024-11-15 20:47:40 +03:00
43985cd5b0 [~] Refactor 2024-11-15 20:47:40 +03:00
ed347e1d21 [~] Refactor 2024-11-15 20:47:40 +03:00
32579007e4 [~] Refactor 2024-11-15 20:47:40 +03:00
82a7c62ca8 [~] Refactor 2024-11-15 20:47:40 +03:00
de05d2cd05 [~] Refactor 2024-11-15 20:47:40 +03:00
723ad56ca9 [~] Refactor 2024-11-15 20:47:40 +03:00
eb310ceef7 [~] Refactor 2024-11-15 20:47:40 +03:00
81bf066e82 [~] Refactor 2024-11-15 20:47:40 +03:00
560e748867 [~] Refactor 2024-11-02 12:26:03 +03:00
48ce6c87a6 [~] Refactor 2024-09-30 23:29:37 +03:00
58a1e5f1be [~] Refactor 2024-09-30 22:27:35 +03:00
62b809bd3c [~] Refactor 2024-09-30 22:26:50 +03:00
6b7bef9c07 [~] Refactor 2024-09-22 17:43:24 +03:00
16a075b19c [~] Refactor 2024-09-18 00:00:51 +03:00
92fe90b042 [~] Refactor 2024-09-08 21:52:10 +03:00
a7f5be4c8e [~] Refactor 2024-08-24 12:42:13 +03:00
392faf5526 [~] Refactor 2024-08-24 12:40:15 +03:00
fd6378a643 [~] Refactor 2024-08-24 12:26:16 +03:00
32ee4316f1 [~] Refactor 2024-08-17 11:25:08 +03:00
1140a46799 [~] Refactor 2024-08-17 11:21:05 +03:00
1ad4fab099 [~] Refactor 2024-08-17 11:18:09 +03:00
edea7a4fab [~] Refactor 2024-08-17 11:13:14 +03:00
e5cb3bbb53 [~] Refactor 2024-08-17 11:04:36 +03:00
f4f214d75b [~] Refactor 2024-08-17 11:01:39 +03:00
27be8c3104 [~] Refactor 2024-08-17 10:46:51 +03:00
c95503fa76 [~] Refactor 2024-08-17 10:46:18 +03:00
ce77de626c [~] Refactor 2024-08-17 10:44:30 +03:00
f2b8862683 [~] Refactor 2024-08-17 10:22:22 +03:00
8dbedd9c28 [~] Refactor 2024-08-17 10:04:32 +03:00
a9393dbff2 [~] Refactor 2024-08-17 10:02:25 +03:00
4ed4dbcbdb [~] Refactor 2024-08-17 09:47:31 +03:00
d0177e7255 [~] Refactor 2024-08-17 09:43:40 +03:00
10be7dc897 [~] Refactor 2024-08-17 09:26:59 +03:00
d7d4260053 [~] Refactor 2024-08-17 09:23:03 +03:00
d4ef7d5ba4 [~] Refactor 2024-08-17 09:16:35 +03:00
b5343c1375 [~] Refactor 2024-08-17 09:10:16 +03:00
a9e8d8a505 [~] Refactor 2024-08-17 09:07:49 +03:00
de292518a5 [~] Refactor 2024-08-17 09:05:15 +03:00
3e9708d442 [~] Refactor 2024-08-17 08:53:54 +03:00
9ad2030f36 [~] Refactor 2024-08-17 01:15:07 +03:00
aa8d84614c [~] Refactor 2024-08-17 01:08:58 +03:00
13f0899b90 [~] Refactor 2024-08-17 00:50:24 +03:00
2385012e35 [~] Refactor 2024-08-17 00:38:20 +03:00
2b3305ab56 [~] Refactor 2024-08-17 00:37:29 +03:00
a67d765569 [~] Refactor 2024-08-17 00:29:20 +03:00
3163641646 [~] Refactor 2024-08-16 17:43:29 +03:00
d06a7655d7 [~] Refactor 2024-08-16 17:24:14 +03:00
ac7515f49d [~] Refactor 2024-08-14 23:49:04 +03:00
d3718cf271 [~] Refactor 2024-08-14 23:45:17 +03:00
45d0be60f9 [~] Refactor 2024-08-14 23:35:01 +03:00
03164b8e34 [~] Refactor 2024-08-14 23:32:53 +03:00
bd89fff408 [~] Refactor 2024-08-14 23:29:10 +03:00
7444095e03 [~] Refactor 2024-08-14 23:17:43 +03:00
1018ad3266 [~] Refactor 2024-08-12 23:19:21 +03:00
d6f5817c78 [~] Refactor 2024-08-12 23:16:10 +03:00
1e55e7baac [~] Refactor 2024-08-12 23:13:56 +03:00
b9297f6863 [~] Refactor 2024-08-12 23:02:41 +03:00
ae897835b2 [~] Refactor 2024-08-12 23:01:51 +03:00
633e1c6424 [~] Refactor 2024-08-12 22:59:56 +03:00
d782fbfbf2 [~] Refactor 2024-08-12 21:35:42 +03:00
aead4c165d [~] Refactor 2024-08-12 21:33:40 +03:00
d50f17eb76 [~] Refactor 2024-08-12 21:31:08 +03:00
f656d94fa3 [~] Refactor 2024-08-12 03:02:30 +03:00
b6192902ff [~] Refactor 2024-08-12 02:56:40 +03:00
d5c616806a [~] Refactor 2024-08-12 02:54:11 +03:00
184340db4f [~] Refactor 2024-08-12 02:45:33 +03:00
58071843be [~] Refactor 2024-08-12 02:44:10 +03:00
b93ee0b7e4 [~] Refactor 2024-08-12 02:42:12 +03:00
71c793cbae [~] Refactor 2024-08-12 02:29:33 +03:00
5c271c518f [~] Refactor 2024-08-12 02:28:10 +03:00
4909d474b1 [~] Refactor 2024-08-12 02:27:11 +03:00
430b517ce7 [~] Refactor 2024-08-12 02:24:25 +03:00
11a3c59961 [~] Refactor 2024-08-12 02:22:28 +03:00
c16f389324 [~] Refactor 2024-08-12 02:20:46 +03:00
4758032a35 [~] Refactor 2024-08-12 02:18:47 +03:00
c1b7bb71b3 [~] Refactor 2024-08-12 02:11:26 +03:00
8ec95247f9 [~] Refactor 2024-08-12 02:08:54 +03:00
b3156b5093 [~] Refactor 2024-08-12 01:09:24 +03:00
f93b604c51 [~] Refactor 2024-08-12 00:39:06 +03:00
437e073411 [~] Refactor 2024-08-12 00:35:31 +03:00
99bc0d5ab1 [~] Refactor 2024-08-12 00:25:08 +03:00
42bfe00ee5 [~] Refactor 2024-08-12 00:23:40 +03:00
45626d85d4 [~] Refactor 2024-08-12 00:12:58 +03:00
cf849b1009 [~] Refactor 2024-08-12 00:09:51 +03:00
c867c7d828 [~] Refactor 2024-08-12 00:07:23 +03:00
0d7c0d9d09 [~] Refactor 2024-08-12 00:03:35 +03:00
9725a1493c [~] Refactor 2024-08-11 23:59:45 +03:00
15611baed2 [~] Refactor 2024-08-11 23:53:12 +03:00
010b426b03 [~] Refactor 2024-08-11 23:50:50 +03:00
826aec8f3f [~] Refactor 2024-08-11 23:37:47 +03:00
4b93c33d66 [~] Refactor 2024-08-11 23:31:41 +03:00
495e901a23 [~] Refactor 2024-08-11 23:25:02 +03:00
29053ceb5d [~] Refactor 2024-08-11 23:23:57 +03:00
1411dc60e5 [~] Refactor 2024-08-11 23:22:43 +03:00
12c55aa0e8 [~] Refactor 2024-08-11 23:20:45 +03:00
508c55bd68 [~] Refactor 2024-08-11 00:38:49 +03:00
c57b449f69 [~] Refactor 2024-08-11 00:34:39 +03:00
45945c0894 [~] Refactor 2024-08-11 00:30:25 +03:00
fb8b741ca0 [~] Refactor 2024-08-11 00:29:14 +03:00
e6038b7060 [~] Refactor 2024-08-11 00:25:15 +03:00
e1aa8edd42 [~] Refactor 2024-08-11 00:14:10 +03:00
39fa0f23ea [~] Refactor 2024-08-11 00:10:20 +03:00
852c15635f [~] Refactor 2024-08-11 00:00:08 +03:00
b1339cad6b [~] Refactor 2024-08-10 23:55:35 +03:00
01a09989ef [~] Refactor 2024-08-10 23:52:53 +03:00
f2926b6f2b [~] Refactor 2024-08-10 22:07:39 +03:00
e60308a28d [~] Refactor 2024-08-10 21:54:29 +03:00
b8b2443c2a [~] Refactor 2024-08-10 21:52:41 +03:00
3f49dd337f [~] Refactor 2024-08-10 21:51:10 +03:00
331e11d728 [~] Refactor 2024-08-10 21:49:26 +03:00
3b2dd8045e [~] Refactor 2024-08-10 21:37:33 +03:00
bbcf3fb16d [~] Refactor 2024-08-10 21:33:29 +03:00
25c9f86ef0 [~] Refactor 2024-08-10 21:32:28 +03:00
16cfa6c481 [~] Refactor 2024-08-10 21:30:58 +03:00
04f8dca7e6 [~] Refactor 2024-08-10 21:19:59 +03:00
a7993b8a82 [~] Refactor 2024-08-10 21:18:59 +03:00
c00d06368f [~] Refactor 2024-08-10 21:18:34 +03:00
b4836b6514 [~] Refactor 2024-08-10 21:16:52 +03:00
11cd349a7e [~] Refactor 2024-08-10 21:11:45 +03:00
34ae744866 [~] Refactor 2024-08-10 21:09:55 +03:00
99c1c3c80b [~] Refactor 2024-07-01 09:53:06 +03:00
9fe12b0be1 [~] Refactor 2024-07-01 09:36:11 +03:00
128 changed files with 22104 additions and 5793 deletions
.gitattributes.gitignore.gitmodules.mypy.ini
.vscode
Makefile
d1
d2/book1
deps
docker-compose.yml
docker
dotfiles
m.py
mypy-stubs
Cython
cython
distutils
marisa-trie-types/marisa_trie
mypyc
tqdm
types-debugpy/debugpy
platform_dotfiles
python
releases/tar

2
.gitattributes vendored Normal file

@ -0,0 +1,2 @@
releases/tar/** filter=lfs diff=lfs merge=lfs -text
releases/whl/** filter=lfs diff=lfs merge=lfs -text

13
.gitignore vendored

@ -2,3 +2,16 @@ tmp
__pycache__
d2/book1/books
.DS_Store
.vim
*.so
.mypy_cache
.ruff_cache
.tmuxp
*.egg-info
*.whl
*.tar.gz
.vscode/*
!.vscode/launch.json
python/build
.*.kate-swp
!releases/whl/*.whl

6
.gitmodules vendored

@ -16,3 +16,9 @@
[submodule "deps/melianmiko-mb7-apps"]
path = deps/melianmiko-mb7-apps
url = https://notabug.org/melianmiko/mb7_apps
[submodule "deps/com.github.aiortc.aiortc"]
path = deps/com.github.aiortc.aiortc
url = https://gitea.fxreader.online/nartes/com.github.aiortc.aiortc
[submodule "deps/online.fxreader.nartes.books"]
path = deps/online.fxreader.nartes.books
url = https://gitea.fxreader.online/nartes/books.git

18
.mypy.ini Normal file

@ -0,0 +1,18 @@
[mypy]
mypy_path =
mypy-stubs,
deps/com.github.aiortc.aiortc/src,
mypy-stubs/marisa-trie-types,
mypy-stubs/types-debugpy,
python
exclude =
python/tmp,
python/build
plugins =
numpy.typing.mypy_plugin,
pydantic.mypy
explicit_package_bases = true
namespace_packages = true

49
.vscode/launch.json vendored Normal file

@ -0,0 +1,49 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
/*
{
"name": "Python Debugger: Module",
"type": "debugpy",
"request": "launch",
"module": "online_fxreader.vpn.vpn",
},
{
"name": "Python Debugger: Current File with Arguments",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"args": [
"${command:pickArgs}"
]
},
*/
{
"name": "Python Debugger: Remote Attach",
"type": "debugpy",
"request": "attach",
"connect": {
"host": "127.0.0.1",
"port": 4444
},
"pathMappings": [
/*
{
"localRoot": "${workspaceFolder}/deps/com.github.aiortc.aiortc/src/",
//"remoteRoot": "."
"remoteRoot": "~/.local/bin/env3/lib/python3.12/site-packages/",
},
{
"localRoot": "${workspaceFolder}/deps/com.github.aiortc.aiortc/",
//"remoteRoot": "."
"remoteRoot": "~/.local/bin/env3/lib/python3.12/site-packages/",
}
*/
]
}
]
}

141
Makefile Normal file

@ -0,0 +1,141 @@
.PHONY: python_clean_online_fxreader_vpn
host_deps:
./m.py host_deps
python_lint:
./m.py mypy -- -f vscode 2>&1 | less
python_tests:
./m.py tests
#python_clean_online_fxreader_vpn:
# rm -fr \
# deps/com.github.aiortc.aiortc/src/online_fxreader/vpn/dist;
PYTHON_PROJECTS ?= \
deps/com.github.aiortc.aiortc/ \
deps/com.github.aiortc.aiortc/src/online_fxreader/vpn/ \
python
INSTALL_ROOT ?= ~/.local/bin
#python_clean: python_clean_online_fxreader_vpn
python_clean_env:
rm -fr \
$(INSTALL_ROOT)/env3;
python_put_env:
[[ -d $(INSTALL_ROOT)/env3 ]] || (\
uv venv --system-site-packages --seed $(INSTALL_ROOT)/env3 && \
$(INSTALL_ROOT)/env3/bin/python3 -m pip install --force-reinstall uv \
);
python_clean_dist:
for o in $(PYTHON_PROJECTS); do \
[[ -d $$o/dist ]] || continue; \
echo $$o/dist; \
rm -fr $$o/dist; \
done
python_clean: python_clean_dist python_clean_env
UV_ARGS ?= --offline
python_put_dist:
for f in \
$(PYTHON_PROJECTS); do \
[[ -d $$f/dist ]] && continue; \
echo $$f; \
python3 -m build -n $$f; \
$(INSTALL_ROOT)/env3/bin/python3 -m uv pip install $(UV_ARGS) $$f/dist/*.whl; \
done
ln -sf $(INSTALL_ROOT)/env3/bin/online-fxreader-pr34-commands $(INSTALL_ROOT)/commands
PYTHON_PROJECTS_NAMES ?= online.fxreader.pr34
python_whl:
for f in $(PYTHON_PROJECTS_NAMES); do \
./m.py deploy:wheel -o releases/whl -p $$f; \
done
python_put: python_put_dist python_put_env
dotfiles_put:
mkdir -p $(INSTALL_ROOT)
cp dotfiles/.local/bin/gnome-shortcuts-macbook-air $(INSTALL_ROOT)/
mkdir -p ~/.sway
cp dotfiles/.sway/config ~/.sway/config
cp dotfiles/.zshenv ~/.zshenv
cp dotfiles/.zshrc ~/.zshrc
cp dotfiles/.vimrc ~/.vimrc
cp dotfiles/.tmux.conf ~/.tmux.conf
cp dotfiles/.py3.vimrc ~/.py3.vimrc
cp dotfiles/.py3.vimrc ~/.py3.vimrc
cp dotfiles/.gitconfig ~/.gitconfig
cp -rp \
dotfiles/.ipython/profile_default/ipython_config.py \
~/.ipython/profile_default/ipython_config.py
D1=Code\ -\ OSS; \
for p in \
"dotfiles/.config/$$D1/User/keybindings.json" \
"dotfiles/.config/$$D1/User/settings.json"; do \
commands install -f -p "dotfiles/.config/$$D1" -s "$$p" -t ~/.config/"$$D1"; \
done
#commands install -f -p dotfiles -s dotfiles/ -t ~/.config/
PLATFORM ?= macbook_air_2012
PLATFORM_TMP ?= tmp/platform_dotfiles/$(PLATFORM)
dotfiles_put_platform:
@echo to be installed
find platform_dotfiles/$(PLATFORM);
echo remove $(PLATFORM_TMP)'?'; read; sudo rm -fr $(PLATFORM_TMP)
sudo mkdir -p $(PLATFORM_TMP)
sudo cp -rp -T platform_dotfiles/$(PLATFORM)/ $(PLATFORM_TMP)
sudo chown -R root:root $(PLATFORM_TMP)
sudo cp -rp -T $(PLATFORM_TMP) /
sudo udevadm control --reload
sudo systemctl daemon-reload
dotfiles_fetch:
commands install -f -p ~ -s ~/.config/katerc -t dotfiles
commands install -f -p ~ -s ~/.mime.types -t dotfiles
commands install -f -p ~ -s ~/.config/rofi/config.rasi -t dotfiles
commands install -f -p ~ -s ~/.config/Code\ -\ OSS/User/keybindings.json -t dotfiles
commands install -f -p ~ -s ~/.config/Code\ -\ OSS/User/settings.json -t dotfiles
DOTFILES_VERSION ?= 0.1
dotfiles_deploy:
mkdir -p releases/tar
tar -cvf - \
dotfiles \
| xz --compress -9 --stdout > \
releases/tar/dotfiles-$(DOTFILES_VERSION).tar.xz
systemd:
/usr/bin/env python3 d1/systemd.py
for d in tmp/d1; do \
(\
cd $$d; \
for i in *.service *.timer; do \
sudo ln -s -f $$PWD/$$i /etc/systemd/system/$$i; \
done; \
); \
done
sudo systemctl daemon-reload
venv:
uv venv
uv pip install -p .venv \
-r requirements.txt
venv_compile:
uv pip compile --generate-hashes \
requirements.in > requirements.txt
MYPY_SOURCES ?= \
d1/cpanel.py
mypy:
. .venv/bin/activate && \
mypy --strict --follow-imports silent \
$(MYPY_SOURCES)

19
d1/certbot.py Normal file

@ -0,0 +1,19 @@
#!/usr/bin/env python3
import subprocess
import time
import logging
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
while True:
subprocess.check_call([
'docker', 'compose', 'exec', 'ssl-app', 'certbot', 'renew',
])
subprocess.check_call([
'docker', 'compose', 'exec', 'ssl-app', 'nginx', '-s', 'reload',
])
break

@ -1,4 +1,5 @@
import subprocess
import os
import requests
import sys
import io
@ -10,103 +11,131 @@ import logging
import json
import time
with io.open(
'tmp/d1/cpanel.json', 'r'
) as f:
t3 = json.load(f)
logger = logging.getLogger(__name__)
t2 = copy.deepcopy(t3)
for k in t2:
v = t2[k]
v['task'] = lambda : subprocess.Popen(
v['task_cmd'],
stdin=subprocess.DEVNULL,
)
def stop_task(task):
task.terminate()
try:
task.wait(1)
except:
task.kill()
class Launcher:
def run(self):
logging.basicConfig(level=logging.INFO)
t1 = dict()
with io.open(
'tmp/d1/cpanel.json', 'r'
) as f:
t3 = json.load(f)
shutdown = False
t2 = copy.deepcopy(t3)
ssh_known_hosts : list[str] = []
while True:
try:
for k, v in t2.items():
if not k in t1:
logging.info(json.dumps(dict(
task=k,
status='starting',
)))
t1[k] = v['task']()
logging.info(json.dumps(dict(
task=k,
status='started',
)))
continue
if 'ssh_known_hosts' in v:
ssh_known_hosts.append(v['ssh_known_hosts'])
o = t1[k]
if len(ssh_known_hosts) > 0:
subprocess.check_call(
r'''
mkdir -p ~/.ssh && \
cat $SSH_KNOWN_HOSTS > ~/.ssh/known_hosts
''', env=dict(list(os.environ.items())) | dict(
SSH_KNOWN_HOSTS=' '.join(ssh_known_hosts),
),
shell=True
)
not_alive = None
for k in t2:
v = t2[k]
v['task'] = lambda : subprocess.Popen(
v['task_cmd'],
stdin=subprocess.DEVNULL,
)
def stop_task(task: subprocess.Popen[bytes]) -> None:
task.terminate()
try:
not_alive = not (
requests.get(v['url'], timeout=0.5).status_code
== 200
)
task.wait(1)
except:
logging.error(json.dumps(dict(
error=traceback.format_exc(),
time_iso=datetime.datetime.now().isoformat(),
)))
not_alive = True
task.kill()
if not_alive:
logging.error(json.dumps(
dict(
args=o.args,
k=k,
#o=pprint.pformat(o.__dict__),
status='not_alive',
time_iso=datetime.datetime.now().isoformat(),
)
))
t1 = dict()
#stop_task(o)
#del t1[k]
continue
shutdown = False
if not o.poll() is None:
logging.error(json.dumps(
dict(
#o=pprint.pformat(o.__dict__),
args=o.args,
k=k,
return_code=o.poll(),
status='crashed',
time_iso=datetime.datetime.now().isoformat(),
)
))
del t1[k]
continue
while True:
try:
for k, v in t2.items():
if not k in t1:
logging.info(json.dumps(dict(
task=k,
status='starting',
)))
t1[k] = v['task']()
logging.info(json.dumps(dict(
task=k,
status='started',
)))
continue
if shutdown:
break
o = t1[k]
print('\r%s tasks %d' % (
datetime.datetime.now().isoformat(),
len(t1),
), end='')
sys.stdout.flush()
except KeyboardInterrupt:
print('\nshutting down')
break
finally:
time.sleep(5 * 60)
not_alive = None
for o in t1:
stop_task(o)
try:
not_alive = not (
requests.get(v['url'], timeout=0.5).status_code
== 200
)
except:
logging.error(json.dumps(dict(
error=traceback.format_exc(),
time_iso=datetime.datetime.now().isoformat(),
)))
not_alive = True
if not_alive:
logging.error(json.dumps(
dict(
args=o.args,
k=k,
#o=pprint.pformat(o.__dict__),
status='not_alive',
time_iso=datetime.datetime.now().isoformat(),
)
))
#stop_task(o)
#del t1[k]
continue
if not o.poll() is None:
logging.error(json.dumps(
dict(
#o=pprint.pformat(o.__dict__),
args=o.args,
k=k,
return_code=o.poll(),
status='crashed',
time_iso=datetime.datetime.now().isoformat(),
)
))
del t1[k]
continue
if shutdown:
break
print('\r%s tasks %d' % (
datetime.datetime.now().isoformat(),
len(t1),
), end='')
sys.stdout.flush()
except KeyboardInterrupt:
print('\nshutting down')
break
finally:
time.sleep(5 * 60)
for o in t1:
stop_task(o)
if __name__ == '__main__':
Launcher().run()

@ -1,15 +0,0 @@
#!/bin/sh
mkdir -p ~/.local/bin
cp dotfiles/.local/bin/commands ~/.local/bin/commands
mkdir -p ~/.sway
cp dotfiles/.sway/config ~/.sway/config
cp dotfiles/.zshenv ~/.zshenv
cp dotfiles/.zshrc ~/.zshrc
cp dotfiles/.vimrc ~/.vimrc
cp dotfiles/.py3.vimrc ~/.py3.vimrc
cp dotfiles/.py3.vimrc ~/.py3.vimrc
cp dotfiles/.gitconfig ~/.gitconfig
cp -rp \
dotfiles/.ipython/profile_default/ipython_config.py \
~/.ipython/profile_default/ipython_config.py

@ -0,0 +1,11 @@
[Unit]
Description=fxreader.online-certbot
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 d1/certbot.py
WorkingDirectory={{PROJECT_ROOT}}
#Restart=always
#[Install]
#WantedBy=multi-user.target

@ -0,0 +1,9 @@
[Unit]
Description=fxreader.online-certbot-timer
[Timer]
OnUnitActiveSec=1d
OnBootSec=1m
[Install]
WantedBy=timers.target

@ -0,0 +1,16 @@
[Unit]
Description=fxreader.online-service
Requires=docker.service
After=docker.service
[Service]
#Type=oneshot
ExecStart=/usr/bin/docker compose up --force-recreate --remove-orphans
ExecStop=/usr/bin/docker compose down
WorkingDirectory={{PROJECT_ROOT}}
StandardOutput=null
StandardError=null
Restart=always
[Install]
WantedBy=multi-user.target

@ -43,9 +43,23 @@ def forward(
else:
server_name = 'default_server'
if not server_name in sections:
if (
not server_name in sections
):
sections[server_name] = []
if 'client_max_body_size' in entry:
client_max_body_size = entry['client_max_body_size']
else:
client_max_body_size = '50M'
assert isinstance(client_max_body_size, str)
sections[server_name].append(
r'''
client_max_body_size %s;
''' % client_max_body_size
)
location_get = lambda location_body, location_path2, prefix=None,: (
r'''
@ -138,7 +152,7 @@ server {
server_name {server_name};
listen 80 {default_server};
client_max_body_size 50M;
#client_max_body_size 50M;
{sections_config}
}
@ -199,6 +213,80 @@ def ssl(input_json, output_conf):
servers = []
if 'stream_server' in ssl_nginx:
upstream_servers = []
server_names = []
if 'by_server_name' in ssl_nginx['stream_server']:
for k, v in ssl_nginx['stream_server']['by_server_name'].items():
upstream_servers.append(
'upstream %s { server %s; }' % (
v['upstream_name'],
v['url'],
)
)
server_names.append(
'"%s" %s;' % (
v['server_name'], v['upstream_name'],
)
)
if 'ssh' in ssl_nginx['stream_server']:
ssh_section = 'upstream ssh { server {ssh}; }'.replace(
'{ssh}',
ssl_nginx['stream_server']['ssh'],
)
else:
ssh_section = ''
ssl_port = 444
stream_server = r'''
stream {
upstream web {
server 127.0.0.1:444;
}
{upstream_servers}
{ssh_section}
map $ssl_preread_protocol $upstream_protocol {
default ssh;
"TLSv1.2" $upstream_server_name;
"TLSv1.3" $upstream_server_name;
}
map $ssl_preread_server_name $upstream_server_name {
default web;
{server_names}
}
# SSH and SSL on the same port
server {
listen 443;
ssl_preread on;
proxy_pass $upstream_protocol;
}
}
'''.replace(
'{upstream_servers}', ''.join([
' ' + o + '\n'
for o in upstream_servers
]),
).replace(
'{ssh_section}', ssh_section,
).replace(
'{server_names}', ''.join([
' ' + o + '\n'
for o in server_names
]),
)
else:
stream_server = ''
ssl_port = 443
if 'default_server' in ssl_nginx:
server = ssl_nginx['default_server']
@ -211,7 +299,7 @@ server {
set $t1 $http_x_forwarded_for;
}
listen 443 ssl default_server;
listen {ssl_port} ssl default_server;
server_name _;
client_max_body_size {client_max_body_size};
@ -227,6 +315,8 @@ server {
'{client_max_body_size}', server['client_max_body_size'],
).replace(
'{domain_key}', server['domain_key'],
).replace(
'{ssl_port}', '%d' % ssl_port,
)
)
@ -264,7 +354,7 @@ server {
set $t1 $http_x_forwarded_for;
}
listen 443 ssl;
listen {ssl_port} ssl;
server_name {server_names};
client_max_body_size {client_max_body_size};
@ -291,20 +381,27 @@ server {
'{client_max_body_size}', server['client_max_body_size'],
).replace(
'{domain_key}', server['domain_key'],
).replace(
'{ssl_port}', '%d' % ssl_port,
)
)
with io.open(
output_conf,
'w'
) as f:
f.write(
r'''
load_module "modules/ngx_stream_module.so";
events {
multi_accept on;
worker_connections 64;
}
{stream_server}
http {
log_format main
'[$time_local][$remote_addr:$remote_port, $http_x_forwarded_for, $t1, $http_host]'
@ -325,7 +422,9 @@ http {
'' close;
}
}
'''.replace('{servers}', '\n'.join(servers))
'''\
.replace('{servers}', '\n'.join(servers)) \
.replace('{stream_server}', stream_server)
)

41
d1/systemd.py Normal file

@ -0,0 +1,41 @@
#!/usr/bin/env python3
import os
import pathlib
import io
import glob
import subprocess
import logging
logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO)
cache_path = pathlib.Path.cwd() / 'tmp'
project_root = pathlib.Path.cwd()
logger.info(dict(project_root=project_root, cache_path=cache_path,))
for service in [
pathlib.Path(o) for o in sum([
glob.glob('d1/*.service'),
glob.glob('d1/*.timer')
], [])
]:
os.makedirs(str((cache_path / service).parent), exist_ok=True)
with io.open(str(service), 'r') as f:
with io.open(
str(cache_path / service), 'w'
) as f2:
f2.write(
f.read().replace(
'{{PROJECT_ROOT}}',
str(project_root),
)
)
logger.info(dict(
service=str(service),
msg='updated',
))

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

@ -1,77 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width">
<script
src="https://code.jquery.com/jquery-3.6.0.slim.min.js"
integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI="
crossorigin="anonymous"
></script>
<title>Speech synthesiser</title>
<script>
window.context = {};
window.context.books = [];
</script>
<script src="NoSleep.min.js"></script>
<script src="script.js"></script>
<script src="book.js"></script>
<link rel="stylesheet" href="style.css">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class=voice-settings>
<h1>Speech synthesiser</h1>
<p>Enter some text in the input below and press return or the "play" button to hear it. change voices using the dropdown menu.</p>
<form>
<input type="text" class="txt">
<div>
<label for="rate">Rate</label><input type="range" min="0.5" max="2" value="1" step="0.1" id="rate">
<div class="rate-value">1</div>
<div class="clearfix"></div>
</div>
<div>
<label for="pitch">Pitch</label><input type="range" min="0" max="2" value="1" step="0.1" id="pitch">
<div class="pitch-value">1</div>
<div class="clearfix"></div>
</div>
<select class=voice-select>
</select>
<div class="controls">
<button id="play" type="submit">Play</button>
</div>
</form>
</div>
<div class=screen>
<div class=widget>
<select name=book>
<!--<option value=0>Death of a Hear</option>-->
</select>
<br/>
<span>Current Sentence: </span>
<input type=input name=current-sentence></input>
<span>Total Sentences: </span>
<input type=input name=total-sentences disabled>
</input>
<br/>
<input type=button name=add-book value="Add Book">
<input type=button name=read-aloud value="Read Aloud">
<input type=button name=debug value="Debug">
</input>
<br/>
</div>
<pre class=status>
</pre>
</div>
</body>
</html>

@ -1,508 +0,0 @@
$(window).on('load', () => {
var synth = window.speechSynthesis;
var inputForm = document.querySelector('form');
var inputTxt = document.querySelector('.txt');
var voiceSelect = document.querySelector('select');
var pitch = document.querySelector('#pitch');
var pitchValue = document.querySelector('.pitch-value');
var rate = document.querySelector('#rate');
var rateValue = document.querySelector('.rate-value');
var voices = [];
context.nosleep_timer = null;
context.ui = {
voice_settings_div: $('.voice-settings'),
voice_select: $('.voice-select'),
status_pre: $('.status'),
books_select: $('.screen .widget select[name=book]'),
current_sentence_input:
$('.screen .widget input[name=current-sentence]'),
total_sentences_input:
$('.screen .widget input[name=total-sentences]'),
read_aloud:
$('.screen .widget input[name=read-aloud]'),
add_book:
$('.screen .widget input[name=add-book]'),
debug:
$('.screen .widget input[name=debug]'),
};
context.update_books = () => {
context.ui.books_select.empty();
window.context.books.map(
(o, i) => $('<option>').attr('value', '' + i).text(o.slice(0, 10))
).forEach((o) => context.ui.books_select.append(o))
}
context.update_books();
context.sentences = null;
context.pending_stop = false;
context.current_book = null;
context.nosleep = new NoSleep();
context.is_debug = false;
context.log = {
error: [],
info: [],
};
context.callbacks = {
log_error: (msg) => {
if (context.is_debug)
{
console.error(msg);
context.log.error.push(msg);
}
},
enable_no_sleep: () => {
if (context.nosleep_timer != null)
{
context.callbacks.log_error('running already');
}
context.nosleep_timer = setInterval(
() => {
location.hash = 'nosleep' + Math.random();
context.callbacks.update_status();
/*
if ('vibrate' in window.navigator)
{
window.navigator.vibrate(200);
}
*/
}, 1000
);
},
get_state: () => {
let t1 = localStorage['state'];
if (t1)
{
return JSON.parse(t1);
}
else
{
return {};
}
},
get_cookie: (key) => {
/*
return document.cookie.split('; ').map(
(o) => o.split('=')
).reduce(
(b, a) => {
if (a.length == 2) {b[a[0]] = a[1]};
return b
},
{}
)[key];
*/
let t1 = localStorage['state'];
if (t1 != undefined)
{
let t2 = JSON.parse(t1);
return t2[key];
}
else
{
return undefined;
}
},
set_cookie: (key, value) => {
let state = context.callbacks.get_state('state');
state[key] = value;
//document.cookie = `${key}=${value};`;
localStorage['state'] = JSON.stringify(state);
context.callbacks.update_status();
},
disable_no_sleep: () => {
if (context.nosleep_timer == null)
{
context.callbacks.log_error('nothing is running');
}
clearInterval(context.nosleep_timer);
location.hash = '';
context.nosleep_timer = null;
synth.cancel();
},
continuous_reading: async() => {
if (context.is_reading)
{
context.pending_stop = true;
return;
}
context.is_reading = true;
context.nosleep.enable();
context.callbacks.enable_no_sleep();
context.ui.voice_settings_div.addClass('hidden');
context.ui.current_sentence_input.attr(
'disabled',
'disabled'
);
while (
context.callbacks.get_cookie('sentence_id') < context.sentences.length &&
!context.pending_stop
)
{
let sentence =
context.sentences[context.callbacks.get_cookie('sentence_id')];
//context.callbacks.log_error('start');
try {
await context.read_aloud(
context.sentences[
context.callbacks.get_cookie('sentence_id')
]
);
} catch (e) {
context.callbacks.log_error(e);
}
//context.callbacks.log_error('finished');
if (!context.pending_stop)
{
context.callbacks.set_cookie(
'sentence_id',
context.callbacks.get_cookie('sentence_id') + 1
);
}
}
context.pending_stop = false;
context.ui.current_sentence_input.removeAttr('disabled');
context.nosleep.disable();
context.ui.voice_settings_div.removeClass('hidden');
context.callbacks.disable_no_sleep();
context.is_reading = false;
},
update_status: () => {
let data = {};
data.state = context.callbacks.get_state();
if (
context.callbacks.get_cookie('sentence_id') != null &&
context.sentences != null &&
context.callbacks.get_cookie('sentence_id') < context.sentences.length
)
{
data.sentence = context.sentences[context.callbacks.get_cookie('sentence_id')];
}
data.pending_stop = context.pending_stop;
data.is_reading = context.is_reading;
data.log = context.log;
context.ui.current_sentence_input.val(
context.callbacks.get_cookie('sentence_id')
);
data.timestamp = (new Date());
data.version = 'v0.1.7';
data.speech_synthesis = {
paused: synth.paused,
pending: synth.pending,
speaking: synth.speaking,
};
/*
if (!synth.speaking && context.is_reading)
{
synth.cancel();
}
*/
context.ui.status_pre.text(
JSON.stringify(
data,
null,
4,
)
);
},
ui_read_aloud_on_click: async() => {
let book_id = parseInt(context.ui.books_select.val());
if (context.current_book != book_id)
{
context.current_book = book_id;
context.sentences =
context.books[
context.current_book
].replaceAll(/([\.\?\!])\s+/g,'$1\n')
.split('\n');
context.ui.total_sentences_input.val(
context.sentences.length,
);
{
let state = context.callbacks.get_state();
}
}
if (
context.ui.current_sentence_input.val() != ''
)
{
try{
let sentence_id = parseInt(
context.ui.current_sentence_input.val()
);
if (
sentence_id >= 0 &&
sentence_id < context.sentences.length
)
{
context.callbacks.set_cookie(
'sentence_id',
sentence_id
);
}
} catch (e) {
context.callbacks.log_error(e);
}
}
if (context.is_reading && !context.pending_stop)
{
context.pending_stop = true;
}
else
{
context.callbacks.continuous_reading();
}
},
populateVoiceList: () => {
voices = synth.getVoices().sort(function (a, b) {
const aname = a.name.toUpperCase(), bname = b.name.toUpperCase();
if ( aname < bname ) return -1;
else if ( aname == bname ) return 0;
else return +1;
});
//var selectedIndex = voiceSelect.selectedIndex < 0 ? 0 : voiceSelect.selectedIndex;
voiceSelect.innerHTML = '';
for(i = 0; i < voices.length ; i++) {
var option = document.createElement('option');
option.textContent = voices[i].name + ' (' + voices[i].lang + ')';
if(voices[i].default) {
option.textContent += ' -- DEFAULT';
}
{
let voice = context.callbacks.get_cookie('voice');
if (voice && option.textContent == voice)
{
$(option).attr('selected', 'selected');
}
}
option.setAttribute('data-lang', voices[i].lang);
option.setAttribute('data-name', voices[i].name);
voiceSelect.appendChild(option);
}
//voiceSelect.selectedIndex = selectedIndex;
},
init: () => {
let state = context.callbacks.get_state();
context.ui.voice_select.val(state.voice);
if (!state.book_id)
{
context.callbacks.set_cookie(
'book_id',
0,
);
}
if (!state.sentence_id)
{
context.callbacks.set_cookie(
'sentence_id',
0,
);
}
if (state.book_id)
{
context.ui.books_select.find(
'>option',
).eq(state.book_id).attr('selected', 'selected');
}
if (state.sentence_id)
{
context.ui.current_sentence_input.val(
state.sentence_id,
);
}
},
};
context.callbacks.populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = context.callbacks.populateVoiceList;
}
context.callbacks.init();
context.ui.add_book.on(
'click',
async () => {
alert('fuck');
let book = await (
(await fetch(
'books/' + prompt('enter book file', '1.txt')
)).text()
);
//let book = prompt('enter text', '');
//let title = prompt('enter title', '');
//window.context.books.push(title + '\n' + book);
window.context.books.push(book);
window.context.update_books();
},
);
context.ui.read_aloud.on(
'click',
context.callbacks.ui_read_aloud_on_click,
);
context.ui.voice_select.on(
'change',
() => {
context.callbacks.set_cookie(
'voice',
context.ui.voice_select.val()
);
}
);
context.ui.debug.on(
'click',
() => {
if (context.is_debug)
{
context.is_debug = false;
}
else
{
context.is_debug = true;
}
context.callbacks.update_status();
}
);
context.read_aloud = async (raw_line) => {
line = raw_line.trim();
if (line.length == 0)
{
return;
}
let sleep_detect = null;
let exit = () => {
if (sleep_detect != null)
{
clearInterval(sleep_detect);
}
}
return new Promise((response, reject) => {
if (synth.speaking) {
context.callbacks.log_error('speechSynthesis.speaking');
if (reject != undefined)
{
reject('error');
}
return;
}
let utterThis = new SpeechSynthesisUtterance(line);
utterThis.onend = function (event) {
exit();
context.callbacks.log_error(
'SpeechSynthesisUtterance.onend ' + event.error
);
if (response != undefined)
{
response('done ' + event.error);
}
}
utterThis.onpause = function (event) {
exit();
context.callbacks.log_error('SpeechSynthesisUtterance.onpause');
if (reject != undefined)
{
reject('paused ' + event.error);
}
}
utterThis.onerror = function (event) {
exit();
context.callbacks.log_error(
'SpeechSynthesisUtterance.onerror ' + event.error
);
if (reject != undefined)
{
reject('error ' + event.error);
}
}
let selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
for(i = 0; i < voices.length ; i++) {
if(voices[i].name === selectedOption) {
utterThis.voice = voices[i];
break;
}
}
//window.alert('fuck3');
utterThis.pitch = pitch.value;
utterThis.rate = rate.value;
synth.speak(utterThis);
let silence_count = 0;
sleep_detect = setInterval(
() => {
if (!synth.speaking)
{
context.callbacks.log_error(
'silence count is ' + silence_count
)
++silence_count;
}
if (silence_count == 3 || context.pending_stop)
{
exit();
if (context.pending_stop)
{
synth.cancel();
reject('pending stop');
}
else
{
context.callbacks.log_error('phone is sleeping, retry');
response('utterance is not present');
}
/*
context.read_aloud(
line
).then(response).catch(reject);
*/
}
},
100,
);
});
}
function speak(){
let line = inputTxt.value;
if (line !== '') {
context.read_aloud(line);
}
}
inputForm.onsubmit = function(event) {
event.preventDefault();
speak();
inputTxt.blur();
}
pitch.onchange = function() {
pitchValue.textContent = pitch.value;
}
rate.onchange = function() {
rateValue.textContent = rate.value;
}
voiceSelect.onchange = function(){
speak();
}
});

@ -1,84 +0,0 @@
body, html {
margin: 0;
}
html {
height: 100%;
}
body {
height: 90%;
max-width: 800px;
margin: 0 auto;
}
h1, p {
font-family: sans-serif;
text-align: center;
padding: 20px;
}
.txt, select, form > div {
display: block;
margin: 0 auto;
font-family: sans-serif;
font-size: 16px;
padding: 5px;
}
.txt {
width: 80%;
}
select {
width: 83%;
}
form > div {
width: 81%;
}
.txt, form > div {
margin-bottom: 10px;
overflow: auto;
}
.clearfix {
clear: both;
}
label {
float: left;
width: 10%;
line-height: 1.5;
}
.rate-value, .pitch-value {
float: right;
width: 5%;
line-height: 1.5;
}
#rate, #pitch {
float: right;
width: 81%;
}
.controls {
text-align: center;
margin-top: 10px;
}
.controls button {
padding: 10px;
}
.hidden
{
display: none !important;
}
pre {
word-break: break-all;
white-space: pre-wrap;
}

1
deps/com.github.aiortc.aiortc vendored Submodule

@ -0,0 +1 @@
Subproject commit adef10a8c41f5c550622879370a40f8a9e545574

10
deps/greasyfork/.editorconfig vendored Normal file

@ -0,0 +1,10 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[*.{js,json,yml}]
charset = utf-8
indent_style = space
indent_size = 2

6
deps/greasyfork/.gitattributes vendored Normal file

@ -0,0 +1,6 @@
/.yarn/** linguist-vendored
/.yarn/releases/* binary
/.yarn/plugins/**/* binary
/.pnp.* binary linguist-generated
/dist/** filter=lfs diff=lfs merge=lfs -text

15
deps/greasyfork/.gitignore vendored Normal file

@ -0,0 +1,15 @@
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
!dist
build
# Swap the comments on the following lines if you wish to use zero-installs
# In that case, don't forget to run `yarn config set enableGlobalCache false`!
# Documentation here: https://yarnpkg.com/features/caching#zero-installs
#!.yarn/cache
.pnp.*

1
deps/greasyfork/README.md vendored Normal file

@ -0,0 +1 @@
# greasyfork

9486
deps/greasyfork/dist/linkedin.user.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

32
deps/greasyfork/package.json vendored Normal file

@ -0,0 +1,32 @@
{
"name": "greasyfork",
"packageManager": "yarn@4.4.0",
"dependencies": {
"@babel/core": "latest",
"@babel/runtime": "latest",
"@gera2ld/plaid-rollup": "latest",
"@violentmonkey/dom": "latest",
"@violentmonkey/ui": "latest",
"jquery": "latest",
"solid-js": "latest",
"typescript": "latest",
"vite": "latest"
},
"devDependencies": {
"@babel/plugin-transform-react-jsx": "latest",
"@babel/plugin-transform-runtime": "latest",
"@rollup/plugin-typescript": "latest",
"@types/babel__core": "latest",
"@types/babel__plugin-transform-runtime": "latest",
"@types/jquery": "latest",
"@violentmonkey/types": "latest",
"cross-env": "latest",
"postcss": "latest",
"prettier": "latest",
"rollup": "latest",
"rollup-plugin-postcss": "latest",
"rollup-plugin-userscript": "latest",
"tslib": "latest",
"unocss": "latest"
}
}

48
deps/greasyfork/rollup.config.mjs vendored Normal file

@ -0,0 +1,48 @@
import { defineExternal, definePlugins } from '@gera2ld/plaid-rollup';
import { defineConfig } from 'rollup';
import userscript from 'rollup-plugin-userscript';
import typescript from '@rollup/plugin-typescript';
import pkg from './package.json' with { type: 'json' };
export default defineConfig(
Object.entries({
'linkedin': 'src/linkedin/index.ts',
}).map(([name, entry]) => ({
input: entry,
plugins: [
...definePlugins({
esm: true,
minimize: false,
postcss: {
inject: false,
minimize: true,
},
extensions: ['.ts', '.tsx', '.mjs', '.js', '.jsx'],
}),
userscript((meta) => meta.replace('process.env.AUTHOR', pkg.author)),
typescript({ sourceMap: true, inlineSources: true }),
],
external: defineExternal([
'@violentmonkey/ui',
//'@violentmonkey/dom',
'solid-js',
'solid-js/web',
]),
output: {
sourcemap: true,
sourcemapBaseUrl: 'https://gitea.fxreader.online/fxreader.online/freelance-project-34-marketing-blog/media/branch/master/deps/greasyfork/dist/',
format: 'iife',
file: `dist/${name}.user.js`,
globals: {
// Note:
// - VM.solid is just a third-party UMD bundle for solid-js since there is no official one
// - If you don't want to use it, just remove `solid-js` related packages from `external`, `globals` and the `meta.js` file.
'solid-js': 'VM.solid',
'solid-js/web': 'VM.solid.web',
//'@violentmonkey/dom': 'VM',
'@violentmonkey/ui': 'VM',
},
indent: false,
},
})),
);

636
deps/greasyfork/src/linkedin/index.ts vendored Normal file

@ -0,0 +1,636 @@
// ==UserScript==
// @name data extraction linkedin
// @namespace Violentmonkey Scripts
// @match https://www.linkedin.com/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_getValues
// @grant GM_setValues
// @grant GM_listValues
// @grant GM_deleteValue
// @grant GM_deleteValues
// @grant GM_addStyle
// @grant GM_addElement
// @version 0.1
// @author Siarhei Siniak
// @license Unlicense
// @description 10/08/2024, 8:44:59 PM
// @run-at document-body
// @inject-into content
// @noframes
// ==/UserScript==
/*
Use this extension to disalbe CSP for linkedin
https://addons.mozilla.org/en-US/firefox/addon/header-editor/
https://github.com/FirefoxBar/HeaderEditor
https://github.com/violentmonkey/violentmonkey/issues/1335
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
{
"request": [],
"sendHeader": [],
"receiveHeader": [
{
"enable": true,
"name": "disable CSP for linkedin",
"ruleType": "modifyReceiveHeader",
"matchType": "domain",
"pattern": "www.linkedin.com",
"exclude": "",
"group": "Ungrouped",
"isFunction": false,
"action": {
"name": "content-security-policy",
"value": ""
}
}
],
"receiveBody": []
}
*/
import $ from "jquery";
import * as VM from "@violentmonkey/dom";
interface Entry {
header: string
teaser?: string
};
interface State {
search: string
};
class Linkedin {
data : Map<string, any>;
is_fullscreen: boolean = false;
ui : {
root: any | null
entries: any | null
search: any | null
state: any | null
};
state : State;
old_state: State | null = null;
constructor() {
this.data = new Map();
this.ui = {
root: null,
entries: null,
search: null,
state: null,
};
this.state = {
search: '',
};
}
clean_page() {
if (location.href.search('empty_body=true') != -1)
{
this.is_fullscreen = true;
$('head').empty();
$('body').empty();
$('body').addClass('no-border');
}
}
async data_load() {
let self = this;
const keys = await GM_listValues();
let loaded = 0;
for (let o of keys)
{
if (!o.startsWith('data-'))
{
return;
}
self.data.set(
o.slice(5,),
await GM_getValue(o)
);
loaded += 1;
}
console.log({action: 'loaded', total: loaded});
}
string_reduce (text: string) {
return text.replaceAll(/\s+/gi, ' ').trim();
}
parse_header() {
let self = this;
return [
$(
'.scaffold-finite-scroll__content > div > .relative .update-components-header'
).map((i, o) => ({
header: o.innerText
})),
$(
'.scaffold-finite-scroll__content > div > .relative .update-components-actor'
).map((i, o) => {
let header = $(o);
let teaser = $(o).parents('.relative')
.parent().find('.feed-shared-update-v2__description-wrapper');
return {
header: self.string_reduce(header.text()),
teaser: self.string_reduce(teaser.text()),
};
})
]
}
async data_add (entry: Entry) {
let self = this;
if (self.data.has(entry.header))
{
return false;
}
self.data.set(entry.header, {
entry: entry,
ts: (new Date()).valueOf(),
});
await GM_setValue(
'data-' + entry.header,
self.data.get(entry.header)
)
console.log('saved ' + entry.header);
console.log(self.data.get(entry.header));
return true;
}
async document_on_changed () {
let self = this;
let state_changed = false;
if (
JSON.stringify(self.state_get()) != JSON.stringify(self.state)
)
{
state_changed = true;
self.old_state = self.state;
self.state = self.state_get();
}
let current_data = self.parse_header();
let changed = false;
for (let o of current_data[0])
{
let current_changed = await self.data_add(o);
if (current_changed)
{
changed = current_changed;
}
}
for (let o of current_data[1])
{
let current_changed = await self.data_add(o);
if (current_changed)
{
changed = current_changed;
}
}
if (
changed || (
state_changed ||
self.ui.entries === null && self.data.size > 0
)
)
{
self.display();
}
}
listener_add() {
let self = this;
return VM.observe(
document.body,
() => {
self.document_on_changed();
}
);
}
display_init() {
let self = this;
self.ui.root = $(`<div class=online-fxreader-linkedin>`);
$(document.body).append(self.ui.root);
if (self.is_fullscreen)
{
self.ui.root.addClass('fullscreen');
}
$('head').append($('<style>').html(`
div.online-fxreader-linkedin {
height: 10em;
overflow: hidden;
z-index: 9999;
position: fixed;
top: 5em;
background: yellow;
margin-left: 1em;
word-wrap: anywhere;
white-space: break-spaces;
margin-right: 1em;
width: calc(100% - 2em);
}
.d-none {
display: none !important;
}
.online-fxreader-linkedin.tray-active .search,
.online-fxreader-linkedin.tray-active .entries
{
display: none;
}
.online-fxreader-linkedin .tray
{
cursor: pointer;
position: absolute;
right: 0px;
z-index: 9999;
}
.online-fxreader-linkedin.tray-active
{
right: 1em;
width: 3em;
height: 3em !important;
}
.online-fxreader-linkedin .search
{
display: flex;
position: sticky;
top: 0px;
background-color: #eee;
}
.online-fxreader-linkedin .search input
{
width: 60em;
}
.online-fxreader-linkedin .entries
{
overflow: scroll;
height: 100%;
}
.online-fxreader-linkedin .entry.even
{
background-color: #eee;
}
.online-fxreader-linkedin .entry.odd
{
background-color: #ddd;
}
.online-fxreader-linkedin .search,
.online-fxreader-linkedin .search input
{
height: 2em;
line-height: 2em;
box-sizing: border-box;
}
.no-border {
padding: unset;
margin: unset;
}
.online-fxreader-linkedin:hover,
.online-fxreader-linkedin.fullscreen
{
height: 80vh;
}
`));
GM_addElement('script', {
"textContent": `
class Linkedin {
constructor() {
let self = this;
this.has_callbacks = false;
this.ui = {
root: () => {
return document.getElementsByClassName('online-fxreader-linkedin')[0];
},
};
self.ui.search = () => {
let search = self.ui.root().getElementsByClassName('search')[0];
let search_input = search.getElementsByTagName('input')[0];
return search_input;
};
self.ui.tray = () => {
// let search = self.ui.root().getElementsByClassName('search')[0];
let tray = self.ui.root().getElementsByClassName('tray')[0];
return tray;
};
self.ui.state = () => {
let state = self.ui.root().getElementsByClassName('state')[0];
return state;
};
}
add_callbacks() {
let self = this;
self.ui.tray().addEventListener(
'click', function(e) {
let o = e.currentTarget;
let cl = o.classList;
let r = self.ui.root();
if (cl.contains('active'))
{
cl.remove('active');
r.classList.add('tray-active');
}
else
{
cl.add('active');
r.classList.remove('tray-active');
}
}
);
}
blah(class_name) {
if (!this.has_callbacks)
{
this.add_callbacks();
this.has_callbacks = true;
}
console.log('blah');
Array.from(
document.getElementsByClassName(class_name)
).forEach((o) => o.remove());
}
state_update(partial) {
let self = this;
let ui_state = self.ui.state();
let old_state = JSON.parse(ui_state.innerText);
ui_state.innerText = JSON.stringify(
{
...old_state,
...partial
}
);
}
search_on_change() {
let self = this;
let search = self.ui.search();
self.state_update(
{
search: search.value
}
);
}
};
const online_fxreader_linkedin = new Linkedin();
console.log('started');
`
});
}
state_get() {
let self = this;
if (self.ui.state && self.ui.state.text() !== '')
{
return JSON.parse(self.ui.state.text());
}
else
{
return {};
}
}
state_set(partial: any) {
let self = this;
self.ui.state.text(
{
...self.state_get(),
...partial
}
);
}
display() {
let self = this;
let sorted_entries = Array.from(self.data.entries()).sort(
(a, b) => a[1].ts - b[1].ts
);
// self.ui.root.empty();
if (self.ui.search === null)
{
self.ui.root.append(
$('<div>').addClass('tray').text('SHOW/HIDE')
);
let search = $('<div>').addClass('search').append(
$('<input>').val(self.state.search)
).attr(
'onkeyup',
`online_fxreader_linkedin.search_on_change()`,
);
search.append(
$('<div>').addClass('total')
);
self.ui.root.append(search);
self.ui.search = search;
}
if (self.ui.state === null)
{
self.ui.state = $('<div>').addClass('state d-none').text(
JSON.stringify(self.state)
);
self.ui.root.append(self.ui.state);
}
else
{
}
//state_set(old_state);
let entries = null;
if (self.ui.entries === null)
{
entries = $('<div>').addClass('entries');
self.ui.root.append(entries);
self.ui.entries = entries
}
else
{
entries = self.ui.entries;
entries.empty();
}
let keywords = (self.state?.search || '').split(/\s+/).map((o) => {
let action = '';
let word = '';
if (o.length > 0)
{
if (o[0] == '+')
{
action = 'include';
word = o.slice(1,);
}
else if (o[0] == '-')
{
action = 'exclude';
word = o.slice(1,);
}
else
{
action = 'include';
word = o;
}
}
return {
action,
word,
};
}).filter((o) => o.action !== '' && o.word !== '');
let filtered_entries = sorted_entries.filter((o) => {
let match = true;
let text = JSON.stringify(o);
for (let k of keywords)
{
if (k.action == 'include')
{
if (text.search(k.word) == -1)
{
match = false;
}
}
else if (k.action == 'exclude')
{
if (text.search(k.word) != -1)
{
match = false;
}
}
if (!match)
{
break;
}
}
return match;
})
self.ui.search.find('.total').text(
filtered_entries.length
);
let i = 0;
for (let o of filtered_entries.reverse())
{
let raw = JSON.stringify(o[1]);
let ts = (new Date(o[1].ts));
let entry = $('<div>').addClass('entry');
if (i % 2 == 0)
{
entry.addClass('even');
}
else
{
entry.addClass('odd');
}
entry.append(
$('<div>').addClass('ts').text(
ts.toISOString(),
)
);
entry.append(
$('<div>').addClass('header').text(
o[1].entry.header
)
);
entry.append(
$('<div>').addClass('teaser').text(
o[1].entry.teaser
)
);
// entry.append($('<pre>').text(raw));
entries.append(entry);
++i;
}
GM_addElement('script', {
"class": 'bridge',
"textContent": `
online_fxreader_linkedin.blah('bridge');
`
});
}
}
const l = new Linkedin();
(async () => {
l.clean_page();
await l.data_load();
const disconnect = l.listener_add();
l.display_init();
})();

1
deps/greasyfork/src/types/vm.d.ts vendored Normal file

@ -0,0 +1 @@
import '@violentmonkey/types';

115
deps/greasyfork/tsconfig.json vendored Normal file

@ -0,0 +1,115 @@
{
"include": ["src"],
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "esnext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"lib": [
"DOM",
"ES6",
"DOM.Iterable",
"ScriptHost",
"ESNext"
], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "esnext", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "build/", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

4844
deps/greasyfork/yarn.lock vendored Normal file

File diff suppressed because it is too large Load Diff

1
deps/online.fxreader.nartes.books vendored Submodule

@ -0,0 +1 @@
Subproject commit 3c691ef68d8899edf328d5b06135c0d3b02e7940

@ -7,7 +7,7 @@ services:
volumes:
- ./d1/:/app/d1/:ro
- ./tmp/cache/:/app/tmp/cache/:ro
restart: always
restart: on-failure
ssl-app:
build:
context: .
@ -16,36 +16,40 @@ services:
- ./d1/:/app/d1/:ro
- ./tmp/d1/:/app/tmp/d1/:ro
- ./tmp/d1/letsencrypt:/etc/letsencrypt:rw
restart: always
restart: on-failure
cpanel:
build:
context: .
dockerfile: ./docker/cpanel/Dockerfile
links:
- app
#links:
# - app
volumes:
- ./d1/:/app/d1:ro
- ./tmp/d1/:/app/tmp/d1/:ro
restart: always
restart: on-failure
dynu:
build:
context: .
dockerfile: ./docker/dynu/Dockerfile
profiles:
- broken
volumes:
- ./d1/dynu_update.py:/app/d1/dynu_update.py:ro
- ./tmp/cache/dynu.auth.json:/app/tmp/cache/dynu.auth.json:ro
restart: always
links:
- ngrok
restart: on-failure
# links:
# - ngrok
ngrok:
image: wernight/ngrok
links:
- app
#links:
# - app
profiles:
- broken
command: ['ngrok', 'http', 'app:80']
volumes:
- ./tmp/cache/ngrok.yml:/home/ngrok/.ngrok2/ngrok.yml:ro
restart: always
restart: on-failure
#forward:
# build:
# context: .

@ -4,7 +4,7 @@ RUN apk add python3
RUN apk add tini
RUN apk add bash curl
RUN apk add py3-pip
RUN pip3 install requests
RUN pip3 install --break-system-packages requests
WORKDIR /app

19
docker/js/.zshrc Normal file

@ -0,0 +1,19 @@
# The following lines were added by compinstall
zstyle ':completion:*' completer _expand _complete _ignored _correct _approximate
zstyle :compinstall filename '~/.zshrc'
setopt INC_APPEND_HISTORY SHARE_HISTORY AUTO_PUSHD PUSHD_IGNORE_DUPS
setopt PROMPTSUBST
autoload -Uz compinit
compinit
# End of lines added by compinstall
# Lines configured by zsh-newuser-install
HISTFILE=~/.histfile
HISTSIZE=1000000
SAVEHIST=1000000
# End of lines configured by zsh-newuser-install
bindkey -d
bindkey -v

15
docker/js/Dockerfile Normal file

@ -0,0 +1,15 @@
FROM node as base
ENV DEBIAN_FRONTEND noninteractive
RUN \
apt-get update -yy && \
apt-get install \
tini zsh less tree \
-yy
RUN chsh -s /usr/bin/zsh
WORKDIR /app/deps/greasyfork
ENTRYPOINT ["tini", "--"]
CMD ["bash", "/app/docker/js/init.sh"]
# CMD ["sleep", "999999999999999999"]

@ -0,0 +1,17 @@
version: '3.7'
services:
js:
build:
context: .
dockerfile: ./docker/js/Dockerfile
volumes:
- ./deps/greasyfork:/app/deps/greasyfork:rw
- ./tmp/cache/js/root-cache:/root/.cache:rw
- ./tmp/cache/js/root-yarn:/root/.yarn:rw
- ./docker/js:/app/docker/js:ro
- ./tmp/cache/js:/app/tmp/cache/js:rw
deploy:
resources:
limits:
cpus: 1.5
memory: 1G

7
docker/js/init.sh Normal file

@ -0,0 +1,7 @@
corepack enable
corepack install
# yarn init -2
ln -sf /app/docker/js/.zshrc ~/.zshrc
ln -sf /app/tmp/cache/js/.histfile ~/.histfile
export EDITOR=vim
exec /usr/bin/zsh -l

@ -7,6 +7,7 @@ RUN apk add nginx
RUN apk add tini
#RUN pip3 install requests certbot
RUN apk add certbot
RUN apk add nginx-mod-stream
WORKDIR /app

@ -0,0 +1,156 @@
// Place your key bindings in this file to override the defaults
[
{
"key": "alt+z",
"command": "-editor.action.toggleWordWrap"
},
{
"key": "alt+z",
"command": "-workbench.action.terminal.sizeToContentWidth",
"when": "terminalFocus && terminalHasBeenCreated && terminalIsOpen || terminalFocus && terminalIsOpen && terminalProcessSupported"
},
{
"key": "alt+r",
"command": "workbench.action.toggleMaximizeEditorGroup",
"when": "editorPartMaximizedEditorGroup || editorPartMultipleEditorGroups"
},
{
"key": "ctrl+k ctrl+m",
"command": "-workbench.action.toggleMaximizeEditorGroup",
"when": "editorPartMaximizedEditorGroup || editorPartMultipleEditorGroups"
},
{
"key": "alt+r",
"command": "workbench.action.toggleMaximizedPanel",
"when": "!editorTextFocus"
},
{
"key": "ctrl+p",
"command": "-extension.vim_ctrl+p",
"when": "editorTextFocus && vim.active && vim.use<C-p> && !inDebugRepl || vim.active && vim.use<C-p> && !inDebugRepl && vim.mode == 'CommandlineInProgress' || vim.active && vim.use<C-p> && !inDebugRepl && vim.mode == 'SearchInProgressMode'"
},
{
"key": "alt+t",
"command": "workbench.action.terminal.toggleTerminal",
"when": "terminal.active"
},
{
"key": "ctrl+`",
"command": "-workbench.action.terminal.toggleTerminal",
"when": "terminal.active"
},
{
"key": "ctrl+e",
"command": "-workbench.action.quickOpen"
},
{
"key": "ctrl+n",
"command": "-extension.vim_ctrl+n",
"when": "editorTextFocus && vim.active && vim.use<C-n> && !inDebugRepl || vim.active && vim.use<C-n> && !inDebugRepl && vim.mode == 'CommandlineInProgress' || vim.active && vim.use<C-n> && !inDebugRepl && vim.mode == 'SearchInProgressMode'"
},
{
"key": "ctrl+t",
"command": "-extension.vim_ctrl+t",
"when": "editorTextFocus && vim.active && vim.use<C-t> && !inDebugRepl"
},
{
"key": "ctrl+f",
"command": "-extension.vim_ctrl+f",
"when": "editorTextFocus && vim.active && vim.use<C-f> && !inDebugRepl && vim.mode != 'Insert'"
},
{
"key": "ctrl+f",
"command": "-actions.find",
"when": "editorFocus || editorIsOpen"
},
{
"key": "ctrl+f",
"command": "workbench.action.findInFiles"
},
{
"key": "ctrl+shift+f",
"command": "-workbench.action.findInFiles"
},
{
"key": "ctrl+g",
"command": "-workbench.action.gotoLine"
},
{
"key": "ctrl+g",
"command": "-workbench.action.terminal.goToRecentDirectory",
"when": "terminalFocus && terminalHasBeenCreated || terminalFocus && terminalProcessSupported"
},
{
"key": "alt+r",
"command": "-toggleSearchRegex",
"when": "searchViewletFocus"
},
{
"key": "alt+r",
"command": "-toggleFindRegex",
"when": "editorFocus"
},
{
"key": "alt+r",
"command": "-workbench.action.terminal.toggleFindRegex",
"when": "terminalFindVisible && terminalHasBeenCreated || terminalFindVisible && terminalProcessSupported"
},
{
"key": "alt+r",
"command": "-toggleSearchEditorRegex",
"when": "inSearchEditor && searchInputBoxFocus"
},
{
"key": "ctrl+/",
"command": "-editor.action.accessibleViewAcceptInlineCompletion",
"when": "accessibleViewIsShown && accessibleViewCurrentProviderId == 'inlineCompletions'"
},
{
"key": "ctrl+k ctrl+/",
"command": "-editor.foldAllBlockComments",
"when": "editorTextFocus && foldingEnabled"
},
{
"key": "ctrl+/",
"command": "-toggleExplainMode",
"when": "suggestWidgetVisible"
},
{
"key": "ctrl+/",
"command": "-workbench.action.chat.attachContext",
"when": "inChatInput && chatLocation == 'editing-session' || inChatInput && chatLocation == 'editor' || inChatInput && chatLocation == 'notebook' || inChatInput && chatLocation == 'panel' || inChatInput && chatLocation == 'terminal'"
},
{
"key": "ctrl+/",
"command": "-workbench.action.terminal.sendSequence",
"when": "terminalFocus"
},
{
"key": "shift+alt+l",
"command": "workbench.action.editorLayoutTwoRowsRight"
},
{
"key": "ctrl+b",
"command": "-extension.vim_ctrl+b",
"when": "editorTextFocus && vim.active && vim.use<C-b> && !inDebugRepl && vim.mode != 'Insert'"
},
{
"key": "ctrl+w",
"command": "-workbench.action.closeActiveEditor"
},
{
"key": "ctrl+w",
"command": "-workbench.action.closeGroup",
"when": "activeEditorGroupEmpty && multipleEditorGroups"
},
{
"key": "ctrl+w",
"command": "-extension.vim_ctrl+w",
"when": "editorTextFocus && vim.active && vim.use<C-w> && !inDebugRepl"
},
{
"key": "ctrl+w",
"command": "workbench.action.closeActiveEditor",
"when": "editorTextFocus"
}
]

@ -0,0 +1,151 @@
{
"editor.wordWrap": "on",
"editor.minimap.autohide": true,
"editor.minimap.maxColumn": 80,
"editor.minimap.size": "fit",
"python.experiments.enabled": false,
"debugpy.debugJustMyCode": false,
"python.REPL.enableREPLSmartSend": false,
"python.terminal.activateEnvironment": false,
"python.testing.autoTestDiscoverOnSaveEnabled": false,
"python.languageServer": "None",
"typescript.surveys.enabled": false,
"typescript.suggestionActions.enabled": false,
"typescript.tsserver.enableRegionDiagnostics": false,
"typescript.tsserver.maxTsServerMemory": 0.05,
"typescript.tsserver.useSyntaxServer": "never",
"typescript.tsserver.web.typeAcquisition.enabled": false,
"typescript.validate.enable": false,
"typescript.workspaceSymbols.excludeLibrarySymbols": false,
"typescript.check.npmIsInstalled": false,
"typescript.tsserver.web.projectWideIntellisense.enabled": false,
"python.REPL.provideVariables": false,
"git.openRepositoryInParentFolders": "never",
"workbench.enableExperiments": false,
"workbench.cloudChanges.continueOn": "off",
"workbench.cloudChanges.autoResume": "off",
"extensions.autoCheckUpdates": false,
"update.mode": "none",
"workbench.settings.enableNaturalLanguageSearch": false,
"update.showReleaseNotes": false,
"extensions.autoUpdate": false,
"telemetry.telemetryLevel": "off",
"json.schemaDownload.enable": false,
"npm.fetchOnlinePackageInfo": false,
"window.experimentalControlOverlay": false,
"window.commandCenter": false,
"window.confirmBeforeClose": "always",
"window.dialogStyle": "custom",
"window.titleBarStyle": "custom",
"window.customTitleBarVisibility": "windowed",
"window.enableMenuBarMnemonics": false,
"window.menuBarVisibility": "compact",
"issueReporter.experimental.auxWindow": false,
"workbench.colorTheme": "Monokai",
"workbench.preferredDarkColorTheme": "Monokai",
"workbench.preferredHighContrastColorTheme": "Monokai",
"workbench.preferredHighContrastLightColorTheme": "Monokai",
"workbench.preferredLightColorTheme": "Monokai",
"mesonbuild.downloadLanguageServer": false,
// "vim.easymotion": true,
// "vim.incsearch": true,
"vim.useSystemClipboard": true,
// "vim.useCtrlKeys": true,
"vim.hlsearch": true,
// "vim.insertModeKeyBindings": [
// {
// "before": ["j", "j"],
// "after": ["<Esc>"]
// }
// ],
"vim.normalModeKeyBindingsNonRecursive": [
{
"before": ["<leader>", "w"],
"after": ["<C-w>"],
// "after": ["d", "d"]
},
// {
// "before": ["<C-n>"],
// "commands": [":nohl"]
// },
// {
// "before": ["K"],
// "commands": ["lineBreakInsert"],
// "silent": true
// }
],
"vim.leader": "\\",
// "vim.handleKeys": {
// "<C-a>": false,
// "<C-f>": false
// },
"extensions.experimental.affinity": {
"vscodevim.vim": 1
},
"diffEditor.experimental.showMoves": true,
"diffEditor.hideUnchangedRegions.enabled": true,
"python.locator": "native",
"python.testing.promptToConfigure": false,
"typescript.format.enable": false,
"typescript.format.indentSwitchCase": false,
"typescript.preferences.renameMatchingJsxTags": false,
"typescript.autoClosingTags": false,
"typescript.format.insertSpaceAfterCommaDelimiter": false,
"typescript.format.insertSpaceAfterKeywordsInControlFlowStatements": false,
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false,
"docker.enableDockerComposeLanguageService": false,
"go.useLanguageServer": false,
"search.maxResults": 128,
"search.ripgrep.maxThreads": 1,
"search.searchEditor.defaultNumberOfContextLines": 7,
"search.searchOnType": false,
"task.allowAutomaticTasks": "off",
"task.autoDetect": "off",
"task.quickOpen.detail": false,
"task.reconnection": false,
"javascript.autoClosingTags": false,
"javascript.format.enable": false,
"javascript.format.insertSpaceAfterCommaDelimiter": false,
"javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"javascript.format.insertSpaceAfterKeywordsInControlFlowStatements": false,
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingEmptyBraces": false,
"javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
"javascript.format.insertSpaceAfterSemicolonInForStatements": false,
"javascript.format.insertSpaceBeforeAndAfterBinaryOperators": false,
"javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": false,
"javascript.inlayHints.variableTypes.suppressWhenTypeMatchesName": false,
"javascript.preferences.renameMatchingJsxTags": false,
"javascript.preferences.useAliasesForRenames": false,
"javascript.suggest.autoImports": false,
"javascript.suggest.classMemberSnippets.enabled": false,
"javascript.suggest.completeJSDocs": false,
"javascript.suggest.enabled": false,
"javascript.suggest.includeAutomaticOptionalChainCompletions": false,
"javascript.suggest.includeCompletionsForImportStatements": false,
"javascript.suggest.jsdoc.generateReturns": false,
"javascript.suggest.names": false,
"javascript.suggest.paths": false,
"javascript.suggestionActions.enabled": false,
"javascript.updateImportsOnFileMove.enabled": "never",
"javascript.validate.enable": false,
"js/ts.implicitProjectConfig.strictFunctionTypes": false,
"js/ts.implicitProjectConfig.strictNullChecks": false,
"typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": false,
"typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": false,
"typescript.format.insertSpaceAfterSemicolonInForStatements": false,
"typescript.format.insertSpaceBeforeAndAfterBinaryOperators": false,
"typescript.inlayHints.parameterNames.suppressWhenArgumentMatchesName": false,
"typescript.inlayHints.variableTypes.suppressWhenTypeMatchesName": false,
"typescript.preferences.useAliasesForRenames": false,
"typescript.reportStyleChecksAsWarnings": false,
"typescript.suggest.autoImports": false,
"typescript.suggest.classMemberSnippets.enabled": false,
"typescript.suggest.completeJSDocs": false,
"typescript.suggest.enabled": false,
"typescript.suggest.includeAutomaticOptionalChainCompletions": false,
"typescript.suggest.includeCompletionsForImportStatements": false,
"typescript.suggest.jsdoc.generateReturns": false,
"typescript.suggest.objectLiteralMethodSnippets.enabled": false,
"typescript.suggest.paths": false,
"typescript.tsc.autoDetect": "off",
}

283
dotfiles/.config/katerc Normal file

@ -0,0 +1,283 @@
[BuildConfig]
AllowedCommandLines=
AutoSwitchToOutput=true
BlockedCommandLines=
UseDiagnosticsOutput=true
[CTags]
GlobalCommand=ctags -R --c++-types=+px --extra=+q --excmd=pattern --exclude=Makefile --exclude=.
GlobalNumTargets=0
[General]
Allow Tab Scrolling=true
Auto Hide Tabs=false
Close After Last=false
Close documents with window=true
Cycle To First Tab=true
Days Meta Infos=30
Diagnostics Limit=12000
Diff Show Style=0
Elide Tab Text=false
Enable Context ToolView=false
Expand Tabs=false
Icon size for left and right sidebar buttons=32
Last Session=calibre
Modified Notification=false
Mouse back button action=0
Mouse forward button action=0
Open New Tab To The Right Of Current=true
Output History Limit=100
Output With Date=false
Quickopen Filter Mode=0
Quickopen List Mode=true
Recent File List Entry Count=10
Restore Window Configuration=true
SDI Mode=false
Save Meta Infos=false
Session Manager Sort Column=0
Session Manager Sort Order=1
Show Full Path in Title=true
Show Menu Bar=true
Show Status Bar=true
Show Symbol In Navigation Bar=true
Show Tab Bar=true
Show Tabs Close Button=true
Show Url Nav Bar=false
Show output view for message type=1
Show text for left and right sidebar=false
Show welcome view for new window=true
Startup Session=manual
Stash new unsaved files=true
Stash unsaved file changes=true
Sync section size with tab positions=false
Tab Double Click New Document=true
Tab Middle Click Close Document=true
Tabbar Tab Limit=0
[KDE]
widgetStyle=Fusion
[KTextEditor Document]
Allow End of Line Detection=true
Auto Detect Indent=true
Auto Reload If State Is In Version Control=true
Auto Save=false
Auto Save Interval=0
Auto Save On Focus Out=false
BOM=false
Backup Local=false
Backup Prefix=
Backup Remote=false
Backup Suffix=~
Camel Cursor=true
Encoding=UTF-8
End of Line=0
Indent On Backspace=true
Indent On Tab=true
Indent On Text Paste=true
Indentation Mode=normal
Indentation Width=2
Keep Extra Spaces=false
Line Length Limit=10000
Newline at End of File=true
On-The-Fly Spellcheck=false
Overwrite Mode=false
PageUp/PageDown Moves Cursor=false
Remove Spaces=1
ReplaceTabsDyn=false
Show Spaces=2
Show Tabs=true
Smart Home=true
Swap Directory=
Swap File Mode=1
Swap Sync Interval=15
Tab Handling=2
Tab Width=2
Trailing Marker Size=1
Use Editor Config=true
Word Wrap=false
Word Wrap Column=80
[KTextEditor Renderer]
Animate Bracket Matching=false
Auto Color Theme Selection=false
Color Theme=Monokai2
Line Height Multiplier=1
Show Indentation Lines=false
Show Whole Bracket Expression=false
Text Font=Terminus,18,-1,5,400,0,0,0,0,0,0,0,0,0,0,1
Text Font Features=
Word Wrap Marker=true
[KTextEditor View]
Allow Mark Menu=true
Auto Brackets=true
Auto Center Lines=0
Auto Completion=true
Auto Completion Preselect First Entry=true
Backspace Remove Composed Characters=false
Bookmark Menu Sorting=0
Bracket Match Preview=true
Chars To Enclose Selection=<>(){}[]'"
Cycle Through Bookmarks=true
Default Mark Type=1
Dynamic Word Wrap=true
Dynamic Word Wrap Align Indent=80
Dynamic Word Wrap At Static Marker=false
Dynamic Word Wrap Indicators=1
Dynamic Wrap not at word boundaries=false
Enable Accessibility=true
Enable Tab completion=false
Enter To Insert Completion=true
Fold First Line=false
Folding Bar=true
Folding Preview=true
Icon Bar=false
Input Mode=1
Keyword Completion=true
Line Modification=true
Line Numbers=true
Max Clipboard History Entries=20
Maximum Search History Size=100
Mouse Paste At Cursor Position=false
Multiple Cursor Modifier=134217728
Persistent Selection=false
Scroll Bar Marks=false
Scroll Bar Mini Map All=true
Scroll Bar Mini Map Width=60
Scroll Bar MiniMap=false
Scroll Bar Preview=true
Scroll Past End=false
Search/Replace Flags=140
Shoe Line Ending Type in Statusbar=false
Show Documentation With Completion=true
Show File Encoding=true
Show Folding Icons On Hover Only=true
Show Line Count=true
Show Scrollbars=0
Show Statusbar Dictionary=true
Show Statusbar Highlighting Mode=true
Show Statusbar Input Mode=true
Show Statusbar Line Column=true
Show Statusbar Tab Settings=true
Show Word Count=true
Smart Copy Cut=true
Statusbar Line Column Compact Mode=true
Text Drag And Drop=true
User Sets Of Chars To Enclose Selection=
Vi Input Mode Steal Keys=false
Vi Relative Line Numbers=false
Word Completion=true
Word Completion Minimal Word Length=3
Word Completion Remove Tail=true
[Konsole]
AutoSyncronizeMode=0
KonsoleEscKeyBehaviour=false
KonsoleEscKeyExceptions=vi,vim,nvim,git
RemoveExtension=false
RunPrefix=
SetEditor=false
[MainWindow]
1366x768 screen: Height=733
1366x768 screen: Width=1362
2 screens: Height=727
2 screens: Width=679
2048x1080 screen: Window-Maximized=true
ToolBarsMovable=Disabled
[PluginSymbolViewer]
ExpandTree=false
SortSymbols=false
TreeView=false
ViewTypes=false
[Printing][HeaderFooter]
FooterBackground=211,211,211
FooterBackgroundEnabled=false
FooterEnabled=true
FooterForeground=0,0,0
FooterFormatCenter=
FooterFormatLeft=
FooterFormatRight=%U
HeaderBackground=211,211,211
HeaderBackgroundEnabled=false
HeaderEnabled=true
HeaderFooterFont=monospace,10,-1,5,400,0,0,0,1,0,0,0,0,0,0,1
HeaderForeground=0,0,0
HeaderFormatCenter=%f
HeaderFormatLeft=%y
HeaderFormatRight=%p
[Printing][Layout]
BackgroundColorEnabled=false
BoxColor=invalid
BoxEnabled=false
BoxMargin=6
BoxWidth=1
ColorScheme=Printing
Font=monospace,10,-1,5,400,0,0,0,1,0,0,0,0,0,0,1
[Printing][Text]
DontPrintFoldedCode=true
Legend=false
LineNumbers=false
[Shortcut Schemes]
Current Scheme=Default
[Shortcuts]
kate_mdi_focus_toolview_kate_private_plugin_katekonsoleplugin=;\s
kate_mdi_sidebar_visibility=;\s
kate_mdi_toolview_kate_private_plugin_katekonsoleplugin=;\s
kate_mdi_toolview_kateproject=Ctrl+B
kate_mdi_toolview_kateprojectinfo=Alt+T
[debugplugin]
DAPConfiguration=
[filetree]
editShade=183,220,246
listMode=false
middleClickToClose=false
shadingEnabled=true
showCloseButton=false
showFullPathOnRoots=false
showToolbar=true
sortRole=0
viewShade=211,190,222
[lspclient]
AllowedServerCommandLines=/usr/bin/clangd -log=error --background-index --limit-results=500 --completion-style=bundled,/usr/bin/pylsp --check-parent-process
AutoHover=true
AutoImport=true
BlockedServerCommandLines=/usr/bin/python -m esbonio
CompletionDocumentation=true
CompletionParens=true
Diagnostics=true
FormatOnSave=false
HighlightGoto=true
IncrementalSync=true
InlayHints=false
Messages=true
ReferencesDeclaration=true
SemanticHighlighting=true
ServerConfiguration=
SignatureHelp=true
SymbolDetails=false
SymbolExpand=true
SymbolSort=false
SymbolTree=true
TypeFormatting=false
[project]
autoCMake=false
autorepository=git
gitStatusDoubleClick=3
gitStatusSingleClick=0
index=false
indexDirectory=
multiProjectCompletion=false
multiProjectGoto=false
restoreProjectsForSessions=false

@ -0,0 +1,157 @@
configuration {
/* modes: "window,drun,run,ssh";*/
/* font: "mono 12";*/
/* location: 0;*/
/* yoffset: 0;*/
/* xoffset: 0;*/
/* fixed-num-lines: true;*/
/* show-icons: false;*/
/* preview-cmd: ;*/
/* terminal: "rofi-sensible-terminal";*/
/* ssh-client: "ssh";*/
/* ssh-command: "{terminal} -e {ssh-client} {host} [-p {port}]";*/
/* run-command: "{cmd}";*/
/* run-list-command: "";*/
/* run-shell-command: "{terminal} -e {cmd}";*/
/* window-command: "wmctrl -i -R {window}";*/
/* window-match-fields: "all";*/
/* icon-theme: ;*/
/* drun-match-fields: "name,generic,exec,categories,keywords";*/
/* drun-categories: ;*/
/* drun-show-actions: false;*/
/* drun-display-format: "{name} [<span weight='light' size='small'><i>({generic})</i></span>]";*/
/* drun-url-launcher: "xdg-open";*/
/* disable-history: false;*/
/* ignored-prefixes: "";*/
/* sort: false;*/
/* sorting-method: "normal";*/
/* case-sensitive: false;*/
/* cycle: true;*/
/* sidebar-mode: false;*/
/* hover-select: false;*/
/* eh: 1;*/
/* auto-select: false;*/
/* parse-hosts: false;*/
/* parse-known-hosts: true;*/
/* combi-modes: "window,run";*/
/* matching: "normal";*/
/* tokenize: true;*/
/* m: "-5";*/
/* filter: ;*/
/* dpi: -1;*/
/* threads: 0;*/
/* scroll-method: 0;*/
/* window-format: "{w} {c} {t}";*/
/* click-to-exit: true;*/
/* global-kb: false;*/
max-history-size: 1000;
/* combi-hide-mode-prefix: false;*/
/* combi-display-format: "{mode} {text}";*/
/* matching-negate-char: '-' /* unsupported */;*/
/* cache-dir: ;*/
/* window-thumbnail: false;*/
/* drun-use-desktop-cache: false;*/
/* drun-reload-desktop-cache: false;*/
/* normalize-match: false;*/
/* steal-focus: false;*/
/* application-fallback-icon: ;*/
/* refilter-timeout-limit: 300;*/
/* xserver-i300-workaround: false;*/
/* completer-mode: "filebrowser";*/
/* pid: "/run/user/1000/rofi.pid";*/
/* display-window: ;*/
/* display-run: ;*/
/* display-ssh: ;*/
/* display-drun: ;*/
/* display-combi: ;*/
/* display-keys: ;*/
/* display-filebrowser: ;*/
/* display-recursivebrowser: ;*/
/* kb-primary-paste: "Control+V,Shift+Insert";*/
/* kb-secondary-paste: "Control+v,Insert";*/
/* kb-secondary-copy: "Control+c";*/
/* kb-clear-line: "Control+w";*/
/* kb-move-front: "Control+a";*/
/* kb-move-end: "Control+e";*/
/* kb-move-word-back: "Alt+b,Control+Left";*/
/* kb-move-word-forward: "Alt+f,Control+Right";*/
/* kb-move-char-back: "Left,Control+b";*/
/* kb-move-char-forward: "Right,Control+f";*/
/* kb-remove-word-back: "Control+Alt+h,Control+BackSpace";*/
/* kb-remove-word-forward: "Control+Alt+d";*/
/* kb-remove-char-forward: "Delete,Control+d";*/
/* kb-remove-char-back: "BackSpace,Shift+BackSpace,Control+h";*/
/* kb-remove-to-eol: "Control+k";*/
/* kb-remove-to-sol: "Control+u";*/
/* kb-accept-entry: "Control+j,Control+m,Return,KP_Enter";*/
/* kb-accept-custom: "Control+Return";*/
/* kb-accept-custom-alt: "Control+Shift+Return";*/
/* kb-accept-alt: "Shift+Return";*/
/* kb-delete-entry: "Shift+Delete";*/
/* kb-mode-next: "Shift+Right,Control+Tab";*/
/* kb-mode-previous: "Shift+Left,Control+ISO_Left_Tab";*/
/* kb-mode-complete: "Control+l";*/
/* kb-row-left: "Control+Page_Up";*/
/* kb-row-right: "Control+Page_Down";*/
/* kb-row-up: "Up,Control+p";*/
/* kb-row-down: "Down,Control+n";*/
/* kb-row-tab: "";*/
/* kb-element-next: "Tab";*/
/* kb-element-prev: "ISO_Left_Tab";*/
/* kb-page-prev: "Page_Up";*/
/* kb-page-next: "Page_Down";*/
/* kb-row-first: "Home,KP_Home";*/
/* kb-row-last: "End,KP_End";*/
/* kb-row-select: "Control+space";*/
/* kb-screenshot: "Alt+S";*/
/* kb-ellipsize: "Alt+period";*/
/* kb-toggle-case-sensitivity: "grave,dead_grave";*/
/* kb-toggle-sort: "Alt+grave";*/
/* kb-cancel: "Escape,Control+g,Control+bracketleft";*/
/* kb-custom-1: "Alt+1";*/
/* kb-custom-2: "Alt+2";*/
/* kb-custom-3: "Alt+3";*/
/* kb-custom-4: "Alt+4";*/
/* kb-custom-5: "Alt+5";*/
/* kb-custom-6: "Alt+6";*/
/* kb-custom-7: "Alt+7";*/
/* kb-custom-8: "Alt+8";*/
/* kb-custom-9: "Alt+9";*/
/* kb-custom-10: "Alt+0";*/
/* kb-custom-11: "Alt+exclam";*/
/* kb-custom-12: "Alt+at";*/
/* kb-custom-13: "Alt+numbersign";*/
/* kb-custom-14: "Alt+dollar";*/
/* kb-custom-15: "Alt+percent";*/
/* kb-custom-16: "Alt+dead_circumflex";*/
/* kb-custom-17: "Alt+ampersand";*/
/* kb-custom-18: "Alt+asterisk";*/
/* kb-custom-19: "Alt+parenleft";*/
/* kb-select-1: "Super+1";*/
/* kb-select-2: "Super+2";*/
/* kb-select-3: "Super+3";*/
/* kb-select-4: "Super+4";*/
/* kb-select-5: "Super+5";*/
/* kb-select-6: "Super+6";*/
/* kb-select-7: "Super+7";*/
/* kb-select-8: "Super+8";*/
/* kb-select-9: "Super+9";*/
/* kb-select-10: "Super+0";*/
/* kb-entry-history-up: "Control+Up";*/
/* kb-entry-history-down: "Control+Down";*/
/* ml-row-left: "ScrollLeft";*/
/* ml-row-right: "ScrollRight";*/
/* ml-row-up: "ScrollUp";*/
/* ml-row-down: "ScrollDown";*/
/* me-select-entry: "MousePrimary";*/
/* me-accept-entry: "MouseDPrimary";*/
/* me-accept-custom: "Control+MouseDPrimary";*/
timeout {
action: "kb-cancel";
delay: 0;
}
filebrowser {
directories-first: true;
sorting-method: "name";
}
}

@ -3,3 +3,5 @@
name = Siarhei Siniak
[core]
pager = less -x2
[fetch]
fsckObjects = true

@ -0,0 +1,13 @@
#!/usr/bin/bash
commands gnome-shortcuts \
-a \
'powersave' \
'commands desktop-services --cpufreq-action powersave' \
'<Shift><Alt>1'
commands gnome-shortcuts \
-a \
'performance' \
'commands desktop-services --cpufreq-action performance' \
'<Shift><Alt>2'

2
dotfiles/.mime.types Normal file

@ -0,0 +1,2 @@
# https://terminalroot.com/how-to-open-markdown-files-with-md-extension-in-firefox/
text/plain txt asc text pm el c h cc hh cxx hxx f90 conf log yaml yml

@ -41,7 +41,7 @@ def f5_1(pattern, flags, info):
#print('fuck')
if b'r' in flags:
while True:
ext_m = re.compile('^.([^\,]+),(.*)$').match(pattern)
ext_m = re.compile(r'^.([^\,]+),(.*)$').match(pattern)
if pattern[:3] in [r'\r,']:
options['recursive'] = True

@ -1,4 +1,3 @@
#
# Copy this to ~/.config/sway/config and edit it to your liking.
#
@ -20,21 +19,10 @@ set $term weston-terminal
# on the original workspace that the command was run on.
#for_window [app_id="^launcher$"] floating enable, sticky enable, resize set 30 ppt 60 ppt, border pixel 10
#set $menu exec $term --class=launcher -e /usr/bin/sway-launcher-desktop
set $dmenu_path /usr/bin/bemenu-run
#set $dmenu_path /usr/bin/bemenu-run
set $dmenu_path rofi -modes run -show run
set $menu $dmenu_path | xargs swaymsg exec --
### Output configuration
#
# Default wallpaper (more resolutions are available in /usr/share/backgrounds/sway/)
#output * bg /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill
#
# Example configuration:
#
# output HDMI-A-1 resolution 1920x1080 position 1920,0
#
# You can get the names of your outputs by running: swaymsg -t get_outputs
output HDMI-A-1 resolution 1920x1080 position 0,0
output eDP-1 resolution 1366x748 position 277,1080
### Idle configuration
#
@ -62,18 +50,27 @@ output eDP-1 resolution 1366x748 position 277,1080
#
# You can get the names of your inputs by running: swaymsg -t get_inputs
# Read `man 5 sway-input` for more information about this section.
input type:pointer {
# tap enabled
natural_scroll enabled
}
input type:touchpad {
tap enabled
natural_scroll enabled
# natural_scroll disabled
}
bindgesture swipe:4:left workspace next
bindgesture swipe:4:right workspace prev
for_window [shell="xwayland"] title_format "[XWayland] %title"
#set $lock_cmd \
# loginctl list-sessions | \
# tail '-n' +2 | head -n -2 | awk '{print $1}' | \
# xargs loginctl lock-session
set $lock_cmd \
loginctl list-sessions | \
tail '-n' +2 | head -n -2 | awk '{print $1}' | \
xargs loginctl lock-session
zsh -c "commands loginctl --action lock-session"
bindgesture swipe:4:up exec $lock_cmd
@ -82,35 +79,48 @@ bindgesture swipe:4:up exec $lock_cmd
#
# Basics:
#
bindsym $mod+Shift+l exec $lock_cmd
bindsym Shift+$mod+l exec $lock_cmd
bindsym XF86KbdBrightnessDown \
exec commands \
bindsym --locked Shift+mod1+1 \
exec ~/.local/bin/commands \
desktop-services \
--backlight-decrease \
--backlight-type keyboard
--cpufreq-action performance
bindsym XF86KbdBrightnessUp \
exec commands \
bindsym --locked Shift+mod1+2 \
exec ~/.local/bin/commands \
desktop-services \
--backlight-increase \
--backlight-type keyboard
--cpufreq-action powersave
bindsym XF86MonBrightnessDown \
exec commands \
bindsym --locked XF86MonBrightnessDown \
exec ~/.local/bin/commands \
desktop-services \
--backlight-decrease \
--backlight-type output
bindsym XF86MonBrightnessUp \
exec commands \
bindsym --locked XF86MonBrightnessUp \
exec ~/.local/bin/commands \
desktop-services \
--backlight-increase \
--backlight-type output
bindsym XF86AudioPlay exec bash -c "commands media-play-pause"
bindsym XF86AudioNext exec bash -c "commands media-next"
bindsym XF86AudioPrev exec bash -c "commands media-prev"
bindsym --locked XF86KbdBrightnessDown \
exec ~/.local/bin/commands \
desktop-services \
--backlight-decrease \
--backlight-type keyboard
bindsym --locked XF86KbdBrightnessUp \
exec ~/.local/bin/commands \
desktop-services \
--backlight-increase \
--backlight-type keyboard
bindsym --locked XF86AudioPlay exec zsh -c "commands media-play-pause"
bindsym --locked XF86AudioRaiseVolume exec zsh -c "commands media-raise-volume"
bindsym --locked XF86AudioLowerVolume exec zsh -c "commands media-lower-volume"
bindsym --locked XF86AudioMute exec zsh -c "commands media-toggle-volume"
bindsym --locked XF86AudioNext exec zsh -c "commands media-next"
bindsym --locked XF86AudioPrev exec zsh -c "commands media-prev"
# Start a terminal
@ -133,11 +143,19 @@ floating_modifier $mod normal
bindsym $mod+Shift+c reload
# Exit sway (logs you out of your Wayland session)
bindsym $mod+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
bindsym $mod+Shift+e \
exec swaynag -t warning \
-m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' \
-b 'Yes, exit sway' \
'swaymsg exit'
#
# Moving around:
#
# Move your focus around
bindsym Shift+mod1+tab focus prev
bindsym mod1+tab focus next
#bindsym mod1+tab focus mode_toggle
bindsym $mod+$left focus left
bindsym $mod+$down focus down
bindsym $mod+$up focus up
@ -201,6 +219,7 @@ bindsym $mod+v splitv
#bindsym $mod+s layout stacking
#bindsym $mod+w layout tabbed
#bindsym $mod+e layout toggle split
bindsym $mod+e layout toggle all
# Make the current focus fullscreen
bindsym $mod+f fullscreen
@ -212,7 +231,8 @@ bindsym $mod+p floating toggle
## Swap focus between the tiling area and the floating area
#bindsym $mod+space focus mode_toggle
bindsym --release Print exec bash -c "commands wl-screenshot"
bindsym --release Print exec zsh -c "commands wl-screenshot"
bindsym --release $mod+s exec zsh -c "commands wl-screenshot"
# Move focus to the parent container
#bindsym $mod+a focus parent
@ -253,6 +273,40 @@ mode "resize" {
}
bindsym $mod+r mode "resize"
set $black #000000
set $red #ff0000
set $green #00ff00
set $blue #0000ff
set $white #ffffff
set $grey #757575
set $pale_green #9df882
set $pale_green2 #6baf54
set $dark_green #1a7000
set $pale_blue #7da9f9
set $dark_blue #005ba6
set $pale_greenblue #2da078
set $pale_greenblue2 #66c473
set $yellow #fffd0d
set $dark_yellow #908f00
set $color1 #18ff00
set $color2 #000000
set $color3 #ff00ff
set $color4 #ff0000
set $color5 #00000000
set $color6 #00000000
set $color7 #00000000
set $border_focused $pale_green
set $border_unfocused $color2
set $background_focused $pale_greenblue2
set $background_unfocused $grey
set $child_border_focused $white
set $child_border_unfocused $color2
set $bright_text $white
set $dark_text $black
#
# Status Bar:
#
@ -263,7 +317,7 @@ bar {
# When the status_command prints a new line to stdout, swaybar updates.
# The default just shows the current date and time.
status_command while true; \
do commands status --config ~/.config/commands-status.json; \
do ~/.local/bin/commands status --config ~/.config/commands-status.json; \
sleep 1; \
done
@ -272,27 +326,34 @@ bar {
height 16
colors {
statusline #565656
background #dfdfdf
inactive_workspace #dfdfdf #dfdfdf #000000
active_workspace #dfdfdf #efefef #000000
focused_workspace #dfdfdf #efefef #000000
statusline $bright_text
background $pale_green2
inactive_workspace $black $white $dark_text
active_workspace $black $white $bright_text
focused_workspace $dark_yellow $yellow $dark_text
}
}
client.focused #f3f3f3 #dfdfdf #565656 #f3f3f3 #f3f3f3
client.unfocused #f3f3f3 #dfdfdf #565656 #f3f3f3 #f3f3f3
#client.focused #f3f3f3 #dfdfdfdd #565656 #f3f3f3 #f3f3f3
client.focused $border_focused $background_focused $white $white $child_border_focused
client.unfocused $border_unfocused $background_unfocused $white $white $child_border_unfocused
for_window [all] border 1
#font pango:Helvetica Neue 10
font pango:Terminus 10
font pango:Terminus 12
titlebar_padding 1 4
titlebar_padding 32 1
titlebar_border_thickness 1
title_align center
#for_window [class=".*"] title_format "<b>%title</b>"
for_window [class="^firefox$"] floating enable
for_window [all] opacity set 0.95
input * {
xkb_layout "us,ru"
xkb_options "grp:win_space_toggle"
@ -300,3 +361,4 @@ input * {
input type:keyboard xkb_model "pc101"
include /etc/sway/config.d/*
include ~/.sway/config.d/*

@ -0,0 +1,20 @@
### Output configuration
#
# Default wallpaper (more resolutions are available in /usr/share/backgrounds/sway/)
#output * bg /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill
#
# Example configuration:
#
# output HDMI-A-1 resolution 1920x1080 position 1920,0
#
# You can get the names of your outputs by running: swaymsg -t get_outputs
#2560 x 1440
output 'Dell Inc. DELL P2418D MY3ND8220WKT' resolution 1920x1080 position 0,0
#output 'Dell Inc. DELL P2418D MY3ND8220WKT' mode resolution 2560x1440 position 0,0
#output HDMI-A-1 resolution 1920x1080 transform 90 position 0,0
output 'LG Electronics LG FHD 403TOAG3C208 ' resolution 1920x1080 transform 90 position 0,0
#output eDP-1 resolution 1366x748 position 277,1080
#output eDP-1 resolution 1366x748 disable power off position 277,1080
output 'Apple Computer Inc Color LCD Unknown' \
resolution 1366x748 enable power on position 277,1080
bindsym --locked $mod+u output 'Apple Computer Inc Color LCD Unknown' toggle

@ -31,19 +31,33 @@ hi MatchParen guifg=white guibg=black gui=NONE ctermfg=1 ctermbg=0
function! MakeSession()
let b:sessiondir = '.vim/'
if exists('g:session_name')
let b:session_name = g:session_name
else
let b:session_name = 'session'
endif
if (filewritable(b:sessiondir) != 2)
exe 'silent !mkdir -p ' b:sessiondir
redraw!
endif
let b:filename = b:sessiondir . '/session.vim'
let b:filename = b:sessiondir . '/' . b:session_name . '.vim'
exe "mksession! " . b:filename
echo 'saved ' . b:session_name
endfunction
function! LoadSession()
let b:sessiondir = '.vim/'
let b:sessionfile = b:sessiondir . "/session.vim"
if (filereadable(b:sessionfile))
exe 'source ' b:sessionfile
if exists('g:session_name')
let b:session_name = g:session_name
else
let b:session_name = 'session'
endif
let b:filename = b:sessiondir . '/' . b:session_name . '.vim'
if (filereadable(b:filename))
exe 'source ' b:filename
" echo 'loaded ' . b:session_name
else
echo "No session loaded."
endif
@ -56,6 +70,7 @@ map <Leader>z :wqa<CR>
map <Leader>m :py3 f1()<CR>
map <Leader>r :redraw!<CR>
map <Leader>s :call MakeSession()<CR>
map <Leader>% :let g:session_name = 'session'
map <Leader>l :call LoadSession()
map <Leader>cq :cq<CR>
map <Leader>f2 :py3 f2()<CR>

@ -1,2 +1,6 @@
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/pci0000:00/0000:00:1b.0/hdaudioC0D0/leds/hda::mute", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/platform/applesmc.768/leds/smc::kbd_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", DEVPATH=="/devices/platform/applesmc.768", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/fan1_manual /sys$devpath/fan1_output"
ACTION=="add|change", DEVPATH=="/class/backlight/intel_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", DEVPATH=="/devices/system/cpu/", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/cpufreq/scaling_governor"
ACTION=="add|change", KERNEL=="cpu[0-9]", SUBSYSTEM=="cpu", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/cpufreq/scaling_governor"

338
m.py Executable file

@ -0,0 +1,338 @@
#!/usr/bin/env python3
import glob
import io
import tempfile
import dataclasses
import pathlib
import sys
import subprocess
import os
import logging
from typing import (Optional, Any,)
from typing_extensions import (
Self, BinaryIO,
)
logger = logging.getLogger(__name__)
def toml_load(f: BinaryIO) -> Any:
try:
import tomllib
return tomllib.load(f)
except:
pass
try:
import tomli
return tomli.load(f)
except:
pass
raise NotImplementedError
@dataclasses.dataclass
class PyProject:
path: pathlib.Path
dependencies: dict[str, list[str]]
early_features: Optional[list[str]] = None
pip_find_links: Optional[list[pathlib.Path]] = None
runtime_libdirs: Optional[list[pathlib.Path]] = None
runtime_preload: Optional[list[pathlib.Path]] = None
requirements: dict[str, pathlib.Path] = dataclasses.field(default_factory=lambda : dict())
def pyproject_load(
d: pathlib.Path,
) -> PyProject:
with io.open(d, 'rb') as f:
content = toml_load(f)
assert isinstance(content, dict)
dependencies : dict[str, list[str]] = dict()
dependencies['default'] = content['project']['dependencies']
if (
'optional-dependencies' in content['project']
):
assert isinstance(
content['project']['optional-dependencies'],
dict
)
for k, v in content['project']['optional-dependencies'].items():
assert isinstance(v, list)
assert isinstance(k, str)
dependencies[k] = v
res = PyProject(
path=d,
dependencies=dependencies,
)
tool_name = 'online.fxreader.pr34'.replace('.', '-')
if (
'tool' in content and
isinstance(
content['tool'], dict
) and
tool_name in content['tool'] and
isinstance(
content['tool'][tool_name],
dict
)
):
if 'early_features' in content['tool'][tool_name]:
res.early_features = content['tool'][tool_name]['early_features']
if 'pip_find_links' in content['tool'][tool_name]:
res.pip_find_links = [
d.parent / pathlib.Path(o)
for o in content['tool'][tool_name]['pip_find_links']
]
if 'runtime_libdirs' in content['tool'][tool_name]:
res.runtime_libdirs = [
d.parent / pathlib.Path(o)
# pathlib.Path(o)
for o in content['tool'][tool_name]['runtime_libdirs']
]
if 'runtime_preload' in content['tool'][tool_name]:
res.runtime_preload = [
d.parent / pathlib.Path(o)
# pathlib.Path(o)
for o in content['tool'][tool_name]['runtime_preload']
]
if 'requirements' in content['tool'][tool_name]:
assert isinstance(content['tool'][tool_name]['requirements'], dict)
res.requirements = {
k : d.parent / pathlib.Path(v)
# pathlib.Path(o)
for k, v in content['tool'][tool_name]['requirements'].items()
}
return res
@dataclasses.dataclass
class BootstrapSettings:
env_path: pathlib.Path
python_path: pathlib.Path
base_dir: pathlib.Path
python_version: Optional[str] = dataclasses.field(
default_factory=lambda : os.environ.get(
'PYTHON_VERSION',
'%d.%d' % (
sys.version_info.major,
sys.version_info.minor,
),
).strip()
)
uv_args: list[str] = dataclasses.field(
default_factory=lambda : os.environ.get(
'UV_ARGS',
'--offline',
).split(),
)
@classmethod
def get(
cls,
base_dir: Optional[pathlib.Path] = None,
) -> Self:
if base_dir is None:
base_dir = pathlib.Path.cwd()
env_path = base_dir / '.venv'
python_path = env_path / 'bin' / 'python3'
return cls(
base_dir=base_dir,
env_path=env_path,
python_path=python_path,
)
def env_bootstrap(
bootstrap_settings: BootstrapSettings,
pyproject: PyProject,
) -> None:
pip_find_links : list[pathlib.Path] = []
if not pyproject.pip_find_links is None:
pip_find_links.extend(pyproject.pip_find_links)
pip_find_links_args = sum([
['-f', str(o),]
for o in pip_find_links
], [])
features : list[str] = []
if pyproject.early_features:
features.extend(pyproject.early_features)
requirements_python_version: Optional[str] = None
if not bootstrap_settings.python_version is None:
requirements_python_version = bootstrap_settings.python_version.replace('.', '_')
requirements_name = '_'.join(sorted(features))
if requirements_python_version:
requirements_name += '_' + requirements_python_version
requirements_path : Optional[pathlib.Path] = None
if requirements_name in pyproject.requirements:
requirements_path = pyproject.requirements[requirements_name]
else:
requirements_path = pyproject.path.parent / 'requirements.txt'
requirements_in : list[str] = []
requirements_in.extend([
'uv', 'pip', 'build', 'setuptools', 'meson-python', 'pybind11'
])
if pyproject.early_features:
early_dependencies = sum([
pyproject.dependencies[o]
for o in pyproject.early_features
], [])
logger.info(dict(
early_dependencies=early_dependencies,
))
requirements_in.extend(early_dependencies)
# if len(early_dependencies) > 0:
# subprocess.check_call([
# bootstrap_settings.python_path,
# '-m',
# 'uv', 'pip', 'install',
# *pip_find_links_args,
# # '-f', str(pathlib.Path(__file__).parent / 'deps' / 'dist'),
# *bootstrap_settings.uv_args,
# *early_dependencies,
# ])
if not requirements_path.exists():
with tempfile.NamedTemporaryFile(
mode='w',
prefix='requirements',
suffix='.in',
) as f:
f.write(
'\n'.join(requirements_in)
)
f.flush()
subprocess.check_call([
'uv',
'pip',
'compile',
'--generate-hashes',
*pip_find_links_args,
# '-p',
# bootstrap_settings.python_path,
*bootstrap_settings.uv_args,
'-o', str(requirements_path),
f.name,
])
uv_python_version: list[str] = []
if not bootstrap_settings.python_version is None:
uv_python_version.extend([
'-p', bootstrap_settings.python_version,
])
subprocess.check_call([
'uv', 'venv',
*uv_python_version,
*pip_find_links_args,
# '--seed',
*bootstrap_settings.uv_args,
str(bootstrap_settings.env_path)
])
subprocess.check_call([
'uv',
'pip',
'install',
*pip_find_links_args,
'-p',
bootstrap_settings.python_path,
'--require-hashes',
*bootstrap_settings.uv_args,
'-r', str(requirements_path),
])
def paths_equal(
a: pathlib.Path | str,
b: pathlib.Path | str
) -> bool:
return (
os.path.abspath(str(a)) ==
os.path.abspath(str(b))
)
def run(
d: Optional[pathlib.Path] = None,
cli_path: Optional[pathlib.Path] = None,
) -> None:
if cli_path is None:
cli_path = pathlib.Path(__file__).parent / 'cli.py'
if d is None:
d = pathlib.Path(__file__).parent / 'pyproject.toml'
bootstrap_settings = BootstrapSettings.get()
pyproject : PyProject = pyproject_load(
d
)
logging.basicConfig(level=logging.INFO)
if not bootstrap_settings.env_path.exists():
env_bootstrap(
bootstrap_settings=bootstrap_settings,
pyproject=pyproject,
)
logger.info([sys.executable, sys.argv, bootstrap_settings.python_path])
if not paths_equal(sys.executable, bootstrap_settings.python_path):
os.execv(
str(bootstrap_settings.python_path),
[
str(bootstrap_settings.python_path),
*sys.argv,
]
)
os.execv(
str(bootstrap_settings.python_path),
[
str(bootstrap_settings.python_path),
str(
cli_path
),
*sys.argv[1:],
]
)
if __name__ == '__main__':
run(
d=pathlib.Path(__file__).parent / 'python' / 'pyproject.toml',
cli_path=pathlib.Path(__file__).parent / 'python' / 'cli.py',
)

@ -0,0 +1,6 @@
import distutils.command
from typing import (Any,)
def _get_build_extension() -> distutils.command.build_ext: ...
def load_dynamic(name: str, path: str) -> Any: ...

@ -0,0 +1,17 @@
import setuptools.extension
from typing import (Iterable,)
def cythonize(
module_list: str | Iterable[str]
#module_list,
#exclude=None,
#nthreads=0,
#aliases=None,
#quiet=False,
#force=None,
#language=None,
#exclude_failures=False,
#show_all_warnings=False,
#**options
) -> list[setuptools.extension.Extension]: ...

@ -0,0 +1,7 @@
from typing import (Type, Any, Self)
class NoGIL:
def __enter__(self) -> Self: ...
def __exit__(self, exc_class: Type[Exception], exc: Exception, tb: Any) -> None: ...
nogil : NoGIL = NoGIL()

@ -0,0 +1,14 @@
import setuptools.extension
import pathlib
class build_ext:
extensions : list[setuptools.extension.Extension]
#build_temp : pathlib.Path
#build_lib: pathlib.Path
build_temp: str
build_lib: str
def run(self) -> None:
...
...

@ -0,0 +1,8 @@
from typing import (Iterable,)
class Trie:
def __init__(self, entries: Iterable[str]) -> None: ...
def keys(self, entry: str) -> list[str]: ...
def __contains__(self, entry: str) -> bool: ...

@ -0,0 +1,18 @@
import setuptools.extension
from typing import (Any, Iterable,)
def mypycify(
paths: 'list[str]',
*,
only_compile_paths: 'Iterable[str] | None' = None,
verbose: 'bool' = False,
opt_level: 'str' = '3',
debug_level: 'str' = '1',
strip_asserts: 'bool' = False,
multi_file: 'bool' = False,
separate: 'bool | list[tuple[list[str], str | None]]' = False,
skip_cgen_input: 'Any | None' = None,
target_dir: 'str | None' = None,
include_runtime_files: 'bool | None' = None,
) -> 'list[setuptools.extension.Extension]': ...

@ -0,0 +1,8 @@
from typing import (Self, Any)
class tqdm:
def __enter__(self) -> Self: ...
def __exit__(self, args: Any) -> None: ...
def update(self, delta: int) -> None: ...
def set_description(self, description: str) -> None: ...

@ -0,0 +1,7 @@
def listen(
addr: tuple[str, int],
) -> None: ...
def wait_for_client() -> None: ...
def breakpoint() -> None: ...

@ -0,0 +1,6 @@
[Unit]
Description=udev scripts
[Service]
Type=simple
ExecStart=/usr/local/bin/online-fxreader-pr34-udev --device=%I

@ -0,0 +1,11 @@
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/pci0000:00/0000:00:1b.0/hdaudioC0D0/leds/hda::mute", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/platform/applesmc.768/leds/smc::kbd_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
# udevadm info --attribute-walk --path=/sys/devices/platform/applesmc.768/
# udevadm trigger --action=add --verbose --parent-match /devices/platform/applesmc.768/
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", RUN{program}+="ls -allh /sys$devpath/", OPTIONS="log_level=debug"
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", RUN{program}+="/usr/bin/ls -allh /sys$devpath/", OPTIONS="log_level=debug"
ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"
#KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", MODE="0660", TAG+="uaccess", OPTIONS="log_level=debug", OPTIONS+="watch"
ACTION=="add|change", DEVPATH=="/class/backlight/intel_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", KERNEL=="cpu0", SUBSYSTEM=="cpu", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"
ACTION=="add|change", KERNEL=="cpu[0-9]", SUBSYSTEM=="cpu", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"

@ -0,0 +1,103 @@
#!/usr/bin/python3
# vi: filetype=python
import re
import sys
import os
import subprocess
import argparse
import logging
from typing import (Any,)
logger = logging.getLogger(__name__)
def run() -> None:
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser()
parser.add_argument(
'--device',
)
options = parser.parse_args()
DEVICES : dict[str, Any] = dict(
applesmc=dict(
devpath='sys/devices/platform/applesmc.768',
node='/sys/devices/platform/applesmc.768/fan1_manual',
cmd=r'''
chown root:fan /sys/devices/platform/applesmc.768/fan1_*
chmod g+w /sys/devices/platform/applesmc.768/fan1_*
''',
),
intel_pstate=dict(
devpath=r'/?sys/devices/system/cpu/cpu0',
node='/sys/devices/system/cpu/intel_pstate/no_turbo',
cmd=r'''
chown root:fan /sys/devices/system/cpu/intel_pstate/no_turbo
chown root:fan /sys/devices/system/cpu/intel_pstate/max_perf_pct
#chown root:fan /sys/devices/system/cpu/intel_pstate/status
chmod g+w /sys/devices/system/cpu/intel_pstate/no_turbo
chmod g+w /sys/devices/system/cpu/intel_pstate/max_perf_pct
#chmod g+w /sys/devices/system/cpu/intel_pstate/status
echo passive > /sys/devices/system/cpu/intel_pstate/status
chown root:fan /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
chown root:fan /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
chmod g+w /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
chmod g+w /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
''',
),
#governor=dict(
# devpath=r'/?sys/devices/system/cpu/cpu(\d+)',
# node=r'/sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor',
# cmd=r'''
# chown root:fan /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor
# chown root:fan /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq
# chmod g+w /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor
# chmod g+w /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq
# ''',
#),
)
processed : int = 0
logger.info(dict(device=options.device))
for k, v in DEVICES.items():
devpath = re.compile(v['devpath'])
devpath_m = devpath.match(options.device)
if devpath_m is None:
continue
node_2 = v['node'].format(*devpath_m.groups())
# logger.info(dict(devpath_m=devpath_m, node=node_2))
while not os.path.exists(node_2):
#continue
time.sleep(1)
cmd_2 = v['cmd'].format(*devpath_m.groups())
subprocess.check_call(cmd_2, shell=True)
logger.info(dict(
devpath_m=devpath_m,
node_2=node_2,
cmd_2=cmd_2,
msg='processed',
label=k,
))
processed += 1
if processed == 0:
raise NotImplementedError
if __name__ == '__main__':
run()

@ -0,0 +1,6 @@
[Unit]
Description=udev scripts
[Service]
Type=simple
ExecStart=/usr/local/bin/online-fxreader-pr34-udev --device=%I

@ -0,0 +1,26 @@
[Unit]
Description=Disable and Re-Enable Apple BCE Module (and Wi-Fi)
Before=sleep.target
Before=hibernate.target
StopWhenUnneeded=yes
[Service]
User=root
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/online-fxreader-pr34-suspend-fix-t2 disable_apple_bce
#ExecStart=/usr/bin/modprobe -r apple_bce
#ExecStart=/usr/bin/modprobe -r brcmfmac_wcc
#ExecStart=/usr/bin/modprobe -r brcmfmac
#ExecStart=/usr/bin/rmmod -f apple-bce
ExecStop=/usr/local/bin/online-fxreader-pr34-suspend-fix-t2 enable_apple_bce
#ExecStop=/usr/bin/modprobe -r apple_bce
#ExecStop=/usr/bin/modprobe apple-bce
#ExecStop=/usr/bin/modprobe brcmfmac
#ExecStop=/usr/bin/modprobe brcmfmac_wcc
[Install]
WantedBy=sleep.target
WantedBy=hibernate.target

@ -0,0 +1,13 @@
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/pci0000:00/0000:00:1b.0/hdaudioC0D0/leds/hda::mute", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
ACTION=="add|change", SUBSYSTEM=="leds", DEVPATH=="/devices/platform/applesmc.768/leds/smc::kbd_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
# udevadm info --attribute-walk --path=/sys/devices/platform/applesmc.768/
# udevadm trigger --action=add --verbose --parent-match /devices/platform/applesmc.768/
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", RUN{program}+="ls -allh /sys$devpath/", OPTIONS="log_level=debug"
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", RUN{program}+="/usr/bin/ls -allh /sys$devpath/", OPTIONS="log_level=debug"
#ACTION=="add|change", KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"
ACTION=="add|change", KERNEL=="cpu0", SUBSYSTEM=="cpu", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"
#KERNEL=="applesmc.768", SUBSYSTEM=="platform", DRIVER=="applesmc", MODE="0660", TAG+="uaccess", OPTIONS="log_level=debug", OPTIONS+="watch"
ACTION=="add|change", DEVPATH=="/class/backlight/intel_backlight", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/brightness"
#ACTION=="add|change", DEVPATH=="/devices/system/cpu/", RUN{program}+="/usr/bin/chmod 666 /sys$devpath/cpufreq/scaling_governor"
ACTION=="add|change", KERNEL=="cpu[0-9]", SUBSYSTEM=="cpu", TAG+="systemd", ENV{SYSTEMD_WANTS}="online.fxreader.pr34.udev@$devnode.service", OPTIONS="log_level=debug"

@ -0,0 +1,113 @@
#!/usr/bin/env python3
# vi: set filetype=python
import sys
import time
import argparse
import subprocess
parser = argparse.ArgumentParser()
parser.add_argument('mode', choices=[
'disable_apple_bce',
'enable_apple_bce',
])
options = parser.parse_args()
if options.mode == 'disable_apple_bce':
while True:
ret = subprocess.call([
'systemctl', 'stop', 'iwd',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', '-r', 'brcmfmac_wcc',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', '-r', 'brcmfmac',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', '-r', 'applesmc',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'rmmod', '-f', 'apple-bce',
])
#if ret != 0:
# time.sleep(1)
#else:
# break
break
elif options.mode == 'enable_apple_bce':
while True:
ret = subprocess.call([
'modprobe', 'applesmc',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', 'apple-bce',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', 'brcmfmac',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'modprobe', 'brcmfmac_wcc',
])
if ret != 0:
time.sleep(1)
else:
break
while True:
ret = subprocess.call([
'systemctl', 'start', 'iwd',
])
if ret != 0:
time.sleep(1)
else:
break
else:
raise NotImplementedError

@ -0,0 +1,103 @@
#!/usr/bin/python3
# vi: filetype=python
import re
import sys
import os
import subprocess
import argparse
import logging
from typing import (Any,)
logger = logging.getLogger(__name__)
def run() -> None:
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser()
parser.add_argument(
'--device',
)
options = parser.parse_args()
DEVICES : dict[str, Any] = dict(
applesmc=dict(
devpath='sys/devices/platform/applesmc.768',
node='/sys/devices/platform/applesmc.768/fan1_manual',
cmd=r'''
chown root:fan /sys/devices/platform/applesmc.768/fan1_*
chmod g+w /sys/devices/platform/applesmc.768/fan1_*
''',
),
intel_pstate=dict(
devpath=r'/?sys/devices/system/cpu/cpu0',
node='/sys/devices/system/cpu/intel_pstate/no_turbo',
cmd=r'''
chown root:fan /sys/devices/system/cpu/intel_pstate/no_turbo
chown root:fan /sys/devices/system/cpu/intel_pstate/max_perf_pct
#chown root:fan /sys/devices/system/cpu/intel_pstate/status
chmod g+w /sys/devices/system/cpu/intel_pstate/no_turbo
chmod g+w /sys/devices/system/cpu/intel_pstate/max_perf_pct
#chmod g+w /sys/devices/system/cpu/intel_pstate/status
echo passive > /sys/devices/system/cpu/intel_pstate/status
chown root:fan /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
chown root:fan /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
chmod g+w /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
chmod g+w /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq
''',
),
#governor=dict(
# devpath=r'/?sys/devices/system/cpu/cpu(\d+)',
# node=r'/sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor',
# cmd=r'''
# chown root:fan /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor
# chown root:fan /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq
# chmod g+w /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_governor
# chmod g+w /sys/devices/system/cpu/cpu{0}/cpufreq/scaling_max_freq
# ''',
#),
)
processed : int = 0
logger.info(dict(device=options.device))
for k, v in DEVICES.items():
devpath = re.compile(v['devpath'])
devpath_m = devpath.match(options.device)
if devpath_m is None:
continue
node_2 = v['node'].format(*devpath_m.groups())
# logger.info(dict(devpath_m=devpath_m, node=node_2))
while not os.path.exists(node_2):
#continue
time.sleep(1)
cmd_2 = v['cmd'].format(*devpath_m.groups())
subprocess.check_call(cmd_2, shell=True)
logger.info(dict(
devpath_m=devpath_m,
node_2=node_2,
cmd_2=cmd_2,
msg='processed',
label=k,
))
processed += 1
if processed == 0:
raise NotImplementedError
if __name__ == '__main__':
run()

254
python/_m.py Normal file

@ -0,0 +1,254 @@
#!/usr/bin/env python3
#vim: set filetype=python
import logging
import json
import enum
import pathlib
import sys
import argparse
#import optparse
import dataclasses
import subprocess
import os
from typing import (
Optional, Any, TypeAlias, Literal, cast, BinaryIO, Generator,
ClassVar, Self,
)
logger = logging.getLogger()
@dataclasses.dataclass
class Settings:
project_root : pathlib.Path = pathlib.Path.cwd()
env_path : pathlib.Path = project_root / 'tmp' / 'env3'
_settings : ClassVar[Optional['Settings']] = None
@classmethod
def settings(cls) -> Self:
if cls._settings is None:
cls._settings = cls()
return cls._settings
def js(argv: list[str]) -> int:
return subprocess.check_call([
'sudo',
'docker-compose',
'--project-directory',
Settings.settings().project_root,
'-f',
Settings.settings().project_root / 'docker' / 'js' / 'docker-compose.yml',
*argv,
])
def env(
argv: Optional[list[str]] = None,
mode: Literal['exec', 'subprocess'] = 'subprocess',
**kwargs: Any,
) -> Optional[subprocess.CompletedProcess[bytes]]:
env_path = Settings.settings().env_path
if not env_path.exists():
subprocess.check_call([
sys.executable, '-m', 'venv',
'--system-site-packages',
str(env_path)
])
subprocess.check_call([
env_path / 'bin' / 'python3',
'-m', 'pip',
'install', '-r', 'requirements.txt',
])
if not argv is None:
python_path = str(env_path / 'bin' / 'python3')
if mode == 'exec':
os.execv(
python_path,
[
python_path,
*argv,
],
)
return None
elif mode == 'subprocess':
return subprocess.run([
python_path,
*argv,
], **kwargs)
else:
raise NotImplementedError
return None
def ruff(argv: list[str]) -> None:
parser = argparse.ArgumentParser()
parser.add_argument(
'-i',
dest='paths',
help='specify paths to check',
default=[],
action='append',
)
parser.add_argument(
'-e',
dest='exclude',
help='rules to ignore',
default=[],
action='append',
)
options, args = parser.parse_known_args(argv)
if len(options.paths) == 0:
options.paths.extend([
'.',
'dotfiles/.local/bin/commands',
])
if len(options.exclude) == 0:
options.exclude.extend([
'E731',
'E713',
'E714',
'E703',
])
res = env([
'-m',
'ruff',
'check',
*args,
'--output-format', 'json',
'--ignore', ','.join(options.exclude),
*options.paths,
], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
assert not res is None
errors = json.loads(res.stdout.decode('utf-8'))
g: dict[str, Any] = dict()
for o in errors:
if not o['filename'] in g:
g[o['filename']] = []
g[o['filename']].append(o)
h = {
k : len(v)
for k, v in g.items()
}
logger.info(json.dumps(errors, indent=4))
logger.info(json.dumps(h, indent=4))
def inside_env() -> bool:
try:
import numpy
return True
except Exception:
return False
#class Commands(enum.StrEnum):
# js = 'js'
# mypy = 'mypy'
# env = 'env'
# ruff = 'ruff'
# m2 = 'm2'
# def mypy(argv: list[str]) -> None:
# import online.fxreader.pr34.commands_typed.mypy as _mypy
# _mypy.run(
# argv,
# )
def host_deps(argv: list[str]) -> None:
if sys.platform in ['linux']:
subprocess.check_call(r'''
exec yay -S $(cat requirements-archlinux.txt)
''', shell=True,)
else:
raise NotImplementedError
Command_args = ['js', 'mypy', 'env', 'ruff', 'm2', 'host_deps',]
Command : TypeAlias = Literal['js', 'mypy', 'env', 'ruff', 'm2', 'host_deps',]
def run(argv: Optional[list[str]] = None) -> None:
logging.basicConfig(
level=logging.INFO,
format=(
'%(levelname)s:%(name)s:%(message)s'
':%(process)d'
':%(asctime)s'
':%(pathname)s:%(funcName)s:%(lineno)s'
),
)
if argv is None:
argv = sys.argv[:]
parser = argparse.ArgumentParser()
parser.add_argument(
'command',
#'_command',
choices=[
o
for o in Command_args
],
#required=True,
)
options, args = parser.parse_known_args(argv[1:])
assert options.command in Command_args
if len(args) > 0 and args[0] == '--':
del args[0]
#options.command = Commands(options._command)
if options.command == 'js':
js(args)
elif options.command == 'host_deps':
host_deps(args)
elif options.command == 'env':
env(args, mode='exec',)
# elif options.command == 'mypy':
# if not inside_env():
# env(
# [
# pathlib.Path(__file__).parent / 'm.py',
# *argv[1:],
# ],
# mode='exec'
# )
# else:
# mypy(args)
elif options.command == 'ruff':
ruff(args)
elif options.command == 'm2':
if not inside_env():
env(['--', '_m.py', 'm2', *args])
return
import python.tasks.cython
python.tasks.cython.mypyc_build(
pathlib.Path('_m.py')
)
else:
raise NotImplementedError
if __name__ == '__main__':
run()

162
python/cli.py Normal file

@ -0,0 +1,162 @@
import sys
import shutil
import glob
import io
import copy
import subprocess
import pathlib
import logging
import enum
import argparse
import dataclasses
from typing import (Optional, override,)
from online.fxreader.pr34.commands_typed.logging import setup as logging_setup
from online.fxreader.pr34.commands_typed import cli as _cli
from online.fxreader.pr34.commands_typed import cli_bootstrap
logging_setup()
logger = logging.getLogger(__name__)
class Command(enum.StrEnum):
mypy = 'mypy'
deploy_wheel = 'deploy:wheel'
tests = 'tests'
@dataclasses.dataclass
class Settings(
_cli.DistSettings,
):
base_dir: pathlib.Path = pathlib.Path(__file__).parent.parent
build_dir: pathlib.Path = base_dir / 'tmp' / 'build'
wheel_dir: pathlib.Path = base_dir / 'deps' / 'dist'
env_path: pathlib.Path = cli_bootstrap.BootstrapSettings.get(base_dir).env_path
python_path: pathlib.Path = cli_bootstrap.BootstrapSettings.get(base_dir).python_path
class CLI(_cli.CLI):
def __init__(self) -> None:
self.settings = Settings()
self._projects: dict[str, _cli.Project] = {
'online.fxreader.pr34': _cli.Project(
source_dir=self.settings.base_dir / 'python',
build_dir=self.settings.base_dir / 'tmp' / 'online' / 'fxreader' / 'pr34' / 'build',
dest_dir=self.settings.base_dir / 'tmp' / 'online' / 'fxreader' / 'pr34' / 'install',
)
}
self._dependencies : dict[str, _cli.Dependency] = dict()
@override
@property
def dist_settings(self) -> _cli.DistSettings:
return self.settings
@override
@property
def projects(self) -> dict[str, _cli.Project]:
return self._projects
def mypy(
self,
argv: list[str],
) -> None:
import online.fxreader.pr34.commands_typed.mypy as _mypy
project = self._projects['online.fxreader.pr34']
_mypy.run(
argv,
settings=_mypy.MypySettings(
paths=[
#Settings.settings().project_root / 'dotfiles/.local/bin/commands',
# project.source_dir / 'm.py',
project.source_dir / '_m.py',
project.source_dir / 'online',
project.source_dir / 'cli.py',
self.settings.base_dir / 'm.py',
# Settings.settings().project_root / 'deps/com.github.aiortc.aiortc/src',
#Settings.settings().project_root / 'm.py',
],
max_errors={
'python/online/fxreader/pr34/commands_typed': 0,
'python/cli.py': 0,
'm.py': 0,
'deps/com.github.aiortc.aiortc/src/online_fxreader': 0,
'deps/com.github.aiortc.aiortc/src/aiortc/contrib/signaling': 0
}
),
)
@override
@property
def dependencies(self) -> dict[str, _cli.Dependency]:
return self._dependencies
def run(self, argv: Optional[list[str]] = None) -> None:
if argv is None:
argv = copy.deepcopy(sys.argv)
parser = argparse.ArgumentParser()
parser.add_argument(
'command',
choices=[
o.value
for o in Command
]
)
parser.add_argument(
'-p', '--project',
choices=[
o
for o in self.projects
]
)
parser.add_argument(
'-o', '--output_dir',
default=None,
help='wheel output dir for deploy:wheel',
)
parser.add_argument(
'-f', '--force',
default=False,
action='store_true',
help='remove install dir, before installing, default = false',
)
options, args = parser.parse_known_args(argv[1:])
options.command = Command(options.command)
if options.command is Command.deploy_wheel:
assert not options.project is None
self.deploy_wheel(
project_name=options.project,
argv=args,
output_dir=options.output_dir,
mypy=True,
)
elif options.command is Command.mypy:
self.mypy(
argv=args,
)
elif options.command is Command.tests:
for k, v in self.projects.items():
subprocess.check_call([
sys.executable,
'-m',
'unittest',
'online.fxreader.pr34.tests.test_crypto',
*args,
], cwd=str(v.source_dir))
else:
raise NotImplementedError
if __name__ == '__main__':
CLI().run()

File diff suppressed because it is too large Load Diff

@ -0,0 +1,27 @@
__all__ = (
'parse_args',
)
import sys
import argparse
from typing import (Optional,)
def parse_args(
parser: argparse.ArgumentParser,
args: Optional[list[str]] = None,
) -> tuple[argparse.Namespace, list[str]]:
if args is None:
args = sys.argv[1:]
argv : list[str] = []
for i, o in enumerate(args):
if o == '--':
argv.extend(args[i + 1:])
del args[i:]
break
return parser.parse_args(args), argv

@ -0,0 +1,14 @@
import logging
import asyncio
from typing import (Any,)
logger = logging.getLogger(__name__)
def handle_task_result(fut: asyncio.Future[Any]) -> None:
try:
fut.result()
logger.debug(dict(fut=fut, msg='done'), stacklevel=2,)
except:
logger.exception('', stacklevel=2,)

@ -0,0 +1,478 @@
import dataclasses
import io
import glob
import os
import pathlib
import logging
import sys
import subprocess
import shutil
import abc
from .os import shutil_which
from typing import (
Optional,
Literal,
Any,
)
logger = logging.getLogger(__name__)
@dataclasses.dataclass
class Project:
source_dir : pathlib.Path
build_dir : pathlib.Path
dest_dir : pathlib.Path
meson_path: Optional[pathlib.Path] = None
@dataclasses.dataclass
class Dependency:
name: str
mode : Literal['pyproject', 'meson', 'meson-python', 'm']
source_path : pathlib.Path
args: Optional[list[str]] = None
@dataclasses.dataclass
class DistSettings:
wheel_dir : pathlib.Path
python_path: pathlib.Path
env_path: pathlib.Path
class CLI(abc.ABC):
@property
@abc.abstractmethod
def dist_settings(self) -> DistSettings:
raise NotImplementedError
@property
@abc.abstractmethod
def projects(self) -> dict[str, Project]:
raise NotImplementedError
@property
@abc.abstractmethod
def dependencies(self) -> dict[str, Dependency]:
raise NotImplementedError
def mypy(
self,
argv: list[str]
) -> None:
from . import mypy as _mypy
_mypy.run(
argv,
)
def ruff(
self,
project_name: str,
argv: list[str],
) -> None:
project = self.projects[project_name]
if len(argv) == 0:
argv = ['check', '.',]
subprocess.check_call([
self.dist_settings.python_path,
'-m',
'ruff',
'--config', str(project.source_dir / 'pyproject.toml'),
*argv,
])
def pyright(
self,
project_name: str,
argv: list[str],
) -> None:
project = self.projects[project_name]
if len(argv) == 0:
argv = ['--threads', '3']
cmd = [
str(self.dist_settings.python_path),
'-m',
'pyright',
'--pythonpath', str(self.dist_settings.python_path),
'-p', str(project.source_dir / 'pyproject.toml'),
*argv,
]
logger.info(cmd)
subprocess.check_call(cmd)
def pip_sync(
self,
project: str,
features: list[str],
) -> None:
from . import cli_bootstrap
pyproject = cli_bootstrap.pyproject_load(
self.projects[project].source_dir / 'pyproject.toml'
)
dependencies = sum([
pyproject.dependencies[o]
for o in features
], [])
pip_find_links : list[pathlib.Path] = []
if not pyproject.pip_find_links is None:
pip_find_links.extend(pyproject.pip_find_links)
logger.info(dict(
dependencies=dependencies,
))
if len(dependencies) > 0:
subprocess.check_call([
self.dist_settings.python_path,
'-m',
'uv', 'pip', 'install',
*sum([
['-f', str(o),]
for o in pip_find_links
], []),
# '-f', str(pathlib.Path(__file__).parent / 'deps' / 'dist'),
'--offline',
*dependencies,
])
def deploy_fetch_dist(
self,
force: bool,
) -> None:
for k, d in self.dependencies.items():
whl_glob = self.dist_settings.wheel_dir / ('*%s*.whl' % d.name.replace('.', '_'))
if len(glob.glob(
str(whl_glob)
)) == 0 or force:
if d.source_path.exists():
def whl_files_get() -> list[dict[str, Any]]:
return [
dict(
path=o,
stat=os.stat(o).st_mtime,
)
for o in glob.glob(
str(whl_glob)
)
]
present_files = whl_files_get()
if d.mode == 'm':
if (d.source_path / 'm.py').exists():
cmd = [
sys.executable,
str(d.source_path / 'm.py'),
'deploy:wheel',
'-o',
str(self.dist_settings.wheel_dir),
]
if not d.args is None:
cmd.extend(d.args)
subprocess.check_call(
cmd,
cwd=d.source_path,
)
else:
raise NotImplementedError
updated_files = whl_files_get()
def index_get(o: dict[str, Any]) -> tuple[Any, ...]:
return (o['path'], o['stat'])
present_files_index = {
index_get(o) : o
for o in present_files
}
new_files : list[dict[str, Any]] = []
for o in updated_files:
entry_index = index_get(o)
if not entry_index in present_files_index:
new_files.append(o)
if len(new_files) == 0:
raise NotImplementedError
latest_file = sorted(
new_files,
key=lambda x: x['stat']
)[-1]
subprocess.check_call([
self.dist_settings.python_path,
'-m', 'pip',
'install',
latest_file['path'],
])
@property
def pkg_config_path(self,) -> set[pathlib.Path]:
return {
pathlib.Path(o)
for o in glob.glob(
str(self.dist_settings.env_path / 'lib' / 'python*' / '**' / 'pkgconfig'),
recursive=True,
)
}
def deploy_wheel(
self,
project_name: str,
argv: Optional[list[str]] = None,
output_dir: Optional[pathlib.Path] = None,
force: Optional[bool] = None,
env: Optional[dict[str, str]] = None,
mypy: bool = False,
tests: bool = False,
) -> None:
project = self.projects[project_name]
# subprocess.check_call([
# sys.argv[0],
# # sys.executable,
# '-p', options.project,
# Command.meson_setup.value,
# ])
if argv is None:
argv = []
# assert argv is None or len(argv) == 0
if not project.meson_path is None:
if tests:
self.meson_test(
project_name=project_name,
)
self.meson_install(
project_name=project_name,
force=force,
)
if mypy:
self.mypy([])
if env is None:
env = dict()
extra_args: list[str] = []
if len(self.third_party_roots) > 0:
extra_args.extend([
'-Csetup-args=%s' % (
'-Dthird_party_roots=%s' % str(o.absolute())
)
for o in self.third_party_roots
])
cmd = [
sys.executable,
'-m',
'build',
'-w', '-n',
*extra_args,
'-Csetup-args=-Dmodes=pyproject',
'-Cbuild-dir=%s' % str(project.build_dir / 'pyproject'),
'-Csetup-args=-Dinstall_path=%s' % str(project.dest_dir),
# '-Cbuild-dir=%s' % str(project.build_dir),
str(project.source_dir),
*argv,
]
if not output_dir is None:
cmd.extend(['-o', str(output_dir)])
logger.info(dict(env=env))
subprocess.check_call(
cmd,
env=dict(list(os.environ.items())) | env,
)
if not project.meson_path is None:
if tests:
subprocess.check_call(
[
'ninja',
'-C',
str(project.build_dir / 'pyproject'),
'test',
]
)
def meson_install(
self,
project_name: str,
force: Optional[bool] = None,
argv: Optional[list[str]] = None,
) -> None:
project = self.projects[project_name]
if force is None:
force = False
if argv is None:
argv = []
if force and project.dest_dir.exists():
shutil.rmtree(project.dest_dir)
subprocess.check_call([
shutil_which('meson', True,),
'install',
'-C',
project.build_dir / 'meson',
'--destdir', project.dest_dir,
*argv,
])
for o in glob.glob(
str(project.dest_dir / 'lib' / 'pkgconfig' / '*.pc'),
recursive=True,
):
logger.info(dict(
path=o,
action='patch prefix',
))
with io.open(o, 'r') as f:
content = f.read()
with io.open(o, 'w') as f:
f.write(
content.replace('prefix=/', 'prefix=${pcfiledir}/../../')
)
def ninja(
self,
project_name: str,
argv: Optional[list[str]] = None,
env: Optional[dict[str, str]] = None,
) -> None:
project = self.projects[project_name]
if argv is None:
argv = []
if env is None:
env = dict()
logger.info(dict(env=env))
subprocess.check_call(
[
shutil_which('ninja', True),
'-C',
str(project.build_dir / 'meson'),
*argv,
],
env=dict(list(os.environ.items())) | env,
)
def meson_test(
self,
project_name: str,
argv: Optional[list[str]] = None,
) -> None:
project = self.projects[project_name]
if argv is None:
argv = []
subprocess.check_call([
shutil_which('meson', True,),
'test',
'-C',
project.build_dir / 'meson',
*argv,
])
def meson_compile(
self,
project_name: str,
argv: Optional[list[str]] = None,
) -> None:
project = self.projects[project_name]
if argv is None:
argv = []
subprocess.check_call([
shutil_which('meson', True,),
'compile',
'-C',
project.build_dir / 'meson',
*argv,
])
@property
def third_party_roots(self) -> list[pathlib.Path]:
return []
def meson_setup(
self,
project_name: str,
force: bool,
argv: Optional[list[str]] = None,
env: Optional[dict[str, str]] = None,
# third_party_roots: Optional[list[pathlib.Path]] = None,
) -> None:
project = self.projects[project_name]
if argv is None:
argv = []
if env is None:
env = dict()
logger.info(dict(env=env))
if force:
if (project.build_dir / 'meson').exists():
logger.info(dict(action='removing build dir', path=project.build_dir / 'meson'))
shutil.rmtree(project.build_dir / 'meson')
extra_args : list[str] = []
if len(self.third_party_roots) > 0:
extra_args.extend([
'-Dthird_party_roots=%s' % str(o.absolute())
for o in self.third_party_roots
])
cmd = [
shutil_which('meson', True,),
'setup',
str(project.source_dir),
str(project.build_dir / 'meson'),
'-Dmodes=["meson"]',
*extra_args,
# '-Dpkgconfig.relocatable=true',
'-Dprefix=/',
*argv,
]
logger.info(dict(cmd=cmd))
subprocess.check_call(
cmd,
env=dict(list(os.environ.items())) | env,
)

@ -0,0 +1,335 @@
#!/usr/bin/env python3
import glob
import io
import tempfile
import dataclasses
import pathlib
import sys
import subprocess
import os
import logging
from typing import (Optional, Any,)
from typing_extensions import (
Self, BinaryIO,
)
logger = logging.getLogger(__name__)
def toml_load(f: BinaryIO) -> Any:
try:
import tomllib
return tomllib.load(f)
except:
pass
try:
import tomli
return tomli.load(f)
except:
pass
raise NotImplementedError
@dataclasses.dataclass
class PyProject:
path: pathlib.Path
dependencies: dict[str, list[str]]
early_features: Optional[list[str]] = None
pip_find_links: Optional[list[pathlib.Path]] = None
runtime_libdirs: Optional[list[pathlib.Path]] = None
runtime_preload: Optional[list[pathlib.Path]] = None
requirements: dict[str, pathlib.Path] = dataclasses.field(default_factory=lambda : dict())
def pyproject_load(
d: pathlib.Path,
) -> PyProject:
with io.open(d, 'rb') as f:
content = toml_load(f)
assert isinstance(content, dict)
dependencies : dict[str, list[str]] = dict()
dependencies['default'] = content['project']['dependencies']
if (
'optional-dependencies' in content['project']
):
assert isinstance(
content['project']['optional-dependencies'],
dict
)
for k, v in content['project']['optional-dependencies'].items():
assert isinstance(v, list)
assert isinstance(k, str)
dependencies[k] = v
res = PyProject(
path=d,
dependencies=dependencies,
)
tool_name = 'online.fxreader.pr34'.replace('.', '-')
if (
'tool' in content and
isinstance(
content['tool'], dict
) and
tool_name in content['tool'] and
isinstance(
content['tool'][tool_name],
dict
)
):
if 'early_features' in content['tool'][tool_name]:
res.early_features = content['tool'][tool_name]['early_features']
if 'pip_find_links' in content['tool'][tool_name]:
res.pip_find_links = [
d.parent / pathlib.Path(o)
for o in content['tool'][tool_name]['pip_find_links']
]
if 'runtime_libdirs' in content['tool'][tool_name]:
res.runtime_libdirs = [
d.parent / pathlib.Path(o)
# pathlib.Path(o)
for o in content['tool'][tool_name]['runtime_libdirs']
]
if 'runtime_preload' in content['tool'][tool_name]:
res.runtime_preload = [
d.parent / pathlib.Path(o)
# pathlib.Path(o)
for o in content['tool'][tool_name]['runtime_preload']
]
if 'requirements' in content['tool'][tool_name]:
assert isinstance(content['tool'][tool_name]['requirements'], dict)
res.requirements = {
k : d.parent / pathlib.Path(v)
# pathlib.Path(o)
for k, v in content['tool'][tool_name]['requirements'].items()
}
return res
@dataclasses.dataclass
class BootstrapSettings:
env_path: pathlib.Path
python_path: pathlib.Path
base_dir: pathlib.Path
python_version: Optional[str] = dataclasses.field(
default_factory=lambda : os.environ.get(
'PYTHON_VERSION',
'%d.%d' % (
sys.version_info.major,
sys.version_info.minor,
),
).strip()
)
uv_args: list[str] = dataclasses.field(
default_factory=lambda : os.environ.get(
'UV_ARGS',
'--offline',
).split(),
)
@classmethod
def get(
cls,
base_dir: Optional[pathlib.Path] = None,
) -> Self:
if base_dir is None:
base_dir = pathlib.Path.cwd()
env_path = base_dir / '.venv'
python_path = env_path / 'bin' / 'python3'
return cls(
base_dir=base_dir,
env_path=env_path,
python_path=python_path,
)
def env_bootstrap(
bootstrap_settings: BootstrapSettings,
pyproject: PyProject,
) -> None:
pip_find_links : list[pathlib.Path] = []
if not pyproject.pip_find_links is None:
pip_find_links.extend(pyproject.pip_find_links)
pip_find_links_args = sum([
['-f', str(o),]
for o in pip_find_links
], [])
features : list[str] = []
if pyproject.early_features:
features.extend(pyproject.early_features)
requirements_python_version: Optional[str] = None
if not bootstrap_settings.python_version is None:
requirements_python_version = bootstrap_settings.python_version.replace('.', '_')
requirements_name = '_'.join(sorted(features))
if requirements_python_version:
requirements_name += '_' + requirements_python_version
requirements_path : Optional[pathlib.Path] = None
if requirements_name in pyproject.requirements:
requirements_path = pyproject.requirements[requirements_name]
else:
requirements_path = pyproject.path.parent / 'requirements.txt'
requirements_in : list[str] = []
requirements_in.extend([
'uv', 'pip', 'build', 'setuptools', 'meson-python', 'pybind11'
])
if pyproject.early_features:
early_dependencies = sum([
pyproject.dependencies[o]
for o in pyproject.early_features
], [])
logger.info(dict(
early_dependencies=early_dependencies,
))
requirements_in.extend(early_dependencies)
# if len(early_dependencies) > 0:
# subprocess.check_call([
# bootstrap_settings.python_path,
# '-m',
# 'uv', 'pip', 'install',
# *pip_find_links_args,
# # '-f', str(pathlib.Path(__file__).parent / 'deps' / 'dist'),
# *bootstrap_settings.uv_args,
# *early_dependencies,
# ])
if not requirements_path.exists():
with tempfile.NamedTemporaryFile(
mode='w',
prefix='requirements',
suffix='.in',
) as f:
f.write(
'\n'.join(requirements_in)
)
f.flush()
subprocess.check_call([
'uv',
'pip',
'compile',
'--generate-hashes',
*pip_find_links_args,
# '-p',
# bootstrap_settings.python_path,
*bootstrap_settings.uv_args,
'-o', str(requirements_path),
f.name,
])
uv_python_version: list[str] = []
if not bootstrap_settings.python_version is None:
uv_python_version.extend([
'-p', bootstrap_settings.python_version,
])
subprocess.check_call([
'uv', 'venv',
*uv_python_version,
*pip_find_links_args,
# '--seed',
*bootstrap_settings.uv_args,
str(bootstrap_settings.env_path)
])
subprocess.check_call([
'uv',
'pip',
'install',
*pip_find_links_args,
'-p',
bootstrap_settings.python_path,
'--require-hashes',
*bootstrap_settings.uv_args,
'-r', str(requirements_path),
])
def paths_equal(
a: pathlib.Path | str,
b: pathlib.Path | str
) -> bool:
return (
os.path.abspath(str(a)) ==
os.path.abspath(str(b))
)
def run(
d: Optional[pathlib.Path] = None,
cli_path: Optional[pathlib.Path] = None,
) -> None:
if cli_path is None:
cli_path = pathlib.Path(__file__).parent / 'cli.py'
if d is None:
d = pathlib.Path(__file__).parent / 'pyproject.toml'
bootstrap_settings = BootstrapSettings.get()
pyproject : PyProject = pyproject_load(
d
)
logging.basicConfig(level=logging.INFO)
if not bootstrap_settings.env_path.exists():
env_bootstrap(
bootstrap_settings=bootstrap_settings,
pyproject=pyproject,
)
logger.info([sys.executable, sys.argv, bootstrap_settings.python_path])
if not paths_equal(sys.executable, bootstrap_settings.python_path):
os.execv(
str(bootstrap_settings.python_path),
[
str(bootstrap_settings.python_path),
*sys.argv,
]
)
os.execv(
str(bootstrap_settings.python_path),
[
str(bootstrap_settings.python_path),
str(
cli_path
),
*sys.argv[1:],
]
)
if __name__ == '__main__':
run()

@ -0,0 +1,90 @@
import base64
import os
import cryptography.hazmat.primitives.kdf.scrypt
from typing import (Literal, overload, Optional,)
class PasswordUtils:
@overload
@classmethod
def secret_hash(
cls,
secret: str | bytes,
mode: Literal['base64'],
salt: Optional[bytes] = None,
) -> tuple[str, str]: ...
@overload
@classmethod
def secret_hash(
cls,
secret: str | bytes,
mode: Literal['bytes'],
salt: Optional[bytes] = None,
) -> tuple[bytes, bytes]: ...
@classmethod
def secret_hash(
cls,
secret: str | bytes,
mode: Literal['bytes', 'base64'],
salt: Optional[bytes] = None,
) -> tuple[str, str] | tuple[bytes, bytes]:
if salt is None:
salt = os.urandom(16)
if isinstance(secret, str):
secret = secret.encode('utf-8')
# derive
kdf = cls._scrypt_init(salt=salt)
hashed_secret = kdf.derive(secret)
if mode == 'bytes':
return (salt, hashed_secret)
elif mode == 'base64':
res_tuple = tuple((
base64.b64encode(o).decode('utf-8')
for o in (salt, hashed_secret,)
))
return (res_tuple[0], res_tuple[1])
else:
raise NotImplementedError
@classmethod
def _scrypt_init(
cls,
salt: bytes
) -> cryptography.hazmat.primitives.kdf.scrypt.Scrypt:
return cryptography.hazmat.primitives.kdf.scrypt.Scrypt(
salt=salt,
length=32,
n=2**14,
r=8,
p=1,
)
@classmethod
def secret_check(
cls,
secret: str | bytes,
salt: str | bytes,
hashed_secret: str | bytes,
) -> bool:
if isinstance(salt, str):
salt = base64.b64decode(salt)
if isinstance(secret, str):
secret = secret.encode('utf-8')
if isinstance(hashed_secret, str):
hashed_secret = base64.b64decode(hashed_secret)
kdf = cls._scrypt_init(salt=salt)
try:
kdf.verify(secret, hashed_secret)
return True
except cryptography.exceptions.InvalidKey:
return False

@ -0,0 +1,35 @@
import os
import logging
from typing import (Optional,)
logger = logging.getLogger(__name__)
class DebugPy:
@classmethod
def set_trace(
cls,
host: Optional[str] = None,
port: Optional[int] = None,
wait: Optional[bool] = None,
) -> None:
if host is None:
host = '127.0.0.1'
if port is None:
port = 4444
if wait is None:
wait = True
import debugpy
if os.environ.get('DEBUGPY_RUNNING') != 'true':
logger.info('debugpy init')
import debugpy
debugpy.listen((host, port))
os.environ['DEBUGPY_RUNNING'] = 'true'
if wait:
debugpy.wait_for_client()
debugpy.breakpoint()
logger.info('debugpy done')

@ -0,0 +1,16 @@
import logging
from typing import (Optional,)
def setup(level: Optional[int] = None) -> None:
if level is None:
level = logging.INFO
logging.basicConfig(
level=level,
format=(
'%(levelname)s:%(name)s:%(message)s'
':%(process)d'
':%(asctime)s'
':%(pathname)s:%(funcName)s:%(lineno)s'
),
)

@ -0,0 +1,216 @@
import pydantic.dataclasses
import datetime
import pydantic_settings
import marisa_trie
import json
import pathlib
import subprocess
import logging
import sys
import argparse
from pydantic import (Field,)
from typing import (ClassVar, Generator, Annotated, Optional, Any,)
logger = logging.getLogger(__name__)
@pydantic.dataclasses.dataclass
class MypyFormatEntry:
name : str
value : str
def __eq__(self, other: object) -> bool:
if not isinstance(other, type(self)):
raise NotImplementedError
return self.value == other.value
class MypyFormat:
vscode : ClassVar[MypyFormatEntry] = MypyFormatEntry(name='vscode', value='vscode')
json : ClassVar[MypyFormatEntry] = MypyFormatEntry(name='json', value='json')
@classmethod
def from_value(cls, value: str) -> MypyFormatEntry:
for e in cls.entries():
if value == e.value:
return e
raise NotImplementedError
@classmethod
def entries(cls) -> Generator[MypyFormatEntry, None, None,]:
for o in dir(cls):
e = getattr(cls, o)
if not isinstance(e, MypyFormatEntry):
continue
yield e
class MypySettings(pydantic_settings.BaseSettings):
model_config = pydantic_settings.SettingsConfigDict(
env_prefix='online_fxreader_pr34_mypy_',
case_sensitive=False,
)
config_path : pathlib.Path = pathlib.Path.cwd() / '.mypy.ini'
max_errors : dict[str, int] = dict()
paths : Annotated[list[pathlib.Path], Field(default_factory=lambda : ['.'])]
def run(
argv: Optional[list[str]] = None,
settings: Optional[MypySettings] = None,
) -> None:
if argv is None:
argv = []
if settings is None:
settings = MypySettings()
parser = argparse.ArgumentParser()
parser.add_argument(
'-q', '--quiet',
dest='quiet',
action='store_true',
help='do not print anything if the program is correct according to max_errors limits',
default=False,
)
parser.add_argument(
'-i',
dest='paths',
help='specify paths to check',
default=[],
action='append',
)
parser.add_argument(
'-f', '--format',
dest='_format',
help='output format of errors',
default=MypyFormat.json.value,
choices=[
o.value
for o in MypyFormat.entries()
],
)
options, args = parser.parse_known_args(argv)
if len(args) > 0 and args[0] == '--':
del args[0]
options.format = MypyFormat.from_value(options._format)
if len(options.paths) == 0:
options.paths.extend(settings.paths)
started_at = datetime.datetime.now()
mypy_cmd = [
sys.executable,
'-m',
'mypy',
'--config-file', str(settings.config_path),
'--strict',
'-O',
'json',
*args,
*options.paths,
]
logger.info(dict(cmd=mypy_cmd))
res = subprocess.run(
mypy_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
done_at = datetime.datetime.now()
try:
assert not res.returncode is None
errors = sorted([
json.loads(o)
for o in res.stdout.decode('utf-8').splitlines()
if not o.strip() == ''
], key=lambda x: (
x.get('file', ''),
x.get('line', 0),
))
if not options.quiet:
if (len(res.stderr)) > 0:
logger.error(res.stderr.decode('utf-8'))
except:
logger.exception('')
logger.error(res.stdout.decode('utf-8'))
logger.error(res.stderr.decode('utf-8'))
sys.exit(res.returncode)
g : dict[str, Any] = dict()
for o in errors:
if not o['file'] in g:
g[o['file']] = []
g[o['file']].append(o)
h = {
k : len(v)
for k, v in sorted(
list(g.items()),
key=lambda x: x[0],
)
}
mentioned_paths = marisa_trie.Trie(list(h))
violated_limits : dict[str, str] = dict()
for k, v in settings.max_errors.items():
matching_paths = mentioned_paths.keys(k)
total_errors = sum([
h[o]
for o in matching_paths
], 0)
if total_errors > v:
violated_limits[k] = '%s - [%s]: has %d errors > %d' % (
k, ', '.join(matching_paths), total_errors, v,
)
if len(violated_limits) > 0 or not options.quiet:
if options.format == MypyFormat.vscode:
for o in errors:
sys.stdout.write('[%s] %s:%d,%d %s - %s - %s\n' % (
o['severity'],
o['file'],
o['line'],
o['column'],
o['message'],
o['hint'],
o['code'],
))
sys.stdout.flush()
#logger.info(json.dumps(errors, indent=4))
else:
logger.info(json.dumps(errors, indent=4))
#if len(violated_limits) > 0:
# logger.info(json.dumps(violated_limits, indent=4))
logger.info(json.dumps(dict(
max_errors=settings.max_errors,
violated_limits=violated_limits,
histogram=h,
elapsed=(done_at - started_at).total_seconds(),
), indent=4))
if len(violated_limits) > 0:
sys.exit(1)
if __name__ == '__main__':
from . import logging as _logging
_logging.setup()
run(sys.argv[1:])

@ -0,0 +1,122 @@
import shutil
import glob
import subprocess
import pydantic
import pathlib
import ctypes
import os
import sys
import logging
import dataclasses
logger = logging.getLogger(__name__)
from typing import (overload, Optional, Literal, Any, Annotated,)
from .cli_bootstrap import PyProject
@overload
def shutil_which(
name: str,
raise_on_failure: Literal[True],
) -> str: ...
@overload
def shutil_which(
name: str,
raise_on_failure: bool,
) -> Optional[str]: ...
def shutil_which(
name: str,
raise_on_failure: bool,
) -> Optional[str]:
res = shutil.which(name)
if res is None and raise_on_failure:
raise NotImplementedError
else:
return res
def runtime_libdirs_init(
project: PyProject,
) -> None:
if sys.platform == 'linux':
ld_library_path : list[pathlib.Path] = [
o
for o in [
*[
o.absolute()
for o in (
project.runtime_libdirs
if project.runtime_libdirs
else []
)
],
*[
pathlib.Path(o)
for o in os.environ.get(
'LD_LIBRARY_PATH',
''
).split(os.path.pathsep)
if o != ''
]
]
]
ld_library_path_present : list[pathlib.Path] = []
for o in ld_library_path:
if not o.exists():
logger.warning(dict(
ld_library_path=o,
msg='not found',
))
ld_library_path_present.append(o)
os.environ.update(
LD_LIBRARY_PATH=os.path.pathsep.join([
str(o) for o in ld_library_path_present
])
)
for preload_path in (project.runtime_preload or []):
for preload_found in glob.glob(str(
preload_path.parent / ('lib%s.so' % preload_path.name)
)):
logger.info(dict(
preload_path=preload_path, preload_found=preload_found,
# lib_path=o,
msg='load_library',
))
ctypes.cdll.LoadLibrary(preload_found)
else:
raise NotImplementedError
class interfaces_index_t:
@dataclasses.dataclass
class Interface:
@dataclasses.dataclass
class AddrInfo:
family: str
local: str
name: Annotated[
str,
pydantic.Field(
alias='ifname',
)
]
addr_info: list[AddrInfo]
def interfaces_index() -> list[interfaces_index_t.Interface]:
res = pydantic.RootModel[
list[interfaces_index_t.Interface]
].model_validate_json(
subprocess.check_output([
'ip', '-j', 'addr',
]).decode('utf-8')
).root
return res

@ -0,0 +1,524 @@
import contextlib
import pathlib
import sys
import enum
import dataclasses
import subprocess
import tempfile
import unittest.mock
import logging
import typing
if typing.TYPE_CHECKING:
import pip._internal.commands.show
import pip._internal.commands.download
import pip._internal.cli.main_parser
import pip._internal.models.index
import pip._internal.utils.temp_dir
import pip._internal.cli.main
import pip._internal.network.download
import pip._internal.resolution.base
import pip._internal.resolution.resolvelib.resolver
import pip._internal.operations.prepare
from typing import (
Literal, Optional, Iterable, Any,
)
logger = logging.getLogger(__name__)
def pip_show(
argv: list[str],
) -> list['pip._internal.commands.show._PackageInfo']:
import pip._internal.commands.show
return list(
pip._internal.commands.show.search_packages_info(
argv,
)
)
class pip_resolve_t:
class kwargs_t:
class mode_t(enum.StrEnum):
copy_paste = "copy_paste"
monkey_patch = "monkey_patch"
uv_pip_freeze = "uv_pip_freeze"
uv_pip_compile = "uv_pip_compile"
@dataclasses.dataclass
class res_t:
@dataclasses.dataclass
class download_info_t:
url: str
sha256: str
constraint: str
txt: Optional[str] = None
entries: Optional[list[download_info_t]] = None
def pip_resolve_entries_to_txt(
entries: list[pip_resolve_t.res_t.download_info_t]
) -> str:
return '\n'.join([
'#%s\n%s %s' % (
o.url,
o.constraint,
' '.join([
'--hash=sha256:%s' % o2
for o2 in o.sha256
])
)
for o in entries
])
def pip_resolve(
argv: list[str],
mode: pip_resolve_t.kwargs_t.mode_t,
requirements: Optional[list[str]] = None,
) -> pip_resolve_t.res_t:
if mode is pip_resolve_t.kwargs_t.mode_t.copy_paste:
import pip._internal.commands.show
import pip._internal.commands.download
import pip._internal.cli.cmdoptions
import pip._internal.cli.main_parser
import pip._internal.models.index
import pip._internal.utils.temp_dir
import pip._internal.cli.main
import pip._internal.network.download
import pip._internal.resolution.base
import pip._internal.req.req_install
import pip._internal.resolution.resolvelib.resolver
import pip._internal.operations.prepare
import pip._internal.utils.temp_dir
import pip._internal.operations.build.build_tracker
import pip._internal.models.direct_url
with contextlib.ExitStack() as stack:
stack.enter_context(pip._internal.utils.temp_dir.global_tempdir_manager())
t2 = pip._internal.cli.main_parser.create_main_parser()
t3 = t2.parse_args(["download"])
t1 = pip._internal.commands.download.DownloadCommand("blah", "shit")
stack.enter_context(t1.main_context())
# options = pip._internal.commands.download.Values()
options = t3[0]
options.python_version = None
options.platforms = []
options.abis = []
options.implementation = []
options.format_control = None
options.ignore_dependencies = None
options.index_url = pip._internal.models.index.PyPI.simple_url
options.extra_index_urls = []
options.no_index = None
options.find_links = []
options.pre = None
options.prefer_binary = True
options.only_binary = True
options.constraints = []
options.use_pep517 = None
options.editables = []
options.requirements = []
options.src_dir = str(pathlib.Path(__file__).parent)
options.build_isolation = None
options.check_build_deps = None
options.progress_bar = True
options.require_hashes = None
options.ignore_requires_python = False
# options.cache_dir
pip._internal.cli.cmdoptions.check_dist_restriction(options)
# t1._in_main_context = True
session = t1.get_default_session(options)
target_python = pip._internal.cli.cmdoptions.make_target_python(options)
finder = t1._build_package_finder(
options=options,
session=session,
target_python=target_python,
ignore_requires_python=options.ignore_requires_python,
)
build_tracker = t1.enter_context(
pip._internal.operations.build.build_tracker.get_build_tracker()
)
reqs = t1.get_requirements(
[
#'pip', 'uv', 'ipython',
*argv,
],
options,
finder,
session,
)
pip._internal.req.req_install.check_legacy_setup_py_options(options, reqs)
directory = pip._internal.utils.temp_dir.TempDirectory(
delete=True, kind="download", globally_managed=True
)
preparer = t1.make_requirement_preparer(
temp_build_dir=directory,
options=options,
build_tracker=build_tracker,
session=session,
finder=finder,
download_dir=None,
use_user_site=False,
verbosity=False,
)
resolver = t1.make_resolver(
preparer=preparer,
finder=finder,
options=options,
ignore_requires_python=options.ignore_requires_python,
use_pep517=options.use_pep517,
py_version_info=options.python_version,
)
t1.trace_basic_info(finder)
requirement_set = resolver.resolve(reqs, check_supported_wheels=True)
res = pip_resolve_t.res_t()
res.entries = []
for k, v in requirement_set.requirements.items():
assert not v.download_info is None
assert isinstance(
v.download_info.info,
pip._internal.models.direct_url.ArchiveInfo,
)
assert not v.download_info.info.hashes is None
res.entries.append(
pip_resolve_t.res_t.download_info_t(
constraint=k,
sha256=v.download_info.info.hashes["sha256"],
url=v.download_info.url,
)
)
res.txt = pip_resolve_entries_to_txt(
res.entries
)
return res
elif mode is pip_resolve_t.kwargs_t.mode_t.monkey_patch:
import pip._internal.commands.show
import pip._internal.commands.download
import pip._internal.cli.main_parser
import pip._internal.models.index
import pip._internal.models.link
from pip._internal.models.link import (
Link,
)
import pip._internal.utils.temp_dir
from pip._internal.metadata.base import (
BaseDistribution,
)
import pip._internal.cli.main
import pip._internal.network.download
import pip._internal.resolution.base
import pip._internal.resolution.resolvelib.resolver
import pip._internal.operations.prepare
from pip._internal.network.download import (
Downloader,
)
from pip._internal.operations.prepare import (
File,
)
from pip._internal.req.req_set import RequirementSet
from pip._internal.utils.hashes import Hashes
from pip._internal.req.req_install import InstallRequirement
downloader_call_def = pip._internal.network.download.Downloader.__call__
def downloader_call(
_self: pip._internal.network.download.Downloader,
link: pip._internal.models.link.Link,
location: str,
) -> tuple[str, str]:
logger.info(
dict(
url=link.url,
)
)
return downloader_call_def(
_self,
link, location,
)
batch_downloader_call_def = (
pip._internal.network.download.BatchDownloader.__call__
)
def batch_downloader_call(
_self: pip._internal.network.download.BatchDownloader,
links: Iterable[pip._internal.models.link.Link],
location: str,
) -> Iterable[
tuple[
pip._internal.models.link.Link,
tuple[str, str]
]
]:
# print(args)
logger.info(
dict(
links=links,
location=location,
)
)
return [
(o, ("/dev/null", ''))
for o in links
]
# base_resolver_resolve_def = pip._internal.resolution.base.BaseResolver.resolve
base_resolver_resolve_def = (
pip._internal.resolution.resolvelib.resolver.Resolver.resolve
)
result_requirements : list[
RequirementSet | InstallRequirement
] = []
def base_resolver_resolve(
_self: pip._internal.resolution.resolvelib.resolver.Resolver,
root_reqs: list[
InstallRequirement,
],
check_supported_wheels: bool,
) -> RequirementSet:
# print(args, kwargs)
res = base_resolver_resolve_def(
_self,
root_reqs,
check_supported_wheels
)
result_requirements.append(res)
raise NotImplementedError
return res
get_http_url_def = pip._internal.operations.prepare.get_http_url
def get_http_url(
link: Link,
download: Downloader,
download_dir: Optional[str] = None,
hashes: Optional[Hashes] = None,
) -> File:
logger.info(
dict(
url=link.url,
hashes=hashes,
)
)
if link.url.endswith(".whl"):
print("blah")
hashes = None
return File(
"/dev/null",
'',
)
else:
return get_http_url_def(
link,
download,
download_dir,
hashes
)
prepare_linked_requirements_more_def = pip._internal.operations.prepare.RequirementPreparer.prepare_linked_requirements_more
def prepare_linked_requirements_more(
_self: pip._internal.resolution.resolvelib.resolver.Resolver,
reqs: Iterable[InstallRequirement],
parallel_builds: bool = False,
) -> None:
result_requirements.extend(
reqs
)
raise NotImplementedError
_complete_partial_requirements_def = pip._internal.operations.prepare.RequirementPreparer._complete_partial_requirements
def _complete_partial_requirements(
_self: pip._internal.resolution.resolvelib.resolver.Resolver,
partially_downloaded_reqs: Iterable[InstallRequirement],
parallel_builds: bool = False,
) -> None:
result_requirements.extend(
partially_downloaded_reqs
)
raise NotImplementedError
patches : list[Any] = []
patches.append(
unittest.mock.patch.object(
pip._internal.network.download.Downloader, "__call__", downloader_call
)
)
# patches.append(
# unittest.mock.patch.object(
# pip._internal.network.download.BatchDownloader,
# '__call__',
# batch_downloader_call
# )
# )
# patches.append(
# unittest.mock.patch.object(
# pip._internal.resolution.base.BaseResolver, 'resolve', base_resolver_resolve))
patches.append(
unittest.mock.patch.object(
pip._internal.resolution.resolvelib.resolver.Resolver,
"resolve",
base_resolver_resolve,
)
)
patches.append(
unittest.mock.patch.object(
pip._internal.operations.prepare,
"get_http_url",
get_http_url,
)
)
patches.append(
unittest.mock.patch.object(
pip._internal.operations.prepare.RequirementPreparer,
"prepare_linked_requirements_more",
prepare_linked_requirements_more,
)
)
# patches.append(
# unittest.mock.patch.object(
# pip._internal.operations.prepare.RequirementPreparer,
# '_complete_partial_requirements',
# _complete_partial_requirements
# )
# )
with contextlib.ExitStack() as stack:
for p in patches:
stack.enter_context(p)
pip._internal.cli.main.main(
[
"download",
"-q",
"--no-cache",
"-d",
"/dev/null",
*argv,
# 'numpy',
]
)
# return sum([
# [
# pip_resolve_t.res_t.download_info_t(
# constraint=k,
# sha256=v.download_info.info.hashes['sha256'],
# url=v.download_info.url,
# )
# for k, v in o.requirements.items()
# ]
# for o in result_requirements
# ], [])
logger.warn(result_requirements)
res = pip_resolve_t.res_t()
res.entries = []
for o in result_requirements:
assert isinstance(o, InstallRequirement)
sha256_hashes = o.hashes()._allowed["sha256"]
assert len(sha256_hashes) == 1
assert not o.link is None
res.entries.append(
pip_resolve_t.res_t.download_info_t(
constraint=str(o.req),
sha256=sha256_hashes[0],
url=o.link.url,
)
)
res.txt = pip_resolve_entries_to_txt(
res.entries
)
return res
elif mode is pip_resolve_t.kwargs_t.mode_t.uv_pip_freeze:
assert len(argv) == 0
pip_freeze = subprocess.check_output(
[
sys.executable,
"-m",
"uv",
"pip",
"freeze",
],
).decode('utf-8')
pip_compile = subprocess.check_output(
[
sys.executable, '-m',
'uv', 'pip', 'compile',
'--generate-hashes',
'-',
],
input=pip_freeze.encode('utf-8')
).decode('utf-8')
return pip_resolve_t.res_t(
txt=pip_compile,
)
elif mode is pip_resolve_t.kwargs_t.mode_t.uv_pip_compile:
with contextlib.ExitStack() as stack:
if not requirements is None:
# assert len(argv) == 0
f = stack.enter_context(
tempfile.NamedTemporaryFile(
suffix='.txt',
)
)
f.write(
('\n'.join(requirements)).encode('utf-8')
)
f.flush()
argv.append(f.name)
if argv[0] == '--':
del argv[0]
pip_compile = subprocess.check_output(
[
sys.executable, '-m',
'uv', 'pip', 'compile',
'--generate-hashes',
*argv,
],
).decode('utf-8')
return pip_resolve_t.res_t(
txt=pip_compile,
)
else:
raise NotImplementedError

@ -0,0 +1,27 @@
# https://github.com/python/typing/issues/59#issuecomment-353878355
# https://gitea.fxreader.online/fxreader.online/freelance-project-34-marketing-blog/issues/2#issue-25
import typing
from typing import Any
from typing_extensions import Protocol
from abc import abstractmethod
C = typing.TypeVar("C", bound="Comparable")
class Comparable(Protocol):
@abstractmethod
def __eq__(self, other: Any) -> bool:
pass
@abstractmethod
def __lt__(self: C, other: C) -> bool:
pass
def __gt__(self: C, other: C) -> bool:
return (not self < other) and self != other
def __le__(self: C, other: C) -> bool:
return self < other or self == other
def __ge__(self: C, other: C) -> bool:
return (not self < other)

@ -0,0 +1,277 @@
import time
import glob
import io
import os
import numpy
import numpy.typing
import functools
import pathlib
import threading
import cython
import datetime
from typing import (Any, Optional, TypeVar, Type, cast)
# from scoping import scoping as s
def test(
_id: int,
T: float,
a: numpy.ndarray[Any, numpy.dtype[numpy.int32]],
) -> None:
with cython.nogil:
#if True:
started_at = datetime.datetime.now()
print('started')
def elapsed() -> float:
return (datetime.datetime.now() - started_at).total_seconds()
#a = 0
while elapsed() < T:
#a += 1
for k in range(1024 * 1024):
a[_id] += 1
print(['done', started_at, elapsed(), a[_id]])
M = TypeVar('M', bound=Type[Any])
def build(content: str, module: M) -> M:
import pathlib
import tempfile
import hashlib
import Cython.Build.Inline
sha256sum = hashlib.sha256(content.encode('utf-8')).digest().hex()
output_dir = (pathlib.Path('.') / 'tmp' / 'cython' / sha256sum).absolute()
if not output_dir.exists() or True:
os.makedirs(str(output_dir), exist_ok=True)
source_path = output_dir / ('_%s.pyx' % sha256sum)
if not source_path.exists():
with io.open(str(source_path), 'w') as f:
f.write(content)
t1 = Cython.Build.Inline._get_build_extension()
t1.extensions = Cython.Build.cythonize(str(source_path))
t1.build_temp = str(pathlib.Path('/'))
t1.build_lib = str(output_dir)
#t2 = Cython.Build.Inline.Extension(
# name=sha256sum,
#)
t1.run()
return cast(
M,
Cython.Build.Inline.load_dynamic(
'_%s' % sha256sum,
glob.glob(
str(output_dir / ('_%s*.so' % sha256sum))
)[0]
)
)
raise NotImplementedError
def mypyc_build(file_path: pathlib.Path) -> Any:
import pathlib
import tempfile
import hashlib
import mypyc.build
import Cython.Build.Inline
assert isinstance(file_path, pathlib.Path)
#sha256sum = hashlib.sha256(content.encode('utf-8')).digest().hex()
#output_dir = (pathlib.Path('.') / 'tmp' / 'cython' / sha256sum).absolute()
output_dir = pathlib.Path('.') / 'tmp' / 'mypyc'
sha256sum = file_path.stem
lib_pattern = file_path.parent / ('%s.cpython*.so' % sha256sum)
lib_dir = pathlib.Path('.')
def lib_path_glob(path: str | pathlib.Path) -> Optional[pathlib.Path]:
res : list[str] = glob.glob(str(path))
if len(res) == 0:
return None
else:
return pathlib.Path(res[0])
need_build : bool = False
lib_path : Optional[pathlib.Path] = None
lib_path = lib_path_glob(lib_pattern)
if not lib_path is None:
t2 = file_path.stat()
t3 = lib_path.stat()
if t3.st_mtime < t2.st_mtime:
need_build = True
del t2
del t3
else:
need_build = True
if need_build:
for o in [
output_dir,
output_dir / 'build' / file_path.parent,
]:
os.makedirs(
str(o),
exist_ok=True
)
#source_path = output_dir / ('_%s.py' % sha256sum)
source_path = file_path
#with io.open(str(source_path), 'w') as f:
# f.write(content)
t1 = Cython.Build.Inline._get_build_extension()
t1.extensions = mypyc.build.mypycify(
[str(source_path)],
target_dir=str(output_dir / 'build')
)
t1.build_temp = str(output_dir)
t1.build_lib = str(lib_dir)
#t2 = Cython.Build.Inline.Extension(
# name=sha256sum,
#)
t1.run()
lib_path = lib_path_glob(lib_pattern)
return Cython.Build.Inline.load_dynamic(
#'_%s' % sha256sum,
#t1.extensions[0].name,
file_path.stem,
str(lib_path),
)
raise NotImplementedError
class Source:
@staticmethod
def test2(
_a : numpy.ndarray[Any, numpy.dtype[numpy.int64]],
_id : numpy.dtype[numpy.int32] | int,
T : float=16
) -> int:
raise NotImplementedError
source = build(r'''
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def test4(int[:] a, int[:] b):
cdef int N = a.shape[0]
assert N == b.shape[0]
with cython.nogil:
for i in range(N):
a[i] += b[i]
return N
import datetime
def elapsed(started_at: datetime.datetime):
res = (datetime.datetime.now() - started_at).total_seconds()
return res
@cython.boundscheck(False) # Deactivate bounds checking
@cython.wraparound(False) # Deactivate negative indexing.
def has_time(started_at: datetime.datetime, T: float):
t1 = elapsed(started_at)
res = t1 < T
return res
@cython.boundscheck(False)
@cython.wraparound(False)
def test2(long long [:] _a, int _id, double T=16) -> int:
started_at = datetime.datetime.now()
print('started')
cdef int C = 1;
cdef int cond;
with cython.nogil:
#if True:
#a = 0
while True:
with cython.gil:
cond = has_time(started_at, T)
#cond = 0
if cond != 1:
break
#a += 1
for k in range(1024 * 1024 * 1024):
_a[_id] += C
print(['done', started_at, elapsed(started_at), _a[_id]])
return _a[_id]
''', Source)
def test_cython(N: int=4, T:int=16) -> None:
#a = [0] * N
a = numpy.zeros((N,), dtype=numpy.int64)
t = [
threading.Thread(
target=functools.partial(
source.test2,
a,
k,
T,
)
)
for k in range(N)
]
for o in t:
o.start()
for o in t:
o.join()
#cython_module['test2'](a, 0)
def test_mypyc(N: int=4, W:int=35) -> None:
cython2 = mypyc_build(
(pathlib.Path(__file__).parent / 'cython2.py').relative_to(
pathlib.Path.cwd()
)
)
# from .cython2 import fib
#a = [0] * N
t = [
threading.Thread(
target=functools.partial(
cython2.fib,
W,
)
)
for k in range(N)
]
for o in t:
o.start()
for o in t:
o.join()

@ -0,0 +1,11 @@
import time
def fib(n: int) -> int:
if n <= 1:
return n
else:
return fib(n - 2) + fib(n - 1)
t0 = time.time()
fib(32)
print(time.time() - t0)

@ -0,0 +1,36 @@
from online.fxreader.pr34.commands_typed import crypto
import unittest
class TestCrypto(unittest.TestCase):
def test_password_utils(self) -> None:
salt = b'asdfasdfasdf'
secret = 'blah'
hash_res = crypto.PasswordUtils.secret_hash(
secret,
mode='bytes',
salt=salt,
)
self.assertEqual(
hash_res,
(
salt,
b'\xdak\xd15\xfa\x8e\xc8\r\xc3\xd2c\xf1m\xb0\xbf\xe6\x98\x01$!j\xc8\xc0Hh\x84\xea,\x91\x8b\x08\xce',
),
)
check_res = crypto.PasswordUtils.secret_check(
secret,
*hash_res,
)
self.assertTrue(check_res)
self.assertFalse(
crypto.PasswordUtils.secret_check(
secret + 'asdfasdfsdf',
*hash_res,
)
)

57
python/pyproject.toml Normal file

@ -0,0 +1,57 @@
[project]
name = 'online.fxreader.pr34'
version = '0.1.5.16'
dependencies = [
#"-r requirements.txt",
'mypy',
'marisa-trie',
'pydantic',
'pydantic-settings',
]
[project.optional-dependencies]
crypto = [
'cryptography',
]
early = [
'numpy',
'cryptography',
]
lint = [
'tomli',
]
[tool.online-fxreader-pr34]
early_features = ['default', 'early', 'lint',]
[build-system]
requires = ['setuptools']
build-backend = 'setuptools.build_meta'
[tool.setuptools]
include-package-data = false
[tool.setuptools.package-dir]
'online.fxreader.pr34' = 'online/fxreader/pr34'
#package_dir = '..'
#packages = ['online_fxreader']
#[tool.setuptools.packages.find]
#where = ['../..']
#include = ['../../online_fxreader/vpn']
#exclude =['../../aiortc/*', '../../_cffi_src/*']
#[tool.setuptools.packages.find]
#exclude = ['*']
#include = ['*.py']
# [tool.setuptools.exclude-package-data]
# 'online.fxreader.pr34' = ['online/fxreader/pr34/py.typed']
#[tool.setuptools.package-data]
#'online_fxreader.vpn' = ['requirements.txt']
[project.scripts]
online-fxreader-pr34-commands = 'online.fxreader.pr34.commands:commands_cli'

513
python/requirements.txt Normal file

@ -0,0 +1,513 @@
# This file was autogenerated by uv via the following command:
# uv pip compile --generate-hashes -o /home/nartes/Documents/current/freelance-project-34-marketing-blog/python/requirements.txt /tmp/requirementsmeh8aapn.in
annotated-types==0.7.0 \
--hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
--hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
# via pydantic
build==1.2.2.post1 \
--hash=sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5 \
--hash=sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7
# via -r /tmp/requirementsmeh8aapn.in
cffi==1.17.1 \
--hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \
--hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \
--hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \
--hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \
--hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \
--hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \
--hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \
--hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \
--hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \
--hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \
--hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \
--hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \
--hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \
--hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \
--hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \
--hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \
--hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \
--hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \
--hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \
--hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \
--hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \
--hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \
--hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \
--hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \
--hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \
--hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \
--hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \
--hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \
--hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \
--hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \
--hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \
--hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \
--hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \
--hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \
--hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \
--hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \
--hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \
--hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \
--hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \
--hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \
--hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \
--hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \
--hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \
--hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \
--hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \
--hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \
--hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \
--hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \
--hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \
--hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \
--hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \
--hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \
--hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \
--hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \
--hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \
--hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \
--hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \
--hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \
--hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \
--hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \
--hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \
--hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \
--hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \
--hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \
--hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \
--hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \
--hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b
# via cryptography
cryptography==44.0.2 \
--hash=sha256:04abd71114848aa25edb28e225ab5f268096f44cf0127f3d36975bdf1bdf3390 \
--hash=sha256:0529b1d5a0105dd3731fa65680b45ce49da4d8115ea76e9da77a875396727b41 \
--hash=sha256:1bc312dfb7a6e5d66082c87c34c8a62176e684b6fe3d90fcfe1568de675e6688 \
--hash=sha256:268e4e9b177c76d569e8a145a6939eca9a5fec658c932348598818acf31ae9a5 \
--hash=sha256:29ecec49f3ba3f3849362854b7253a9f59799e3763b0c9d0826259a88efa02f1 \
--hash=sha256:2bf7bf75f7df9715f810d1b038870309342bff3069c5bd8c6b96128cb158668d \
--hash=sha256:3b721b8b4d948b218c88cb8c45a01793483821e709afe5f622861fc6182b20a7 \
--hash=sha256:3c00b6b757b32ce0f62c574b78b939afab9eecaf597c4d624caca4f9e71e7843 \
--hash=sha256:3dc62975e31617badc19a906481deacdeb80b4bb454394b4098e3f2525a488c5 \
--hash=sha256:4973da6ca3db4405c54cd0b26d328be54c7747e89e284fcff166132eb7bccc9c \
--hash=sha256:4e389622b6927d8133f314949a9812972711a111d577a5d1f4bee5e58736b80a \
--hash=sha256:51e4de3af4ec3899d6d178a8c005226491c27c4ba84101bfb59c901e10ca9f79 \
--hash=sha256:5f6f90b72d8ccadb9c6e311c775c8305381db88374c65fa1a68250aa8a9cb3a6 \
--hash=sha256:6210c05941994290f3f7f175a4a57dbbb2afd9273657614c506d5976db061181 \
--hash=sha256:6f101b1f780f7fc613d040ca4bdf835c6ef3b00e9bd7125a4255ec574c7916e4 \
--hash=sha256:7bdcd82189759aba3816d1f729ce42ffded1ac304c151d0a8e89b9996ab863d5 \
--hash=sha256:7ca25849404be2f8e4b3c59483d9d3c51298a22c1c61a0e84415104dacaf5562 \
--hash=sha256:81276f0ea79a208d961c433a947029e1a15948966658cf6710bbabb60fcc2639 \
--hash=sha256:8cadc6e3b5a1f144a039ea08a0bdb03a2a92e19c46be3285123d32029f40a922 \
--hash=sha256:8e0ddd63e6bf1161800592c71ac794d3fb8001f2caebe0966e77c5234fa9efc3 \
--hash=sha256:909c97ab43a9c0c0b0ada7a1281430e4e5ec0458e6d9244c0e821bbf152f061d \
--hash=sha256:96e7a5e9d6e71f9f4fca8eebfd603f8e86c5225bb18eb621b2c1e50b290a9471 \
--hash=sha256:9a1e657c0f4ea2a23304ee3f964db058c9e9e635cc7019c4aa21c330755ef6fd \
--hash=sha256:9eb9d22b0a5d8fd9925a7764a054dca914000607dff201a24c791ff5c799e1fa \
--hash=sha256:af4ff3e388f2fa7bff9f7f2b31b87d5651c45731d3e8cfa0944be43dff5cfbdb \
--hash=sha256:b042d2a275c8cee83a4b7ae30c45a15e6a4baa65a179a0ec2d78ebb90e4f6699 \
--hash=sha256:bc821e161ae88bfe8088d11bb39caf2916562e0a2dc7b6d56714a48b784ef0bb \
--hash=sha256:c505d61b6176aaf982c5717ce04e87da5abc9a36a5b39ac03905c4aafe8de7aa \
--hash=sha256:c63454aa261a0cf0c5b4718349629793e9e634993538db841165b3df74f37ec0 \
--hash=sha256:c7362add18b416b69d58c910caa217f980c5ef39b23a38a0880dfd87bdf8cd23 \
--hash=sha256:d03806036b4f89e3b13b6218fefea8d5312e450935b1a2d55f0524e2ed7c59d9 \
--hash=sha256:d1b3031093a366ac767b3feb8bcddb596671b3aaff82d4050f984da0c248b615 \
--hash=sha256:d1c3572526997b36f245a96a2b1713bf79ce99b271bbcf084beb6b9b075f29ea \
--hash=sha256:efcfe97d1b3c79e486554efddeb8f6f53a4cdd4cf6086642784fa31fc384e1d7 \
--hash=sha256:f514ef4cd14bb6fb484b4a60203e912cfcb64f2ab139e88c2274511514bf7308
# via -r /tmp/requirementsmeh8aapn.in
marisa-trie==1.2.1 \
--hash=sha256:06b099dd743676dbcd8abd8465ceac8f6d97d8bfaabe2c83b965495523b4cef2 \
--hash=sha256:0ee6cf6a16d9c3d1c94e21c8e63c93d8b34bede170ca4e937e16e1c0700d399f \
--hash=sha256:0fe69fb9ffb2767746181f7b3b29bbd3454d1d24717b5958e030494f3d3cddf3 \
--hash=sha256:1db3213b451bf058d558f6e619bceff09d1d130214448a207c55e1526e2773a1 \
--hash=sha256:20948e40ab2038e62b7000ca6b4a913bc16c91a2c2e6da501bd1f917eeb28d51 \
--hash=sha256:2428b495003c189695fb91ceeb499f9fcced3a2dce853e17fa475519433c67ff \
--hash=sha256:24a81aa7566e4ec96fc4d934581fe26d62eac47fc02b35fa443a0bb718b471e8 \
--hash=sha256:25688f34cac3bec01b4f655ffdd6c599a01f0bd596b4a79cf56c6f01a7df3560 \
--hash=sha256:36aa4401a1180615f74d575571a6550081d84fc6461e9aefc0bb7b2427af098e \
--hash=sha256:3a27c408e2aefc03e0f1d25b2ff2afb85aac3568f6fa2ae2a53b57a2e87ce29d \
--hash=sha256:3ad356442c2fea4c2a6f514738ddf213d23930f942299a2b2c05df464a00848a \
--hash=sha256:429858a0452a7bedcf67bc7bb34383d00f666c980cb75a31bcd31285fbdd4403 \
--hash=sha256:436f62d27714970b9cdd3b3c41bdad046f260e62ebb0daa38125ef70536fc73b \
--hash=sha256:46e528ee71808c961baf8c3ce1c46a8337ec7a96cc55389d11baafe5b632f8e9 \
--hash=sha256:4728ed3ae372d1ea2cdbd5eaa27b8f20a10e415d1f9d153314831e67d963f281 \
--hash=sha256:536ea19ce6a2ce61c57fed4123ecd10d18d77a0db45cd2741afff2b8b68f15b3 \
--hash=sha256:5685a14b3099b1422c4f59fa38b0bf4b5342ee6cc38ae57df9666a0b28eeaad3 \
--hash=sha256:594f98491a96c7f1ffe13ce292cef1b4e63c028f0707effdea0f113364c1ae6c \
--hash=sha256:5bd39a4e1cc839a88acca2889d17ebc3f202a5039cd6059a13148ce75c8a6244 \
--hash=sha256:5e43891a37b0d7f618819fea14bd951289a0a8e3dd0da50c596139ca83ebb9b1 \
--hash=sha256:5e649f3dc8ab5476732094f2828cc90cac3be7c79bc0c8318b6fda0c1d248db4 \
--hash=sha256:5fe5a286f997848a410eebe1c28657506adaeb405220ee1e16cfcfd10deb37f2 \
--hash=sha256:638506eacf20ca503fff72221a7e66a6eadbf28d6a4a6f949fcf5b1701bb05ec \
--hash=sha256:6532615111eec2c79e711965ece0bc95adac1ff547a7fff5ffca525463116deb \
--hash=sha256:66b23e5b35dd547f85bf98db7c749bc0ffc57916ade2534a6bbc32db9a4abc44 \
--hash=sha256:6704adf0247d2dda42e876b793be40775dff46624309ad99bc7537098bee106d \
--hash=sha256:67f0c2ec82c20a02c16fc9ba81dee2586ef20270127c470cb1054767aa8ba310 \
--hash=sha256:6946100a43f933fad6bc458c502a59926d80b321d5ac1ed2ff9c56605360496f \
--hash=sha256:6c50c861faad0a5c091bd763e0729f958c316e678dfa065d3984fbb9e4eacbcd \
--hash=sha256:735c363d9aaac82eaf516a28f7c6b95084c2e176d8231c87328dc80e112a9afa \
--hash=sha256:746a7c60a17fccd3cfcfd4326926f02ea4fcdfc25d513411a0c4fc8e4a1ca51f \
--hash=sha256:7ac170d20b97beb75059ba65d1ccad6b434d777c8992ab41ffabdade3b06dd74 \
--hash=sha256:7cca7f96236ffdbf49be4b2e42c132e3df05968ac424544034767650913524de \
--hash=sha256:7e7b1786e852e014d03e5f32dbd991f9a9eb223dd3fa9a2564108b807e4b7e1c \
--hash=sha256:852d7bcf14b0c63404de26e7c4c8d5d65ecaeca935e93794331bc4e2f213660b \
--hash=sha256:875a6248e60fbb48d947b574ffa4170f34981f9e579bde960d0f9a49ea393ecc \
--hash=sha256:8951e7ce5d3167fbd085703b4cbb3f47948ed66826bef9a2173c379508776cf5 \
--hash=sha256:8cf4f25cf895692b232f49aa5397af6aba78bb679fb917a05fce8d3cb1ee446d \
--hash=sha256:952af3a5859c3b20b15a00748c36e9eb8316eb2c70bd353ae1646da216322908 \
--hash=sha256:98042040d1d6085792e8d0f74004fc0f5f9ca6091c298f593dd81a22a4643854 \
--hash=sha256:9c9b32b14651a6dcf9e8857d2df5d29d322a1ea8c0be5c8ffb88f9841c4ec62b \
--hash=sha256:9e956e6a46f604b17d570901e66f5214fb6f658c21e5e7665deace236793cef6 \
--hash=sha256:9f627f4e41be710b6cb6ed54b0128b229ac9d50e2054d9cde3af0fef277c23cf \
--hash=sha256:a2eb41d2f9114d8b7bd66772c237111e00d2bae2260824560eaa0a1e291ce9e8 \
--hash=sha256:a3c98613180cf1730e221933ff74b454008161b1a82597e41054127719964188 \
--hash=sha256:a4177dc0bd1374e82be9b2ba4d0c2733b0a85b9d154ceeea83a5bee8c1e62fbf \
--hash=sha256:a8443d116c612cfd1961fbf76769faf0561a46d8e317315dd13f9d9639ad500c \
--hash=sha256:aa7cd17e1c690ce96c538b2f4aae003d9a498e65067dd433c52dd069009951d4 \
--hash=sha256:ad548117744b2bcf0e3d97374608be0a92d18c2af13d98b728d37cd06248e571 \
--hash=sha256:aefe0973cc4698e0907289dc0517ab0c7cdb13d588201932ff567d08a50b0e2e \
--hash=sha256:b0ef26733d3c836be79e812071e1a431ce1f807955a27a981ebb7993d95f842b \
--hash=sha256:b1ce340da608530500ab4f963f12d6bfc8d8680900919a60dbdc9b78c02060a4 \
--hash=sha256:b1ec93f0d1ee6d7ab680a6d8ea1a08bf264636358e92692072170032dda652ba \
--hash=sha256:b2a7d00f53f4945320b551bccb826b3fb26948bde1a10d50bb9802fabb611b10 \
--hash=sha256:b2eacb84446543082ec50f2fb563f1a94c96804d4057b7da8ed815958d0cdfbe \
--hash=sha256:b5ea16e69bfda0ac028c921b58de1a4aaf83d43934892977368579cd3c0a2554 \
--hash=sha256:bd45142501300e7538b2e544905580918b67b1c82abed1275fe4c682c95635fa \
--hash=sha256:c0fe2ace0cb1806badbd1c551a8ec2f8d4cf97bf044313c082ef1acfe631ddca \
--hash=sha256:c484410911182457a8a1a0249d0c09c01e2071b78a0a8538cd5f7fa45589b13a \
--hash=sha256:ce37d8ca462bb64cc13f529b9ed92f7b21fe8d1f1679b62e29f9cb7d0e888b49 \
--hash=sha256:ce59bcd2cda9bb52b0e90cc7f36413cd86c3d0ce7224143447424aafb9f4aa48 \
--hash=sha256:d2a82eb21afdaf22b50d9b996472305c05ca67fc4ff5a026a220320c9c961db6 \
--hash=sha256:d5648c6dcc5dc9200297fb779b1663b8a4467bda034a3c69bd9c32d8afb33b1d \
--hash=sha256:d659fda873d8dcb2c14c2c331de1dee21f5a902d7f2de7978b62c6431a8850ef \
--hash=sha256:d7eb20bf0e8b55a58d2a9b518aabc4c18278787bdba476c551dd1c1ed109e509 \
--hash=sha256:da4e4facb79614cc4653cfd859f398e4db4ca9ab26270ff12610e50ed7f1f6c6 \
--hash=sha256:de1665eaafefa48a308e4753786519888021740501a15461c77bdfd57638e6b4 \
--hash=sha256:e2699255d7ac610dee26d4ae7bda5951d05c7d9123a22e1f7c6a6f1964e0a4e4 \
--hash=sha256:e58788004adda24c401d1751331618ed20c507ffc23bfd28d7c0661a1cf0ad16 \
--hash=sha256:e70869737cc0e5bd903f620667da6c330d6737048d1f44db792a6af68a1d35be \
--hash=sha256:eba6ca45500ca1a042466a0684aacc9838e7f20fe2605521ee19f2853062798f \
--hash=sha256:ed3fb4ed7f2084597e862bcd56c56c5529e773729a426c083238682dba540e98 \
--hash=sha256:f2806f75817392cedcacb24ac5d80b0350dde8d3861d67d045c1d9b109764114 \
--hash=sha256:f35c2603a6be168088ed1db6ad1704b078aa8f39974c60888fbbced95dcadad4 \
--hash=sha256:f4cd800704a5fc57e53c39c3a6b0c9b1519ebdbcb644ede3ee67a06eb542697d \
--hash=sha256:f713af9b8aa66a34cd3a78c7d150a560a75734713abe818a69021fd269e927fa
# via -r /tmp/requirementsmeh8aapn.in
meson==1.8.0 \
--hash=sha256:0a9b23311271519bd03dca12d7d8b0eab582c3a2c5da433d465b6e519dc88e2f \
--hash=sha256:472b7b25da286447333d32872b82d1c6f1a34024fb8ee017d7308056c25fec1f
# via meson-python
meson-python==0.17.1 \
--hash=sha256:30a75c52578ef14aff8392677b09c39346e0a24d2b2c6204b8ed30583c11269c \
--hash=sha256:efb91f69f2e19eef7bc9a471ed2a4e730088cc6b39eacaf3e49fc4f930eb5f83
# via -r /tmp/requirementsmeh8aapn.in
mypy==1.15.0 \
--hash=sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e \
--hash=sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22 \
--hash=sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f \
--hash=sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2 \
--hash=sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f \
--hash=sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b \
--hash=sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5 \
--hash=sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f \
--hash=sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43 \
--hash=sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e \
--hash=sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c \
--hash=sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828 \
--hash=sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba \
--hash=sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee \
--hash=sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d \
--hash=sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b \
--hash=sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445 \
--hash=sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e \
--hash=sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13 \
--hash=sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5 \
--hash=sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd \
--hash=sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf \
--hash=sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357 \
--hash=sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b \
--hash=sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036 \
--hash=sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559 \
--hash=sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3 \
--hash=sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f \
--hash=sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464 \
--hash=sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980 \
--hash=sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078 \
--hash=sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5
# via -r /tmp/requirementsmeh8aapn.in
mypy-extensions==1.1.0 \
--hash=sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505 \
--hash=sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558
# via mypy
numpy==2.2.5 \
--hash=sha256:0255732338c4fdd00996c0421884ea8a3651eea555c3a56b84892b66f696eb70 \
--hash=sha256:02f226baeefa68f7d579e213d0f3493496397d8f1cff5e2b222af274c86a552a \
--hash=sha256:059b51b658f4414fff78c6d7b1b4e18283ab5fa56d270ff212d5ba0c561846f4 \
--hash=sha256:0bcb1d057b7571334139129b7f941588f69ce7c4ed15a9d6162b2ea54ded700c \
--hash=sha256:0cd48122a6b7eab8f06404805b1bd5856200e3ed6f8a1b9a194f9d9054631beb \
--hash=sha256:19f4718c9012e3baea91a7dba661dcab2451cda2550678dc30d53acb91a7290f \
--hash=sha256:1a161c2c79ab30fe4501d5a2bbfe8b162490757cf90b7f05be8b80bc02f7bb8e \
--hash=sha256:1f4a922da1729f4c40932b2af4fe84909c7a6e167e6e99f71838ce3a29f3fe26 \
--hash=sha256:261a1ef047751bb02f29dfe337230b5882b54521ca121fc7f62668133cb119c9 \
--hash=sha256:262d23f383170f99cd9191a7c85b9a50970fe9069b2f8ab5d786eca8a675d60b \
--hash=sha256:2ba321813a00e508d5421104464510cc962a6f791aa2fca1c97b1e65027da80d \
--hash=sha256:2c1a1c6ccce4022383583a6ded7bbcda22fc635eb4eb1e0a053336425ed36dfa \
--hash=sha256:352d330048c055ea6db701130abc48a21bec690a8d38f8284e00fab256dc1376 \
--hash=sha256:369e0d4647c17c9363244f3468f2227d557a74b6781cb62ce57cf3ef5cc7c610 \
--hash=sha256:36ab5b23915887543441efd0417e6a3baa08634308894316f446027611b53bf1 \
--hash=sha256:37e32e985f03c06206582a7323ef926b4e78bdaa6915095ef08070471865b906 \
--hash=sha256:3a801fef99668f309b88640e28d261991bfad9617c27beda4a3aec4f217ea073 \
--hash=sha256:3d14b17b9be5f9c9301f43d2e2a4886a33b53f4e6fdf9ca2f4cc60aeeee76372 \
--hash=sha256:422cc684f17bc963da5f59a31530b3936f57c95a29743056ef7a7903a5dbdf88 \
--hash=sha256:4520caa3807c1ceb005d125a75e715567806fed67e315cea619d5ec6e75a4191 \
--hash=sha256:47834cde750d3c9f4e52c6ca28a7361859fcaf52695c7dc3cc1a720b8922683e \
--hash=sha256:47f9ed103af0bc63182609044b0490747e03bd20a67e391192dde119bf43d52f \
--hash=sha256:498815b96f67dc347e03b719ef49c772589fb74b8ee9ea2c37feae915ad6ebda \
--hash=sha256:54088a5a147ab71a8e7fdfd8c3601972751ded0739c6b696ad9cb0343e21ab73 \
--hash=sha256:55f09e00d4dccd76b179c0f18a44f041e5332fd0e022886ba1c0bbf3ea4a18d0 \
--hash=sha256:5a0ac90e46fdb5649ab6369d1ab6104bfe5854ab19b645bf5cda0127a13034ae \
--hash=sha256:6411f744f7f20081b1b4e7112e0f4c9c5b08f94b9f086e6f0adf3645f85d3a4d \
--hash=sha256:6413d48a9be53e183eb06495d8e3b006ef8f87c324af68241bbe7a39e8ff54c3 \
--hash=sha256:7451f92eddf8503c9b8aa4fe6aa7e87fd51a29c2cfc5f7dbd72efde6c65acf57 \
--hash=sha256:8b4c0773b6ada798f51f0f8e30c054d32304ccc6e9c5d93d46cb26f3d385ab19 \
--hash=sha256:8dfa94b6a4374e7851bbb6f35e6ded2120b752b063e6acdd3157e4d2bb922eba \
--hash=sha256:97c8425d4e26437e65e1d189d22dff4a079b747ff9c2788057bfb8114ce1e133 \
--hash=sha256:9d75f338f5f79ee23548b03d801d28a505198297534f62416391857ea0479571 \
--hash=sha256:9de6832228f617c9ef45d948ec1cd8949c482238d68b2477e6f642c33a7b0a54 \
--hash=sha256:a4cbdef3ddf777423060c6f81b5694bad2dc9675f110c4b2a60dc0181543fac7 \
--hash=sha256:a9c0d994680cd991b1cb772e8b297340085466a6fe964bc9d4e80f5e2f43c291 \
--hash=sha256:aa70fdbdc3b169d69e8c59e65c07a1c9351ceb438e627f0fdcd471015cd956be \
--hash=sha256:abe38cd8381245a7f49967a6010e77dbf3680bd3627c0fe4362dd693b404c7f8 \
--hash=sha256:b13f04968b46ad705f7c8a80122a42ae8f620536ea38cf4bdd374302926424dd \
--hash=sha256:b4ea7e1cff6784e58fe281ce7e7f05036b3e1c89c6f922a6bfbc0a7e8768adbe \
--hash=sha256:b6f91524d31b34f4a5fee24f5bc16dcd1491b668798b6d85585d836c1e633a6a \
--hash=sha256:c26843fd58f65da9491165072da2cccc372530681de481ef670dcc8e27cfb066 \
--hash=sha256:c42365005c7a6c42436a54d28c43fe0e01ca11eb2ac3cefe796c25a5f98e5e9b \
--hash=sha256:c8b82a55ef86a2d8e81b63da85e55f5537d2157165be1cb2ce7cfa57b6aef38b \
--hash=sha256:ced69262a8278547e63409b2653b372bf4baff0870c57efa76c5703fd6543282 \
--hash=sha256:d2e3bdadaba0e040d1e7ab39db73e0afe2c74ae277f5614dad53eadbecbbb169 \
--hash=sha256:d403c84991b5ad291d3809bace5e85f4bbf44a04bdc9a88ed2bb1807b3360bb8 \
--hash=sha256:d7543263084a85fbc09c704b515395398d31d6395518446237eac219eab9e55e \
--hash=sha256:d8882a829fd779f0f43998e931c466802a77ca1ee0fe25a3abe50278616b1471 \
--hash=sha256:e4f0b035d9d0ed519c813ee23e0a733db81ec37d2e9503afbb6e54ccfdee0fa7 \
--hash=sha256:e8b025c351b9f0e8b5436cf28a07fa4ac0204d67b38f01433ac7f9b870fa38c6 \
--hash=sha256:eb7fd5b184e5d277afa9ec0ad5e4eb562ecff541e7f60e69ee69c8d59e9aeaba \
--hash=sha256:ec31367fd6a255dc8de4772bd1658c3e926d8e860a0b6e922b615e532d320ddc \
--hash=sha256:ee461a4eaab4f165b68780a6a1af95fb23a29932be7569b9fab666c407969051 \
--hash=sha256:f5045039100ed58fa817a6227a356240ea1b9a1bc141018864c306c1a16d4175
# via -r /tmp/requirementsmeh8aapn.in
packaging==25.0 \
--hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \
--hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f
# via
# build
# meson-python
# pyproject-metadata
pip==25.1 \
--hash=sha256:13b4aa0aaad055020a11bec8a1c2a70a2b2d080e12d89b962266029fff0a16ba \
--hash=sha256:272bdd1289f80165e9070a4f881e8f9e1001bbb50378561d1af20e49bf5a2200
# via -r /tmp/requirementsmeh8aapn.in
pybind11==2.13.6 \
--hash=sha256:237c41e29157b962835d356b370ededd57594a26d5894a795960f0047cb5caf5 \
--hash=sha256:ba6af10348c12b24e92fa086b39cfba0eff619b61ac77c406167d813b096d39a
# via -r /tmp/requirementsmeh8aapn.in
pycparser==2.22 \
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
# via cffi
pydantic==2.11.4 \
--hash=sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d \
--hash=sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb
# via
# -r /tmp/requirementsmeh8aapn.in
# pydantic-settings
pydantic-core==2.33.2 \
--hash=sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d \
--hash=sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac \
--hash=sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02 \
--hash=sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56 \
--hash=sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4 \
--hash=sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22 \
--hash=sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef \
--hash=sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec \
--hash=sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d \
--hash=sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b \
--hash=sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a \
--hash=sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f \
--hash=sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052 \
--hash=sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab \
--hash=sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916 \
--hash=sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c \
--hash=sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf \
--hash=sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27 \
--hash=sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a \
--hash=sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8 \
--hash=sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7 \
--hash=sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612 \
--hash=sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1 \
--hash=sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039 \
--hash=sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca \
--hash=sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7 \
--hash=sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a \
--hash=sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6 \
--hash=sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782 \
--hash=sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b \
--hash=sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7 \
--hash=sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025 \
--hash=sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849 \
--hash=sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7 \
--hash=sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b \
--hash=sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa \
--hash=sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e \
--hash=sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea \
--hash=sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac \
--hash=sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51 \
--hash=sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e \
--hash=sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162 \
--hash=sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65 \
--hash=sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2 \
--hash=sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954 \
--hash=sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b \
--hash=sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de \
--hash=sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc \
--hash=sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64 \
--hash=sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb \
--hash=sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9 \
--hash=sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101 \
--hash=sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d \
--hash=sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef \
--hash=sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3 \
--hash=sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1 \
--hash=sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5 \
--hash=sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88 \
--hash=sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d \
--hash=sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290 \
--hash=sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e \
--hash=sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d \
--hash=sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808 \
--hash=sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc \
--hash=sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d \
--hash=sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc \
--hash=sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e \
--hash=sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640 \
--hash=sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30 \
--hash=sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e \
--hash=sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9 \
--hash=sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a \
--hash=sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9 \
--hash=sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f \
--hash=sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb \
--hash=sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5 \
--hash=sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab \
--hash=sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d \
--hash=sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572 \
--hash=sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593 \
--hash=sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29 \
--hash=sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535 \
--hash=sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1 \
--hash=sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f \
--hash=sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8 \
--hash=sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf \
--hash=sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246 \
--hash=sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9 \
--hash=sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011 \
--hash=sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9 \
--hash=sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a \
--hash=sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3 \
--hash=sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6 \
--hash=sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8 \
--hash=sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a \
--hash=sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2 \
--hash=sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c \
--hash=sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6 \
--hash=sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d
# via pydantic
pydantic-settings==2.9.1 \
--hash=sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef \
--hash=sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268
# via -r /tmp/requirementsmeh8aapn.in
pyproject-hooks==1.2.0 \
--hash=sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8 \
--hash=sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913
# via build
pyproject-metadata==0.9.1 \
--hash=sha256:b8b2253dd1b7062b78cf949a115f02ba7fa4114aabe63fa10528e9e1a954a816 \
--hash=sha256:ee5efde548c3ed9b75a354fc319d5afd25e9585fa918a34f62f904cc731973ad
# via meson-python
python-dotenv==1.1.0 \
--hash=sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5 \
--hash=sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d
# via pydantic-settings
setuptools==80.0.1 \
--hash=sha256:20fe373a22ef9f3925512650d1db90b1b8de01cdb6df91ab1788263139cbf9a2 \
--hash=sha256:f4b49d457765b3aae7cbbeb1c71f6633a61b729408c2d1a837dae064cca82ef2
# via
# -r /tmp/requirementsmeh8aapn.in
# marisa-trie
tomli==2.2.1 \
--hash=sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6 \
--hash=sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd \
--hash=sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c \
--hash=sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b \
--hash=sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8 \
--hash=sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6 \
--hash=sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77 \
--hash=sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff \
--hash=sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea \
--hash=sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192 \
--hash=sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249 \
--hash=sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee \
--hash=sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4 \
--hash=sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98 \
--hash=sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8 \
--hash=sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4 \
--hash=sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281 \
--hash=sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744 \
--hash=sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69 \
--hash=sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13 \
--hash=sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140 \
--hash=sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e \
--hash=sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e \
--hash=sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc \
--hash=sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff \
--hash=sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec \
--hash=sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2 \
--hash=sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222 \
--hash=sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106 \
--hash=sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272 \
--hash=sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a \
--hash=sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7
# via -r /tmp/requirementsmeh8aapn.in
typing-extensions==4.13.2 \
--hash=sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c \
--hash=sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef
# via
# mypy
# pydantic
# pydantic-core
# typing-inspection
typing-inspection==0.4.0 \
--hash=sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f \
--hash=sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122
# via
# pydantic
# pydantic-settings
uv==0.7.1 \
--hash=sha256:1d6f914601b769ad0f9a090573e2dc4365e0eaeb377d09cd74c5d47c97002c20 \
--hash=sha256:2220b942b2eb8a0c5cc91af5d57c2eef7a25053037f9f311e85a2d5dd9154f88 \
--hash=sha256:40a15f1fc73df852d7655530e5768e29dc7227ab25d9baeb711a8dde9e7f8234 \
--hash=sha256:425064544f1e20b014447cf523e04e891bf6962e60dd25f495724b271f8911e0 \
--hash=sha256:53eabd3aabc774d01da7836c58675c3e5cafd4285540e846debddfd056345d2c \
--hash=sha256:5526f68ce9a5ba35ef13a14d144dc834b4940bd460fedc55f8313f9b7534b63c \
--hash=sha256:57690b6e3b946dcf8b7b5836806d632f1a0d7667eae7af1302da812dbb7be7e5 \
--hash=sha256:6bbf096970de17be0c2a1e28f24ebddaad9ad4d0f8d8f75364149cdde75d7462 \
--hash=sha256:7025c9ba6f6f3d842a2b2915a579ff87eda901736105ee0379653bb4ff6b50d2 \
--hash=sha256:7239a0ffd4695300a3b6d2004ab664e80be7ef2c46b677b0f47d6409affe2212 \
--hash=sha256:877145523c348344c6fa2651559e9555dc4210730ad246afb4dd3414424afb3d \
--hash=sha256:9b503d808310a978453bb91a448ffaf61542b192127c30be136443debac9cdaa \
--hash=sha256:bf54fab715d6eb2332ff3276f80fddc6ee9e7faf29669d4bfb1918dd53ffc408 \
--hash=sha256:c5572a2b1d6dbf1cbff315e55931f891d8706ef5ed76e94a7d5e6e6dae075b3a \
--hash=sha256:c94cb14377c0efa65eb0267cfebfb5212729dc73fd61e4897e38839e3e72d763 \
--hash=sha256:d9c0c70bd3734cdae20cf22889a0394307a86451bb7c9126f0542eb998dd1472 \
--hash=sha256:ea2024e6a9daeea3ff6cab8ad4afe3b2aa0be9e07bad57646a749896e58648ad \
--hash=sha256:ef8765771785a56b2e5485f3c6f9ec04cbd2c077be2fe1f2786ded5710e33c0d
# via -r /tmp/requirementsmeh8aapn.in

BIN
releases/tar/dotfiles-0.1.tar.xz (Stored with Git LFS) Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More