Compare commits

..

315 Commits

Author SHA1 Message Date
epoberezkin a3a12f27f8 deploy: 5d8e11c3a2 2024-12-10 18:40:40 +00:00
epoberezkin c0dc9b8aee deploy: df8ce2b06d 2024-12-10 18:14:33 +00:00
epoberezkin c7a964c0c6 deploy: 6ff5f31bee 2024-12-10 17:17:54 +00:00
epoberezkin 48fbee2bff deploy: 93319d947d 2024-12-07 16:12:42 +00:00
epoberezkin fba8ca4df3 deploy: 586671c307 2024-12-05 21:51:58 +00:00
epoberezkin 732049e790 deploy: 4f1cf6e79f 2024-12-04 10:25:54 +00:00
epoberezkin 6c68d68347 deploy: b9777c92a5 2024-12-03 18:53:47 +00:00
epoberezkin 7ec02ab64a deploy: a182cf5730 2024-12-03 18:24:38 +00:00
epoberezkin 70985a26c4 deploy: a1e25620f7 2024-12-03 15:24:37 +00:00
epoberezkin ca9b2e514c deploy: 43fa4c43a2 2024-12-03 13:07:43 +00:00
epoberezkin 803f588fff deploy: 614846465f 2024-11-28 00:00:10 +00:00
epoberezkin 9a76f968c8 deploy: 97b472fd9c 2024-11-25 09:25:25 +00:00
epoberezkin 870958c387 deploy: 30a24df9c0 2024-11-23 14:38:55 +00:00
epoberezkin ad022a5bdd deploy: 4f640c96d1 2024-11-22 18:40:01 +00:00
epoberezkin 5cc1de7585 deploy: e45a96935c 2024-11-14 12:18:18 +00:00
epoberezkin dd24bc16c5 deploy: 8af54539f6 2024-11-12 10:38:38 +00:00
epoberezkin 56b566ec34 deploy: 3c8c9d8b52 2024-11-02 13:45:07 +00:00
epoberezkin 1f7d236309 deploy: 515a0ddfdd 2024-10-16 18:27:01 +00:00
epoberezkin 3d1d7eb44a deploy: b7131e16f2 2024-10-14 12:28:30 +00:00
epoberezkin 3ee8a7bed2 deploy: f8f5c3c6be 2024-10-14 08:38:53 +00:00
epoberezkin 307772015f deploy: 213f6cf372 2024-10-08 17:36:34 +00:00
epoberezkin 56fff8ff56 deploy: 49c91283d8 2024-10-05 18:57:34 +00:00
epoberezkin 27b127828c deploy: 55d180466a 2024-09-21 20:47:24 +00:00
epoberezkin 3d643299c5 deploy: 630fea42c3 2024-09-20 11:54:18 +00:00
epoberezkin b43a5e1548 deploy: ea320f531f 2024-09-16 16:15:34 +00:00
epoberezkin baa52a70f5 deploy: 2ab5f14119 2024-09-11 20:32:15 +00:00
epoberezkin d963370307 deploy: e00001b571 2024-09-08 22:03:05 +00:00
epoberezkin 6b770df1c8 deploy: f94f0dea08 2024-08-31 13:36:03 +00:00
epoberezkin dfcdd7e0b1 deploy: 7a5b04d523 2024-08-31 10:49:50 +00:00
epoberezkin 1f1f98f691 deploy: 41cb734d56 2024-08-30 20:33:11 +00:00
epoberezkin ea98986c5a deploy: edfcced1fa 2024-08-14 20:24:17 +00:00
epoberezkin 1a25104957 deploy: e9baeba31f 2024-08-14 13:11:38 +00:00
epoberezkin 84ad989b7a deploy: 53368713a0 2024-08-08 14:51:01 +00:00
epoberezkin 9231718490 deploy: 9ca7031f82 2024-08-05 08:37:58 +00:00
epoberezkin 66f51ea2b0 deploy: 2ee16f9398 2024-08-01 13:16:03 +00:00
epoberezkin d9837d172b deploy: 391e9d57f2 2024-07-16 20:32:34 +00:00
epoberezkin 04632351ef deploy: 23f24b1677 2024-07-12 19:37:11 +00:00
epoberezkin e72531f748 deploy: 1c10209a31 2024-07-04 20:15:18 +00:00
epoberezkin c03854df7f deploy: 4364aba34d 2024-07-04 19:30:55 +00:00
epoberezkin e7e2b47e1f deploy: 0509ff9a1b 2024-07-04 07:01:26 +00:00
epoberezkin 7e85398051 deploy: 6a273677f1 2024-07-03 21:52:34 +00:00
epoberezkin 136d9cba77 deploy: 231082860e 2024-07-01 08:35:50 +00:00
epoberezkin 3b8d16c5d0 deploy: c6366cb269 2024-06-29 15:54:45 +00:00
epoberezkin 56d8ffc0eb deploy: d8126e0cd0 2024-06-28 18:10:21 +00:00
epoberezkin 942f5ac850 deploy: fba0478e50 2024-06-25 07:39:08 +00:00
epoberezkin e458fe7924 deploy: 1af513c548 2024-06-23 19:37:35 +00:00
epoberezkin c444bc44eb deploy: d993381d31 2024-06-18 22:48:05 +00:00
epoberezkin b4f2d46b18 deploy: c4083e00c5 2024-06-16 21:33:30 +00:00
epoberezkin b90d7cddbc deploy: 7cd35b9068 2024-06-16 21:24:30 +00:00
epoberezkin 5c3cf40f7e deploy: d3274b28ba 2024-06-16 15:25:25 +00:00
epoberezkin 9d4830e128 deploy: 40bd5dc2da 2024-06-16 15:20:59 +00:00
epoberezkin e6b00f20ee deploy: a5bf3cbca8 2024-06-10 17:34:47 +00:00
epoberezkin ac5dfd9e66 deploy: 5695bb9d46 2024-06-08 14:43:22 +00:00
epoberezkin f4507a8173 deploy: cf2eb76cb7 2024-06-05 16:35:16 +00:00
epoberezkin 008b6b4b33 deploy: 48f9dcab9a 2024-06-04 19:05:02 +00:00
epoberezkin ae70ed9d8f deploy: ac2ef54838 2024-06-04 18:53:19 +00:00
epoberezkin 373fa12bc5 deploy: 4000fe383d 2024-06-03 19:38:47 +00:00
epoberezkin 263c88e50b deploy: dc8d08ec04 2024-06-02 18:45:13 +00:00
epoberezkin dce409bc75 deploy: d01515e755 2024-06-01 20:48:54 +00:00
epoberezkin ea81436643 deploy: 0110385e65 2024-05-29 09:00:52 +00:00
epoberezkin f36b3416ef deploy: 0495a4cd78 2024-05-28 21:27:50 +00:00
epoberezkin 381d331482 deploy: 0ae9f5ebba 2024-05-28 11:11:07 +00:00
epoberezkin 049df12172 deploy: 3e76a2d49c 2024-05-16 18:48:42 +00:00
epoberezkin 198fc8e860 deploy: 17a45b3f12ccee356aa7d4598f850b34a49e986b 2024-05-16 18:44:54 +00:00
epoberezkin dd6586fe9e deploy: ed3365bb6d 2024-05-16 17:17:36 +00:00
epoberezkin c27a8be2b2 deploy: 4575dc6e30 2024-05-12 17:20:33 +00:00
epoberezkin 18c62b7a25 deploy: 41597e563e 2024-05-10 17:26:23 +00:00
epoberezkin ad1f228e36 deploy: 10f41aa1c9 2024-05-08 08:32:15 +00:00
epoberezkin 9a8f323736 deploy: 9615e525c0 2024-05-06 07:37:19 +00:00
epoberezkin 69969244ac deploy: db136116d3 2024-05-06 07:32:47 +00:00
epoberezkin 164b5a9fb6 deploy: 9f33e5d35e 2024-05-05 18:01:23 +00:00
epoberezkin 23506b0c79 deploy: d832afa7e8 2024-05-05 15:57:46 +00:00
epoberezkin 15e1eb962e deploy: a28d965a65 2024-04-26 22:26:07 +00:00
epoberezkin a8fb2fa095 deploy: 9148425eba 2024-04-26 22:11:50 +00:00
epoberezkin d1519367fd deploy: 406c35958e 2024-04-26 22:01:57 +00:00
epoberezkin 564c34ad74 deploy: db05436e50 2024-04-25 10:01:09 +00:00
epoberezkin 4fce32cbf9 deploy: 5ba7b58d7d 2024-04-24 11:46:27 +00:00
epoberezkin 7ec6c9016e deploy: ab76e93df7 2024-04-23 19:04:23 +00:00
epoberezkin 5eebee802c deploy: f30287c4df 2024-04-23 18:38:03 +00:00
epoberezkin 9f959e0152 deploy: d864603d01 2024-04-22 23:15:19 +00:00
epoberezkin 10961ead33 deploy: 7c74f02d01 2024-04-22 17:35:22 +00:00
epoberezkin 621899b9f2 deploy: c8c81a840b 2024-04-19 20:18:36 +00:00
epoberezkin 9953bd1f22 deploy: 4eafdc3723 2024-04-16 19:36:36 +00:00
epoberezkin 4e60513f97 deploy: 35b7f2cb1c 2024-04-14 15:43:09 +00:00
epoberezkin be2f25bf3d deploy: b6fd5e61b6 2024-04-13 11:14:01 +00:00
epoberezkin f036409058 deploy: fe639eed48 2024-04-13 11:13:29 +00:00
epoberezkin 18d02fb3f9 deploy: 005d99ad50 2024-04-09 20:46:58 +00:00
epoberezkin 27c4ab5141 deploy: 36f86beafd 2024-04-09 19:33:15 +00:00
epoberezkin 650756922d deploy: 5f9710e4bb 2024-04-04 12:22:00 +00:00
epoberezkin 02276b6d7b deploy: 095d613f01 2024-03-28 12:31:37 +00:00
epoberezkin a416b650da deploy: 72082af139 2024-03-23 19:21:56 +00:00
epoberezkin e3c7bac980 deploy: 84fbff6148 2024-03-23 18:48:11 +00:00
epoberezkin 29e4769206 deploy: dd75d30c08 2024-03-23 18:30:17 +00:00
epoberezkin 313b6e107e deploy: 2546ad5351 2024-03-21 17:39:10 +00:00
epoberezkin a9c9053b7b deploy: e925d87548 2024-03-19 10:54:55 +00:00
epoberezkin f8dd98bf38 deploy: c2e2408394 2024-03-19 09:54:34 +00:00
epoberezkin 5e9a439997 deploy: 5a016378a8 2024-03-14 10:43:34 +00:00
epoberezkin 77b7fa5958 deploy: bac4e61997 2024-03-14 10:42:44 +00:00
epoberezkin c6ecf51ad1 deploy: 9ff11f886e 2024-03-07 15:41:28 +00:00
epoberezkin 0248e68ba4 deploy: 7213913d51 2024-02-24 21:29:27 +00:00
epoberezkin 193dc75303 deploy: 5807a0a2fa 2024-02-24 13:41:35 +00:00
epoberezkin 914a3a29a3 deploy: cd21a74b83 2024-02-18 00:07:12 +00:00
spaced4ndy 660ca30980 deploy: dfa9775d7e 2024-02-13 08:12:04 +00:00
epoberezkin b6d7a53b07 deploy: 91f10c056f 2024-02-11 16:27:36 +00:00
epoberezkin a491f2ffec deploy: c4cbb49f57 2024-01-27 16:52:34 +00:00
epoberezkin b649c5f42b deploy: 14d5078404 2024-01-24 19:55:56 +00:00
epoberezkin 5c032dab93 deploy: 4f602d4571 2024-01-23 23:23:10 +00:00
epoberezkin de3ee560f6 deploy: 5aa4b7687e 2024-01-20 13:49:50 +00:00
epoberezkin e06c7d43eb deploy: c130905efa 2024-01-17 19:33:03 +00:00
epoberezkin 8c54abcfbf deploy: afbb3b4e4b 2024-01-10 20:41:35 +00:00
epoberezkin 931cea2e1e deploy: c9b1d54f13 2023-12-30 22:05:14 +00:00
epoberezkin 62a449c35b deploy: d637714963 2023-12-28 17:53:30 +00:00
epoberezkin 14a74c54fd deploy: 700f6fa663 2023-12-24 11:14:42 +00:00
epoberezkin da125b88c1 deploy: 57a6e85668 2023-12-22 08:48:55 +00:00
epoberezkin 87578963bb deploy: ca6dfb5ea1 2023-12-12 10:26:19 +00:00
spaced4ndy 75ade2c427 deploy: 7099776357 2023-12-04 15:18:55 +00:00
epoberezkin 4f75e4cb41 deploy: fec5ff3f15 2023-12-03 22:22:23 +00:00
epoberezkin 9c107097cb deploy: 8cc0954430 2023-11-26 11:51:41 +00:00
epoberezkin daef119189 deploy: 1e6891e222 2023-11-25 18:28:49 +00:00
epoberezkin 42e59222af deploy: 962964a73d 2023-11-25 14:16:52 +00:00
epoberezkin dedfa0d372 deploy: 7f9a490edb 2023-11-24 14:22:17 +00:00
epoberezkin 82923f0e40 deploy: febf3e0a45 2023-11-21 19:39:09 +00:00
epoberezkin 5cabc08a38 deploy: 624a3abba2 2023-11-20 22:30:24 +00:00
epoberezkin 8748d38bac deploy: bf8457fb40 2023-11-19 11:15:13 +00:00
epoberezkin 7e25f666be deploy: 1e8ae6d861 2023-11-14 09:38:51 +00:00
epoberezkin fde920279d deploy: 9cc232054c 2023-11-10 17:58:37 +00:00
epoberezkin 5eb48e030d deploy: d233d07ddc 2023-11-08 12:51:57 +00:00
epoberezkin 2bffc1bbd6 deploy: 66d8bb94d6 2023-10-23 20:18:32 +00:00
epoberezkin 654d5b64c1 deploy: 6eb09625ab 2023-10-23 19:55:03 +00:00
epoberezkin fb37daff2f deploy: a35dc263b7 2023-10-13 21:30:52 +00:00
epoberezkin 7ead1a490d deploy: da2a94578a 2023-10-02 20:22:57 +00:00
epoberezkin f010300305 deploy: 8545a1e8f9 2023-10-01 19:48:04 +00:00
epoberezkin ffdeea1928 deploy: 50d624ef6b 2023-09-25 19:10:38 +00:00
epoberezkin 1f03cae08d deploy: 11e448267d 2023-09-25 17:14:35 +00:00
epoberezkin 8aff6dd39f deploy: 4f42c2b0d8 2023-09-25 08:34:09 +00:00
epoberezkin baf826e0cb deploy: 20f90ee865 2023-09-22 08:40:47 +00:00
epoberezkin 98a1166a35 deploy: be3eb740a7 2023-09-21 12:02:42 +00:00
epoberezkin db99e4fc10 deploy: 027ce2c559 2023-09-21 08:35:59 +00:00
epoberezkin f9d2bdcdfe deploy: 02864a894e 2023-09-21 08:30:29 +00:00
epoberezkin 13d6497d8a deploy: 0a2513c9e7 2023-09-20 16:55:22 +00:00
epoberezkin 622be4068b deploy: ba71a42aa0 2023-09-20 13:53:12 +00:00
epoberezkin c0f9f010fe deploy: 3cd279bd20 2023-09-18 15:24:25 +00:00
epoberezkin 38a4efb38b deploy: 603e745aa1 2023-09-18 12:46:37 +00:00
epoberezkin 9589451ebb deploy: 70fb10189b 2023-09-12 17:36:49 +00:00
epoberezkin 07839be874 deploy: c6dbbcc84e 2023-09-12 17:03:26 +00:00
epoberezkin 95409cf69e deploy: 181323ce13 2023-09-11 08:10:13 +00:00
epoberezkin 876d8af0cc deploy: a87aaa50c7 2023-09-10 10:23:33 +00:00
epoberezkin 863d4dceab deploy: 923a5e2984 2023-09-10 09:47:12 +00:00
epoberezkin a492315b99 deploy: 272b02b686 2023-09-10 09:46:40 +00:00
epoberezkin 3155843571 deploy: 45682aa7ce 2023-09-08 10:46:54 +00:00
epoberezkin 1a6c8840b8 deploy: a90641c1d1 2023-09-07 09:05:01 +00:00
epoberezkin 82974f052f deploy: 4d6283630a 2023-09-05 11:51:31 +00:00
epoberezkin e0f89ee1d4 deploy: 4aac3c7922 2023-08-28 21:25:10 +00:00
epoberezkin 62c7c43740 deploy: 10f8b8086e 2023-08-27 16:46:49 +00:00
epoberezkin eec817e8b5 deploy: 7fc108e6fa 2023-08-25 16:07:03 +00:00
epoberezkin f86cb6d9fb deploy: 538cdd16de 2023-08-21 18:11:24 +00:00
epoberezkin 3b448cb242 deploy: 41c68c82ac 2023-08-18 13:33:12 +00:00
epoberezkin 3ba122fb72 deploy: 45b7d09f83 2023-08-17 16:15:48 +00:00
epoberezkin 53e71ea97b deploy: 97a1a00f17 2023-08-10 20:16:39 +00:00
epoberezkin 44a5312d09 deploy: 631dfff5e9 2023-07-30 12:25:29 +00:00
epoberezkin de98110877 deploy: f69c842ba6 2023-07-29 13:22:10 +00:00
epoberezkin 02420e7642 deploy: 8fc3f5a0f7 2023-07-27 19:27:45 +00:00
epoberezkin 0570ea7575 deploy: 80bd734cc1 2023-07-22 19:09:33 +00:00
epoberezkin 323e7361c2 deploy: 576c886ba0 2023-07-20 17:18:43 +00:00
epoberezkin 81941e6a47 deploy: c2177f3684 2023-07-17 09:46:48 +00:00
epoberezkin f71966426a deploy: 90b616cd28 2023-07-14 12:10:56 +00:00
epoberezkin 384105a278 deploy: 842bbf26c6 2023-07-04 13:22:36 +00:00
epoberezkin 0a42db945b deploy: 324a6ba38e 2023-07-03 16:22:48 +00:00
epoberezkin 0c11fcfdc0 deploy: 4c33ed92bb 2023-07-01 05:48:09 +00:00
epoberezkin 474ca4894a deploy: a0ae4125c5 2023-06-30 10:13:12 +00:00
epoberezkin d91c983f14 deploy: 8abad4f711 2023-06-25 22:27:23 +00:00
epoberezkin 0236973fea deploy: 4c668f7a34 2023-06-25 15:08:07 +00:00
epoberezkin 25cd0ead8d deploy: 0bf5fbd641 2023-06-25 12:47:37 +00:00
epoberezkin b3eef9bfff deploy: cfec60bf86 2023-06-25 11:02:30 +00:00
epoberezkin 3f31588f45 deploy: 9caaab0e8e 2023-06-24 13:40:06 +00:00
epoberezkin 7678cdd798 deploy: d4f9429fc1 2023-06-11 09:41:04 +00:00
epoberezkin 30737e39bb deploy: 161b43e85d 2023-06-11 07:41:52 +00:00
epoberezkin 8ac8d1ab08 deploy: 925813b14c 2023-06-07 20:05:09 +00:00
epoberezkin 6564191f3a deploy: 0ee91b0280 2023-05-26 21:53:08 +00:00
epoberezkin a34df3376f deploy: d7d38fddb8 2023-05-23 15:01:58 +00:00
epoberezkin df0b6650dd deploy: 1d84c5cad8 2023-05-20 13:58:13 +00:00
epoberezkin 93ebc5aac5 deploy: 690c8ea2c9 2023-05-19 19:10:32 +00:00
epoberezkin 8640c51118 deploy: 3a50da1b53 2023-05-18 10:04:15 +00:00
epoberezkin c06ba4f5d0 deploy: 8b400d4f2c 2023-05-05 12:26:49 +00:00
epoberezkin cb903b6435 deploy: d838e7b44d 2023-05-05 12:23:37 +00:00
epoberezkin 4d34f34842 deploy: 02fdd058ec 2023-05-01 08:44:56 +00:00
epoberezkin 6f57dc4b02 deploy: fa6ba3110b 2023-05-01 06:39:41 +00:00
epoberezkin 173712a515 deploy: 6f82ddc032 2023-05-01 06:14:10 +00:00
epoberezkin 75ee9f878a deploy: 9fa93e40cb 2023-04-24 18:32:31 +00:00
epoberezkin 9a56777ffc deploy: f4b852d2dd 2023-04-24 17:55:34 +00:00
epoberezkin a72e37ca04 deploy: b9575cc869 2023-04-22 16:20:30 +00:00
epoberezkin 38d08c376f deploy: 8097593f5e 2023-04-21 12:43:21 +00:00
epoberezkin 4c6b458c34 deploy: 549ffcefc0 2023-04-20 18:57:44 +00:00
epoberezkin 004d9397e8 deploy: 80a68012a2 2023-04-20 10:57:25 +00:00
epoberezkin b2bf4721de deploy: b8d74b74a6 2023-04-18 17:53:18 +00:00
epoberezkin 146141b124 deploy: 834487e548 2023-04-14 13:08:08 +00:00
epoberezkin 1f3038b239 deploy: 06ad2b7972 2023-04-13 22:28:45 +00:00
epoberezkin 5be9d57d9a deploy: e1b6b54209 2023-04-08 20:03:22 +00:00
epoberezkin 7a80f907db deploy: a596bd9011 2023-04-01 13:38:42 +00:00
epoberezkin 4c45ac19f7 deploy: 1420084f5e 2023-03-31 21:59:36 +00:00
epoberezkin 044a40ac3c deploy: df1775a1e6 2023-03-31 18:15:20 +00:00
epoberezkin 6bc01406d3 deploy: 30ccea18ab 2023-03-31 18:13:51 +00:00
epoberezkin 35746bc9cf deploy: 4cd90d74ad 2023-03-31 16:14:59 +00:00
epoberezkin 1a144bbdae deploy: afa24722b2 2023-03-30 15:49:08 +00:00
epoberezkin 53d9c6736b deploy: ea5cec53bc 2023-03-30 15:44:56 +00:00
epoberezkin f5c55950fc deploy: a58b3a42db 2023-03-27 11:24:23 +00:00
epoberezkin 9efe742d3b deploy: e344958224 2023-03-27 11:23:57 +00:00
epoberezkin 28a897a2e8 deploy: 09c4609b6c 2023-03-25 17:32:33 +00:00
epoberezkin 69093c3204 deploy: a86725480f 2023-03-24 22:52:29 +00:00
epoberezkin 929907ea37 deploy: 63909defaf 2023-03-22 19:55:43 +00:00
epoberezkin 813514c65b deploy: 5282551f3d 2023-03-19 23:12:35 +00:00
epoberezkin 122172e14c deploy: dcadaaf29b 2023-03-19 23:10:27 +00:00
epoberezkin 322060b87e deploy: c986a4b88b 2023-03-18 17:20:58 +00:00
epoberezkin 62f183bb02 deploy: 09940ccf8d 2023-03-18 17:13:02 +00:00
epoberezkin f162b3c370 deploy: 13706c4f64 2023-03-12 23:44:54 +00:00
epoberezkin eaa3306fd2 deploy: f5670c39da 2023-03-06 22:26:35 +00:00
epoberezkin efe3dc12fa deploy: 01acbb970a 2023-03-01 20:03:39 +00:00
epoberezkin e0e61768d9 deploy: 36cad35d46 2023-03-01 19:30:30 +00:00
epoberezkin 0ca3696682 deploy: ae75be56ea 2023-02-25 17:54:06 +00:00
epoberezkin 9545830f69 deploy: cee8f3a4b6 2023-02-24 21:04:32 +00:00
epoberezkin 74deb4b90a deploy: 894af0602d 2023-02-08 14:04:25 +00:00
epoberezkin f7b96b3d11 deploy: c8fae0ec43 2023-02-05 23:47:17 +00:00
epoberezkin 7ae5e62d50 deploy: af173ee5c4 2023-02-05 13:54:12 +00:00
epoberezkin b1aa4c28cd deploy: 8a78943e94 2023-02-02 09:01:13 +00:00
epoberezkin e421323ad8 deploy: a96fb2f8d1 2023-01-27 12:07:54 +00:00
epoberezkin d9f6a54d7c deploy: abff42a264 2023-01-03 13:08:09 +00:00
epoberezkin bf87709b91 deploy: e14966d36e 2023-01-01 14:05:50 +00:00
epoberezkin 306e6ae366 deploy: 0535d84719 2022-12-11 15:41:56 +00:00
epoberezkin 0c0242d41a deploy: 05fdd07409 2022-12-07 10:28:21 +00:00
epoberezkin 9c3d11569a deploy: edf2d02a0d 2022-12-06 12:53:48 +00:00
epoberezkin 2ce8829793 deploy: c167f594b9 2022-12-05 11:28:56 +00:00
epoberezkin 825c699722 deploy: ce5124594d 2022-12-04 18:19:02 +00:00
epoberezkin 42bc54141c deploy: 6b71cc59c8 2022-11-22 08:50:19 +00:00
epoberezkin 0d6f903b67 deploy: 2742fc3ca9 2022-11-12 12:24:47 +00:00
epoberezkin 529d1d14e9 deploy: 7a78dfd3e3 2022-11-12 12:05:13 +00:00
epoberezkin 47b093730a deploy: 8d0ec01a9b 2022-11-12 09:49:41 +00:00
epoberezkin a6fe8b2597 deploy: 1caaca83cb 2022-11-11 14:27:31 +00:00
epoberezkin f26e5f962b deploy: 0b6b8bd327 2022-11-10 12:43:47 +00:00
epoberezkin 2398d1a28e deploy: 29f919b3d6 2022-11-09 20:46:20 +00:00
jr-simplex 96c7e23001 deploy: 941660625d 2022-11-09 11:33:23 +00:00
jr-simplex ac3c785998 deploy: 54ad071655 2022-11-09 06:25:52 +00:00
epoberezkin 028ac17ffe deploy: 992c934fd1 2022-11-08 20:42:51 +00:00
epoberezkin 4b76b8ffc5 deploy: a6c6f1dbff 2022-11-08 20:29:42 +00:00
epoberezkin d6063dc72c deploy: a652a14d58 2022-11-08 19:58:32 +00:00
epoberezkin 39645196af deploy: 9e77f05e58 2022-11-08 19:46:40 +00:00
epoberezkin ac39d4530a deploy: 355a3c429c 2022-11-08 18:41:50 +00:00
epoberezkin 4f6996e7d9 deploy: a1ce3b9c69 2022-11-08 17:55:22 +00:00
epoberezkin fd0864c9a2 deploy: 00af82cb19 2022-11-08 17:43:29 +00:00
epoberezkin 8f99391db7 deploy: 68b6d9e966 2022-11-08 17:20:48 +00:00
Evgeny Poberezkin 7368e3f888 Update CNAME 2022-11-08 17:18:26 +00:00
epoberezkin 3aa1373a8c deploy: 75165cc70a 2022-11-08 17:02:21 +00:00
epoberezkin 943e676607 deploy: e5a4cca5e0 2022-11-08 16:59:56 +00:00
epoberezkin ddb44eab9e deploy: 41f4f11155 2022-11-08 16:43:52 +00:00
epoberezkin 11cc0cdadc deploy: dd740e82cf 2022-11-08 15:24:11 +00:00
epoberezkin 849b4c4e94 deploy: 324730f8ae 2022-11-08 13:20:10 +00:00
epoberezkin 227fbc6a4e deploy: ed1faff500 2022-11-08 13:02:46 +00:00
epoberezkin ab724cc73e deploy: 75dccf95c4 2022-11-08 11:46:02 +00:00
epoberezkin ade8ec09a8 deploy: fa5a70cd19 2022-11-08 11:04:39 +00:00
Evgeny Poberezkin 55214e8828 Update CNAME 2022-11-08 11:04:22 +00:00
Evgeny Poberezkin 9c1e3ad3b8 Update CNAME 2022-11-08 10:42:11 +00:00
Evgeny Poberezkin 1d347a4722 Update CNAME 2022-11-08 10:40:00 +00:00
epoberezkin 6fe457bb2b deploy: dd9e94eefd 2022-11-08 10:29:17 +00:00
epoberezkin d410eacce7 deploy: eb0f78bd80 2022-11-06 15:28:37 +00:00
epoberezkin 9f650e2ebd deploy: 1e10b0a49c 2022-10-24 20:55:59 +00:00
epoberezkin 9c9101b864 deploy: 91460932fe 2022-10-12 16:16:38 +00:00
epoberezkin 757ce631f2 deploy: f70a203f0e 2022-10-12 16:12:29 +00:00
epoberezkin 860dc86ad6 deploy: 6730a687e2 2022-09-28 08:24:06 +00:00
jr-simplex 6b33b83bc5 deploy: 937492c204 2022-09-27 10:47:11 +00:00
epoberezkin 6a47e020e9 deploy: bce8af16de 2022-09-25 10:17:06 +00:00
epoberezkin 9586f5d028 deploy: a26f2a58d1 2022-09-10 09:42:40 +00:00
MSarmadQadeer 06fc614139 deploy: 3835ffa599 2022-09-09 13:27:41 +00:00
epoberezkin 1c008f6ff5 deploy: 3c406c3e63 2022-09-08 10:40:02 +00:00
epoberezkin 7f2560c49e deploy: 89782639c2 2022-09-08 10:34:37 +00:00
Evgeny Poberezkin c73e57715f Create CNAME 2022-09-08 10:40:02 +01:00
MSarmadQadeer ec8b2be6bd deploy: 6494ead667 2022-09-06 17:55:26 +00:00
Evgeny Poberezkin bde5547023 Create CNAME 2022-09-06 16:53:42 +01:00
MSarmadQadeer 3b840beae4 deploy: 82e1e3b52b46d4ab7175614a6b2fe386e5f82c41 2022-09-06 14:28:39 +00:00
MSarmadQadeer bc6b600204 deploy: 9ca82683ab 2022-09-06 14:18:38 +00:00
Evgeny Poberezkin 7737a8d65f Create CNAME 2022-09-05 16:11:08 +01:00
epoberezkin 019cef8bac deploy: 8b35825b00 2022-09-05 15:08:44 +00:00
epoberezkin 5f38b2895b deploy: 4b87f0121c 2022-09-05 14:59:51 +00:00
epoberezkin 342d0e5c10 deploy: 2c198bb25c 2022-09-05 14:56:23 +00:00
MSarmadQadeer 2a32b3727f deploy: 1811c7a83e 2022-09-05 08:25:57 +00:00
MSarmadQadeer 3092049615 deploy: f03cf09b9a 2022-09-04 13:25:21 +00:00
MSarmadQadeer 43db91b794 deploy: 0093c57e44 2022-09-04 08:36:35 +00:00
MSarmadQadeer 1e67e4f30e deploy: 6743948fc8 2022-09-04 08:25:46 +00:00
epoberezkin f94861e30c deploy: 889bc57c0e 2022-08-28 15:19:41 +00:00
epoberezkin d5ba5169f0 deploy: 39d8489fb2 2022-08-28 15:16:38 +00:00
epoberezkin 98a449ff9f deploy: 225af5f5fb 2022-08-28 15:05:25 +00:00
epoberezkin c7bbf76a2d deploy: 8bf6b616de217017a162a9fa7fd74deec3947db0 2022-08-28 14:07:36 +00:00
MSarmadQadeer 4e02abb1da deploy: 428d6ca1df 2022-08-22 10:52:17 +00:00
MSarmadQadeer 682f512271 deploy: da5012d6ac 2022-08-22 10:21:23 +00:00
MSarmadQadeer 46abad9a99 deploy: d6e4795c45 2022-08-22 09:20:18 +00:00
MSarmadQadeer 34afd6f43a deploy: 852cea9d67 2022-08-19 20:29:08 +00:00
MSarmadQadeer e1bc1c1fed deploy: f108f1ef49 2022-08-19 17:39:39 +00:00
MSarmadQadeer 9e3b82294b deploy: 19c9a9968f142905e37e289d3c69bb1bfa53ff00 2022-08-19 17:37:26 +00:00
MSarmadQadeer 970c833385 deploy: f108f1ef49 2022-08-19 17:31:11 +00:00
MSarmadQadeer 036dea907d deploy: 1c22af4846 2022-08-18 13:06:42 +00:00
MSarmadQadeer 6a99bd9112 deploy: 94223792d5 2022-08-18 08:13:24 +00:00
MSarmadQadeer d34be00373 deploy: b032b3eacd 2022-08-15 09:25:04 +00:00
MSarmadQadeer 276af45489 deploy: 5c6906e340 2022-08-08 12:36:53 +00:00
MSarmadQadeer 3d019a2389 deploy: c7c003cea3 2022-08-08 12:16:08 +00:00
MSarmadQadeer ec13380bdd deploy: a944ab1f38 2022-08-08 11:51:41 +00:00
MSarmadQadeer c9c9d03194 deploy: c6c1005f45 2022-08-08 09:59:29 +00:00
MSarmadQadeer bd1539da23 deploy: bf10f9d093 2022-08-08 09:40:44 +00:00
MSarmadQadeer f75a6fa63f deploy: 6bd90cbb45 2022-08-08 08:41:31 +00:00
MSarmadQadeer ed5ea8f8d9 deploy: 14f2a1d227 2022-08-08 08:39:52 +00:00
MSarmadQadeer 6b447153d7 deploy: 7e103fe580 2022-07-31 10:28:07 +00:00
MSarmadQadeer 617c53ff40 deploy: a3fb741cff 2022-07-31 10:24:51 +00:00
MSarmadQadeer 667a376efb deploy: ddc7954d02 2022-07-31 10:14:19 +00:00
MSarmadQadeer f506d56e69 deploy: 6e4f755d36 2022-07-31 10:04:50 +00:00
MSarmadQadeer bc0c38ed4c deploy: 4e09eae4a2 2022-07-31 09:53:18 +00:00
MSarmadQadeer db43839d61 deploy: 04a98e603c 2022-07-31 09:44:07 +00:00
MSarmadQadeer f715b01279 deploy: 333883603c 2022-07-28 16:35:16 +00:00
MSarmadQadeer eadc319a18 deploy: 43d87c6f8aea8544b29129deb1ee6f2cd02a0859 2022-07-28 09:27:17 +00:00
668 changed files with 197299 additions and 912 deletions
View File
+17
View File
@@ -0,0 +1,17 @@
# .well-known
This website files allow opening SimpleX Chat links (1-time invitations, contact addresses and groups) directly in the app.
## Android
File `assetlinks.json` includes certificate hashes for:
- Play Store (5E:3E:DC:C2:00:FB:A8:D5:F4:88:F3:CA:4C:32:5B:05:78:C5:6A:9C:03:A1:CC:B5:92:9C:D7:5C:7E:57:E2:4D)
- APK in GitHub releases (3C:52:C4:FD:3C:AD:1C:07:C9:B0:0A:70:80:E3:58:FA:B9:FE:FC:B8:AF:5A:EC:14:77:65:F1:6D:0F:21:AD:85)
- F-Droid (AE:C1:95:DC:FD:46:14:BD:3A:91:EC:26:D1:D5:14:C8:75:71:C5:CC:8D:CF:48:08:3F:92:83:14:3C:A2:B9:A6)
## iOS
`apple-app-site-association` needs to be served with `Content-type: application/json; charset=utf-8` and GitHub pages do not support adding this header to files without JSON extension.
To workaround this (thanks to [StackOverflow - Serve json data from github pages](https://stackoverflow.com/questions/39199042/serve-json-data-from-github-pages)) we're creating directory named `apple-app-site-association` with `index.json` file that contains all the necessary configs.
+12
View File
@@ -0,0 +1,12 @@
<h1 id="well-known" tabindex="-1">.well-known</h1>
<p>This website files allow opening SimpleX Chat links (1-time invitations, contact addresses and groups) directly in the app.</p>
<h2 id="android" tabindex="-1">Android</h2>
<p>File <code>assetlinks.json</code> includes certificate hashes for:</p>
<ul>
<li>Play Store (5E:3E:DC:C2:00:FB:A8:D5:F4:88:F3:CA:4C:32:5B:05:78:C5:6A:9C:03:A1:CC:B5:92:9C:D7:5C:7E:57:E2:4D)</li>
<li>APK in GitHub releases (3C:52:C4:FD:3C:AD:1C:07:C9:B0:0A:70:80:E3:58:FA:B9:FE:FC:B8:AF:5A:EC:14:77:65:F1:6D:0F:21:AD:85)</li>
<li>F-Droid (AE:C1:95:DC:FD:46:14:BD:3A:91:EC:26:D1:D5:14:C8:75:71:C5:CC:8D:CF:48:08:3F:92:83:14:3C:A2:B9:A6)</li>
</ul>
<h2 id="ios" tabindex="-1">iOS</h2>
<p><code>apple-app-site-association</code> needs to be served with <code>Content-type: application/json; charset=utf-8</code> and GitHub pages do not support adding this header to files without JSON extension.</p>
<p>To workaround this (thanks to <a href="https://stackoverflow.com/questions/39199042/serve-json-data-from-github-pages">StackOverflow - Serve json data from github pages</a>) we're creating directory named <code>apple-app-site-association</code> with <code>index.json</code> file that contains all the necessary configs.</p>
@@ -0,0 +1,25 @@
{
"applinks": {
"details": [
{
"appIDs": [
"5NN7GUYB6T.chat.simplex.app"
],
"components": [
{
"/": "/contact/*"
},
{
"/": "/contact"
},
{
"/": "/invitation/*"
},
{
"/": "/invitation"
}
]
}
]
}
}
+16
View File
@@ -0,0 +1,16 @@
[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "chat.simplex.app",
"sha256_cert_fingerprints": [
"5E:3E:DC:C2:00:FB:A8:D5:F4:88:F3:CA:4C:32:5B:05:78:C5:6A:9C:03:A1:CC:B5:92:9C:D7:5C:7E:57:E2:4D",
"3C:52:C4:FD:3C:AD:1C:07:C9:B0:0A:70:80:E3:58:FA:B9:FE:FC:B8:AF:5A:EC:14:77:65:F1:6D:0F:21:AD:85",
"AE:C1:95:DC:FD:46:14:BD:3A:91:EC:26:D1:D5:14:C8:75:71:C5:CC:8D:CF:48:08:3F:92:83:14:3C:A2:B9:A6"
]
}
}
]
+18
View File
@@ -0,0 +1,18 @@
{
"names": {
"_": "c998a5739f04f7fff202c54962aa5782b34ecb10d6f915bdfdd7582963bf9171"
},
"relays": {
"c998a5739f04f7fff202c54962aa5782b34ecb10d6f915bdfdd7582963bf9171": [
"wss://nostr.orangepill.dev",
"wss://eden.nostr.land",
"wss://relay.damus.io",
"wss://relay.snort.social",
"wss://relay.current.fyi",
"wss://nos.lol",
"wss://relay.nostr.bg",
"wss://nostr-verified.wellorder.net",
"wss://nostr.milou.lol"
]
}
}
+1
View File
@@ -0,0 +1 @@
ae8b5b2e-76c9-4a31-a044-bcbda1cdf264
+1
View File
@@ -0,0 +1 @@
simplex.chat
-79
View File
@@ -1,79 +0,0 @@
{-# LANGUAGE LambdaCase #-}
module ChatOptions (getChatOpts, ChatOpts (..)) where
import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Options.Applicative
import Simplex.Messaging.Agent.Transmission (SMPServer (..), smpServerP)
import System.FilePath (combine)
import System.Info (os)
import Types
data ChatOpts = ChatOpts
{ name :: Maybe ByteString,
dbFileName :: String,
smpServer :: SMPServer,
termMode :: TermMode
}
chatOpts :: FilePath -> Parser ChatOpts
chatOpts appDir =
ChatOpts
<$> option
(Just <$> str)
( long "name"
<> short 'n'
<> metavar "NAME"
<> help "optional name to use for invitations"
<> value Nothing
)
<*> strOption
( long "database"
<> short 'd'
<> metavar "DB_FILE"
<> help ("sqlite database file path (" <> defaultDbFilePath <> ")")
<> value defaultDbFilePath
)
<*> option
parseSMPServer
( long "server"
<> short 's'
<> metavar "SERVER"
<> help "SMP server to use (smp.simplex.im:5223)"
<> value (SMPServer "smp.simplex.im" (Just "5223") Nothing)
)
<*> option
parseTermMode
( long "term"
<> short 't'
<> metavar "TERM"
<> help ("terminal mode: editor or basic (" <> termModeName deafultTermMode <> ")")
<> value deafultTermMode
)
where
defaultDbFilePath = combine appDir "smp-chat.db"
deafultTermMode
| os == "mingw32" = TermModeBasic
| otherwise = TermModeEditor
parseSMPServer :: ReadM SMPServer
parseSMPServer = eitherReader $ A.parseOnly (smpServerP <* A.endOfInput) . B.pack
parseTermMode :: ReadM TermMode
parseTermMode = maybeReader $ \case
"basic" -> Just TermModeBasic
"editor" -> Just TermModeEditor
_ -> Nothing
getChatOpts :: FilePath -> IO ChatOpts
getChatOpts appDir = execParser opts
where
opts =
info
(chatOpts appDir <**> helper)
( fullDesc
<> header "Chat prototype using Simplex Messaging Protocol (SMP)"
<> progDesc "Start chat with DB_FILE file and use SERVER as SMP server"
)
-105
View File
@@ -1,105 +0,0 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
module ChatTerminal
( ChatTerminal (..),
newChatTerminal,
chatTerminal,
updateUsername,
ttyContact,
ttyFromContact,
)
where
import ChatTerminal.Basic (getLn, putLn)
import ChatTerminal.Core
import ChatTerminal.POSIX
import Control.Concurrent (threadDelay)
import Control.Concurrent.Async (race_)
import Control.Concurrent.STM
import Control.Monad
import Data.Maybe (fromMaybe)
import Numeric.Natural
import Styled
import qualified System.Console.ANSI as C
import Types
newChatTerminal :: Natural -> Maybe Contact -> TermMode -> IO ChatTerminal
newChatTerminal qSize user termMode = do
inputQ <- newTBQueueIO qSize
outputQ <- newTBQueueIO qSize
activeContact <- newTVarIO Nothing
username <- newTVarIO user
termSize <- fromMaybe (0, 0) <$> C.getTerminalSize
let lastRow = fst termSize - 1
termState <- newTVarIO $ newTermState user
termLock <- newTMVarIO ()
nextMessageRow <- newTVarIO lastRow
threadDelay 500000 -- this delay is the same as timeout in getTerminalSize
return ChatTerminal {inputQ, outputQ, activeContact, username, termMode, termState, termSize, nextMessageRow, termLock}
newTermState :: Maybe Contact -> TerminalState
newTermState user =
TerminalState
{ inputString = "",
inputPosition = 0,
inputPrompt = promptString user
}
chatTerminal :: ChatTerminal -> IO ()
chatTerminal ct
| termSize ct == (0, 0) || termMode ct == TermModeBasic =
run basicReceiveFromTTY basicSendToTTY
| otherwise = do
initTTY
updateInput ct
run receiveFromTTY sendToTTY
where
run receive send = race_ (receive ct) (send ct)
basicReceiveFromTTY :: ChatTerminal -> IO ()
basicReceiveFromTTY ct =
forever $ getLn >>= atomically . writeTBQueue (inputQ ct)
basicSendToTTY :: ChatTerminal -> IO ()
basicSendToTTY ct = forever $ readOutputQ ct >>= putLn
withTermLock :: ChatTerminal -> IO () -> IO ()
withTermLock ChatTerminal {termLock} action = do
_ <- atomically $ takeTMVar termLock
action
atomically $ putTMVar termLock ()
receiveFromTTY :: ChatTerminal -> IO ()
receiveFromTTY ct@ChatTerminal {inputQ, activeContact, termSize, termState} =
forever $
getKey >>= processKey >> withTermLock ct (updateInput ct)
where
processKey :: Key -> IO ()
processKey = \case
KeyEnter -> submitInput
key -> atomically $ do
ac <- readTVar activeContact
modifyTVar termState $ updateTermState ac (snd termSize) key
submitInput :: IO ()
submitInput = do
msg <- atomically $ do
ts <- readTVar termState
writeTVar termState $ ts {inputString = "", inputPosition = 0}
let s = inputString ts
writeTBQueue inputQ s
return s
withTermLock ct . printMessage ct $ styleMessage msg
sendToTTY :: ChatTerminal -> IO ()
sendToTTY ct = forever $ do
msg <- readOutputQ ct
withTermLock ct $ do
printMessage ct msg
updateInput ct
readOutputQ :: ChatTerminal -> IO StyledString
readOutputQ = atomically . readTBQueue . outputQ
-81
View File
@@ -1,81 +0,0 @@
{-# LANGUAGE LambdaCase #-}
module ChatTerminal.Basic where
import Control.Monad.IO.Class (liftIO)
import Styled
import System.Console.ANSI.Types
import System.Exit (exitSuccess)
import System.Terminal as C
getLn :: IO String
getLn = withTerminal $ runTerminalT getTermLine
putLn :: StyledString -> IO ()
putLn s =
withTerminal . runTerminalT $
putStyled s >> C.putLn >> flush
putStyled :: MonadTerminal m => StyledString -> m ()
putStyled (s1 :<>: s2) = putStyled s1 >> putStyled s2
putStyled (Styled [] s) = putString s
putStyled (Styled sgr s) = setSGR sgr >> putString s >> resetAttributes
setSGR :: MonadTerminal m => [SGR] -> m ()
setSGR = mapM_ $ \case
Reset -> resetAttributes
SetConsoleIntensity BoldIntensity -> setAttribute bold
SetConsoleIntensity _ -> resetAttribute bold
SetItalicized True -> setAttribute italic
SetItalicized _ -> resetAttribute italic
SetUnderlining NoUnderline -> resetAttribute underlined
SetUnderlining _ -> setAttribute underlined
SetSwapForegroundBackground True -> setAttribute inverted
SetSwapForegroundBackground _ -> resetAttribute inverted
SetColor l i c -> setAttribute . layer l . intensity i $ color c
SetBlinkSpeed _ -> pure ()
SetVisible _ -> pure ()
SetRGBColor _ _ -> pure ()
SetPaletteColor _ _ -> pure ()
SetDefaultColor _ -> pure ()
where
layer = \case
Foreground -> foreground
Background -> background
intensity = \case
Dull -> id
Vivid -> bright
color = \case
Black -> black
Red -> red
Green -> green
Yellow -> yellow
Blue -> blue
Magenta -> magenta
Cyan -> cyan
White -> white
getTermLine :: MonadTerminal m => m String
getTermLine = getChars ""
where
getChars s = awaitEvent >>= processKey s
processKey s = \case
Right (KeyEvent key ms) -> case key of
CharKey c
| ms == mempty || ms == shiftKey -> do
C.putChar c
flush
getChars (c : s)
| otherwise -> getChars s
EnterKey -> do
C.putLn
flush
pure $ reverse s
BackspaceKey -> do
moveCursorBackward 1
eraseChars 1
flush
getChars $ if null s then s else tail s
_ -> getChars s
Left Interrupt -> liftIO exitSuccess
_ -> getChars s
-130
View File
@@ -1,130 +0,0 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module ChatTerminal.Core where
import Control.Concurrent.STM
import qualified Data.ByteString.Char8 as B
import Data.List (dropWhileEnd)
import qualified Data.Text as T
import SimplexMarkdown
import Styled
import System.Console.ANSI.Types
import Types
data ChatTerminal = ChatTerminal
{ inputQ :: TBQueue String,
outputQ :: TBQueue StyledString,
activeContact :: TVar (Maybe Contact),
username :: TVar (Maybe Contact),
termMode :: TermMode,
termState :: TVar TerminalState,
termSize :: (Int, Int),
nextMessageRow :: TVar Int,
termLock :: TMVar ()
}
data TerminalState = TerminalState
{ inputPrompt :: String,
inputString :: String,
inputPosition :: Int
}
data Key
= KeyLeft
| KeyRight
| KeyUp
| KeyDown
| KeyAltLeft
| KeyAltRight
| KeyCtrlLeft
| KeyCtrlRight
| KeyShiftLeft
| KeyShiftRight
| KeyEnter
| KeyBack
| KeyTab
| KeyEsc
| KeyChars String
| KeyUnsupported
deriving (Eq)
inputHeight :: TerminalState -> ChatTerminal -> Int
inputHeight ts ct = length (inputPrompt ts <> inputString ts) `div` snd (termSize ct) + 1
updateTermState :: Maybe Contact -> Int -> Key -> TerminalState -> TerminalState
updateTermState ac tw key ts@TerminalState {inputString = s, inputPosition = p} = case key of
KeyChars cs -> insertCharsWithContact cs
KeyTab -> insertChars " "
KeyBack -> backDeleteChar
KeyLeft -> setPosition $ max 0 (p - 1)
KeyRight -> setPosition $ min (length s) (p + 1)
KeyUp -> setPosition $ let p' = p - tw in if p' > 0 then p' else p
KeyDown -> setPosition $ let p' = p + tw in if p' <= length s then p' else p
KeyAltLeft -> setPosition prevWordPos
KeyAltRight -> setPosition nextWordPos
KeyCtrlLeft -> setPosition prevWordPos
KeyCtrlRight -> setPosition nextWordPos
KeyShiftLeft -> setPosition 0
KeyShiftRight -> setPosition $ length s
_ -> ts
where
insertCharsWithContact cs
| null s && cs /= "@" && cs /= "/" =
insertChars $ contactPrefix <> cs
| otherwise = insertChars cs
insertChars = ts' . if p >= length s then append else insert
append cs = let s' = s <> cs in (s', length s')
insert cs = let (b, a) = splitAt p s in (b <> cs <> a, p + length cs)
contactPrefix = case ac of
Just (Contact c) -> "@" <> B.unpack c <> " "
Nothing -> ""
backDeleteChar
| p == 0 || null s = ts
| p >= length s = ts' backDeleteLast
| otherwise = ts' backDelete
backDeleteLast = if null s then (s, 0) else let s' = init s in (s', length s')
backDelete = let (b, a) = splitAt p s in (init b <> a, p - 1)
setPosition p' = ts' (s, p')
prevWordPos
| p == 0 || null s = p
| otherwise =
let before = take p s
beforeWord = dropWhileEnd (/= ' ') $ dropWhileEnd (== ' ') before
in max 0 $ p - length before + length beforeWord
nextWordPos
| p >= length s || null s = p
| otherwise =
let after = drop p s
afterWord = dropWhile (/= ' ') $ dropWhile (== ' ') after
in min (length s) $ p + length after - length afterWord
ts' (s', p') = ts {inputString = s', inputPosition = p'}
styleMessage :: String -> StyledString
styleMessage = \case
"" -> ""
s@('@' : _) -> let (c, rest) = span (/= ' ') s in Styled selfSGR c <> markdown rest
s -> markdown s
where
markdown :: String -> StyledString
markdown = styleMarkdown . parseMarkdown . T.pack
updateUsername :: ChatTerminal -> Maybe Contact -> STM ()
updateUsername ct a = do
writeTVar (username ct) a
modifyTVar (termState ct) $ \ts -> ts {inputPrompt = promptString a}
promptString :: Maybe Contact -> String
promptString a = maybe "" (B.unpack . toBs) a <> "> "
ttyContact :: Contact -> StyledString
ttyContact (Contact a) = Styled contactSGR $ B.unpack a
ttyFromContact :: Contact -> StyledString
ttyFromContact (Contact a) = Styled contactSGR $ B.unpack a <> ">"
contactSGR :: [SGR]
contactSGR = [SetColor Foreground Vivid Yellow]
selfSGR :: [SGR]
selfSGR = [SetColor Foreground Vivid Cyan]
-102
View File
@@ -1,102 +0,0 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
module ChatTerminal.POSIX where
import ChatTerminal.Core
import Control.Concurrent.STM
import Styled
import qualified System.Console.ANSI as C
import System.IO
initTTY :: IO ()
initTTY = do
hSetEcho stdin False
hSetBuffering stdin NoBuffering
hSetBuffering stdout NoBuffering
updateInput :: ChatTerminal -> IO ()
updateInput ct@ChatTerminal {termSize, termState, nextMessageRow} = do
C.hideCursor
ts <- readTVarIO termState
nmr <- readTVarIO nextMessageRow
let (th, tw) = termSize
ih = inputHeight ts ct
iStart = th - ih
prompt = inputPrompt ts
(cRow, cCol) = relativeCursorPosition tw $ length prompt + inputPosition ts
if nmr >= iStart
then atomically $ writeTVar nextMessageRow iStart
else clearLines nmr iStart
C.setCursorPosition (max nmr iStart) 0
putStr $ prompt <> inputString ts <> " "
C.clearFromCursorToLineEnd
C.setCursorPosition (iStart + cRow) cCol
C.showCursor
where
clearLines :: Int -> Int -> IO ()
clearLines from till
| from >= till = return ()
| otherwise = do
C.setCursorPosition from 0
C.clearFromCursorToLineEnd
clearLines (from + 1) till
relativeCursorPosition :: Int -> Int -> (Int, Int)
relativeCursorPosition width pos =
let row = pos `div` width
col = pos - row * width
in (row, col)
printMessage :: ChatTerminal -> StyledString -> IO ()
printMessage ChatTerminal {termSize, nextMessageRow} msg = do
nmr <- readTVarIO nextMessageRow
C.setCursorPosition nmr 0
let (th, tw) = termSize
lc <- printLines tw msg
atomically . writeTVar nextMessageRow $ min (th - 1) (nmr + lc)
where
printLines :: Int -> StyledString -> IO Int
printLines tw ss = do
let s = styledToANSITerm ss
ls
| null s = [""]
| otherwise = lines s <> ["" | last s == '\n']
print_ ls
return $ foldl (\lc l -> lc + (length l `div` tw) + 1) 0 ls
print_ :: [String] -> IO ()
print_ [] = return ()
print_ (l : ls) = do
putStr l
C.clearFromCursorToLineEnd
putStr "\n"
print_ ls
getKey :: IO Key
getKey = charsToKey . reverse <$> keyChars ""
where
charsToKey = \case
"\ESC" -> KeyEsc
"\ESC[A" -> KeyUp
"\ESC[B" -> KeyDown
"\ESC[D" -> KeyLeft
"\ESC[C" -> KeyRight
"\ESCb" -> KeyAltLeft
"\ESCf" -> KeyAltRight
"\ESC[1;5D" -> KeyCtrlLeft
"\ESC[1;5C" -> KeyCtrlRight
"\ESC[1;2D" -> KeyShiftLeft
"\ESC[1;2C" -> KeyShiftRight
"\n" -> KeyEnter
"\DEL" -> KeyBack
"\t" -> KeyTab
'\ESC' : _ -> KeyUnsupported
cs -> KeyChars cs
keyChars cs = do
c <- getChar
more <- hReady stdin
-- for debugging - uncomment this, comment line after:
-- (if more then keyChars else \c' -> print (reverse c') >> return c') (c : cs)
(if more then keyChars else return) (c : cs)
-250
View File
@@ -1,250 +0,0 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import ChatOptions
import ChatTerminal
import Control.Applicative ((<|>))
import Control.Concurrent.STM
import Control.Logger.Simple
import Control.Monad.Reader
import Data.Attoparsec.ByteString.Char8 (Parser)
import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.Functor (($>))
import qualified Data.Text as T
import Data.Text.Encoding
import Numeric.Natural
import Simplex.Messaging.Agent (getSMPAgentClient, runSMPAgentClient)
import Simplex.Messaging.Agent.Client (AgentClient (..))
import Simplex.Messaging.Agent.Env.SQLite
import Simplex.Messaging.Agent.Transmission
import Simplex.Messaging.Client (smpDefaultConfig)
import Simplex.Messaging.Util (raceAny_)
import SimplexMarkdown
import Styled
import System.Directory (getAppUserDataDirectory)
import System.Exit (exitFailure)
import System.Info (os)
import Types
cfg :: AgentConfig
cfg =
AgentConfig
{ tcpPort = undefined, -- TODO maybe take it out of config
rsaKeySize = 2048 `div` 8,
connIdBytes = 12,
tbqSize = 16,
dbFile = "smp-chat.db",
smpCfg = smpDefaultConfig
}
logCfg :: LogConfig
logCfg = LogConfig {lc_file = Nothing, lc_stderr = True}
data ChatClient = ChatClient
{ inQ :: TBQueue ChatCommand,
outQ :: TBQueue ChatResponse,
smpServer :: SMPServer,
username :: TVar (Maybe Contact)
}
-- | GroupMessage ChatGroup ByteString
-- | AddToGroup Contact
data ChatCommand
= ChatHelp
| AddContact Contact
| AcceptContact Contact SMPQueueInfo
| ChatWith Contact
| SetName Contact
| SendMessage Contact ByteString
chatCommandP :: Parser ChatCommand
chatCommandP =
"/help" $> ChatHelp
<|> "/add " *> (AddContact <$> contact)
<|> "/accept " *> acceptContact
<|> "/chat " *> chatWith
<|> "/name " *> setName
<|> "@" *> sendMessage
where
acceptContact = AcceptContact <$> contact <* A.space <*> smpQueueInfoP
chatWith = ChatWith <$> contact
setName = SetName <$> contact
sendMessage = SendMessage <$> contact <* A.space <*> A.takeByteString
contact = Contact <$> A.takeTill (== ' ')
data ChatResponse
= ChatHelpInfo
| Invitation SMPQueueInfo
| Connected Contact
| ReceivedMessage Contact ByteString
| Disconnected Contact
| YesYes
| ErrorInput ByteString
| ChatError AgentErrorType
| NoChatResponse
serializeChatResponse :: Maybe Contact -> ChatResponse -> StyledString
serializeChatResponse name = \case
ChatHelpInfo -> chatHelpInfo
Invitation qInfo -> "ask your contact to enter: /accept " <> showName name <> " " <> (bPlain . serializeSmpQueueInfo) qInfo
Connected c -> ttyContact c <> " connected"
ReceivedMessage c t -> ttyFromContact c <> " " <> msgPlain t
Disconnected c -> "disconnected from " <> ttyContact c <> " - try \"/chat " <> bPlain (toBs c) <> "\""
YesYes -> "you got it!"
ErrorInput t -> "invalid input: " <> bPlain t
ChatError e -> "chat error: " <> plain (show e)
NoChatResponse -> ""
where
showName Nothing = "<your name>"
showName (Just (Contact a)) = bPlain a
msgPlain = styleMarkdown . parseMarkdown . decodeUtf8With onError
onError _ _ = Just '?'
chatHelpInfo :: StyledString
chatHelpInfo =
"Using chat:\n\
\/add <name> - create invitation to send out-of-band\n\
\ to your contact <name>\n\
\ (any unique string without spaces)\n\
\/accept <name> <invitation> - accept <invitation>\n\
\ (a string that starts from \"smp::\")\n\
\ from your contact <name>\n\
\/name <name> - set <name> to use in invitations\n\
\@<name> <message> - send <message> (any string) to contact <name>\n\
\ @<name> can be omitted to send to previous"
main :: IO ()
main = do
ChatOpts {dbFileName, smpServer, name, termMode} <- welcomeGetOpts
let user = Contact <$> name
t <- getChatClient smpServer user
ct <- newChatTerminal (tbqSize cfg) user termMode
-- setLogLevel LogInfo -- LogError
-- withGlobalLogging logCfg $
env <- newSMPAgentEnv cfg {dbFile = dbFileName}
dogFoodChat t ct env
welcomeGetOpts :: IO ChatOpts
welcomeGetOpts = do
appDir <- getAppUserDataDirectory "simplex"
opts@ChatOpts {dbFileName, termMode} <- getChatOpts appDir
putStrLn "simpleX chat prototype"
putStrLn $ "db: " <> dbFileName
when (os == "mingw32") $ windowsWarning termMode
putStrLn "type \"/help\" for usage information"
pure opts
windowsWarning :: TermMode -> IO ()
windowsWarning = \case
m@TermModeBasic -> do
putStrLn $ "running in Windows (terminal mode is " <> termModeName m <> ", no utf8 support)"
putStrLn "it is recommended to use Windows Subsystem for Linux (WSL)"
m -> do
putStrLn $ "running in Windows, terminal mode " <> termModeName m <> " is not supported"
exitFailure
dogFoodChat :: ChatClient -> ChatTerminal -> Env -> IO ()
dogFoodChat t ct env = do
c <- runReaderT getSMPAgentClient env
raceAny_
[ runReaderT (runSMPAgentClient c) env,
sendToAgent t ct c,
sendToChatTerm t ct,
receiveFromAgent t ct c,
receiveFromChatTerm t ct,
chatTerminal ct
]
getChatClient :: SMPServer -> Maybe Contact -> IO ChatClient
getChatClient srv name = atomically $ newChatClient (tbqSize cfg) srv name
newChatClient :: Natural -> SMPServer -> Maybe Contact -> STM ChatClient
newChatClient qSize smpServer name = do
inQ <- newTBQueue qSize
outQ <- newTBQueue qSize
username <- newTVar name
return ChatClient {inQ, outQ, smpServer, username}
receiveFromChatTerm :: ChatClient -> ChatTerminal -> IO ()
receiveFromChatTerm t ct = forever $ do
atomically (readTBQueue $ inputQ ct)
>>= processOrError . A.parseOnly (chatCommandP <* A.endOfInput) . encodeUtf8 . T.pack
where
processOrError = \case
Left err -> atomically . writeTBQueue (outQ t) . ErrorInput $ B.pack err
Right ChatHelp -> atomically . writeTBQueue (outQ t) $ ChatHelpInfo
Right (SetName a) -> atomically $ do
let user = Just a
writeTVar (username (t :: ChatClient)) user
updateUsername ct user
writeTBQueue (outQ t) YesYes
Right cmd -> atomically $ writeTBQueue (inQ t) cmd
sendToChatTerm :: ChatClient -> ChatTerminal -> IO ()
sendToChatTerm ChatClient {outQ, username} ChatTerminal {outputQ} = forever $ do
atomically (readTBQueue outQ) >>= \case
NoChatResponse -> return ()
resp -> do
name <- readTVarIO username
atomically . writeTBQueue outputQ $ serializeChatResponse name resp
sendToAgent :: ChatClient -> ChatTerminal -> AgentClient -> IO ()
sendToAgent ChatClient {inQ, smpServer} ct AgentClient {rcvQ} = do
atomically $ writeTBQueue rcvQ ("1", "", SUBALL) -- hack for subscribing to all
forever . atomically $ do
cmd <- readTBQueue inQ
writeTBQueue rcvQ `mapM_` agentTransmission cmd
setActiveContact cmd
where
setActiveContact :: ChatCommand -> STM ()
setActiveContact cmd =
writeTVar (activeContact ct) $ case cmd of
ChatWith a -> Just a
SendMessage a _ -> Just a
_ -> Nothing
agentTransmission :: ChatCommand -> Maybe (ATransmission 'Client)
agentTransmission = \case
AddContact a -> transmission a $ NEW smpServer
AcceptContact a qInfo -> transmission a $ JOIN qInfo $ ReplyVia smpServer
ChatWith a -> transmission a SUB
SendMessage a msg -> transmission a $ SEND msg
ChatHelp -> Nothing
SetName _ -> Nothing
transmission :: Contact -> ACommand 'Client -> Maybe (ATransmission 'Client)
transmission (Contact a) cmd = Just ("1", a, cmd)
receiveFromAgent :: ChatClient -> ChatTerminal -> AgentClient -> IO ()
receiveFromAgent t ct c = forever . atomically $ do
resp <- chatResponse <$> readTBQueue (sndQ c)
writeTBQueue (outQ t) resp
setActiveContact resp
where
chatResponse :: ATransmission 'Agent -> ChatResponse
chatResponse (_, a, resp) = case resp of
INV qInfo -> Invitation qInfo
CON -> Connected contact
END -> Disconnected contact
MSG {m_body} -> ReceivedMessage contact m_body
SENT _ -> NoChatResponse
OK -> Connected contact -- hack for subscribing to all
ERR e -> ChatError e
where
contact = Contact a
setActiveContact :: ChatResponse -> STM ()
setActiveContact = \case
Connected a -> set $ Just a
ReceivedMessage a _ -> set $ Just a
Disconnected _ -> set Nothing
_ -> return ()
where
set a = writeTVar (activeContact ct) a
-122
View File
@@ -1,122 +0,0 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module SimplexMarkdown where
import Control.Applicative ((<|>))
import Data.Attoparsec.Text (Parser)
import qualified Data.Attoparsec.Text as A
import Data.Either (fromRight)
import Data.Functor (($>))
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Data.String
import Data.Text (Text)
import qualified Data.Text as T
import Styled
import System.Console.ANSI.Types
data Markdown = Markdown Format Text | Markdown :|: Markdown
deriving (Show)
data Format
= Bold
| Italic
| Underline
| StrikeThrough
| Colored Color
| NoFormat
deriving (Show)
instance Semigroup Markdown where (<>) = (:|:)
instance Monoid Markdown where mempty = unmarked ""
instance IsString Markdown where fromString = unmarked . T.pack
unmarked :: Text -> Markdown
unmarked = Markdown NoFormat
styleMarkdown :: Markdown -> StyledString
styleMarkdown (s1 :|: s2) = styleMarkdown s1 <> styleMarkdown s2
styleMarkdown (Markdown f s) = Styled sgr $ T.unpack s
where
sgr = case f of
Bold -> [SetConsoleIntensity BoldIntensity]
Italic -> [SetUnderlining SingleUnderline, SetItalicized True]
Underline -> [SetUnderlining SingleUnderline]
StrikeThrough -> [SetSwapForegroundBackground True]
Colored c -> [SetColor Foreground Vivid c]
NoFormat -> []
formats :: Map Char Format
formats =
M.fromList
[ ('*', Bold),
('_', Italic),
('+', Underline),
('~', StrikeThrough),
('^', Colored White)
]
colors :: Map Text Color
colors =
M.fromList
[ ("red", Red),
("green", Green),
("blue", Blue),
("yellow", Yellow),
("cyan", Cyan),
("magenta", Magenta),
("r", Red),
("g", Green),
("b", Blue),
("y", Yellow),
("c", Cyan),
("m", Magenta)
]
parseMarkdown :: Text -> Markdown
parseMarkdown s = fromRight (unmarked s) $ A.parseOnly (markdownP <* A.endOfInput) s
markdownP :: Parser Markdown
markdownP = merge <$> A.many' fragmentP
where
merge :: [Markdown] -> Markdown
merge [] = ""
merge [f] = f
merge (f : fs) = foldl (:|:) f fs
fragmentP :: Parser Markdown
fragmentP =
A.anyChar >>= \case
' ' -> unmarked . (" " <>) <$> A.takeWhile (== ' ')
c -> case M.lookup c formats of
Just (Colored White) -> coloredP
Just f -> formattedP c "" f
Nothing -> unformattedP c
formattedP :: Char -> Text -> Format -> Parser Markdown
formattedP c p f = do
s <- A.takeTill (== c)
(A.char c $> Markdown f s) <|> noFormat (T.singleton c <> p <> s)
coloredP :: Parser Markdown
coloredP = do
color <- A.takeWhile (\c -> c /= ' ' && c /= '^')
case M.lookup color colors of
Just c ->
let f = Colored c
in (A.char ' ' *> formattedP '^' (color <> " ") f)
<|> (A.char '^' $> Markdown f color)
<|> noFormat ("^" <> color)
_ -> noFormat ("^" <> color)
unformattedP :: Char -> Parser Markdown
unformattedP c = unmarked . (T.singleton c <>) <$> wordsP
wordsP :: Parser Text
wordsP = do
s <- (<>) <$> A.takeTill (== ' ') <*> A.takeWhile (== ' ')
A.peekChar >>= \case
Nothing -> pure s
Just c -> case M.lookup c formats of
Just _ -> pure s
Nothing -> (s <>) <$> wordsP
noFormat :: Text -> Parser Markdown
noFormat = pure . unmarked
-29
View File
@@ -1,29 +0,0 @@
module Styled (StyledString (..), plain, bPlain, styledToANSITerm, styledToPlain) where
import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import Data.String
import System.Console.ANSI (SGR (..), setSGRCode)
data StyledString = Styled [SGR] String | StyledString :<>: StyledString
instance Semigroup StyledString where (<>) = (:<>:)
instance Monoid StyledString where mempty = plain ""
instance IsString StyledString where fromString = plain
plain :: String -> StyledString
plain = Styled []
bPlain :: ByteString -> StyledString
bPlain = Styled [] . B.unpack
styledToANSITerm :: StyledString -> String
styledToANSITerm (Styled [] s) = s
styledToANSITerm (Styled sgr s) = setSGRCode sgr <> s <> setSGRCode [Reset]
styledToANSITerm (s1 :<>: s2) = styledToANSITerm s1 <> styledToANSITerm s2
styledToPlain :: StyledString -> String
styledToPlain (Styled _ s) = s
styledToPlain (s1 :<>: s2) = styledToPlain s1 <> styledToPlain s2
-14
View File
@@ -1,14 +0,0 @@
{-# LANGUAGE LambdaCase #-}
module Types where
import Data.ByteString.Char8 (ByteString)
newtype Contact = Contact {toBs :: ByteString}
data TermMode = TermModeBasic | TermModeEditor deriving (Eq)
termModeName :: TermMode -> String
termModeName = \case
TermModeBasic -> "basic"
TermModeEditor -> "editor"
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2194
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2184
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

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