Compare commits
4232 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b25513a06f | |||
| 370140143d | |||
| 10092ba792 | |||
| d376e202c8 | |||
| d7646274c0 | |||
| f3d767d794 | |||
| 8cb0f916aa | |||
| ba1c274ffb | |||
| 3708680aed | |||
| e96acf011b | |||
| 9034c9a2c2 | |||
| 504346d9a0 | |||
| ae5b140da0 | |||
| a33c3d8602 | |||
| fc5bfeaee1 | |||
| c4b761cce0 | |||
| 2b98a1e0a1 | |||
| 27d3449960 | |||
| 44ffd2aea1 | |||
| cc56552cb0 | |||
| ca85c9e803 | |||
| a70d98338b | |||
| ecef927e95 | |||
| fb9816791e | |||
| 44ed070a28 | |||
| 8a2a84fa35 | |||
| 0825ea0160 | |||
| bc3b798d04 | |||
| 598e696338 | |||
| 6e90f6876e | |||
| d3aec6b6d0 | |||
| 9af2f378e8 | |||
| e0461b89fb | |||
| 7e6abebf9e | |||
| ec5514a4a0 | |||
| e88cd97b30 | |||
| d6e35d35c3 | |||
| f2b212dc2e | |||
| 9681e7eb19 | |||
| 0e1b53dfa7 | |||
| d9649bc8d9 | |||
| 3cd2246a51 | |||
| fdf75eebf3 | |||
| 697f5b77b5 | |||
| 9e63567532 | |||
| bf7c6acba9 | |||
| 5700265c39 | |||
| 6267eed8b3 | |||
| 52cc4762ba | |||
| 1beea1586e | |||
| cbef2a0cfc | |||
| f778829e81 | |||
| bba4eba3d5 | |||
| 4c6f774553 | |||
| 1fc7a6de95 | |||
| 47489fd513 | |||
| caf68ba5e6 | |||
| 5532acf426 | |||
| bfe2b8bc10 | |||
| 876117bbf4 | |||
| 092f81dad6 | |||
| 5d768d81b0 | |||
| 56851519da | |||
| 810ebff849 | |||
| 7e77f629f6 | |||
| 1abea47914 | |||
| ae7ab838f4 | |||
| c79f62d874 | |||
| f34e62f24a | |||
| 4f89780cfe | |||
| f1b3588465 | |||
| fdc0f1e648 | |||
| c0bcdc3829 | |||
| d34f875d35 | |||
| 7b22a2aea7 | |||
| 4b26971b48 | |||
| 640d1f459b | |||
| 8386608953 | |||
| d7cfa68a3f | |||
| 2a816019b6 | |||
| e9944ba83d | |||
| 9c21d99e01 | |||
| 7b720b2a3f | |||
| 3bddcb5461 | |||
| 4187b3a3c9 | |||
| 4e526476e3 | |||
| 3697e1b674 | |||
| 58c7467720 | |||
| 1d035109ea | |||
| fc85b09e88 | |||
| b51c0f1ee5 | |||
| 4d692e635b | |||
| 07a952a2a6 | |||
| 2589a244dd | |||
| 99ed365695 | |||
| 7f93d7ec6f | |||
| 17b72ef1bd | |||
| e99442cb1c | |||
| 085f139abd | |||
| f616d19a4e | |||
| 61cf3a960c | |||
| f94ec5a8a9 | |||
| a2f228e74d | |||
| 3ec1ff8c7e | |||
| 631fe4f362 | |||
| 6153480e43 | |||
| e1789d40d4 | |||
| 0fff162c65 | |||
| 0b70be9a9b | |||
| 04aec11daa | |||
| 91145dc868 | |||
| 252bf3e363 | |||
| 22449a0913 | |||
| 5ef60debc2 | |||
| eac7141ce7 | |||
| 6468b8ab19 | |||
| 11e84ffbef | |||
| 6a1212de82 | |||
| 92192715bb | |||
| 786e8999e1 | |||
| 02f0d7bb8a | |||
| f543c2569e | |||
| 9878ee6fa7 | |||
| 827ec824d1 | |||
| c9ca79ab47 | |||
| ed1e3cabc3 | |||
| 6419bb15fb | |||
| d53ee9c241 | |||
| 5bb03928a1 | |||
| c354ed7814 | |||
| 3fbe30231e | |||
| b5f3ea60b7 | |||
| bc2eb3df82 | |||
| 92488b29d5 | |||
| ef848e0a1b | |||
| 4319245dd3 | |||
| 5eed8136dd | |||
| 66b38ccb5f | |||
| aae5631f19 | |||
| 6cc58e3701 | |||
| 2cd90eb3ce | |||
| 1b96772126 | |||
| f31421a311 | |||
| e3a34eae29 | |||
| ce10b71122 | |||
| d39af8edf3 | |||
| b87df709df | |||
| 0e7a483c7b | |||
| 668a91bd15 | |||
| 59e9a91a1e | |||
| 33dda9dffd | |||
| f9d86283a3 | |||
| c5317e6de9 | |||
| d36f7d598c | |||
| 59e64f56fa | |||
| 05d2881c16 | |||
| ab61ddaf16 | |||
| cfa8ecbb2e | |||
| d6cb8d62af | |||
| faa7c1ca55 | |||
| 52615a3ccb | |||
| de737b3cbe | |||
| 9245c2e49b | |||
| 365cd728b8 | |||
| d6d7046edb | |||
| 418233fa2e | |||
| 37d870fdd9 | |||
| 9af4fb4a26 | |||
| 24edbf43ed | |||
| 8ed9085474 | |||
| a1389ac778 | |||
| 4f8b3efa5c | |||
| 2200dbb406 | |||
| f6d1208992 | |||
| 5ff29c41c1 | |||
| 1d04cae3c2 | |||
| 57c5ddc774 | |||
| 6f4c9f6f5a | |||
| 0dd4722865 | |||
| 045cb6822f | |||
| f4cbbb251f | |||
| 978116b107 | |||
| 2ff6ac44dc | |||
| 0a43ca759b | |||
| fcb695d691 | |||
| 51021d1508 | |||
| ac3c731b64 | |||
| 2994268b83 | |||
| 05cf8aaa0f | |||
| 9a9307ead3 | |||
| 33f86dc7b0 | |||
| a4e7923b15 | |||
| 4a0b47d286 | |||
| b4b3446135 | |||
| 82650f5420 | |||
| 4646cc7f21 | |||
| 2810b186bb | |||
| 8f2fbff93e | |||
| cdf1f16944 | |||
| 8dfb14cf7a | |||
| 432072a3d4 | |||
| c773f16a4a | |||
| bdcdafab2d | |||
| a8b59804fa | |||
| 07250a1bcf | |||
| d0e24b555c | |||
| 61f89d7b33 | |||
| 88404cfddb | |||
| 111b15a855 | |||
| 263ddc3bcf | |||
| 4009a47377 | |||
| 7cd4bd3cd4 | |||
| 1c94acdeca | |||
| e37bbb2bb7 | |||
| d1cac7804a | |||
| b3e5356b07 | |||
| 84e7520707 | |||
| e3e72ffd01 | |||
| 3f84f27354 | |||
| 4b470a9205 | |||
| 2079c8d4cf | |||
| 7871bc7097 | |||
| ae8de84828 | |||
| 9fc2ed338d | |||
| d9c6e3a322 | |||
| ca3eb7dca4 | |||
| f6abf7a2d2 | |||
| a8f9cf430d | |||
| 98f342227f | |||
| 55e284729e | |||
| fef4e14fb0 | |||
| eeafe97614 | |||
| f869ad620e | |||
| a5307489ff | |||
| b1d21600cf | |||
| 3bbef51448 | |||
| a17199c7a9 | |||
| 13ddffd66a | |||
| cebd3edb9a | |||
| b7b6329e7a | |||
| 6e21752528 | |||
| c9fcb8fdb4 | |||
| 172d842635 | |||
| 7a45cfa8e9 | |||
| a50dbd5886 | |||
| a17f20463f | |||
| b80f25fbc5 | |||
| 9cb41f4517 | |||
| 494833236f | |||
| 7c26a251cf | |||
| d164a49675 | |||
| 59b089a0cc | |||
| c031f09886 | |||
| 3af2bf61fe | |||
| 6f4ed6883b | |||
| ec94dc26ac | |||
| 8decb55e51 | |||
| 8346a90d65 | |||
| 4191ecc2e6 | |||
| 783ed506bd | |||
| 00bd28278d | |||
| b51c0ca5e7 | |||
| c6c2479268 | |||
| 300e0f2fb7 | |||
| 00154dcbe9 | |||
| 3884348e07 | |||
| a7745a2086 | |||
| 9caeea7edd | |||
| ae4e5ad54a | |||
| 18ea990e7a | |||
| 5d557b44e4 | |||
| ec312a1f15 | |||
| 87877fb506 | |||
| 9dce30e904 | |||
| 6fc6bb48ff | |||
| 8fecab58a9 | |||
| df71142949 | |||
| 4b65fd1126 | |||
| 814739b52b | |||
| 2f5970d57c | |||
| 79263209b3 | |||
| d56c2c5fc3 | |||
| 9e922e0610 | |||
| c9792e7bbc | |||
| 8c85ece0cb | |||
| 10bb323eb5 | |||
| 2c16e4b897 | |||
| 969cc0778b | |||
| b83533637d | |||
| c8d1044596 | |||
| 7011e205d5 | |||
| 6d2cf80f10 | |||
| 172bbb1b29 | |||
| cf45065e15 | |||
| d3460cafd0 | |||
| 3386e427a0 | |||
| a1a078f998 | |||
| a4da0f67f7 | |||
| fe04679307 | |||
| 8628e79245 | |||
| edb549bef6 | |||
| 085c4ba65d | |||
| 805225de3f | |||
| 8de878693d | |||
| 90ec66c34c | |||
| eba39d12aa | |||
| 5328e8a750 | |||
| df27d58597 | |||
| 8a519995da | |||
| 407bf19641 | |||
| 7091a3d156 | |||
| 990dc0f95c | |||
| 77f89d1967 | |||
| 3d2b8439ee | |||
| f3315e2c45 | |||
| 4fcaa1d1bb | |||
| 883a61e5a0 | |||
| 2f2fae3892 | |||
| 1fa0a8e7ee | |||
| cd1e0d710d | |||
| beeb4663c4 | |||
| a6d5300057 | |||
| a228e9c0ad | |||
| 829b0b5d27 | |||
| 7e07336e3b | |||
| 4663ea659a | |||
| 86a07d3ab0 | |||
| 2119dae0b5 | |||
| 6769944e16 | |||
| 6b45727129 | |||
| d98b5b2fe6 | |||
| 959863c70a | |||
| 689fc57932 | |||
| 5732b4f48c | |||
| 9febcd88d4 | |||
| af550199d4 | |||
| 87eedb822c | |||
| cbe908da79 | |||
| 666e40f002 | |||
| 2c003bc22e | |||
| bcaa449510 | |||
| 08f9fb2492 | |||
| 6bcf4cb42d | |||
| a36d90481c | |||
| 0f85080c15 | |||
| afddcbdd40 | |||
| ca63b12670 | |||
| 74e1c8c7d8 | |||
| a504dc2287 | |||
| 82884b8311 | |||
| 30fa759cde | |||
| 0fad7fc234 | |||
| 92fc06fd51 | |||
| f04a4d5c7f | |||
| d958f66e77 | |||
| aa74efdee7 | |||
| 76c5a7f8d0 | |||
| 3ec37968e9 | |||
| bb6fc19768 | |||
| b6ae741000 | |||
| 0c3cec0da4 | |||
| fe199447d5 | |||
| 96f23bf006 | |||
| 4aee7bfbc1 | |||
| 892de6154d | |||
| 6df0333ca2 | |||
| f5486e3090 | |||
| 989cbf0837 | |||
| 4d8244edd5 | |||
| 4c6404ed64 | |||
| 82f9aa1a2a | |||
| 73d0b4cb84 | |||
| 94b8685f23 | |||
| 8f56ef4502 | |||
| 27b041c4c5 | |||
| d4ad55f006 | |||
| 50cd572754 | |||
| f8efc992ef | |||
| 95a53d51a3 | |||
| f62ae325df | |||
| 8a1001333e | |||
| 8158c7f798 | |||
| 3c8d8d9243 | |||
| 319a914b66 | |||
| d24e73d6c7 | |||
| 175cb10ef6 | |||
| 1b153ded83 | |||
| 8349e7504a | |||
| 828eed0c34 | |||
| c4e53b55ce | |||
| 3e6da6210e | |||
| aa5e0440d4 | |||
| 8f4b6f80ad | |||
| b5b563fdec | |||
| faa48cad44 | |||
| 71afa9a481 | |||
| bd6c50c4c2 | |||
| cec81616a4 | |||
| 59bf5515c3 | |||
| d5f4c5366c | |||
| ee073f2e9b | |||
| b86ed7775a | |||
| 90191819bd | |||
| 094c43293d | |||
| d099e29fb9 | |||
| 90297d838d | |||
| 2c9137571e | |||
| a479459d76 | |||
| 0685687161 | |||
| 9f4923fc79 | |||
| f2c80f5b44 | |||
| bcb447520e | |||
| e66a5a3442 | |||
| 4b3945dec8 | |||
| daa46ab296 | |||
| 055bea4562 | |||
| 73dd472e28 | |||
| 763e9dad87 | |||
| 6eb486d885 | |||
| 48027ae66b | |||
| c0ae279031 | |||
| 74f2c49284 | |||
| 42e5bdeca5 | |||
| 7cd8b21af9 | |||
| fbc217d60c | |||
| ec3d981998 | |||
| 75632f7c86 | |||
| c7ec23b872 | |||
| 5472f97797 | |||
| 79d97463ec | |||
| 4015192c4a | |||
| c467238344 | |||
| 3a75568c2f | |||
| b6b9edcbea | |||
| 0f337ebbea | |||
| 65094326e8 | |||
| a29acd4882 | |||
| fa8eaaff4f | |||
| de42fb83c5 | |||
| e974d02b44 | |||
| e3f2e68947 | |||
| 5907145fcc | |||
| 2e7c5c8d7b | |||
| 6a187bff11 | |||
| 8579f1db95 | |||
| aeed2a0bcd | |||
| 3747d2d91d | |||
| 97f120a6e2 | |||
| 1f3ac5170f | |||
| 60ff46b012 | |||
| dc113c0620 | |||
| 5b10802cc8 | |||
| 6b5b32a62a | |||
| 3ceb28cd5e | |||
| 7e6fcc09f0 | |||
| c22e6b7cbf | |||
| bb84330289 | |||
| ee84743fb0 | |||
| da6956df3d | |||
| 0d003967e8 | |||
| 589e486cb8 | |||
| fd634164ed | |||
| 82ffe0f91f | |||
| f992678e3a | |||
| 23c6d595ff | |||
| 4221ea66da | |||
| c34f25f2bd | |||
| 5080556836 | |||
| 62674467ed | |||
| 42eaddfaba | |||
| 5f60eb53ff | |||
| b01e0b77fe | |||
| d1406f3f17 | |||
| 7942a24c0c | |||
| 5a2c0b1a19 | |||
| 36373574cf | |||
| 8585e8cb0c | |||
| 9fe4419269 | |||
| 8b37591882 | |||
| 7a5eefcc70 | |||
| bb6a008309 | |||
| 77529fb698 | |||
| edbdbef2eb | |||
| 0d93cb580d | |||
| 4f446e0102 | |||
| 969108381a | |||
| 53dc6d45b9 | |||
| db8878932f | |||
| cbf8f791bb | |||
| 27e04f3e0c | |||
| 58a2c0f834 | |||
| bb4d4e239f | |||
| ab1af9371e | |||
| 73baa8e679 | |||
| 6e89ec538c | |||
| c992e883b5 | |||
| 39ce6a1a0a | |||
| a91c2cd0a2 | |||
| b28b46bdc9 | |||
| f055478b6e | |||
| 7a586e680c | |||
| 54da1bf21b | |||
| 2b89fb9d40 | |||
| 07ca74ca0b | |||
| 554ba411f6 | |||
| 9f887dda4b | |||
| 7bb2f590c7 | |||
| ee58a97156 | |||
| 41aabe486b | |||
| 5515a662b8 | |||
| 66c450fc0d | |||
| 7e7af4118d | |||
| 5fec51d0c6 | |||
| 47e1d56033 | |||
| 89bee2dd51 | |||
| 26b437fcd6 | |||
| ad38e06555 | |||
| 64c172f590 | |||
| 471eaf7498 | |||
| b8888025ec | |||
| b0227e1bf6 | |||
| ecff8e3670 | |||
| d5ce6fff77 | |||
| b311c33473 | |||
| d58ec07343 | |||
| 8e746dcfbd | |||
| 2411009071 | |||
| 646f8c32f9 | |||
| 83de6c640c | |||
| bbdc6abea8 | |||
| 49e75e1ab0 | |||
| c24a58672b | |||
| a98b2f4a39 | |||
| 0328de897c | |||
| 48de6c495e | |||
| 39b3f0a386 | |||
| a0304b5147 | |||
| b06573b5c9 | |||
| 8c131cc616 | |||
| dc3d27993b | |||
| 9ed0520607 | |||
| c32fbf918f | |||
| dafcaa66a4 | |||
| d7f440513a | |||
| 8145b0b96e | |||
| 9e482556ea | |||
| 546c786ed3 | |||
| e613a89d02 | |||
| 3c3683a41e | |||
| 945373eb5b | |||
| b21e6860b3 | |||
| 99a5218eb3 | |||
| 5ccb58b1bb | |||
| 303d10939e | |||
| 963db7487b | |||
| 150f7dedcd | |||
| 80abcd70b5 | |||
| bbf23cefb6 | |||
| f73793ce8a | |||
| d48ceab73d | |||
| 4935ceda5b | |||
| 73e45b9cc7 | |||
| fe03dbab96 | |||
| 507af0a14d | |||
| 1dca7c2a69 | |||
| 712e79d0a2 | |||
| 353c95adae | |||
| c64f175b19 | |||
| b185900b4f | |||
| b55d80212c | |||
| 5f61c96ed9 | |||
| fa7b00c0e2 | |||
| 9dc17b1daf | |||
| a3d03a3c63 | |||
| 3fc8796bda | |||
| 34c9b24123 | |||
| 591f131972 | |||
| 8f610401ae | |||
| 1fa219c1cd | |||
| 19a1bd9451 | |||
| 577e8f14af | |||
| 3da3334131 | |||
| 3a5b2c6ecf | |||
| 391a3b02f0 | |||
| c57e40620b | |||
| 0dd30d4668 | |||
| 66e4cab8f8 | |||
| d462ca3241 | |||
| 1100b38b4c | |||
| f07510bd67 | |||
| 82d496ba24 | |||
| b6b6e18896 | |||
| f36ad1c37a | |||
| 21c6efa32a | |||
| c12e152618 | |||
| d455d6ee32 | |||
| 4069e4412c | |||
| 4d76520ce3 | |||
| 0bc9ee3cf1 | |||
| 90eda7c03a | |||
| eb6e6ec89a | |||
| 358a9f87a1 | |||
| 8224e6ece1 | |||
| 87ebd2720f | |||
| 98a6af1ca9 | |||
| ac19655d21 | |||
| 53a2d4704d | |||
| 994dd2e05c | |||
| 28637308ed | |||
| 68dd72f4fe | |||
| 5a39484407 | |||
| 4fcfbed7d2 | |||
| 5b3d9cf3ba | |||
| 9f57a82c75 | |||
| 1e6f7c7f3f | |||
| 8890ed606e | |||
| 41b699d8ad | |||
| b4f7c0fe9b | |||
| ba4715a3af | |||
| e49bf706c5 | |||
| 1c9ac520cb | |||
| 102f882ca4 | |||
| b93c93a20c | |||
| abb73d624e | |||
| 0aa7e85228 | |||
| dea23ce3c9 | |||
| aa60283fcb | |||
| 96231c217c | |||
| 7868e5e905 | |||
| d061c569b7 | |||
| 04eb23ae32 | |||
| 6edf31beb6 | |||
| 5dbeedd914 | |||
| 1d7c45b324 | |||
| 5b9ab96b19 | |||
| cfad40f7bb | |||
| 840366b385 | |||
| b4c04bd3b5 | |||
| 8bd64c62c2 | |||
| 42e7f625cd | |||
| 55fb7aeb68 | |||
| dfc6718bea | |||
| 06c5154e99 | |||
| 294516c2be | |||
| f1117b0071 | |||
| 776260d265 | |||
| af4c7bc754 | |||
| ff54ea88e2 | |||
| eef6ba797f | |||
| 18e9882916 | |||
| c299e673ad | |||
| 9533e95dd2 | |||
| 1610ad345f | |||
| 4ba2581df8 | |||
| d9b9a40119 | |||
| bb6481f194 | |||
| 1cbcef17c8 | |||
| 921d5a62d2 | |||
| 2cce6ddb3e | |||
| 73cbef5b82 | |||
| dc2d6e9d12 | |||
| b5f8abf45c | |||
| 36a3542d63 | |||
| 4fd4b14fcc | |||
| 5b916a5f5e | |||
| 7d1a7c2b6c | |||
| aa78825b7b | |||
| 308116f792 | |||
| d581bdcf56 | |||
| cf7ebb0f4a | |||
| 9275b45ab8 | |||
| a8452601d7 | |||
| a242e76f26 | |||
| 380c333185 | |||
| 02eac1ee14 | |||
| d0d1d91ef3 | |||
| 91df896f8e | |||
| 537375b92b | |||
| a5a43dcc7f | |||
| a4f0a636e2 | |||
| d189b1966e | |||
| 55649cba30 | |||
| 4b521e687e | |||
| 6ed80c9706 | |||
| 898eebbf4b | |||
| c4847e752c | |||
| 8aa09d32dc | |||
| 00ef43657e | |||
| 7c5475e62a | |||
| 8256ebd5aa | |||
| 38f059cfb2 | |||
| fca5b6f378 | |||
| 57b8740adf | |||
| c86d2c6986 | |||
| ccb563eff1 | |||
| e0d28a580c | |||
| f85da1ad12 | |||
| 87ef5d06df | |||
| f0a47c8769 | |||
| 27080d4b96 | |||
| a61334247d | |||
| f5281b7418 | |||
| 08be7f1960 | |||
| 5e44170091 | |||
| ff3dc8987d | |||
| f4a2be34ea | |||
| b1a537801c | |||
| 5521ff621a | |||
| 37037d0713 | |||
| 9672c147e2 | |||
| b7d3aa4b07 | |||
| 09f9819233 | |||
| cf2a44792f | |||
| c61c249405 | |||
| 3670e1d9db | |||
| aa582be321 | |||
| 4dff43a65e | |||
| 97345dbd59 | |||
| 6564a42f21 | |||
| f7679c50d8 | |||
| dbb7e34950 | |||
| 34f0d7026e | |||
| 59ecfd67f0 | |||
| 6acc2633a5 | |||
| 07649b3c16 | |||
| a2c268c923 | |||
| 0b98b88dfc | |||
| c2f64700c1 | |||
| f6ac2c5aa9 | |||
| ff08ab1023 | |||
| b30948fd81 | |||
| 008600f6d3 | |||
| 73686ae930 | |||
| 3223e6389c | |||
| b9d3b9364c | |||
| 7f71e9dd52 | |||
| 71497e592c | |||
| b24a13d962 | |||
| 4212be1b6c | |||
| 5f1121123c | |||
| 68e1504685 | |||
| ffea1e3917 | |||
| 8eab8af02d | |||
| 9d371ddb94 | |||
| 58d334c1c8 | |||
| 5507e9c00d | |||
| 2de7fb5c25 | |||
| 485d820fe2 | |||
| b1d08b3e30 | |||
| e86fec4ab6 | |||
| a4c4ea129c | |||
| 56e675ec9c | |||
| 61b7b2d5dc | |||
| 64562b6171 | |||
| ec7c76b8d2 | |||
| 1a35929eb8 | |||
| 151f3f6cc4 | |||
| dc6b9dda4d | |||
| f9bf1e9372 | |||
| e3689a1f12 | |||
| c65ab01647 | |||
| 63a76b273a | |||
| cc7ad543ee | |||
| 48e2e2c2db | |||
| f8fc9956d0 | |||
| 719cae0406 | |||
| 7a9b62fc40 | |||
| d804a327aa | |||
| 87caf0e2c4 | |||
| a08f8d890d | |||
| d9ddb12500 | |||
| f68db94c81 | |||
| b84345c083 | |||
| f06ca5a07c | |||
| 25026d1657 | |||
| 1782f5c463 | |||
| 66a5e67cbf | |||
| f1bf8e554e | |||
| d4a5bb788c | |||
| df1a8346e0 | |||
| ccce8756ed | |||
| 1e0a16a214 | |||
| d7e8199365 | |||
| cec580a645 | |||
| 8a9409005f | |||
| 8c7d38ea25 | |||
| fe4f460a3b | |||
| 47beb2e7e1 | |||
| 04ccdc4b30 | |||
| ad5b451182 | |||
| 11474102cd | |||
| 5f8702fc62 | |||
| ba7b3422c9 | |||
| 115017c8cd | |||
| 769da0ec15 | |||
| 151b169dda | |||
| 84b7de1405 | |||
| 3a7bf449ed | |||
| f2701e89bd | |||
| 1bb89e818e | |||
| 28af45c65a | |||
| d52d82f7e6 | |||
| ca0c9ab659 | |||
| de4d55e06a | |||
| 221d79283d | |||
| 1705e5a03e | |||
| 06c5b6c2fb | |||
| 9b0b154bd3 | |||
| 15778fc6db | |||
| 932ea86b45 | |||
| 4ea9355f5f | |||
| e8a98abcd1 | |||
| af5695d462 | |||
| bfc1c83c0b | |||
| e5f2bcad03 | |||
| e972a297e1 | |||
| 439a8543e2 | |||
| 02bf8e52af | |||
| c569781921 | |||
| 343261d6ae | |||
| 7c0698739b | |||
| c30608d7eb | |||
| e37894d011 | |||
| 43581b0b64 | |||
| 79195cac36 | |||
| 38917114f0 | |||
| ddb3798ab0 | |||
| a58047e88a | |||
| 794c2c495d | |||
| 284173ec3c | |||
| ae3925b9cd | |||
| 20f79c5ae5 | |||
| cb902dae76 | |||
| 2ce5e5530b | |||
| 70e7758c0c | |||
| d349a28d76 | |||
| 9efa707b64 | |||
| 15be845421 | |||
| d343431e75 | |||
| f1199852a2 | |||
| aa89e2c5e7 | |||
| 826b3912ce | |||
| 87f53ce1bf | |||
| b622ca45d2 | |||
| c9ac77ccbf | |||
| 8a98369a0e | |||
| c1ec676262 | |||
| 6327bac6c2 | |||
| cd5b185c12 | |||
| f93e1f4188 | |||
| 72f690ce99 | |||
| 90129c10d8 | |||
| e5804fb213 | |||
| 2aae67cb81 | |||
| efc31d6e58 | |||
| 0c9340e380 | |||
| c39c0b597c | |||
| 6d0ff399fb | |||
| d77e23df86 | |||
| 5022950c32 | |||
| 8d08d83ba1 | |||
| 2418fb311e | |||
| a83890b03e | |||
| 0f6a5480df | |||
| 4d767fb279 | |||
| 3621dc754a | |||
| f14c592148 | |||
| f5bee133a4 | |||
| fc2fd60cdb | |||
| edc3006fbe | |||
| e1a2fd2481 | |||
| de1e3cc975 | |||
| d88f817874 | |||
| 3e7fa1bde3 | |||
| a9e35afbd7 | |||
| f60dfaf14a | |||
| cefce69fda | |||
| 5ab68c9ebb | |||
| 5c62bce037 | |||
| 92fe61610f | |||
| ab41a469c7 | |||
| 75636d69ff | |||
| c20bf7aeb1 | |||
| 4c2d72d00b | |||
| 2e538b5d38 | |||
| 660e753ce7 | |||
| f4dec97178 | |||
| e9fced5c2c | |||
| 3dba01535b | |||
| e509aa8072 | |||
| e85bb2085c | |||
| aa94491ad7 | |||
| 7969795a01 | |||
| 62d32a1bdf | |||
| 4e9c0ea3a5 | |||
| 5c7d2723ed | |||
| 17e8fd5636 | |||
| 18ab2dd0d1 | |||
| 03e78536f0 | |||
| 7fb0e3900f | |||
| 9b483c390d | |||
| 385f05b21b | |||
| 7d310e56cc | |||
| 7899e4943b | |||
| 1848748118 | |||
| 04dbbab4a1 | |||
| 3ebec4db75 | |||
| ff3b0fe2d9 | |||
| d62f294494 | |||
| 46758a82a7 | |||
| 1292bbd954 | |||
| 234e0b247b | |||
| d9d0410797 | |||
| eabeae20b6 | |||
| 215303cc69 | |||
| 17db3361d3 | |||
| 91fb6d405d | |||
| d5634d5aa4 | |||
| dbeebd2efd | |||
| 0bcec5f10c | |||
| d285b2409b | |||
| 3030a80f37 | |||
| 47bf9f2429 | |||
| 827bd7c9a9 | |||
| 9dc236b685 | |||
| 0cddac16fb | |||
| c26d158bc7 | |||
| 17281314e7 | |||
| aa7d8cd39c | |||
| 6489311ab8 | |||
| 6b8e680510 | |||
| 52a522c5b8 | |||
| a0604c5594 | |||
| 1b12c3379f | |||
| 12610c994a | |||
| 666b9a354f | |||
| be8a3c8a61 | |||
| 5a6a38da29 | |||
| ce8682e0ee | |||
| 79c537eeb8 | |||
| a671960ba7 | |||
| 7ffebafb60 | |||
| dff3698432 | |||
| ca8959fc67 | |||
| 3d6b1feee0 | |||
| f9e2b5f9a2 | |||
| 3134f6a08f | |||
| d98011ccdc | |||
| 7201f8a86e | |||
| 770c39677d | |||
| 8bfd3bee99 | |||
| 1a29b6ac6e | |||
| b2531b588f | |||
| f7098efc36 | |||
| 491f569ca3 | |||
| 8d258d013a | |||
| 2fc23dc8fb | |||
| a22f6c28d6 | |||
| 4cdea65aa5 | |||
| a8a3c1555b | |||
| b9f1c21b5e | |||
| 4c5ca97e75 | |||
| 8c86a6e55e | |||
| c66c670ce3 | |||
| fede50ef48 | |||
| 648c60bee8 | |||
| dd8368a58b | |||
| 4a3be62dd1 | |||
| 06fec79ce7 | |||
| cf72307b95 | |||
| 48c7a4046c | |||
| 9952048550 | |||
| b6d19149d9 | |||
| 4107597a3a | |||
| 6092d9a4ad | |||
| e46d2615a6 | |||
| c91baa5179 | |||
| 0543491bab | |||
| cb13636622 | |||
| 51178d7dd7 | |||
| 359675b446 | |||
| 95387d58b0 | |||
| 6387a1591c | |||
| 93542f89fb | |||
| b49f2a7187 | |||
| 4732d7810e | |||
| b915198205 | |||
| b36d165fc3 | |||
| c6817a60cb | |||
| 5d9271ea86 | |||
| dfd5df4265 | |||
| f777ad8d8c | |||
| c085245747 | |||
| e04b6e9201 | |||
| b6121a5d64 | |||
| 2a48c002f9 | |||
| 446b3941c8 | |||
| 0134b928dc | |||
| 17b88c46b9 | |||
| d6765ab394 | |||
| 09c43a0f1d | |||
| 9e434a9136 | |||
| d80cd8d7aa | |||
| 2f80db329b | |||
| cfc8d28a59 | |||
| 6619cccd3e | |||
| b28cc7c548 | |||
| 12b192a15b | |||
| 29462e44dc | |||
| 535f5410ad | |||
| f25c5f7bfe | |||
| e6e9dc201b | |||
| 92bb0910c0 | |||
| 48aecae2d9 | |||
| 6e368fedeb | |||
| e1be829246 | |||
| 5f4335d560 | |||
| 86b4155605 | |||
| 6b0fc1bef6 | |||
| 51d2276259 | |||
| 36c398908a | |||
| 1a388698f4 | |||
| 63d69a4faa | |||
| 16b667040d | |||
| 96696c3983 | |||
| 1695bdd63c | |||
| edae1efabe | |||
| d1caea2a3a | |||
| 5c87c43007 | |||
| 998b3af598 | |||
| 647c2b351b | |||
| 9ea08a28d6 | |||
| 0d4a6f8e8d | |||
| 5521b4e2bb | |||
| 5f4c3841a0 | |||
| 2ccb55f675 | |||
| 2a28b53400 | |||
| 7884b7de44 | |||
| d96ed0d241 | |||
| b3dcb1596a | |||
| 93539f078e | |||
| 32ea2638c4 | |||
| d367b0902d | |||
| 5edea056ef | |||
| 73658c3604 | |||
| e6ceea6bfc | |||
| df14515927 | |||
| 8dd754c1fa | |||
| 8aa13b4910 | |||
| b0f7846832 | |||
| e94373f264 | |||
| 8d85f1d76f | |||
| 955319fc23 | |||
| dad5f9511c | |||
| 3c3a65cc70 | |||
| 3e7a9943a7 | |||
| 5aed7a7b89 | |||
| b0bcb2132c | |||
| 9468dad455 | |||
| 9ea48a12dd | |||
| 737ea42698 | |||
| 27db7eee26 | |||
| f45925fb54 | |||
| 3c15ec6e49 | |||
| b6ec635c52 | |||
| 9694a0c296 | |||
| 63e21abb60 | |||
| 1651f54208 | |||
| c80d0b73c2 | |||
| 2015a1c69f | |||
| 36e312193f | |||
| bb5e765cfe | |||
| 61e3c5d730 | |||
| dfcc968c3a | |||
| 19f2579640 | |||
| ed8b3e1bba | |||
| c9dbb83fba | |||
| 25cd88fb01 | |||
| ecc4a034ca | |||
| c46096ade2 | |||
| 35f4f40b3e | |||
| 66c080559d | |||
| 9dc71ad9fa | |||
| 28d22d2332 | |||
| 6590a8b769 | |||
| a7ae420645 | |||
| 0f2ae9bde6 | |||
| afae88f6cc | |||
| 606bc5523d | |||
| 85e6b0b018 | |||
| aab3ad6bc0 | |||
| 71158ca331 | |||
| 7d172a6427 | |||
| c3d17d1fd5 | |||
| 1b26fea1e0 | |||
| ca2bb144b9 | |||
| d06a9539da | |||
| 50c7308980 | |||
| 868e1fe22d | |||
| b5cd717a8b | |||
| f96fe33747 | |||
| 24c8738ad7 | |||
| a5dba00155 | |||
| fcbdf3e87b | |||
| 51bbe4d2bb | |||
| 3304801e9a | |||
| b2169ff7d7 | |||
| 026b4df014 | |||
| 86a622c49c | |||
| f0599a34c7 | |||
| 4189c0b2dc | |||
| eb1d383c05 | |||
| be1fc22a05 | |||
| 15bd2132c2 | |||
| f9174327d8 | |||
| 134b4b4273 | |||
| 0bbab2bd59 | |||
| affbcea601 | |||
| 85456f401a | |||
| 4e0e87aa49 | |||
| cdf3481de9 | |||
| 7418e6acbf | |||
| 89e750a6aa | |||
| 7a573bf809 | |||
| 2fd50c5401 | |||
| 949ea7b8df | |||
| c9b5d64c83 | |||
| c450e8374b | |||
| de0f768e7f | |||
| 41eb626338 | |||
| 3e456dbcb9 | |||
| 8086ab45ea | |||
| 60d9d92060 | |||
| 00fd140ff6 | |||
| f5aabb414a | |||
| 701215381a | |||
| 966968db7b | |||
| e3adbb469f | |||
| b67ac293fd | |||
| 1a7b934af9 | |||
| 372f7b4198 | |||
| 3f922f2333 | |||
| d556d3f575 | |||
| de3862950e | |||
| d6c3f0b5e0 | |||
| ed14a0342d | |||
| 79ff1c9902 | |||
| 42cb36481c | |||
| 08dae545a2 | |||
| a716f2be36 | |||
| 3a548a0383 | |||
| a9a47e6f55 | |||
| 3076747d3e | |||
| c977983a1f | |||
| 80099b3ff3 | |||
| 0e62acc2a6 | |||
| 41d825a4db | |||
| d3784d423b | |||
| 8c515d3751 | |||
| 28564475ea | |||
| ce59100bc6 | |||
| 8d7b75c329 | |||
| 1da7ba6446 | |||
| db09c071d8 | |||
| 8c0c87b2c9 | |||
| 1cb648c103 | |||
| aa56a7362a | |||
| 7d1bc28103 | |||
| 7a88485999 | |||
| 3c76f0f917 | |||
| 68abf86e2c | |||
| 16b9732b82 | |||
| 18661709d0 | |||
| 59c9f28078 | |||
| d26510a1e9 | |||
| ab27005dfc | |||
| b0e2f948a9 | |||
| 42f38b042f | |||
| e672041a79 | |||
| 9a04220129 | |||
| fa785b745b | |||
| 527e742a89 | |||
| 54683b2d21 | |||
| d33293ba6b | |||
| 64c5796d1a | |||
| f9699e19af | |||
| e5cc336011 | |||
| c215b9fd5f | |||
| 46cb49865a | |||
| e4c7d62012 | |||
| 85167d34e9 | |||
| 0e7a20fe9f | |||
| f9f3778a4a | |||
| 49be0d2679 | |||
| f7f3539f48 | |||
| 2a3c260dd6 | |||
| 1ac081d695 | |||
| e537279692 | |||
| a111727302 | |||
| 5c900c2b54 | |||
| dc3d4ad873 | |||
| 76e597f57f | |||
| 4d1b25ce78 | |||
| 4ef57e5ffd | |||
| 0368722c4d | |||
| baecfd6775 | |||
| ccf6428633 | |||
| e73fe08212 | |||
| 2c85060c49 | |||
| 0729bd7f83 | |||
| 27e1867346 | |||
| ecae9c7794 | |||
| 594dc126e7 | |||
| fafe2f96c1 | |||
| 4c2e73a3ae | |||
| eff86fc84d | |||
| 55624b3410 | |||
| e022c6e0f9 | |||
| 16442e2013 | |||
| 38832396bc | |||
| b60f6b0705 | |||
| f822d23509 | |||
| 55d43e7cad | |||
| af28ef7c94 | |||
| 81b095e73d | |||
| 49253a9586 | |||
| 374b877323 | |||
| 2b5732f586 | |||
| 38d8aa2a33 | |||
| ead60ebfcd | |||
| d2933428a4 | |||
| ec683d7488 | |||
| 0d88925f83 | |||
| f5319724e3 | |||
| d37216815d | |||
| 4982814d36 | |||
| e84e8a7cf6 | |||
| 480dcd8a7a | |||
| 6bda4dd0d8 | |||
| 18114458b8 | |||
| 7e5b85c4b3 | |||
| 4199bba706 | |||
| d7fa4048c1 | |||
| 20408aa531 | |||
| 518993cb4c | |||
| 8a017226c3 | |||
| 31f3d6810d | |||
| ac5b9a3e78 | |||
| cde0a11c74 | |||
| b0ddca72ae | |||
| 7dbeb56111 | |||
| df347ad0f4 | |||
| 4c5cf47bc9 | |||
| 53cb0e79cb | |||
| 9316cec95d | |||
| 86398de8bd | |||
| d966dc2343 | |||
| fd4c42a156 | |||
| 5b14d62ede | |||
| 1fa68effdd | |||
| 4fc45c590e | |||
| 8812b892c4 | |||
| e60db7cfb1 | |||
| 8c97e5f942 | |||
| 057e21905e | |||
| ca5e18391b | |||
| 802917de12 | |||
| 8d30a03f50 | |||
| 94b5a20c0a | |||
| 7c06e847f9 | |||
| 7a3f6a6994 | |||
| c39bc10d2f | |||
| 28acb19032 | |||
| d94abec352 | |||
| bf0ba68092 | |||
| df1410d84d | |||
| 1d0c41b295 | |||
| 7064de6eef | |||
| 0e36d45233 | |||
| fdfe1f1cb5 | |||
| 1e5a93249c | |||
| 808a9e6fb9 | |||
| ca4677686a | |||
| 7bf2318b80 | |||
| 194810cd56 | |||
| 5426bf1761 | |||
| f34995cfd3 | |||
| 795b73325a | |||
| cb28a50017 | |||
| f447423e2e | |||
| 1b3e275cf2 | |||
| a86529c22c | |||
| 47b2b604e4 | |||
| ff35468dac | |||
| 0c5c5d3c42 | |||
| 74f204e8e8 | |||
| 375a8cea12 | |||
| 156942f8fb | |||
| 4cd0e2c9d7 | |||
| ae851b8733 | |||
| 67818a2c28 | |||
| 7c675a378c | |||
| ff3f434acc | |||
| 5146c05ec3 | |||
| b97322c198 | |||
| d1abbae1b3 | |||
| ebc2190779 | |||
| 3fdfd76f6e | |||
| c7459af4ec | |||
| 61e0e39641 | |||
| da3b62341f | |||
| a5db6cd363 | |||
| 786b0e77b8 | |||
| 6dce4e360f | |||
| f40064333e | |||
| 160075c22b | |||
| ce0f10f764 | |||
| a7def1ee87 | |||
| 6bdbf85279 | |||
| c7dd173858 | |||
| 9541e983d2 | |||
| 1ea7d979a8 | |||
| fa190a74da | |||
| 1696e4495a | |||
| 8b3498aaf1 | |||
| 5865891797 | |||
| 4c655a6b9d | |||
| d0448569b7 | |||
| 03d7736b99 | |||
| 70604b6e8b | |||
| 2f6e8bbef9 | |||
| e2ed9baacb | |||
| b45896b294 | |||
| 3ea8d14521 | |||
| 9fb25bfada | |||
| 481de1e3e3 | |||
| 2781e6c304 | |||
| a05d85673a | |||
| 2c68df9696 | |||
| 97a1d5c592 | |||
| 7134363905 | |||
| e6369eaae1 | |||
| 8585a00051 | |||
| 1f072631e5 | |||
| 8343178219 | |||
| b28bb112fe | |||
| 68f65ea000 | |||
| 49b27d6b0d | |||
| 5a425dc5be | |||
| 18acef841b | |||
| 6022c79cbb | |||
| a86c84b1a1 | |||
| 70bddf76fa | |||
| 82c6e50753 | |||
| d3f2270f22 | |||
| fb90685a7c | |||
| bbd865ddec | |||
| 895c988ba6 | |||
| e15d380dd1 | |||
| 1f6806d68b | |||
| dde6ee67a2 | |||
| dbfc556cb9 | |||
| 6e412f43b2 | |||
| d6d4dc9826 | |||
| 96230fb4d0 | |||
| cd065beb0c | |||
| 5f8a9dddff | |||
| 659640b851 | |||
| e8566002d6 | |||
| 4f96812b90 | |||
| 20b5de755d | |||
| b8a17d4266 | |||
| 5d9523466b | |||
| 4a1a21bc4f | |||
| 5eeb9e561d | |||
| 4ffddae162 | |||
| 309e3f804d | |||
| 0d853c9393 | |||
| 6d145be8d2 | |||
| 81820a220d | |||
| 513d4f962f | |||
| 9d09a637fe | |||
| b958e0a275 | |||
| 8952277ae9 | |||
| 4a482540cb | |||
| f9ba0092bc | |||
| b0fa6170e5 | |||
| 83668b3b93 | |||
| e5683489bb | |||
| f82a6f7f98 | |||
| 3502287832 | |||
| 38a3f00de2 | |||
| c5d4b3affc | |||
| 36da011736 | |||
| 58e9d933c3 | |||
| 38e586c8e2 | |||
| 9027e3b7ee | |||
| bac03ac47b | |||
| e6c01c4434 | |||
| bb7c4fbb21 | |||
| e6ad773c89 | |||
| e3d7791a9c | |||
| 9f65e14adb | |||
| a05d7aaf91 | |||
| 350a5dd7bc | |||
| be92c59b1b | |||
| 29028d60cd | |||
| dd424ef25d | |||
| 64975f2dd5 | |||
| 13d4a2f8ca | |||
| b498a41f58 | |||
| 80ba8a93b0 | |||
| adcae206b2 | |||
| 20e6e771d7 | |||
| 813b12baeb | |||
| 1e6912f560 | |||
| e26e73b6f2 | |||
| bb3f54efcb | |||
| 65c7d0bc39 | |||
| 89848a644d | |||
| b370b859aa | |||
| 73c1adea5f | |||
| 6d66194c38 | |||
| 5396d78f9a | |||
| 1ba2e78f4d | |||
| d8a3df644b | |||
| 05d3c2dc4a | |||
| f4515558c2 | |||
| 5726026289 | |||
| c8c327566b | |||
| 02667395ee | |||
| e3465ba688 | |||
| 29ca797b3b | |||
| 3ac4eefe1d | |||
| 34c35ece99 | |||
| a5f76235eb | |||
| a8f3a04b43 | |||
| 9f36721631 | |||
| 3959c4fac6 | |||
| 91ef6f814a | |||
| a2af6d8d46 | |||
| 2f9853799d | |||
| ae725fa0db | |||
| 75fe14ad28 | |||
| b495e37130 | |||
| 8875f85336 | |||
| e43e5e8beb | |||
| 490c07bfe0 | |||
| 6e04ad19d4 | |||
| 19e965ce45 | |||
| b5d6d46ed8 | |||
| 6c6b592502 | |||
| 58cd2b2a2e | |||
| ef7efd7796 | |||
| 607226d196 | |||
| 3366ddf0eb | |||
| db143b875b | |||
| f2dc58d4a8 | |||
| e9ea9832bd | |||
| 672ca18dde | |||
| cb24e7d085 | |||
| 580c688b2b | |||
| 6b985764f8 | |||
| e7ef873935 | |||
| 628b2c714f | |||
| 01fc8ea1c1 | |||
| 6dd4af8ad5 | |||
| c2bc02928b | |||
| b69ff3f862 | |||
| 8638d26156 | |||
| e4a16e7e83 | |||
| 4e2114e2fe | |||
| 8bf30e67a9 | |||
| 4f8e230efb | |||
| 71a4d7d310 | |||
| 1002e8e6ad | |||
| cad9790e0b | |||
| 3aa5ad7204 | |||
| db2ccb7c68 | |||
| 60e114469a | |||
| 9f43dacf25 | |||
| a36a30ce01 | |||
| c294582ffe | |||
| ff3e346433 | |||
| 0dc2970e90 | |||
| 43e6431b4e | |||
| 0a98ee7a99 | |||
| 802373f108 | |||
| a7a0378cfb | |||
| 6ca4de8457 | |||
| 6a8707cc09 | |||
| 0b8877cc5b | |||
| 7472f612e6 | |||
| 992aaca272 | |||
| 093eb28e75 | |||
| 57754be6f0 | |||
| f13c6109db | |||
| f30e91c946 | |||
| 784e8f2799 | |||
| 13453351bf | |||
| 77f31ca4b5 | |||
| 7f70af58ee | |||
| c8d5817942 | |||
| 4a7148e20a | |||
| a96e00e44c | |||
| 89ddff7f1a | |||
| ebc22c5e3b | |||
| 926bb91fac | |||
| fb670b7cdf | |||
| b1d9dba775 | |||
| 6499665d98 | |||
| 3d61da74ed | |||
| 23d61dd1c0 | |||
| c695545f97 | |||
| a3465ea80c | |||
| 3ed0a093b0 | |||
| dc4e5185ed | |||
| 5739a37c7f | |||
| 8639936e45 | |||
| 89d9270ea6 | |||
| e52aa98a9f | |||
| af24830233 | |||
| bece15eaac | |||
| e762ec4631 | |||
| 7341c05d36 | |||
| b1bf68b830 | |||
| 1a071c5c6b | |||
| 6de7e7f4a8 | |||
| 632a14e65a | |||
| 321576658f | |||
| fac241b87e | |||
| 39bd52c1e2 | |||
| e55f394db5 | |||
| 00d7eeb742 | |||
| bcfa106959 | |||
| fe3c545455 | |||
| 885d431d65 | |||
| a103047e03 | |||
| b04866a2fc | |||
| 28434f4bee | |||
| 53324d5494 | |||
| 66645ce523 | |||
| 06caf65a6a | |||
| 5026b07626 | |||
| 8cfa722966 | |||
| f31337ecb5 | |||
| f468666973 | |||
| 590421daaa | |||
| e1248ba0b2 | |||
| 89b15142ef | |||
| 57b22d2ad2 | |||
| d51dd1cdb5 | |||
| 6418af0ada | |||
| 08d6e8c7eb | |||
| cf7ae1adf2 | |||
| 691f796df6 | |||
| 2775074113 | |||
| bf9014342c | |||
| fb9a456b59 | |||
| e36e52fd9e | |||
| f076793fa6 | |||
| 0116f098f8 | |||
| fc728e7a13 | |||
| 5114c9a58e | |||
| 3bd896b8fa | |||
| dddefc3904 | |||
| fc0cbaadd5 | |||
| 6b862688cb | |||
| 767eedaa76 | |||
| 1578c3c09d | |||
| 9496ebd19e | |||
| b4e8d580d0 | |||
| d48a40fa5f | |||
| 1ea2d936b5 | |||
| 6ce7641971 | |||
| 98f5247126 | |||
| bf36718c93 | |||
| 11c193b699 | |||
| 5c1604fc53 | |||
| 4c545181ad | |||
| 5ee8100274 | |||
| 86351f48d6 | |||
| 6996e410d5 | |||
| 5d6994f170 | |||
| beb4fafdf3 | |||
| 3e22cb6d0a | |||
| 849def7e75 | |||
| 1a4195f7e2 | |||
| 0b4a718afe | |||
| b53ca51d37 | |||
| 60c9707a64 | |||
| 08a979e638 | |||
| 629158fedb | |||
| f15e99ce1d | |||
| 18f9c040e0 | |||
| 7f6baa0fdc | |||
| bb9a112677 | |||
| 7952d2688e | |||
| 0f41fd1356 | |||
| 8c3a8a7d20 | |||
| dbbe4b9398 | |||
| e0b0f00621 | |||
| 516d6cf11e | |||
| 673db168ac | |||
| 496e96d00a | |||
| 88fdc16070 | |||
| df98cdb127 | |||
| 68b245c3d6 | |||
| 0248c8d8c0 | |||
| 3ac517b716 | |||
| 8414c3e382 | |||
| 9f8dc1d7d3 | |||
| 56927d2780 | |||
| a027284826 | |||
| e0159c32cc | |||
| 9cc30741d9 | |||
| 863752e974 | |||
| cb76031165 | |||
| c45cf07b06 | |||
| d35d425918 | |||
| d4a3a53484 | |||
| 5d90b12a08 | |||
| e3ce190f4e | |||
| ffd50c5582 | |||
| c758f05a7a | |||
| 9263c08068 | |||
| 703f77ac93 | |||
| 32bdb5a519 | |||
| d8484a7b2b | |||
| eca8dfb0ec | |||
| 29b714dd5f | |||
| 3f3b2cb2ba | |||
| c31d9ded27 | |||
| 03df5b8546 | |||
| 03e1e5cca9 | |||
| 10d5cc0d24 | |||
| 506c8ff73c | |||
| 924e9a21b5 | |||
| 2f528a9853 | |||
| 7f58650794 | |||
| b9a109c146 | |||
| 9fb4f4b556 | |||
| 52d78ef724 | |||
| 7ce7b88a40 | |||
| 4a43dfd091 | |||
| 52cc76636c | |||
| f0a3ddb184 | |||
| b172c9a3b2 | |||
| 6cfda1dd43 | |||
| cc7c14a529 | |||
| 60a73c3915 | |||
| 77e300b551 | |||
| 2ae31f7285 | |||
| 412c06160a | |||
| c27c47dd52 | |||
| 6ea30feb18 | |||
| a7be550550 | |||
| a279f0a296 | |||
| 1c4f663941 | |||
| 94f9321db9 | |||
| ae70b10cea | |||
| 4f685552e7 | |||
| e085a76165 | |||
| 30bd3ed013 | |||
| 25edab4c94 | |||
| 3aa241d825 | |||
| 9b867af7fd | |||
| 0df3be8630 | |||
| 542326af8f | |||
| ea5052e69e | |||
| 2dd96b2269 | |||
| 627152e2a9 | |||
| f01c93ed58 | |||
| 6fe61ed58a | |||
| 43347f671c | |||
| 0b67fa65f2 | |||
| 65b3a36984 | |||
| b08cf75f0b | |||
| 0cc21e5ca2 | |||
| 48f9a92cc3 | |||
| 939882ef68 | |||
| 52084cf0ae | |||
| f06f654191 | |||
| 356d20542e | |||
| 31ea4cfe80 | |||
| 1e89ee4e50 | |||
| 6fccbf036c | |||
| 41d206e354 | |||
| 23880ac6c1 | |||
| 4439cbf553 | |||
| f506f1b830 | |||
| feb1ea6502 | |||
| fea80b4919 | |||
| 373bb8d74c | |||
| 3ddefd78ba | |||
| d62e4da163 | |||
| 8c60863e11 | |||
| d5be8c8989 | |||
| 255b30e88a | |||
| d2dd124be0 | |||
| 1053b30a6d | |||
| e7c1073e13 | |||
| 0480c6a4af | |||
| c70a49c0f3 | |||
| 7840fd481a | |||
| 2a8b491c95 | |||
| 39c4344047 | |||
| cdb58e4ebd | |||
| 972325fb6d | |||
| 933b6bedc9 | |||
| 2db8a5d00a | |||
| be043ea349 | |||
| e531abf31b | |||
| a6af680e59 | |||
| 8292334c9b | |||
| f20c5a1d3c | |||
| d1e2ec0309 | |||
| fe91cae8bc | |||
| 7bb30bc4a8 | |||
| 2d41d5903b | |||
| df672ffaf5 | |||
| cb100623fb | |||
| 30ef7270b3 | |||
| 91694a69eb | |||
| cb07bcf0db | |||
| a31e384409 | |||
| 4829c6d028 | |||
| ccf6a3fb97 | |||
| 2005814fca | |||
| 7319665bda | |||
| d74074a21b | |||
| 113115f58c | |||
| e84799283d | |||
| 71272ed2ec | |||
| 6787c338ac | |||
| 774a44ac7e | |||
| 29cdd358cc | |||
| b9b1bd5e58 | |||
| 59814aaeb0 | |||
| fd52b3c23b | |||
| 6e75a41ee6 | |||
| 84266aef2c | |||
| 40a7f8ea50 | |||
| 7c4fcdd9cb | |||
| 92e87852c1 | |||
| 73c4da2b21 | |||
| 9f4da7e890 | |||
| 8b23457373 | |||
| ab2fd7c749 | |||
| 040a6ddf3a | |||
| 55afe0912f | |||
| ee48127094 | |||
| 445576d568 | |||
| 8f1d40892e | |||
| 766db9660c | |||
| 68665ec1f2 | |||
| b400964aa1 | |||
| 317530cfa3 | |||
| e8fba23b59 | |||
| ef749e695e | |||
| 712ef33d6b | |||
| 0441b7dbc3 | |||
| 3ee0dcbacd | |||
| 57411b962f | |||
| 4eee00d95e | |||
| 957a08962f | |||
| 21c82f5fe1 | |||
| 27964993f6 | |||
| 14e296e1f9 | |||
| 23c0ff934f | |||
| c64ef1e20e | |||
| ed97619c6c | |||
| 924ec592b1 | |||
| 669c581701 | |||
| e97ae3d537 | |||
| 08800b68f4 | |||
| a59db6529c | |||
| 02a54ceea6 | |||
| f0a7c547e8 | |||
| ecfb343690 | |||
| c65472c9b3 | |||
| c42864d35e | |||
| b02ce599e6 | |||
| 1ae5495b91 | |||
| c4fbb8c199 | |||
| 313872dacc | |||
| ef15136a3b | |||
| 4342c8d761 | |||
| 644744ac9e | |||
| cbc03d1e45 | |||
| 7f56192b97 | |||
| 6590f3b741 | |||
| c0bbb669e0 | |||
| 63014adfef | |||
| 1ad055c8c8 | |||
| 9b558564e9 | |||
| 476e66d027 | |||
| fc11d81673 | |||
| 629754a353 | |||
| 147dbee051 | |||
| 7204c3c25d | |||
| b412241d25 | |||
| f9883afd61 | |||
| 181f811f18 | |||
| 2f0bd3c085 | |||
| a9d8332766 | |||
| f5036171cf | |||
| cdc8b8e473 | |||
| ab404c5452 | |||
| 0585f9d667 | |||
| 19225c7dd3 | |||
| 8c1844b1c0 | |||
| af63d86e24 | |||
| 1f2fd3ad96 | |||
| f41fdcdb98 | |||
| f78a9b4220 | |||
| 06b3ce58ed | |||
| 7c70d8b1c2 | |||
| 2b1e032a9b | |||
| 4f5d6a2fd5 | |||
| c3b90aa492 | |||
| bb2daac007 | |||
| bc2449c3f9 | |||
| 0bf50de77a | |||
| 473bc32b71 | |||
| e5e143dcf8 | |||
| 2de08746ac | |||
| ae6833b4d5 | |||
| f1fe5f6a71 | |||
| 5054d0615e | |||
| 4f5007ea64 | |||
| 233f6ed13b | |||
| f15b883471 | |||
| 312d5f0121 | |||
| 75a1657c49 | |||
| 667d92100e | |||
| a88ddbac2c | |||
| 537268ed63 | |||
| 8ff4bc8cff | |||
| c310b14421 | |||
| b025209c31 | |||
| 656b262648 | |||
| a063ce3c45 | |||
| c554372ba4 | |||
| c1769b9ba2 | |||
| 04c9d92b4a | |||
| 0babef5a09 | |||
| cd52407723 | |||
| 68c0aa7fb9 | |||
| f1622c40a4 | |||
| 688e7316eb | |||
| ef5ec47797 | |||
| 147ad4a773 | |||
| 9752145b49 | |||
| 662b862d2f | |||
| 6d469509a4 | |||
| 0dfbb8a5ae | |||
| 1e12ecda70 | |||
| 035087987c | |||
| 18422c4193 | |||
| f1f9fe27a9 | |||
| 10667e14e2 | |||
| b04c7efdf4 | |||
| 0119731360 | |||
| 8f337684d5 | |||
| dae93552f0 | |||
| 351bbb240f | |||
| 5716de2e6e | |||
| 14295d59d1 | |||
| df0849473c | |||
| 9736706894 | |||
| 12343a5c31 | |||
| a7f046a617 | |||
| 67bf796f1e | |||
| 22d632abc3 | |||
| 25094c1ee6 | |||
| 5b71ad0456 | |||
| 9146ba996f | |||
| 42900787e1 | |||
| ba10c10a94 | |||
| 3f37e9ca6f | |||
| c5ea86b474 | |||
| 76720092a5 | |||
| 7a75c80b27 | |||
| b2dcbebb5b | |||
| aadc81279a | |||
| febd6dd18f | |||
| 1236b35aaf | |||
| 41a9a25823 | |||
| 55ae81524d | |||
| a9cf5dd6f2 | |||
| 1e45692ba4 | |||
| 997cff63a8 | |||
| 5db513cc55 | |||
| 4a7280be5e | |||
| 59826d492f | |||
| 85c2a5fd75 | |||
| 33dd3342e8 | |||
| 94fc50f793 | |||
| 1e79f4a9a5 | |||
| f56825c526 | |||
| d7c0f9dee8 | |||
| a71c59beae | |||
| 5f729433f6 | |||
| a1d37475c9 | |||
| 9275dfce70 | |||
| ff9afdae3e | |||
| 12a2dcf484 | |||
| c3f5f69c2a | |||
| 1320e7ac2f | |||
| ae6b0dd753 | |||
| e43830c08e | |||
| 4a5cdbcfb2 | |||
| 9b599644d9 | |||
| cab93600dd | |||
| 0e5e4ca7ea | |||
| a293134b5e | |||
| 3831860943 | |||
| 1f8214e658 | |||
| 58d2e2ece2 | |||
| 424f416fdd | |||
| 95c12a0b8e | |||
| 45d42c8c31 | |||
| 5b94095c78 | |||
| 605ad0a01c | |||
| 10b8dc3595 | |||
| 432f6aeae6 | |||
| 6702ff3c55 | |||
| 8f205f13d8 | |||
| 22a133b182 | |||
| bc61175e79 | |||
| 874e344f91 | |||
| f832e31c7b | |||
| 4cdd793e0c | |||
| 0d11cb603f | |||
| 1e197ae66c | |||
| 2a88103b5f | |||
| 49caea416b | |||
| 5bfe270f24 | |||
| e8f10f2b45 | |||
| 834986410c | |||
| deffbcf231 | |||
| 2d720a8349 | |||
| 182d45b7ea | |||
| 3cd68842bf | |||
| 861ada351e | |||
| e32d863daa | |||
| 81fc652dc1 | |||
| b72deb1a0e | |||
| cab38f00c2 | |||
| 137594ccee | |||
| 449f7fb2a3 | |||
| 2a5bea7e4e | |||
| ea309caa22 | |||
| 89bc58ab29 | |||
| 2d754c93a7 | |||
| 1017d4cda3 | |||
| 68dab26be5 | |||
| 8eb0ec9f7a | |||
| 1da47f62fc | |||
| 70939c4b9c | |||
| 491ad744ea | |||
| a1565c7fff | |||
| 496dbfb2f0 | |||
| 0e44dac208 | |||
| 2b808933d2 | |||
| ba0f682e3a | |||
| ef49652415 | |||
| 8e30ee1192 | |||
| 74a676026f | |||
| af93c2ee49 | |||
| 6b05d253a7 | |||
| 797b2a5085 | |||
| b898cf4fde | |||
| 1c17432f70 | |||
| a6c96df51f | |||
| d7abe73753 | |||
| 1b84063dd3 | |||
| ed5b7fe3e6 | |||
| 699ac83729 | |||
| 1e1ce492e6 | |||
| 7afb9f1fc8 | |||
| 7bfe418c3e | |||
| 94c1388b6a | |||
| 90f53cba31 | |||
| a675fca607 | |||
| bf58171f64 | |||
| e619bd4acc | |||
| 5f5b7ffb66 | |||
| 2216e75cab | |||
| a61d73f48a | |||
| ecdca38d9e | |||
| a34bc7cc89 | |||
| d12a0be66c | |||
| 890421e00e | |||
| dc57886b68 | |||
| 832fb023e8 | |||
| af8c171b1a | |||
| 58264f8b57 | |||
| eb7d614566 | |||
| c11cab858d | |||
| 18438b17a5 | |||
| f2464df96f | |||
| 5ee0a2fea2 | |||
| 1296505d01 | |||
| 332b70a27d | |||
| c4d5d52b96 | |||
| 7a5554202e | |||
| df2c426096 | |||
| b33cdc581b | |||
| 3cd213b9bf | |||
| aebb37b516 | |||
| d016c80ba5 | |||
| 882f1c4d1a | |||
| 3ffdf8d281 | |||
| c183243711 | |||
| eeb2c953ad | |||
| bfb2f3015a | |||
| 9c54f53613 | |||
| 257c7af2f3 | |||
| 4ed256814a | |||
| 1f8ea32388 | |||
| 69403e7967 | |||
| 7cc4c76c54 | |||
| cf74a81d07 | |||
| 417d151f2c | |||
| ff42b7f61a | |||
| 658c2a0a78 | |||
| 90d6899577 | |||
| 5db0e53c0c | |||
| 7dea4f36fb | |||
| 6fea6393c6 | |||
| 53f063fe16 | |||
| 6ee72b9c32 | |||
| 5faefa7997 | |||
| b0726cd31a | |||
| 64f5fa8dc3 | |||
| ad300f5eae | |||
| 7331160e22 | |||
| 6af82e5ae5 | |||
| 9b2347171f | |||
| c60629c17d | |||
| 353e18e8e3 | |||
| f069df285d | |||
| 6c5f8dffa6 | |||
| 4a77e23b54 | |||
| 942e53b59b | |||
| 21a6a256b9 | |||
| 99567d3a53 | |||
| eddad6b690 | |||
| d02a8cbca1 | |||
| 3b079aa29a | |||
| df5307dd32 | |||
| 65891508e0 | |||
| b5f4e40c3e | |||
| a427730acd | |||
| d7639a1ab6 | |||
| 01a140ea29 | |||
| 6e0ff9b6a0 | |||
| fb14eeeb1e | |||
| 0c701d9d95 | |||
| f1ceb1c95a | |||
| 6bd41a07a1 | |||
| 2b78bb6e79 | |||
| 7e5d5ddafe | |||
| 150c25c81a | |||
| 95319bdaca | |||
| d982835b50 | |||
| 6f040aa0b5 | |||
| 080ecece66 | |||
| 31ece2c26e | |||
| 9a20f4b935 | |||
| ea61fd22f5 | |||
| c77f8f9f41 | |||
| ad758c51c2 | |||
| 8ac7fd14ec | |||
| ed7c5e97cb | |||
| fb928a15a6 | |||
| f60155e7b8 | |||
| 7c28b1a6a6 | |||
| a300f4662e | |||
| 354ef0fc58 | |||
| e624b238b2 | |||
| 369fe832ea | |||
| 4a7552fdab | |||
| aa57a17af6 | |||
| 926c6a55ce | |||
| 3d005e8e87 | |||
| 3ff376774f | |||
| e16c05385f | |||
| 6e8825cdd5 | |||
| 1c19895ce7 | |||
| e62a4b065a | |||
| ba363285a7 | |||
| 679c932697 | |||
| 581ec70bf3 | |||
| 4d2700ab1c | |||
| b365136639 | |||
| f23153e1ac | |||
| 26cb931dcf | |||
| 42d2190d17 | |||
| 63ad80200e | |||
| 68e9c63693 | |||
| 542ff88d3b | |||
| bf7f73e472 | |||
| c9f195be90 | |||
| 715da30a72 | |||
| 4e9f2aaadd | |||
| 71cbb037ce | |||
| 35ea9070e4 | |||
| 67c5ff4939 | |||
| 4e8a6f4098 | |||
| 66a4b1a9f1 | |||
| 9e43972313 | |||
| 4a8bb75851 | |||
| 80dce3b65a | |||
| 056534fb41 | |||
| e444b82683 | |||
| b59115e27c | |||
| d9e4f686fb | |||
| 2cd224af98 | |||
| 4af1ca65ed | |||
| a50141ac8a | |||
| f11b36cdb1 | |||
| f30af1c4ed | |||
| 45def31826 | |||
| a22afce820 | |||
| af874bebfd | |||
| 7cdb651538 | |||
| 5e1752bcbc | |||
| eb295cb19c | |||
| ace42226b6 | |||
| 5e1b4b4e6a | |||
| f009fa9e47 | |||
| f08c00557d | |||
| a0e0d95775 | |||
| a4acab983d | |||
| 5237a7977d | |||
| eb285bc1ac | |||
| 7d97cd25ab | |||
| 55f4a99824 | |||
| 34373836b9 | |||
| 1509891ec0 | |||
| 877ef7d78f | |||
| 8f26a24f78 | |||
| 6abd4bae58 | |||
| f8844750f5 | |||
| de984d44ac | |||
| babcefeb23 | |||
| 71a55290ab | |||
| 8ef0b88633 | |||
| f9c3415aa7 | |||
| deb7d5914f | |||
| 469e4394bd | |||
| 1bcf9dda0a | |||
| 02fafde09d | |||
| de5e1b3452 | |||
| 4381db691b | |||
| bd879262c2 | |||
| da88b4c475 | |||
| 276a18cddd | |||
| 6eb54e55a5 | |||
| e7fa330215 | |||
| 27ed160a40 | |||
| 180b614c86 | |||
| e2e6b64632 | |||
| be46aacbe5 | |||
| 3bd46f3415 | |||
| 7e6e2960bd | |||
| 9df4377450 | |||
| 294ab035f0 | |||
| f96554e271 | |||
| 2c1fdbe55b | |||
| b5bce29514 | |||
| 97557b85d9 | |||
| 8a5cc70d9b | |||
| d5075891b2 | |||
| 4df778f4e9 | |||
| 3cda66f1f3 | |||
| e0991d9376 | |||
| 8c94742070 | |||
| 419b2b02bc | |||
| b4998527dd | |||
| 8ac8598b20 | |||
| f7ddf8b024 | |||
| 18f1563829 | |||
| 20ba35c0a7 | |||
| de4764c1c7 | |||
| 31bb8a3ac5 | |||
| e0156abe7c | |||
| 7d02e92843 | |||
| 80aef75ea5 | |||
| c940062787 | |||
| 4b3b9ad140 | |||
| 1bb2efc346 | |||
| 0b699b45b1 | |||
| 3c0487db81 | |||
| f62869e4df | |||
| fce459f612 | |||
| 6a003114db | |||
| 39ed5cab0d | |||
| 4b67c8f4bb | |||
| 65604add65 | |||
| 3e69f65d1c | |||
| 0b26dbbc9e | |||
| 152d943f3d | |||
| 7fffd1d318 | |||
| 5d875341f4 | |||
| 61dbd4c4c2 | |||
| 5f42011c7b | |||
| 7e56174ba9 | |||
| 0a83b3f58c | |||
| 71fec23311 | |||
| 2ba3035a13 | |||
| 7a653a8e1b | |||
| a93b32fb53 | |||
| d82cc350c0 | |||
| 5997a7d48a | |||
| 7641fb6712 | |||
| dfaf9b9d43 | |||
| 6147b0eec0 | |||
| 2eefef3649 | |||
| 1905a67e6c | |||
| 38ab18f6fb | |||
| ddcc20c8a7 | |||
| f3c6763058 | |||
| 91a11d2e74 | |||
| fb880481a4 | |||
| 9e6703f02f | |||
| da5435d1cb | |||
| db0726364b | |||
| 944b2de852 | |||
| 53927502af | |||
| 828d8ea051 | |||
| f2e345b39f | |||
| 6f625a899c | |||
| 28bc8c3bf3 | |||
| ef30949943 | |||
| 4f888bc418 | |||
| 34caf6967e | |||
| a728c783d9 | |||
| 934d232653 | |||
| 4fbc7771c9 | |||
| 571ab422bf | |||
| 9592f4de6e | |||
| c126d99fd0 | |||
| 11c8a272ec | |||
| f7170b8c50 | |||
| 9ce28f4cb7 | |||
| 522a457d98 | |||
| 9e9ffaa27b | |||
| 9ab4a8ab6e | |||
| 5c784081c2 | |||
| 9c84c0afe9 | |||
| accc5e8b10 | |||
| 1e0c71a411 | |||
| 663687884b | |||
| ade2bdcafd | |||
| 9e01e64f63 | |||
| 7cc0fd879d | |||
| 42bd835800 | |||
| ef7b5cb8e7 | |||
| 2651d79b63 | |||
| ddc12c3f71 | |||
| 9c3c2e9fa7 | |||
| 564f9ac38d | |||
| 1b49bd0843 | |||
| 831d79d912 | |||
| d61f809cca | |||
| 130176fd7e | |||
| 1ea9be9877 | |||
| e3b56aa05b | |||
| 4f4195c88a | |||
| 1d9a8af174 | |||
| 8b1e7e1fa9 | |||
| eeb0b62bfa | |||
| 0a114bbe4a | |||
| 474458e4c3 | |||
| c6b73631d8 | |||
| bce318c48e | |||
| 9e4ac1c835 | |||
| 53933db077 | |||
| 4156d8e908 | |||
| 6491d83085 | |||
| 6259d30e2b | |||
| 3ee7a0dc16 | |||
| 43d8723e35 | |||
| d59ab17ac5 | |||
| d26cda097f | |||
| 6daa58b596 | |||
| d0920d9eb9 | |||
| fbd353501b | |||
| 9876aa64e0 | |||
| b8ccf7b3d4 | |||
| c15b5914b2 | |||
| 73aebb8890 | |||
| f9270710be | |||
| 0b63abf5b4 | |||
| 51ae4af83e | |||
| 4832982988 | |||
| b4d49715dc | |||
| 0de7b4eb39 | |||
| 3e88451ea8 | |||
| 5468fde492 | |||
| f17e13cad0 | |||
| f511449273 | |||
| bbe65e212a | |||
| ab9dbbab70 | |||
| 51a7739436 | |||
| 4cfe4153b1 | |||
| af6b0cb189 | |||
| df2a069371 | |||
| 5ebd0df15f | |||
| 66a34bcb89 | |||
| acad1d4175 | |||
| c8a096537c | |||
| 716fade52a | |||
| 3b9312d9ac | |||
| f87d072c79 | |||
| b61724019a | |||
| 3ffdb1ee56 | |||
| 5fbf280e4a | |||
| f787e0fa1d | |||
| 0d33b92d24 | |||
| 8e5d0c66db | |||
| ba1d4e97bb | |||
| 6e8ac60399 | |||
| f8bd80109c | |||
| de89d349ad | |||
| dbc9beaa19 | |||
| 1f171c4ed1 | |||
| 2e03888505 | |||
| ab5eafbe68 | |||
| 73014a33fe | |||
| 7bdbe0ef77 | |||
| d4dbad4649 | |||
| 24b23bbb5a | |||
| abab44a02b | |||
| b9c07e644f | |||
| ce9c3b4ef8 | |||
| 13862bd561 | |||
| 856d38df49 | |||
| 27a5e13107 | |||
| a71c24f803 | |||
| 758ec52b91 | |||
| 96418bb9f1 | |||
| f750d94b2d | |||
| 6eb9695e1e | |||
| 33bbad8053 | |||
| 3ea34461b2 | |||
| b6a202b721 | |||
| 4d8cb022c5 | |||
| 3046318de5 | |||
| c351598f13 | |||
| ab9c47e4bc | |||
| 20e5e7cdbd | |||
| d0dd95c198 | |||
| 28d554af82 | |||
| 02084be583 | |||
| e117d08b2c | |||
| 58783170cd | |||
| 9ba2426c02 | |||
| 2cbaa7b03d | |||
| 836a0f3a73 | |||
| e9977f551f | |||
| 78abe362cd | |||
| 47c2922d55 | |||
| 690f3fecbb | |||
| d9242db7b3 | |||
| a9b5e22b37 | |||
| 7b8f1704dc | |||
| de88ddf42b | |||
| b1e707c346 | |||
| 36b7b3a7cd | |||
| d44349d612 | |||
| 53919be913 | |||
| 8dd7d04fff | |||
| 384f6d9a31 | |||
| d51195a537 | |||
| 10bedad9bf | |||
| 4027d3c07f | |||
| c11b4131bc | |||
| ec78d3b83b | |||
| acf61c24bd | |||
| 338183e647 | |||
| 59e0de85e3 | |||
| 2e6941c23f | |||
| e1c33aa87b | |||
| 70d8cede9b | |||
| 7587bbd4bc | |||
| 668f0498ed | |||
| 32ff331744 | |||
| bc90463893 | |||
| 7fb486d8d2 | |||
| 538df0e67c | |||
| 60bb93170e | |||
| 766370221b | |||
| 8007e6d354 | |||
| 443053b927 | |||
| b6000bc1a8 | |||
| 8bdf8d42d9 | |||
| c084396f8f | |||
| b29877554c | |||
| a2d17f6f3f | |||
| 54018aec90 | |||
| 2699f9bcf6 | |||
| 094890622a | |||
| bee4ec5ddf | |||
| 29f533b170 | |||
| 296c2a7b5b | |||
| c4decce7f0 | |||
| a396f507f8 | |||
| eb96fd1b97 | |||
| 8cc7d80121 | |||
| d59139202d | |||
| a3cd4a55de | |||
| 0cb7388ee0 | |||
| 2700e9b326 | |||
| d36d5b2980 | |||
| 028437549d | |||
| 1f17551bf4 | |||
| cd301c9df2 | |||
| ce43aab4cd | |||
| 86d1ab00e0 | |||
| 93b2a52f34 | |||
| d3da830ef8 | |||
| ec4deb87c6 | |||
| d832a0a186 | |||
| 65800e17a5 | |||
| 9c5dd452dd | |||
| 78940413a0 | |||
| cc2f459f26 | |||
| d1c98eb22a | |||
| 1fe9a0ee5a | |||
| 80a87f963a | |||
| 2c0051b083 | |||
| 4a938170e1 | |||
| f3a27c4fcb | |||
| f43b11fd6a | |||
| 93d382c416 | |||
| 48e4060d62 | |||
| bbc7ef100c | |||
| c22468c943 | |||
| 7d538ea080 | |||
| aad1ff95be | |||
| 72f0fb6892 | |||
| a0baad4942 | |||
| 5e40d60e34 | |||
| 314f787042 | |||
| 7f340da0ec | |||
| acafa2bcad | |||
| 404d8da1a3 | |||
| 26be7840b4 | |||
| 520b84f967 | |||
| e7f6a8a476 | |||
| 0f3ef4b35c | |||
| 60d88693ec | |||
| ff6e2b6d31 | |||
| bc52ad7bf2 | |||
| daa24de171 | |||
| 68f0e25227 | |||
| 320f2bea7b | |||
| 666692e341 | |||
| 304cc33b76 | |||
| e0f4aca336 | |||
| ccdff5baef | |||
| 16fe056c99 | |||
| fb5c155f7e | |||
| eccbb0df7a | |||
| 0bcfcb4ea4 | |||
| b6b4d5c387 | |||
| bb7bfe95e5 | |||
| ac1e5a08d8 | |||
| 4a05f0fd05 | |||
| f1dff4d0b7 | |||
| 96343603cd | |||
| 9dccab915d | |||
| 0decf928f0 | |||
| 44faef3027 | |||
| 52a590334c | |||
| 8ea9709305 | |||
| 751c7e05f9 | |||
| ebe0aa27e4 | |||
| 4ef7f0dd24 | |||
| 4779c036f5 | |||
| 1480a4e270 | |||
| 6a167a4b0f | |||
| 9b43f57dfa | |||
| fc74840b55 | |||
| f408b1bb11 | |||
| 7a3e16b92f | |||
| 939045d606 | |||
| b3ee80e495 | |||
| 1c17a76b80 | |||
| 08a55721bf | |||
| 42991bfa2c | |||
| 46897689d3 | |||
| 9b3acf7162 | |||
| 4436e3ba69 | |||
| 78b3f21e7a | |||
| e2ae0a7a4f | |||
| 5ed8f0baa5 | |||
| f1d4e48c59 | |||
| 48ac431134 | |||
| d6a27c04b9 | |||
| 388e9cec09 | |||
| b01f70176b | |||
| e7b4a5db61 | |||
| d5a1d28779 | |||
| e0da4159ae | |||
| 0eef766ea1 | |||
| aebd53363c | |||
| f18bb1c780 | |||
| eecb7c0622 | |||
| 84c0b46266 | |||
| fb030b3520 | |||
| 42aac81fd8 | |||
| 09175d2b6b | |||
| 46f64f75c7 | |||
| 9b5425de14 | |||
| 7b1135ecd4 | |||
| 2ca63ae324 | |||
| 5b02323487 | |||
| cf99eef9c9 | |||
| c54e05d220 | |||
| a651853534 | |||
| a1a81b812a | |||
| e74d0ef4e2 | |||
| ca4caec819 | |||
| 900c12d1d0 | |||
| 4d61701790 | |||
| 4fd0e734ea | |||
| b4d1ba07a6 | |||
| 6974c511ea | |||
| d30dd7450f | |||
| f877e653e9 | |||
| 699ffc8b50 | |||
| 135b81bbb4 | |||
| d9f5c2d16e | |||
| 2e0f04ce93 | |||
| 8ebb084f0f | |||
| f2bc07458d | |||
| b4daca860f | |||
| ac6919680a | |||
| c6749f2d5c | |||
| 47fd936306 | |||
| e2d772dd3a | |||
| afd7679028 | |||
| da668a7905 | |||
| 78dd5511c7 | |||
| f4171402b7 | |||
| 68d227bf72 | |||
| e842780a31 | |||
| 2ee8fe532d | |||
| decef2ca9e | |||
| f1bf1275b8 | |||
| b3dc9d1de1 | |||
| 43e2b4d85f | |||
| d2c6c5b14a | |||
| 8e895bb78d | |||
| 89ae7cfca2 | |||
| d0ca602f3f | |||
| 147439ad34 | |||
| 8ad26c0426 | |||
| 1a3eb0f209 | |||
| acd2c514ce | |||
| fccff0c03a | |||
| 7cf8483f9a | |||
| 63bad22ac4 | |||
| b009f06375 | |||
| 8aa5ebf621 | |||
| 53ac770772 | |||
| fbfe47528b | |||
| 71443f7def | |||
| a1b1165039 | |||
| c060243201 | |||
| 93f84e2b65 | |||
| 9cd971a53f | |||
| b22b819683 | |||
| 8779ac3ec3 | |||
| 16ec935feb | |||
| e59d229097 | |||
| 9028d9a339 | |||
| 6999a1b5e4 | |||
| 7ef6d33ea9 | |||
| 3824f19ce5 | |||
| 930268ed0d | |||
| cb0a3fdb6e | |||
| 4c0a2b1d3d | |||
| 6fd34dee5a | |||
| 1c56c4dfe5 | |||
| 53321160c4 | |||
| 5b29d3bb72 | |||
| 4796a3116a | |||
| 6183569dc2 | |||
| 3296a2addb | |||
| 235cb0c574 | |||
| 570fbd9a00 | |||
| e205b521fd | |||
| ce15754575 | |||
| 18085bae70 | |||
| 61536b42c9 | |||
| 532f166b22 | |||
| c1d3a78316 | |||
| e524d9694d | |||
| 1efa889913 | |||
| c73788da24 | |||
| 5ec277b2ed | |||
| e327e1bc9c | |||
| e38fbf814b | |||
| 67c946f24a | |||
| 2647cefdcc | |||
| c1e5d2a781 | |||
| 9cf11ff45d | |||
| d2272ec75e | |||
| 37c5c1dc98 | |||
| 156e1a00d3 | |||
| 3aa9a2f2c0 | |||
| e1f5b57fd3 | |||
| cf757b6c7b | |||
| bd2da8d632 | |||
| 01b7e387eb | |||
| 60bf6b1f70 | |||
| 7839c6294c | |||
| f8b0d788a2 | |||
| 3e0ee584aa | |||
| 698e4a0af4 | |||
| 20cadfad29 | |||
| 2b93362a57 | |||
| 5476f297e1 | |||
| b79fbe2123 | |||
| d9a76fdd9a | |||
| 721a69f2b1 | |||
| a49b3e67d0 | |||
| 297600ca6d | |||
| 15019051c0 | |||
| 2b7e8bf449 | |||
| 928798dc16 | |||
| 1a01ec17d6 | |||
| 69da4d749b | |||
| b1fc95b1d9 | |||
| 0b7f104c95 | |||
| 912974cb80 | |||
| 9bbb8ef31c | |||
| e01f53a58c | |||
| 82c69a03ef | |||
| f8aa79aaf5 | |||
| 700ae79b93 | |||
| 8dd8ab6366 | |||
| 28d19a99e1 | |||
| 6627de6460 | |||
| 795d452493 | |||
| 2d7f52972d | |||
| 5b7926c590 | |||
| 1f6d0b143c | |||
| 8558af8189 | |||
| 28ceb0bed2 | |||
| 41523b03d1 | |||
| 4a46207fa5 | |||
| dfb9ac91e9 | |||
| 6229c0020c | |||
| 8db1bf9052 | |||
| 2740c5db23 | |||
| 512e6de39b | |||
| e3c328c7e3 | |||
| 9eb5ea599e | |||
| 929032d598 | |||
| 09fb42291d | |||
| e6665a8305 | |||
| a785d83791 | |||
| 08a64f0dc0 | |||
| 0babad837d | |||
| fb1f70f5de | |||
| d4dd1b7ba0 | |||
| 82c921d739 | |||
| 180a570f99 | |||
| 9960a7a7e4 | |||
| 2164d08c3c | |||
| 4b2d0d1a67 | |||
| d0341d191b | |||
| 10237a2d90 | |||
| 59390ddaa1 | |||
| 312c94f386 | |||
| d697677fab | |||
| bf484b5518 | |||
| 74b530259d | |||
| 4052c3d101 | |||
| 86262333a4 | |||
| 3419b49381 | |||
| ec5725d8de | |||
| 9df98352a8 | |||
| c0c5ad21b6 | |||
| 4a23da6ce1 | |||
| 6d1e5243d8 | |||
| c52a31384e | |||
| 36447eb1e3 | |||
| 811dfee42c | |||
| b075bb9f4e | |||
| 00919f3232 | |||
| 6dcd52deb5 | |||
| edc70e9acb | |||
| 4ad12b6862 | |||
| d63f3b6da1 | |||
| 84c70a0905 | |||
| 8f65a7ac19 | |||
| c78262be91 | |||
| cb51238bfc | |||
| 87f873c8b6 | |||
| a37528b377 | |||
| 51a58182ee | |||
| cc4b768f54 | |||
| b016be6eb5 | |||
| 881d73d4ab | |||
| 8859e352f9 | |||
| 5b0fc5b97b | |||
| 76cc59acab | |||
| e792088ceb | |||
| 1dc70d5a8d | |||
| e876a0f6bd | |||
| 50450de3e4 | |||
| c8abc84c3c | |||
| 1f3996032c | |||
| b868cfdca9 | |||
| d51944e6a5 | |||
| 4419ba55e8 | |||
| 9e8ae54821 | |||
| 4ed266780a | |||
| 46886b4dcc | |||
| 1e2531f0b1 | |||
| 0e43fd4d00 | |||
| 10448bcc3d | |||
| 4f1c2788b8 | |||
| dbaa7b5e67 | |||
| 6211b7733d | |||
| 0d6ea0845e | |||
| b8e10fb34b | |||
| b9c6e595d7 | |||
| 7d701d3e9c | |||
| 92d9c3c92b | |||
| 7007977891 | |||
| 9f5d24bbc9 | |||
| 2834a83eec | |||
| eb82473395 | |||
| 4a33d3227e | |||
| 235456e18e | |||
| 1f9e532fbc | |||
| 8bc2d3184a | |||
| 9ef54d1218 | |||
| 7e48cb97b0 | |||
| a226f0b58c | |||
| 65fd47a082 | |||
| 600b7d1d54 | |||
| b8f4d4877e | |||
| 6a114e1275 | |||
| 5d3d8640e3 | |||
| f09d2d22eb | |||
| 94ccd8f8b6 | |||
| c96ce890d6 | |||
| de55be397b | |||
| 1420714cae | |||
| b15305bc69 | |||
| db25b111e0 | |||
| eeea9932ed | |||
| c710e9a54d | |||
| 62613e7da1 | |||
| 946b597471 | |||
| 691c55bedd | |||
| 8387969467 | |||
| 90d21375c8 | |||
| 86daf2a9dc | |||
| 90473957cb | |||
| 3549c00141 | |||
| 1c1d13545b | |||
| f1b3db89fb | |||
| 8c77baca6f | |||
| 36a40d97a7 | |||
| 1eb9b40607 | |||
| 05c10e3f57 | |||
| 0cf3325655 | |||
| 48525de714 | |||
| 7e15722eab | |||
| 719c209c7b | |||
| d05ad44b84 | |||
| b352c97479 | |||
| 063085a6bb | |||
| b4bca16109 | |||
| 03770c52fe | |||
| 10fe5cdd5d | |||
| 57d459b917 | |||
| fe26594f12 | |||
| 0d8065fc1f | |||
| a3cdae1e94 | |||
| 29d77b649b | |||
| 9e190cee81 | |||
| 687bfd0f17 | |||
| 7d7df4f749 | |||
| 958dede319 | |||
| 76e814944d | |||
| fbc1d75e9a | |||
| b3c7ce05dc | |||
| feea881e09 | |||
| b978bc4876 | |||
| f84181e7a5 | |||
| 313ae0f86c | |||
| a39c018359 | |||
| a09f57d908 | |||
| 596828cf78 | |||
| 44843aa9cd | |||
| 5f930cc4d1 | |||
| 7defad5d95 | |||
| 707af8a295 | |||
| e0fb9ffbb0 | |||
| d614de6f5e | |||
| 86b94b4723 | |||
| 5070300050 | |||
| 1919546441 | |||
| 1c3cd8d44b | |||
| 292296266f | |||
| a3e8848bc8 | |||
| ced146fc63 | |||
| 6ed79f6a0d | |||
| 15e4d86e92 | |||
| 5a29a7d2a3 | |||
| 034740ce46 | |||
| a2847246e6 | |||
| 04479ad660 | |||
| 35d2fff593 | |||
| 2b93fe9a30 | |||
| 5c33a2bd5c | |||
| a28f113105 | |||
| eb7976a2ef | |||
| 15db1c0c30 | |||
| 2b83c95869 | |||
| 273d5596d7 | |||
| b423dab152 | |||
| 1b104bcf29 | |||
| 5cad9a8c44 | |||
| ec8a475a2c | |||
| e656cb8118 | |||
| 7f2a0b6630 | |||
| f9bf40a771 | |||
| 96360619e1 | |||
| 4cefc21819 | |||
| 192a56ee15 | |||
| cf16472dd0 | |||
| b2fb2d5821 | |||
| c939eda7bb | |||
| 428e059895 | |||
| 1b4ea2e9c6 | |||
| d60bfa238f | |||
| cc98f7da36 | |||
| 87cdc22990 | |||
| 60f6ea3252 | |||
| 86cffae001 | |||
| 77cec0e338 | |||
| ee85bb9a1b | |||
| bf0b85afd1 | |||
| 5473696491 | |||
| 0bc59a82ba | |||
| a8430d8ecf | |||
| 9672b2ec23 | |||
| 60447f073f | |||
| 62329c104c | |||
| 536884bb46 | |||
| efb213fb9f | |||
| 02b43c9375 | |||
| 9a2679efaa | |||
| 00a396c3e7 | |||
| b4272c306d | |||
| b876605e93 | |||
| 7f896a9f40 | |||
| a96874ac55 | |||
| 1f8d3ed911 | |||
| 56be0ef4be | |||
| 67079545b3 | |||
| 54b8811843 | |||
| 0bbfe20089 | |||
| 667822ca08 | |||
| 051b8c4b63 | |||
| c2f5e7eb45 | |||
| 45ebf7b5c6 | |||
| 2ccdcf8a92 | |||
| 88d9fd42c4 | |||
| 6d81636d1e | |||
| 22fb456d13 | |||
| 62c9666013 | |||
| e1b2f940ad | |||
| d2c0ec12f3 | |||
| 61bdbdb5d6 | |||
| a28ca46460 | |||
| 719179c1c2 | |||
| 1851e0c02d | |||
| 5d7ae16b4a | |||
| 3bb8cb52f8 | |||
| 3d4d3b000e | |||
| e3e97db101 | |||
| 057b8d9e74 | |||
| 003e42a2ae | |||
| baf932dd8b | |||
| e2acab67e1 | |||
| 095b171db3 | |||
| 9d36d7119b | |||
| 507bcbd332 | |||
| 71a15b7202 | |||
| 1718a123e8 | |||
| b5c1046dca | |||
| 608481df38 | |||
| 4aab5da7ae | |||
| 79650cf318 | |||
| 170544f68d | |||
| 9bc26b0068 | |||
| 9765319027 | |||
| 3b1c7dc5e1 | |||
| 2a50d0856b | |||
| 23c0fcada6 | |||
| aa499eab61 | |||
| 985324ac12 | |||
| 3c89907403 | |||
| 953487bb65 | |||
| 677891d0ff | |||
| 8d2a7b00dc | |||
| d4d4f3c082 | |||
| c26e8a69ca | |||
| 1c251a308a | |||
| c8015898ff | |||
| a1e36594c2 | |||
| 043bc754ae | |||
| 472d9dd467 | |||
| f6a3662b0e | |||
| fb777d0c3a | |||
| 2a3ee968ff | |||
| 0b2661ad45 | |||
| 1dfe68e9f3 | |||
| 64b824671a | |||
| 4940d85b29 | |||
| d458748a7a | |||
| 7f346ef606 | |||
| ca544dbbae | |||
| 5704a07b68 | |||
| 5b1739246d | |||
| 8ead33bc59 | |||
| 2f3792a3ee | |||
| 86d306632d | |||
| cc79c2cb49 | |||
| 26b3b13bc4 | |||
| bc20e65aae | |||
| d458bf6be3 | |||
| 58375f06e5 | |||
| cd39853dc8 | |||
| c94a44aeb8 | |||
| 237d7c1ec1 | |||
| a80b67fdc9 | |||
| de44c57ada | |||
| 448356f534 | |||
| 2b16b0fc7c | |||
| 22515c8c29 | |||
| bf050a2d5e | |||
| 74065714cb | |||
| b95a39dc10 | |||
| bcdd202ef9 | |||
| 20ce2ead75 | |||
| a81b9344cf | |||
| a7fe004344 | |||
| 66e8f9865a | |||
| 1cb4413869 | |||
| be6dbefe7c | |||
| f655297052 | |||
| 232c797507 | |||
| 25d4a9c7a6 | |||
| 65e3111e35 | |||
| 048d995922 | |||
| dcac27e072 | |||
| b754ad5248 | |||
| 321c7120df | |||
| 4b85c9e2df | |||
| 62aec34507 | |||
| 427487c598 | |||
| ccb8c43961 | |||
| fee892f9a2 | |||
| 9b990728f6 | |||
| 9b490c9552 | |||
| 133effef0e | |||
| 15706a7af8 | |||
| 2a15faf12e | |||
| 9149792846 | |||
| c90c53c878 | |||
| e6387738ce | |||
| 3882690ee1 | |||
| 4c049d0d75 | |||
| e070af3163 | |||
| 1c35a91d13 | |||
| 4c20e79d1f | |||
| 669f46d6a1 | |||
| ea89a9f706 | |||
| 918985449b | |||
| 18ab93a9f6 | |||
| a6a8363527 | |||
| 90edb0903d | |||
| ba1274ff3a | |||
| 60f91bff50 | |||
| ef2e9406c7 | |||
| 3d6783597f | |||
| 7cab32f71b | |||
| 78a72b42b0 | |||
| 157039946f | |||
| 09083beed0 | |||
| 8aa6c4582c | |||
| aeb610ff70 | |||
| 1586386d6c | |||
| 2eee51f891 | |||
| adf46969ca | |||
| bd6ee188f8 | |||
| 57893bdbf8 | |||
| 7a37ab1b25 | |||
| 72618f98d1 | |||
| d98e6fd51e | |||
| 608bcf7d42 | |||
| 06d8d14ad7 | |||
| aef400db0f | |||
| cdfdaf9f5f | |||
| 5270f155ff | |||
| 0514f13af0 | |||
| e6a6763228 | |||
| 38c74bf2cf | |||
| a770e47575 | |||
| c998352ab7 | |||
| 3683fa3814 | |||
| e62881e08b | |||
| 01e313e56b | |||
| 2dd5f80468 | |||
| 275fb3e96a | |||
| 3463916b9b | |||
| a20de2515a | |||
| 79ea992a0f | |||
| 0132436dc8 | |||
| a285c1abec | |||
| 1c41e01f0d | |||
| f2e53ea490 | |||
| bff86b90fb | |||
| b5c9b6f552 | |||
| 23f5102f1b | |||
| bf51e911b8 | |||
| 4039d7ab71 | |||
| 77a09a0e59 | |||
| 154c777788 | |||
| 628c36c87d | |||
| a746b7abcf | |||
| 64184e6c90 | |||
| ecc955d2ce | |||
| f7e1b2c70c | |||
| 284cbda7c0 | |||
| e5ca9e4c39 | |||
| 02aaa71e78 | |||
| f56b5ea03e | |||
| 6afd4dcdd1 | |||
| 52bb189996 | |||
| aafdac6da4 | |||
| bd202fce21 | |||
| f450001edb | |||
| 8ff6f9af45 | |||
| 36bb1d0cf3 | |||
| c7c8e39e20 | |||
| 8e9630459b | |||
| 1c53fca925 | |||
| 7d78de0673 | |||
| f8acc55365 | |||
| c3157fe90d | |||
| 35b129287b | |||
| d05155a403 | |||
| e5ca216c99 | |||
| 13a96ee1d3 | |||
| 12879207ef | |||
| e097a5de58 | |||
| 0cd2617576 | |||
| 6c303b8f87 | |||
| 91224d8a1c | |||
| 48e961392d | |||
| 5b08a1adfb | |||
| 3bbb9daa34 | |||
| 3f5f17705d | |||
| f0aca45b11 | |||
| d205e3b4a3 | |||
| 8b40a77297 | |||
| a7e87cc722 | |||
| 09f106bd49 | |||
| 8a0869fb75 | |||
| 7ccf26310d | |||
| e1420ba26c | |||
| c693c9cd44 | |||
| e698557092 | |||
| 1238c90450 | |||
| e991dca5a0 | |||
| 37093c9f33 | |||
| 1dd4f62ece | |||
| 9ec27aad53 | |||
| f1d3a946d5 | |||
| fd24f7045e | |||
| 33671e7737 | |||
| 13ecc6a56b | |||
| 20815eecbc | |||
| f2f5ffd861 | |||
| b0971601b1 | |||
| 7253d764d2 | |||
| 71f3a1f7cf | |||
| 950659b29d | |||
| b4392d0e3c | |||
| 4571302642 | |||
| 5121f04d66 | |||
| 77642d2876 | |||
| ef69796798 | |||
| 869854fbc2 | |||
| 4584d912cc | |||
| ddd3d38dac | |||
| fcba6bc7d7 | |||
| a147c0fb4f | |||
| c3cc3fa9bd | |||
| 0f0e14132a | |||
| a2c2ed0b4a | |||
| 8bebca4502 | |||
| e9a550d458 | |||
| bee567f2b1 | |||
| 0fd7061671 | |||
| 96951576c1 | |||
| a665d7cc3c | |||
| 9b989329d4 | |||
| eccfd75a83 | |||
| 7e8a152eef | |||
| 44810f95a5 | |||
| bcd42dbb6a | |||
| 6e77126a65 | |||
| 735bbef655 | |||
| 7006a07dd3 | |||
| 7284926db4 | |||
| b506bf9506 | |||
| 3fea28f8b0 | |||
| cc6649667c | |||
| 24121fbbce | |||
| ef280dae3e | |||
| 49f580a36b | |||
| a56d2b1313 | |||
| f083180401 | |||
| 7b870edefa | |||
| a293fa1de6 | |||
| 3a8898dd24 | |||
| b97c8b9a17 | |||
| a0a8d76441 | |||
| 9199612cf7 | |||
| abfd37c045 | |||
| ac243136b9 | |||
| c93e948bb3 | |||
| 388803ffdb | |||
| a809ccf229 | |||
| d1796a515e | |||
| a11d3efed6 | |||
| a8fb7cd225 | |||
| 9d7aab4326 | |||
| a3b76fed4c | |||
| 21f5f96d69 | |||
| 70d3061d59 | |||
| 8f7a66a21a | |||
| cd8e944751 | |||
| 66e05594f6 | |||
| d06a9e2e5c | |||
| 64df9222dd | |||
| 900ac46583 | |||
| fda1c8399f | |||
| c2cd4fc75f | |||
| ef5a9eb777 | |||
| 8e3100acdd | |||
| 50d74fcf25 | |||
| 140862ce5a | |||
| 966453dd8f | |||
| fcd37adc38 | |||
| 6a3989488e | |||
| fbfdef8f9a | |||
| b66c61573f | |||
| 9186b28b60 | |||
| 915a1b105c | |||
| 12b9b3ce71 | |||
| deb4c48551 | |||
| 9dfaac8582 | |||
| bd5b9f5347 | |||
| ff4b9a3cfe | |||
| e844d7ed89 | |||
| f3ae8f7f75 | |||
| f137eddbf9 | |||
| c70f75b21a | |||
| 141fb875f9 | |||
| 344d47e7dd | |||
| 4840a9094b | |||
| 6f305c8974 | |||
| c83bae3bb5 | |||
| 4c1b962486 | |||
| b929e2a7b2 | |||
| 1ecd7aa7cf | |||
| 881aed50ea | |||
| 6272b79f70 | |||
| 0fa50f1951 | |||
| dc19f2e76c | |||
| 498116c3f6 | |||
| e29dcf7489 | |||
| ec28eea7f0 | |||
| ebce4d0f31 | |||
| bf9492e083 | |||
| cb987c1baf | |||
| e4a4be1f53 | |||
| f6d1fe6c04 | |||
| 7e5a29a5cc | |||
| 8dbc175c02 | |||
| 0473374d51 | |||
| b2d7342b9e | |||
| b965aecc6c | |||
| 9290c90bdc | |||
| d83a80ec53 | |||
| 248fe1b53f | |||
| bf217bf7aa | |||
| e5de8e22b7 | |||
| 5666e84d92 | |||
| a97d1b8669 | |||
| 06db13a0ab | |||
| 9832af7cce | |||
| cf4a617f2b | |||
| 5a6a5fd4d1 | |||
| e6ebc19b4f | |||
| 2250fe75c4 | |||
| e27b1840c6 | |||
| 717d197998 | |||
| 02dd0dbbef | |||
| 2e4a437d32 | |||
| 63e1d6dab6 | |||
| 23133499c7 | |||
| 67bd87b50c | |||
| 6d31a4246f | |||
| d4f38b6d66 | |||
| 959229f143 | |||
| 22f9b1a0b1 | |||
| a8fc5a722f | |||
| 69420f5750 | |||
| 20976ac9f9 | |||
| dc33accae7 | |||
| 29d1f1f14a | |||
| 6102119673 | |||
| 0c635a05ff | |||
| 307a7791df | |||
| 49b056a0ce | |||
| af58ffadcb | |||
| dcbda7b3af | |||
| 553cc0c6ae | |||
| 067dcbfbeb | |||
| 759258bb39 | |||
| 3667ef551c | |||
| a3308087a5 | |||
| bfb4652425 | |||
| 03c24e2906 | |||
| dc61faace1 | |||
| 73ea86ceeb | |||
| 9a622ab466 | |||
| 65cfd6c81c | |||
| 08681ac1b9 | |||
| f9acb5d19b | |||
| e9e187c58b | |||
| 3bc20c3550 | |||
| 4b25406d14 | |||
| 265b7904a8 | |||
| fb2274c58d | |||
| 3cfdc9d897 | |||
| 11986ac698 | |||
| a08436ecd2 | |||
| e92adf94a7 | |||
| d25356917d | |||
| 0adb3b062f | |||
| 9316480884 | |||
| 4e5082f6c6 | |||
| 16d5dbe71c | |||
| 133d7874e3 | |||
| 4659d5db5d | |||
| af061125dd | |||
| 5c4b1f6638 | |||
| ee3d70f879 | |||
| 7dadaa1b28 | |||
| a72782e232 | |||
| 8654ffb6fb | |||
| 90e445eec9 | |||
| 910b6d8879 | |||
| 8d1c2f832d | |||
| 158d2a4124 | |||
| 66473738d6 | |||
| 6a43107bb2 | |||
| 28e7afa412 | |||
| 8dc151e14d | |||
| a330a3f2eb | |||
| 8f7195d3b2 | |||
| a4e4502d50 | |||
| 902da90100 | |||
| d775760f98 | |||
| dfb6600104 | |||
| 41ed487d5e | |||
| d156de05a5 | |||
| f4582ddf36 | |||
| 7f7b764f7b | |||
| dd8fdfc3d4 | |||
| 6c80d443b9 | |||
| cd05586d51 | |||
| dfc1ec3ccf | |||
| ffe6786ad1 | |||
| 6068678fa1 | |||
| 50b761fab2 | |||
| 0d43f16db2 | |||
| 3278de9ba1 | |||
| abe1962002 | |||
| 5b15f377cd | |||
| d0e5ea78a5 | |||
| 853757e611 | |||
| c3860cfe72 | |||
| 90b2c077a6 | |||
| fdce4bada7 | |||
| 4c8ff1c7ec | |||
| 2a153214f6 | |||
| d7c964afc5 | |||
| 5943052cd1 | |||
| 8512154b45 | |||
| 0e5419c60b | |||
| 1d26482298 | |||
| 126749f04c | |||
| e0e69ce740 | |||
| 72b57924b7 | |||
| fdbdeeb956 | |||
| 3dbdecf73d | |||
| 7dc8943840 | |||
| 646b852717 | |||
| 075f754a71 | |||
| f65556acb7 | |||
| b2c01991a6 | |||
| 4bc5e81513 | |||
| 2b24fe95c2 | |||
| 358e64f2cc | |||
| 5dc50b6d96 | |||
| b91a040a32 | |||
| 76db55ff19 | |||
| e17bf18350 | |||
| 43b4499125 | |||
| c6d43a802c | |||
| 21f8403357 | |||
| 40053e3388 | |||
| abcf7e3a47 | |||
| f8913bf9b9 | |||
| 51878ab38e | |||
| d3f9a84a0a | |||
| 23eedb468f | |||
| 9cb89fff45 | |||
| 79f0b22276 | |||
| 8b2a728a0d | |||
| b4120b156e | |||
| 1ae3122c20 | |||
| 727acca217 | |||
| 5f8d662d67 | |||
| 81b432140c | |||
| adc1ee71a9 | |||
| 5ac373d4aa | |||
| 5b9e24f3f4 | |||
| 0e44de2fe3 | |||
| b0125e8165 | |||
| a532067a93 | |||
| f456071c08 | |||
| 3896f0995c | |||
| 56ff5808a3 | |||
| 15c817dd15 | |||
| 7246c3f304 | |||
| e4f59f1ec4 | |||
| 5f0e9538cf | |||
| 73649128f3 | |||
| edc84731ac | |||
| 108b116b06 | |||
| dda587dc6f | |||
| 4a9dd43598 | |||
| a64cfe661a | |||
| 7e418a16ae | |||
| ecf1fa2bbd | |||
| a6157a34bc | |||
| 8e37e66706 | |||
| dd6a4931e5 | |||
| 2d000e826b | |||
| c1028e7408 | |||
| 28b54fac37 | |||
| 845fddf5f2 | |||
| e3e2a477c1 | |||
| bf4442ecf5 | |||
| 3be793032f | |||
| 0fab18e8e8 | |||
| ab6375ef2a | |||
| 2535b6e08c | |||
| 2f003d416a | |||
| 579b358f8b | |||
| 231a583bf7 | |||
| f0cfbacb4f | |||
| ae45189436 | |||
| ff8292b863 | |||
| ebe45f73a0 | |||
| c91f41e988 | |||
| 3c7f3e8740 | |||
| 3a9899529a | |||
| 88ce676c46 | |||
| 426cc2798e | |||
| 5a015888d4 | |||
| 1d2df63652 | |||
| be378eaacb | |||
| 631f5a1043 | |||
| 353e9adec1 | |||
| e572da4927 | |||
| d22afa36c3 | |||
| a7296f15ac | |||
| b20caee548 | |||
| 519832edd7 | |||
| a2cea1e5bc | |||
| b3c198f0d2 | |||
| b45a696b5d | |||
| a2b3fe6411 | |||
| 13d4f37726 | |||
| 71f34f4e31 | |||
| 018f147de6 | |||
| da012cbf8b | |||
| 3907a103fc | |||
| efb566bcc7 | |||
| 53e8df3542 | |||
| a00d262773 | |||
| b64db54793 | |||
| 97c0e3d4a9 | |||
| ba31bbace8 | |||
| 606dfd29d3 | |||
| 9411d0781b | |||
| 7aea200860 | |||
| 5d8ac95d07 | |||
| cd0ebb41aa | |||
| eb028b0dad | |||
| 61803f7516 | |||
| 50bfed79be | |||
| 1c77ae818e | |||
| 66ede6037d | |||
| 01452b7309 | |||
| b5f2470b79 | |||
| 49403e9fee | |||
| 66d512f26f | |||
| 2ba0ebf3e8 | |||
| bbcd27d3c2 | |||
| 837a3528cd | |||
| f39662588f | |||
| 4b12f52029 | |||
| f2920ddefb | |||
| ce010653d5 | |||
| ce764c862f | |||
| 60d821ae3e | |||
| 8f7f8fc0b5 | |||
| ec45041a66 | |||
| 67a666b282 | |||
| d9404fc566 | |||
| bcd899c641 | |||
| ec61ac29ea | |||
| 180e663a43 | |||
| ae1711a685 | |||
| 9c3b62574d | |||
| a3637c12d6 | |||
| cae192682b | |||
| 6c68bacaef | |||
| ee7a2b564b | |||
| fb25d90b48 | |||
| 9075a521f0 | |||
| 00a0e595ff | |||
| 694ff32b01 | |||
| a74635ff56 | |||
| 8c6f3d66b5 | |||
| a49cb06d77 | |||
| f96f478470 | |||
| 1d2f713673 | |||
| 57d24d0fbf | |||
| 584e55a89c | |||
| 4560a83441 | |||
| f4658728e8 | |||
| 54825dc66f | |||
| d4056ac10a | |||
| 8f409a8fe2 | |||
| d369d988b0 | |||
| 2a74736761 | |||
| 6bd0bf6e69 | |||
| 53cee177e8 | |||
| a8afc62db7 | |||
| 14328eb601 | |||
| 2184755fdf | |||
| 3a3cd1f856 | |||
| 24a3a41cd6 | |||
| 197f6b05ae | |||
| c2e887a86e | |||
| 12b16577ef | |||
| 409165dec6 | |||
| 4870d59a43 | |||
| 70c3bb3288 | |||
| 36156997ee | |||
| 2c2728448c | |||
| d1781a7c47 | |||
| dc1459438c | |||
| 00e6da9d64 | |||
| 68b3d75705 | |||
| 3e538b732a | |||
| 833341dea7 | |||
| bc3efe2f4c | |||
| 10e4c59f2e | |||
| d9016b7979 | |||
| d975610ecd | |||
| 5d1251f6d8 | |||
| bdf802e64a | |||
| f2b888f9ae | |||
| 9583007769 | |||
| eb81c33308 | |||
| 8d734f5cc4 | |||
| 3375ff6152 | |||
| 80fc58f83e | |||
| 17c0124747 | |||
| c220d4dd17 | |||
| 15146725e3 | |||
| ddfab824c3 | |||
| 8b5a00ca27 | |||
| 04a7f14c0e | |||
| 18f14b828c | |||
| 0a92e12a62 | |||
| 5b71281ec4 | |||
| 08fdc4f1fc | |||
| c726bef740 | |||
| 94e0ac3f54 | |||
| 284f7fc4f7 | |||
| e629460942 | |||
| 904e531113 | |||
| ca2f2adc90 | |||
| 78a3e329f5 | |||
| 5938e0f821 | |||
| 4a6ae3b46c | |||
| 2327d661b9 | |||
| 9790e37154 | |||
| f97d751343 | |||
| 81c1f6bd8e | |||
| e3a5a4239b | |||
| fcec85881f | |||
| cfefb8b2e0 | |||
| e81a2a5011 | |||
| d62b488459 | |||
| 932bd92b95 | |||
| 9fd1f95ab8 | |||
| cf414cb9cb | |||
| f676d32f96 | |||
| 939c9afeb4 | |||
| 7d88c48c39 | |||
| 26337a6bd4 | |||
| 1263a5bfc0 | |||
| fe21ca5b95 | |||
| 0fe9dad515 | |||
| 75b33c906d | |||
| 835fa77964 | |||
| 3e13186560 | |||
| 01f191289d | |||
| 6586791655 | |||
| b4f6774ca8 | |||
| 75d346fe69 | |||
| 27780c7327 | |||
| 100a8882f1 | |||
| 983bd1a57b | |||
| 810f7949f4 | |||
| 28c502bd85 | |||
| b8c313965f | |||
| 8a2dcbbcff | |||
| 263b9fa611 | |||
| 793e15f80c | |||
| 23d1394fb2 | |||
| f97bb23c9d | |||
| d557739a28 | |||
| 8d06243b57 | |||
| 9a4b73b942 | |||
| d73e0dd13c | |||
| 2f3818fe4b | |||
| d3d773079c | |||
| 0b2acec50c | |||
| 3501e4f44d | |||
| 384c540197 | |||
| 1b78ffc018 | |||
| 79f4f0adbf | |||
| 98d71308a8 | |||
| 4f0fa66575 | |||
| ecac3a0f16 | |||
| d1898b9a0b | |||
| 868c7b170e | |||
| b1c5c53687 | |||
| 6704886c6e | |||
| 7e45283ba2 | |||
| ff67d876b2 | |||
| 4975a0a8d8 | |||
| e34a4338a1 | |||
| 0b4986b47a | |||
| 937eab5f27 | |||
| 70378bfac8 | |||
| 29d87f692a | |||
| b1b2798be1 | |||
| 2b74ad8b5f | |||
| 3098fa6855 | |||
| 53883a7f1f | |||
| 2c048376d4 | |||
| b583240d58 | |||
| 844be11d43 | |||
| 53b739139b | |||
| d09d1d72e6 | |||
| 01d927aceb | |||
| 59abfcbd6d | |||
| 4c2ec15f70 | |||
| 2b6dfbf4eb | |||
| eb8372eb91 | |||
| c6b2967da0 | |||
| 042f51e58f | |||
| c72cf46db7 | |||
| 2a7aac76d9 | |||
| a569495f5d | |||
| 59e56600bc | |||
| 915dec7ba5 | |||
| 909bd3dd2d | |||
| d50fad615f | |||
| b036bedbc3 | |||
| 55c05d1a6e | |||
| 344c0f6427 | |||
| 8ab1a7268b | |||
| e5f31dbe8e | |||
| 783c5c12e9 | |||
| c972485555 | |||
| c507382d19 | |||
| fbbcbc8753 | |||
| a5fa595627 | |||
| 502045f1fa | |||
| e9280777fd | |||
| c36f402b88 | |||
| 3a68dd50ce | |||
| eb06c0da08 | |||
| 6528567746 | |||
| 09229812f4 | |||
| aaa37a3e0d | |||
| c5531b1bd8 | |||
| 021115b463 | |||
| 698d9c208f | |||
| 01a6b432f3 | |||
| a5f44b3ed6 | |||
| a3ba99c682 | |||
| 7c709fddba | |||
| 8f313b4603 | |||
| 41c0a5ee3b | |||
| 346f7aadd6 | |||
| be611c1920 | |||
| e33a866a63 | |||
| c846eeed9d | |||
| d052eac019 | |||
| 9dbd134601 | |||
| 6451e1cfe2 | |||
| 9f3f715527 | |||
| 0d8e5b139b | |||
| 5d5dda548a | |||
| 1d32e5267c | |||
| a300a25419 | |||
| 4eaf03b922 | |||
| 4401ea388c | |||
| dfe6ad3a32 | |||
| e3ef870b29 | |||
| 7deb5bfdf2 | |||
| 0e46a4402a | |||
| 33a15e69bb | |||
| ebe11fdb1e | |||
| f9a7c46868 | |||
| c80c23e8e8 | |||
| 5e6c81a98e | |||
| 214cc83d4a | |||
| 8e643fbf87 | |||
| 6008d9e12b | |||
| 81da453ec4 | |||
| f34835463d | |||
| eb3419f3fc | |||
| 5886a07300 | |||
| 69e7c27fd0 | |||
| 165cf6809f | |||
| 9b2b8b6796 | |||
| 3ed6d1dec1 | |||
| 9ad1d1c25d | |||
| 667e614bf3 | |||
| d49da1fdd0 | |||
| 85b0733169 | |||
| 7f2bba7c4a | |||
| 664ec62396 | |||
| b4a9e45214 | |||
| 2eab7044ba | |||
| 8d449f91c6 | |||
| be8a836528 | |||
| 423782fd2b | |||
| dc1dc8dffa | |||
| 16a77e2975 | |||
| df69a70dd7 | |||
| 0638c86211 | |||
| 8c0de22c14 | |||
| f83568c6c9 | |||
| 10d472728c | |||
| 2c3cb3f5ce | |||
| fbfe3fd5ed | |||
| b280a26317 | |||
| 640db8af7d | |||
| 98d9357208 | |||
| f3b6c7c09b | |||
| 3a622f111a | |||
| e0b1ed87e8 | |||
| 63578affa4 | |||
| 74b188fa46 | |||
| fadaf852b7 | |||
| ac6124951a | |||
| 89e42af149 | |||
| cf5987b2b4 | |||
| 069d8d376c | |||
| fe3d8ea2be | |||
| 3ac03b43e1 | |||
| eaf1a532f4 | |||
| f2b0116c1e | |||
| 155b5fa831 | |||
| 130c77a305 | |||
| 2e168d152f | |||
| e0890541ea | |||
| 1447b62999 | |||
| 518ae8044d | |||
| 314a90995a | |||
| 8f29e32577 | |||
| b6e25a353d | |||
| 635ed02198 | |||
| cd81a54062 | |||
| 1035d787ab | |||
| 29567df407 | |||
| 79cb4668f1 | |||
| 9bdc19e2fd | |||
| 25cd6106f5 | |||
| 13fbe59164 | |||
| c261c3367a | |||
| 8b92ab25c7 | |||
| 0aa1031270 | |||
| dec8bdb39d | |||
| f318aeb67c | |||
| 8b791e77d6 | |||
| 260b72fec1 | |||
| 7d0beafce0 | |||
| 3c2f8b65ce | |||
| 5f73e8b3bf | |||
| 74afeeb85f | |||
| f8920e5fef | |||
| dd76313084 | |||
| 627ff6f26e | |||
| 705db0b9cf | |||
| 47a958d81d | |||
| 906fc9cc1d | |||
| 44d9525476 | |||
| 8b2a549fab | |||
| 7312e34f46 | |||
| 696be858f6 | |||
| e1f4fd0c7b | |||
| f51320d1bc | |||
| a0764190f2 | |||
| 33c5b35444 | |||
| 04e10f81b5 | |||
| 7f2545a9ef | |||
| a2a16f3f23 | |||
| ab2a947992 | |||
| 7d0a73a6b0 | |||
| e3c3a68566 | |||
| 4fc026b13c | |||
| c0fed4d2c3 | |||
| b656e14453 | |||
| fbab3964e6 | |||
| d9b270b477 | |||
| 7f53a19647 | |||
| 9f1e90d007 | |||
| 9a439e1941 | |||
| 4e4c69993c | |||
| 0d085d500f | |||
| f734c0475b | |||
| a30951dc91 | |||
| c4b37950a9 | |||
| 7cf832a2f4 | |||
| 1f07e7978d | |||
| 5adab2739b | |||
| 2be76760de | |||
| 28c125a3ec | |||
| bdf8a37a8f | |||
| 838711e2ac | |||
| c085691c54 | |||
| 47506d70ed | |||
| efc7cc4980 | |||
| f2016a8aa5 | |||
| d6bbc375c4 | |||
| 885996c5cf | |||
| 4e4604e00a | |||
| b057d4fcb7 | |||
| cdf27296e4 | |||
| 889f111300 | |||
| 520b4f92ab | |||
| feb1d4ebcc | |||
| c11a7589e2 | |||
| c332b7cb40 | |||
| 418dcedc4e | |||
| a21eb9d59e | |||
| 25ed8fe044 | |||
| b079c79390 | |||
| d7a89ef122 | |||
| b95035e7a2 | |||
| e28d29f276 | |||
| c29d78ac0d | |||
| ad9106b815 | |||
| f3ea24f9f9 | |||
| 96fdece478 | |||
| c30a5782df | |||
| c924fcb91f | |||
| 46e7b6d6df | |||
| bb8ecf2f84 | |||
| 7123a6d647 | |||
| eb4ef8b3d7 | |||
| 0d346610a2 | |||
| fe0c1acd79 | |||
| b3552d8c2c | |||
| 206a15191f | |||
| 22de3980d1 | |||
| af35beefc2 | |||
| 532258bea8 | |||
| 5b257293eb | |||
| 8e6d23ddd6 | |||
| 6d5d61c842 | |||
| 9d2e2a1739 | |||
| 19e2642ec1 | |||
| f9df522b41 | |||
| b3e5c4a4aa | |||
| 06ed6c81a7 | |||
| d1e4dbb603 | |||
| abe8079296 | |||
| 033cb2790c | |||
| 188edce258 | |||
| 34858b36c1 | |||
| 044ef3447c | |||
| 2660439160 | |||
| 9502120ee3 | |||
| 7f1a3320dd | |||
| 8a4fd7f182 | |||
| b0a4d15d64 | |||
| 3f6f96cfb4 | |||
| 99a1c98ae0 | |||
| fd718dfd5c | |||
| 31cb2f1999 | |||
| a6a8e32be7 | |||
| 594bb8a76b | |||
| 228bbc1e8e | |||
| b14c2878b3 | |||
| 57f10040e1 | |||
| 0fb67c78a9 | |||
| ff0f7f49da | |||
| 9682e37547 | |||
| 7197d9480b | |||
| 3315c9c7f4 | |||
| f57eff4195 | |||
| f0c8e48403 | |||
| de87bed375 | |||
| 5cdfaab2db | |||
| acb0b029b9 | |||
| 4c74cbbbe9 | |||
| ad64e068db | |||
| 6bed3f3f09 | |||
| d02e55da06 | |||
| d662a8f2b9 | |||
| 13a93102a5 | |||
| 0d6a1e6610 | |||
| 05cd9eebb8 | |||
| d93d8ab1cc | |||
| 540fa0e669 | |||
| 17a10cf6bb | |||
| 11d0f9db03 | |||
| f024ceecdd | |||
| 08c07a0785 | |||
| b843f91b3c | |||
| 4b2c5b3321 | |||
| 2b43f2682a | |||
| 7da0124286 | |||
| feaeef6482 | |||
| 15bcfeec1d | |||
| 5fb002ab4c | |||
| f56ddbb1e0 | |||
| 6bd2a7c962 | |||
| 9d591ae806 | |||
| 7d30e3913c | |||
| 19d7dd7aa3 | |||
| 45444253fd | |||
| 308ade6a7e | |||
| 66d54ccd54 | |||
| ccf8d91f01 | |||
| 7c940a0480 | |||
| 277a2edb57 | |||
| bd742689e9 | |||
| 9ca0c3c41d | |||
| ce8650b4de | |||
| 4bce9d440e | |||
| adc691f516 | |||
| fc67a801e3 | |||
| 6a3657ca87 | |||
| 0537c5f273 | |||
| cc4a5f30b6 | |||
| b0d7c3e9b1 | |||
| 3bf7c44fc9 | |||
| 4ff4e63a11 | |||
| 72a35ba58b | |||
| b6a31979f2 | |||
| 7c710e22cc | |||
| ab58e7a225 | |||
| c9fb97cd7c | |||
| 789f3e1584 | |||
| 0fc8229be1 | |||
| a1e555267e | |||
| 0ac88c0cb5 | |||
| d43a6da62b | |||
| 940455f786 | |||
| 0f74456f30 | |||
| 7840fa6d90 | |||
| 95ccc99fee | |||
| 7b0a156bba | |||
| 0d8ae7bb37 | |||
| 9491cff1df | |||
| 51dc5d6e37 | |||
| f4c739ab92 | |||
| 0dd8ae3d77 | |||
| 7d2878d81c | |||
| bd70a05861 | |||
| 0605c7b2bc | |||
| 8e83a55143 | |||
| 4ab4eb8ef2 | |||
| d1e6150874 | |||
| 4121c99f36 | |||
| 827040f487 | |||
| 9032489786 | |||
| 8ea7bd4913 | |||
| 97b021efaf | |||
| b3f9a77ba7 | |||
| 63fdc1f876 | |||
| 17cf354c58 | |||
| c6fd8bcb99 | |||
| 1684465e04 | |||
| fe2df96953 | |||
| ee9d0cfd99 | |||
| 7b7e18e752 | |||
| 928be4151b | |||
| 37dd648686 | |||
| 93a590774e | |||
| 22b99b6d3e | |||
| 101d626d4f | |||
| 3633c19208 | |||
| e302f328f7 | |||
| f74ba95e95 | |||
| c38982d286 | |||
| fe9bac096b | |||
| 5b809c4fc6 | |||
| 4729e51e14 | |||
| 960cf7a34b | |||
| 852ab19760 | |||
| 2e45d9fc6b | |||
| 74b71b92b6 | |||
| bbc14ba74f | |||
| 45c7829cd8 | |||
| f2aa3afbbb | |||
| 909b01241b | |||
| abb58c58a0 | |||
| 700e10d32c | |||
| 4ac48d0e4a | |||
| 345b2cb835 | |||
| b962309498 | |||
| e99cb9bfb8 | |||
| 9e12e18f90 | |||
| 66fc9b38df | |||
| 5dbe429e6b | |||
| b2481ea6c1 | |||
| 86a294ce4b | |||
| a8d1eadfbf | |||
| b07d3c5403 | |||
| 892db55ae1 | |||
| 93615fef65 | |||
| 87452706ef | |||
| 3569615b21 | |||
| 86f7d09d31 | |||
| d5d1254393 | |||
| 4df90cfb9e | |||
| ec6862d31a | |||
| 6f23010382 | |||
| c672f105d3 | |||
| e60d501e4a | |||
| 0d7175058b | |||
| 3b0bd9d1d1 | |||
| bd28ac6e1f | |||
| 0c2d00c792 | |||
| 140ba653b9 | |||
| f64f008f77 | |||
| a6315bef05 | |||
| f810d7c82a | |||
| cf61dedc79 | |||
| 2ab9587f5f | |||
| 4950b52359 | |||
| 03af444735 | |||
| 7f6221b409 | |||
| 57aebdd300 | |||
| 25821ba338 | |||
| 7dda5461ad | |||
| ee0238bad8 | |||
| 451940e6a7 | |||
| 6163cc8a5a | |||
| ef859d77e9 | |||
| 0fd752657a | |||
| f1451a1de3 | |||
| fa96f25683 | |||
| 9e447383df | |||
| 5e762be32b | |||
| 75de81a3ab | |||
| d26b64a5bb | |||
| cb8d40eaf2 | |||
| ded0936bc4 | |||
| 16830a410c | |||
| 9f79dda463 | |||
| 15dc7c74d7 | |||
| f9abef9e05 | |||
| ba84499f00 | |||
| 79ce24222a | |||
| 6cb9264864 | |||
| 247a070405 | |||
| e05bb75b8a | |||
| 6a415cf232 | |||
| e8034189df | |||
| 107f329b4f | |||
| 999a13358e | |||
| 2077f51084 | |||
| 1e77a3df20 | |||
| 141a291523 | |||
| cb03d5a9d3 | |||
| b618d1e56a | |||
| 23ae638512 | |||
| eda749d7cb | |||
| 08d0186e53 | |||
| 443981ba31 | |||
| f3ed7c5e19 | |||
| dd2378b591 | |||
| b885779365 | |||
| 32b95f0d9a | |||
| 2b8eec8666 | |||
| 3f24627f54 | |||
| 0c4bca312e | |||
| e36afc675e | |||
| d754014321 | |||
| 9f73242cc5 | |||
| fae9649773 | |||
| 4b43f4cbec | |||
| b61befa210 | |||
| 5e2bc337bc | |||
| af1608cbfa | |||
| 9aa80976ff | |||
| c9cfe9e90f | |||
| 482e337762 | |||
| a0821f5a01 | |||
| 5ebdf3ed39 | |||
| 86096db02d | |||
| a93e01b896 | |||
| 0585e72c35 | |||
| c82fbefcfc | |||
| 23542a1db1 | |||
| 1bf50d60d8 | |||
| 8596b0309e | |||
| 7f6e871b26 | |||
| 8912d4d55a | |||
| 7ac849ab12 | |||
| 4cab699b04 | |||
| 03aa05e4d2 | |||
| 428a3cf0ce | |||
| 1c8b165a64 | |||
| 1869071ef7 | |||
| 33ca5ee39f | |||
| e46d5a86d3 | |||
| 2729bcac3b | |||
| d60ce41fa9 | |||
| 958db945f3 | |||
| 057f906ca4 | |||
| 8df7a45e29 | |||
| e4af1570cb | |||
| 049ebf9027 | |||
| f2f0c7df92 | |||
| bee4118513 | |||
| a1096f7ecb | |||
| dac0a6ec20 | |||
| 4327fd4c58 | |||
| 3243f57fd5 | |||
| 383c488268 | |||
| 53392d6e5d | |||
| bf48025d12 | |||
| 5e624605cf | |||
| 026490acc6 | |||
| 709ce3adb8 | |||
| a8d23489c4 | |||
| 296df113e3 | |||
| 292de83c35 | |||
| 7fe66c07e4 | |||
| 9aa8f30e2b | |||
| e3ebb30518 | |||
| 51122ab3ba | |||
| 5d96eab7b4 | |||
| 97c4e79e96 | |||
| f89bac7781 | |||
| 1d8a7f8fd3 | |||
| ef9f7ab27a | |||
| a676138745 | |||
| 7442ea7a16 | |||
| 0089cad740 | |||
| cf1fa718a8 | |||
| d6ba6ac41e | |||
| bbdd5feaa4 | |||
| 678527254b | |||
| a43943ec3d | |||
| ab3a61794b | |||
| 46bf7781aa | |||
| 99c547b625 | |||
| 6976e97de3 | |||
| f8e3e70273 | |||
| 23c9f7a957 | |||
| 2ca763cc77 | |||
| 2adc811351 | |||
| be18be4a86 | |||
| 8d7abb1b8a | |||
| 1cc5988c40 | |||
| da426ae03b | |||
| 3cebd6d923 | |||
| f1019c8ca4 | |||
| edfb7b6b24 | |||
| 157a928f5a | |||
| 5f5a2a3ef2 | |||
| 8534cf3756 | |||
| 39b90092ff | |||
| d3142ebe6d | |||
| d914c6be2e | |||
| 05c3e968df | |||
| 7756cce123 | |||
| 8287d717f8 | |||
| db9e60b4b5 | |||
| 28a79bfccb | |||
| 321490e528 | |||
| 6f752357d7 | |||
| e1f71baed6 | |||
| df377cd5bb | |||
| 691a0acdab | |||
| 5e2eda6af3 | |||
| 17cdc2b585 | |||
| c08266f81b | |||
| f90a4db569 | |||
| 22ec7a6d75 | |||
| 1b16a84810 | |||
| d778276f5d | |||
| e3030a168f | |||
| dfd07a4f4f | |||
| f9fc65d7de | |||
| 46cf7db242 | |||
| 2b94cffe7e | |||
| 2e74ad6fbe | |||
| df7dc1583d | |||
| 88e80b4fae | |||
| aea90f4b65 | |||
| 80db076f38 | |||
| 27bba8250a | |||
| 3fb0fa6892 | |||
| c3195cfcbe | |||
| 51661a872c | |||
| 64706ea103 | |||
| ec69d557dc | |||
| addd37fb1f | |||
| 9dc947ecb6 | |||
| 7d74d3da3a | |||
| aa0c56876c | |||
| 37c7b0c6d1 | |||
| 0d07d238bc | |||
| fa4e74ffef | |||
| c22d76e5be | |||
| 18850ebd83 | |||
| 17abef95eb | |||
| d135151477 | |||
| 07fd9b3074 | |||
| 0523ae705a | |||
| 9db2502cd0 | |||
| a174119877 | |||
| 569dd19932 | |||
| 530e2a1feb | |||
| de732ba692 | |||
| c6649e84a6 | |||
| e3517aceab | |||
| 6d7abd1718 | |||
| e9e493707b | |||
| c25adf8b57 | |||
| d2be10cd4e | |||
| 006ecf9a56 | |||
| a53cc52241 | |||
| 961d283325 | |||
| 4e46529eb6 | |||
| 81001e04e9 | |||
| 2fd174ab9c | |||
| 6ff5e221ea | |||
| 232077b919 | |||
| fecddb5203 | |||
| d0132c0f7b | |||
| 37d32b32f8 | |||
| 51213b499f | |||
| dcb98ce0fb | |||
| 428e90a844 | |||
| 017535cf7b | |||
| 409389a994 | |||
| ba34d92cd3 | |||
| b412ee258d | |||
| f1ffe2a641 | |||
| a13ca95894 | |||
| 0989a80a57 | |||
| d72c15e9d3 | |||
| 7084cf9526 | |||
| 67cc0ef75c | |||
| 75714cc358 | |||
| 75e454f3fd | |||
| 97afb4e01a | |||
| 8fcbf43410 | |||
| 15a834b883 | |||
| 3d8396e586 | |||
| 3257fd364a | |||
| d690af99fc | |||
| 1c28495162 | |||
| ec82d5674f | |||
| 4a22e76bdb | |||
| 527be95618 | |||
| 41985c0a5f | |||
| 522e45ce92 |
@@ -0,0 +1,559 @@
|
||||
# Phase Prompts
|
||||
|
||||
Use these templates as Codex subagent messages. Use them as same-session checklists only for Phase 0, intentional main-session build work, Phase 7, or when delegation is unavailable from the start. Replace `<TASK>`, `<PROJECT>`, `<LETTER>`, and `<REPO_ROOT>`.
|
||||
|
||||
## Orchestration Rules
|
||||
|
||||
- Phase 0 runs in the main session.
|
||||
- When delegation is available, use a fresh subagent for Phase 1, Phase 2, Phase 3, each Phase 4 implementation unit, and each Phase 6 pass. Do not switch those phases to same-session midstream because of a timeout or missing artifact.
|
||||
- Phase 7 runs in the main session on Windows because it depends on the final local diff and touched-file set.
|
||||
- Write each phase prompt to `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.prompt.md` before execution.
|
||||
- If you delegate a phase, send the prompt file contents as the initial `spawn_agent` message.
|
||||
- When writing the phase prompt file, append the standard progress file contract and the standard compact reply block below so the subagent knows how to surface progress before the final artifact.
|
||||
- After each phase completes, write `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.result.md` summarizing the status, files touched, and any follow-up notes.
|
||||
- Use `fork_context: false` by default. If the phase depends on thread-only context or UI attachments, pass that context explicitly or enable `fork_context` only for that phase.
|
||||
- Prefer `worker` for phases that write files. Use `default` for plan or review passes if that fits the host better. Use `explorer` only for narrow read-only questions.
|
||||
- When supported, request `model: gpt-5.4` and `reasoning_effort: xhigh` for delegated phases.
|
||||
- Default wait budget for delegated phases is 5 minutes while the phase is clearly still in progress. Successful completion may wake earlier, so this does not delay finished work.
|
||||
- When a phase appears close to landing, use 1-2 minute waits until it finishes.
|
||||
- A `wait_agent` timeout is not failure. On timeout, inspect both the expected artifact and the matching progress file before deciding anything.
|
||||
- If the expected artifact exists and shows progress, wait again.
|
||||
- If the expected artifact is not ready but the progress file mtime moved or its heartbeat counter increased since the previous check, wait again. Prefer mtime checks first and avoid rereading the file unless you need detail. Do not count that as a failed wait.
|
||||
- If neither the expected artifact nor the progress file moved since the previous blocked check, send one short follow-up asking the same agent to refresh the progress file, finish the required artifact, and return the standard compact reply block, then wait again.
|
||||
- If the same agent still produces no usable artifact and no meaningful progress-file movement after two full default waits and one follow-up, close it and retry the phase in a fresh subagent.
|
||||
- For Phase 1, Phase 2, Phase 3, Phase 4, and Phase 6, if delegated retries still fail, stop and ask the user rather than rerunning the phase locally.
|
||||
- Never use `codex exec`, background shell child processes, or JSONL child-session logging from this skill.
|
||||
|
||||
## Standard Progress File Contract
|
||||
|
||||
Append this verbatim to every delegated phase prompt:
|
||||
|
||||
```text
|
||||
Before deep work, create or update the matching progress file in `.ai/<PROJECT>/<LETTER>/logs/`.
|
||||
|
||||
Use `<phase-name>.progress.md` as a concise heartbeat with:
|
||||
- `Heartbeat: <N>` on the first line, incremented on each meaningful update
|
||||
- Current step
|
||||
- Files being read or edited
|
||||
- Concrete findings or decisions so far
|
||||
- Blocker or next checkpoint
|
||||
|
||||
Update it sparingly: preferably at natural milestones, and otherwise only after a longer quiet stretch such as roughly 5-10 minutes.
|
||||
Keep it tiny so the parent can usually rely on file mtime or the heartbeat counter instead of rereading the whole file.
|
||||
Do not wait until the final artifact to write progress.
|
||||
```
|
||||
|
||||
## Standard Compact Reply Block
|
||||
|
||||
Append this verbatim to every delegated phase prompt:
|
||||
|
||||
```text
|
||||
Before replying in chat, write the required artifact(s) to disk.
|
||||
|
||||
Reply in 8 lines or fewer using exactly these keys:
|
||||
STATUS: <DONE|BLOCKED|APPROVED|NEEDS_CHANGES>
|
||||
ARTIFACTS: <paths>
|
||||
TOUCHED: <repo paths or none>
|
||||
BLOCKER: <none or one short line>
|
||||
|
||||
Do not restate the full context, plan, diff, or long reasoning in the chat reply.
|
||||
```
|
||||
|
||||
## Artifact-Based Completion Checks
|
||||
|
||||
- Phase 1 is complete only when `about.md` and `context.md` both exist and are non-empty.
|
||||
- Phase 2 is complete only when `plan.md` exists, contains a `## Status` section, and no unintended source edits were made.
|
||||
- Phase 3 is complete only when `plan.md` contains both `Phases:` in the Status section and `Assessed: yes`.
|
||||
- Phase 4 is complete only when the target phase checkbox changed to checked and the touched-file list matches the owned write set, or the blocker explains any mismatch.
|
||||
- Phase 5 is complete only when the build outcome is known and the build checkbox is updated on success.
|
||||
- Phase 6a is complete only when `review<R>.md` exists and contains a verdict line.
|
||||
- Phase 6b is complete only when the requested fixes were applied and the post-fix build outcome is known.
|
||||
|
||||
## Phase 0: Setup
|
||||
|
||||
Record the current time now and store it as `$START_TIME`. You will use this at the end to display total elapsed time.
|
||||
|
||||
Before running any phase prompts, determine whether this is a new project or a follow-up task.
|
||||
|
||||
Follow-up detection:
|
||||
1. Extract the first word or token from the task description. Call it `FIRST_TOKEN`.
|
||||
2. Check `.ai/` to see existing project names.
|
||||
3. Check whether `.ai/<FIRST_TOKEN>/about.md` exists.
|
||||
4. If the file exists, this is a follow-up task. The project name is `FIRST_TOKEN`. The task description is everything after `FIRST_TOKEN`.
|
||||
5. If the file does not exist, this is a new project. The full input is the task description.
|
||||
|
||||
Do not proceed until you have determined follow-up vs new.
|
||||
|
||||
For new projects:
|
||||
- Using the list of existing projects, pick a unique short name (1-2 lowercase words, hyphen-separated) that does not collide.
|
||||
- Create `.ai/<PROJECT>/`, `.ai/<PROJECT>/a/`, and `.ai/<PROJECT>/a/logs/`.
|
||||
- Set `<LETTER>` = `a`.
|
||||
|
||||
For follow-up tasks:
|
||||
- Scan `.ai/<PROJECT>/` for existing task folders (`a/`, `b/`, ...). Find the latest one (highest letter).
|
||||
- The previous task letter = that highest letter.
|
||||
- The new task letter = next letter in sequence.
|
||||
- Create `.ai/<PROJECT>/<LETTER>/` and `.ai/<PROJECT>/<LETTER>/logs/`.
|
||||
|
||||
Then proceed to Phase 1. Follow-up tasks do not skip context gathering. They use a modified Phase 1F prompt.
|
||||
|
||||
## Phase 1: Context (New Project, letter = `a`)
|
||||
|
||||
```text
|
||||
You are a context-gathering agent for a large C++ codebase (Telegram Desktop).
|
||||
|
||||
TASK: <TASK>
|
||||
|
||||
YOUR JOB: Read AGENTS.md, inspect the codebase, find all files and code relevant to this task, and write two documents.
|
||||
|
||||
Steps:
|
||||
1. Read AGENTS.md for project conventions and build instructions.
|
||||
2. Search the codebase for files, classes, functions, and patterns related to the task.
|
||||
3. Read all potentially relevant files. Be thorough and prefer reading more rather than less.
|
||||
4. For each relevant file, note:
|
||||
- file path
|
||||
- relevant line ranges
|
||||
- what the code does and how it relates to the task
|
||||
- key data structures, function signatures, and patterns used
|
||||
5. Look for similar existing features that could serve as a reference implementation.
|
||||
6. Check api.tl if the task involves Telegram API.
|
||||
7. Check .style files if the task involves UI.
|
||||
8. Check lang.strings if the task involves user-visible text.
|
||||
|
||||
Write two files.
|
||||
|
||||
File 1: .ai/<PROJECT>/about.md
|
||||
|
||||
This file is not used by any agent in the current task. It exists solely as a starting point for a future follow-up task's context gatherer. No planning, implementation, or review phase should rely on it during the current task.
|
||||
|
||||
Write it as if the project is already fully implemented and working. It should contain:
|
||||
- Project: What this project does (feature description, goals, scope)
|
||||
- Architecture: High-level architectural decisions, which modules are involved, how they interact
|
||||
- Key Design Decisions: Important choices made about the approach
|
||||
- Relevant Codebase Areas: Which parts of the codebase this project touches, key types and APIs involved
|
||||
|
||||
Do not include temporal state like "Current State", "Pending Changes", "Not yet implemented", or "TODO". Describe the project as a complete, coherent whole.
|
||||
|
||||
File 2: .ai/<PROJECT>/a/context.md
|
||||
|
||||
This is the primary task-specific implementation context. All downstream phases should be able to work from this file plus the referenced source files. It must be self-contained. Include:
|
||||
- Task Description: The full task restated clearly
|
||||
- Relevant Files: Every file path with line ranges and descriptions
|
||||
- Key Code Patterns: How similar things are done in the codebase, with snippets when useful
|
||||
- Data Structures: Relevant types, structs, classes
|
||||
- API Methods: Any TL schema methods involved, copied from api.tl when useful
|
||||
- UI Styles: Any relevant style definitions
|
||||
- Localization: Any relevant string keys
|
||||
- Build Info: Build command and any special notes
|
||||
- Reference Implementations: Similar features that can serve as templates
|
||||
|
||||
Be extremely thorough. Another agent with no prior context will rely on this file.
|
||||
|
||||
Do not implement code in this phase.
|
||||
```
|
||||
|
||||
## Phase 1F: Context (Follow-up Task, letter = `b`, `c`, ...)
|
||||
|
||||
```text
|
||||
You are a context-gathering agent for a follow-up task on an existing project in a large C++ codebase (Telegram Desktop).
|
||||
|
||||
NEW TASK: <TASK>
|
||||
|
||||
YOUR JOB: Read the existing project state, gather any additional context needed, and produce fresh documents for the new task.
|
||||
|
||||
Steps:
|
||||
1. Read AGENTS.md for project conventions and build instructions.
|
||||
2. Read .ai/<PROJECT>/about.md. This is the project-level blueprint describing everything done so far.
|
||||
3. Read .ai/<PROJECT>/<PREV_LETTER>/context.md. This is the previous task's gathered context.
|
||||
4. Understand what has already been implemented by reading the actual source files referenced in about.md and the previous context.
|
||||
5. Based on the new task description, search the codebase for any additional files, classes, functions, and patterns that are relevant to the new task but not already covered.
|
||||
6. Read all newly relevant files thoroughly.
|
||||
|
||||
Write two files.
|
||||
|
||||
File 1: .ai/<PROJECT>/about.md (rewrite)
|
||||
|
||||
Rewrite this file instead of appending to it. The new about.md must be a single coherent document that describes the project as if everything, including this new task's changes, is already fully implemented and working.
|
||||
|
||||
It should incorporate:
|
||||
- everything from the old about.md that is still accurate and relevant
|
||||
- the new task's functionality described as part of the project, not as a pending change
|
||||
- any changed design decisions or architectural updates from the new task requirements
|
||||
|
||||
It should not contain:
|
||||
- temporal state such as "Current State", "Pending Changes", or "TODO"
|
||||
- history of how requirements changed between tasks
|
||||
- references to "the old approach" versus "the new approach"
|
||||
- task-by-task changelog or timeline
|
||||
- information that contradicts the new task requirements
|
||||
|
||||
File 2: .ai/<PROJECT>/<LETTER>/context.md
|
||||
|
||||
This is the primary document for the new task. It must be self-contained and should include:
|
||||
- Task Description: The new task restated clearly, with enough project background that an implementation agent can understand it without reading any other .ai files
|
||||
- Relevant Files: Every file path with line ranges relevant to this task
|
||||
- Key Code Patterns: How similar things are done in the codebase
|
||||
- Data Structures: Relevant types, structs, classes
|
||||
- API Methods: Any TL schema methods involved
|
||||
- UI Styles: Any relevant style definitions
|
||||
- Localization: Any relevant string keys
|
||||
- Build Info: Build command and any special notes
|
||||
- Reference Implementations: Similar features that can serve as templates
|
||||
|
||||
Be extremely thorough. Another agent with no prior context should be able to work from this file alone.
|
||||
|
||||
Do not implement code in this phase.
|
||||
```
|
||||
|
||||
## Phase 2: Plan
|
||||
|
||||
```text
|
||||
You are a planning agent. You must create a detailed implementation plan.
|
||||
|
||||
Read these files:
|
||||
- .ai/<PROJECT>/<LETTER>/context.md
|
||||
- Then read the specific source files referenced in context.md to understand the code deeply.
|
||||
|
||||
Create a detailed plan in: .ai/<PROJECT>/<LETTER>/plan.md
|
||||
|
||||
The plan.md should contain:
|
||||
|
||||
## Task
|
||||
<one-line summary>
|
||||
|
||||
## Approach
|
||||
<high-level description of the implementation approach>
|
||||
|
||||
## Files to Modify
|
||||
<list of files that will be created or modified>
|
||||
|
||||
## Files to Create
|
||||
<list of new files, if any>
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
Each step must be specific enough that an agent can execute it without ambiguity:
|
||||
- exact file paths
|
||||
- exact function names
|
||||
- what code to add, modify, or remove
|
||||
- where exactly in the file (after which function, in which class, and so on)
|
||||
|
||||
Number every step. Group steps into phases if there are more than about eight steps.
|
||||
|
||||
### Phase 1: <name>
|
||||
1. <specific step>
|
||||
2. <specific step>
|
||||
|
||||
### Phase 2: <name> (if needed)
|
||||
1. <specific step>
|
||||
|
||||
## Build Verification
|
||||
- build command to run
|
||||
- expected outcome
|
||||
|
||||
## Status
|
||||
- [ ] Phase 1: <name>
|
||||
- [ ] Phase 2: <name> (if applicable)
|
||||
- [ ] Build verification
|
||||
- [ ] Code review
|
||||
|
||||
Do not implement code in this phase.
|
||||
```
|
||||
|
||||
## Phase 3: Plan Assessment
|
||||
|
||||
```text
|
||||
You are a plan assessment agent. Review and refine an implementation plan.
|
||||
|
||||
Read these files:
|
||||
- .ai/<PROJECT>/<LETTER>/context.md
|
||||
- .ai/<PROJECT>/<LETTER>/plan.md
|
||||
- Then read the actual source files referenced to verify the plan makes sense.
|
||||
|
||||
Assess the plan:
|
||||
|
||||
1. Correctness: Are the file paths and line references accurate? Does the plan reference real functions and types?
|
||||
2. Completeness: Are there missing steps? Edge cases not handled?
|
||||
3. Code quality: Will the plan minimize code duplication? Does it follow existing codebase patterns from AGENTS.md?
|
||||
4. Design: Could the approach be improved? Are there better patterns already used in the codebase?
|
||||
5. Phase sizing: Each phase should be implementable by a single agent in one session. If a phase has more than about 8-10 substantive code changes, split it further.
|
||||
|
||||
Update plan.md with your refinements. Keep the same structure but:
|
||||
- fix any inaccuracies
|
||||
- add missing steps
|
||||
- improve the approach if you found better patterns
|
||||
- ensure phases are properly sized for single-agent execution
|
||||
- add a line at the top of the Status section: `Phases: <N>`
|
||||
- add `Assessed: yes` at the bottom of the file
|
||||
|
||||
If the plan is small enough for a single agent (roughly 8 steps or fewer), mark it as a single phase.
|
||||
|
||||
Do not implement code in this phase.
|
||||
```
|
||||
|
||||
## Phase 4: Implementation
|
||||
|
||||
Run one implementation unit per plan phase. Keep implementation phases sequential by default. Parallelize only if their write sets are disjoint and the plan makes that safe.
|
||||
|
||||
For each phase in the plan that is not yet marked as done, use this prompt:
|
||||
|
||||
```text
|
||||
You are an implementation agent working on phase <N> of an implementation plan.
|
||||
|
||||
Read these files first:
|
||||
- .ai/<PROJECT>/<LETTER>/context.md
|
||||
- .ai/<PROJECT>/<LETTER>/plan.md
|
||||
|
||||
Then read the source files you will be modifying.
|
||||
|
||||
Your owned write set for this phase:
|
||||
<OWNED_WRITE_SET>
|
||||
|
||||
YOUR TASK: Implement only Phase <N> from the plan:
|
||||
<paste the specific phase steps here>
|
||||
|
||||
Rules:
|
||||
- Follow the plan precisely.
|
||||
- Follow AGENTS.md coding conventions.
|
||||
- You are not alone in the codebase. Respect existing changes and do not revert unrelated work.
|
||||
- Do not modify .ai/ files except to update the Status section in plan.md.
|
||||
- When done, update plan.md Status section: change `- [ ] Phase <N>: ...` to `- [x] Phase <N>: ...`
|
||||
- Do not work on other phases.
|
||||
|
||||
When finished, report what you did, which files you changed, and any issues encountered.
|
||||
```
|
||||
|
||||
After each implementation phase:
|
||||
1. Use a narrow read or search to confirm the status line was updated.
|
||||
2. Verify the owned write set and touched files with a small diff summary such as `git diff --name-only`.
|
||||
3. If more phases remain, run the next implementation phase.
|
||||
4. If all phases are done, proceed to build verification.
|
||||
|
||||
## Phase 5: Build Verification
|
||||
|
||||
Only run this phase if the task modified project source code.
|
||||
|
||||
Prefer running the build in the main session because it is critical-path work. If you delegate it, use a worker subagent and wait immediately for the result.
|
||||
|
||||
```text
|
||||
You are a build verification agent.
|
||||
|
||||
Read these files:
|
||||
- .ai/<PROJECT>/<LETTER>/context.md
|
||||
- .ai/<PROJECT>/<LETTER>/plan.md
|
||||
|
||||
The implementation is complete. Your job is to build the project and fix any build errors that block the planned work.
|
||||
|
||||
Steps:
|
||||
1. Run (from repository root): cmake --build ./out --config Debug --target Telegram
|
||||
2. If the build succeeds, update plan.md: change `- [ ] Build verification` to `- [x] Build verification`
|
||||
3. If the build fails:
|
||||
a. Read the error messages carefully
|
||||
b. Read the relevant source files
|
||||
c. Fix the errors in accordance with the plan and AGENTS.md conventions
|
||||
d. Rebuild and repeat until the build passes
|
||||
e. Update plan.md status when done
|
||||
|
||||
Rules:
|
||||
- Only fix build errors. Do not refactor or improve code beyond what is needed for a passing build.
|
||||
- Follow AGENTS.md conventions.
|
||||
- If build fails with file-locked errors (C1041, LNK1104, "cannot open output file", or similar access-denied lock issues), stop and report the lock. Do not retry.
|
||||
- You are not alone in the codebase. Respect existing changes and do not revert unrelated work.
|
||||
|
||||
When finished, report the build result and which files, if any, you changed.
|
||||
```
|
||||
|
||||
## Phase 6: Code Review Loop
|
||||
|
||||
After build verification passes, run up to 3 review-fix iterations. Set iteration counter `R = 1`.
|
||||
|
||||
Review loop:
|
||||
|
||||
```text
|
||||
LOOP:
|
||||
1. Run review phase 6a with iteration R.
|
||||
2. Read review<R>.md verdict:
|
||||
- "APPROVED" -> go to FINISH
|
||||
- "NEEDS_CHANGES" -> run fix phase 6b
|
||||
3. After fix work completes and build passes:
|
||||
R = R + 1
|
||||
If R > 3 -> go to FINISH
|
||||
Otherwise -> go to step 1
|
||||
|
||||
FINISH:
|
||||
- Update plan.md: change `- [ ] Code review` to `- [x] Code review`
|
||||
- Proceed to Phase 7 on Windows, otherwise proceed to Completion
|
||||
```
|
||||
|
||||
### Step 6a: Code Review
|
||||
|
||||
```text
|
||||
You are a code review agent for Telegram Desktop (C++ / Qt).
|
||||
|
||||
Read these files:
|
||||
- .ai/<PROJECT>/<LETTER>/context.md
|
||||
- .ai/<PROJECT>/<LETTER>/plan.md
|
||||
- REVIEW.md
|
||||
- If R > 1, also read .ai/<PROJECT>/<LETTER>/review<R-1>.md
|
||||
|
||||
Then run `git diff` to see the current uncommitted changes for this task.
|
||||
|
||||
Read the modified source files in full to understand the changes in context.
|
||||
|
||||
Perform a focused code review using these criteria, in order:
|
||||
|
||||
1. Correctness and safety: Obvious logic errors, missing null checks at API boundaries, potential crashes, use-after-free, dangling references, race conditions.
|
||||
2. Dead code: Added or left-behind code that is never used within the scope of the changes.
|
||||
3. Redundant changes: Diff hunks that have no functional effect.
|
||||
4. Code duplication: Repeated logic that should be shared.
|
||||
5. Wrong placement: Code added to a module where it does not logically belong.
|
||||
6. Function decomposition: Whether an extracted helper would clearly improve readability.
|
||||
7. Module structure: Only in exceptional cases where a large new chunk of code clearly belongs elsewhere.
|
||||
8. Style compliance: REVIEW.md rules and AGENTS.md conventions.
|
||||
|
||||
Important guidelines:
|
||||
- Review only the changes made, not pre-existing code outside the scope of the task.
|
||||
- Be pragmatic. Each suggestion should have a clear, concrete benefit.
|
||||
- Do not suggest comments, docstrings, or over-engineering.
|
||||
|
||||
Write your review to: .ai/<PROJECT>/<LETTER>/review<R>.md
|
||||
|
||||
The review document should contain:
|
||||
|
||||
## Code Review - Iteration <R>
|
||||
|
||||
## Summary
|
||||
<1-2 sentence overall assessment>
|
||||
|
||||
## Verdict: <APPROVED or NEEDS_CHANGES>
|
||||
|
||||
If the verdict is NEEDS_CHANGES, continue with:
|
||||
|
||||
## Changes Required
|
||||
|
||||
### <Issue 1 title>
|
||||
- Category: <dead code | duplication | wrong placement | function decomposition | module structure | style | correctness>
|
||||
- File(s): <file paths>
|
||||
- Problem: <clear description>
|
||||
- Fix: <specific description of what to change>
|
||||
|
||||
Keep the list focused. Prioritize the most impactful issues.
|
||||
|
||||
When finished, report your verdict clearly as: APPROVED or NEEDS_CHANGES.
|
||||
```
|
||||
|
||||
### Step 6b: Review Fix
|
||||
|
||||
```text
|
||||
You are a review fix agent. You implement improvements identified during code review.
|
||||
|
||||
Read these files:
|
||||
- .ai/<PROJECT>/<LETTER>/context.md
|
||||
- .ai/<PROJECT>/<LETTER>/plan.md
|
||||
- .ai/<PROJECT>/<LETTER>/review<R>.md
|
||||
|
||||
Then read the source files mentioned in the review.
|
||||
|
||||
YOUR TASK: Implement all changes listed in review<R>.md.
|
||||
|
||||
Rules:
|
||||
- Implement exactly the review changes, nothing more.
|
||||
- Follow AGENTS.md coding conventions.
|
||||
- You are not alone in the codebase. Respect existing changes and do not revert unrelated work.
|
||||
- Do not modify .ai/ files except where the review process explicitly requires it.
|
||||
|
||||
After all changes are made:
|
||||
1. Build (from repository root): cmake --build ./out --config Debug --target Telegram
|
||||
2. If the build fails, fix build errors and rebuild until it passes.
|
||||
3. If build fails with file-locked errors (C1041, LNK1104, "cannot open output file", or similar access-denied lock issues), stop and report the lock. Do not retry.
|
||||
|
||||
When finished, report what changes were made and which files you touched.
|
||||
```
|
||||
|
||||
## Phase 7: Windows Text Normalization
|
||||
|
||||
Run this phase only on Windows hosts and only after the review loop has finished.
|
||||
|
||||
Use the current task's result logs as the source of truth for what Codex touched. Do not sweep the whole repo and do not rewrite unrelated files from a dirty worktree.
|
||||
|
||||
```text
|
||||
You are performing the final Windows-only text normalization phase for task-think.
|
||||
|
||||
Read these files:
|
||||
- .ai/<PROJECT>/<LETTER>/plan.md
|
||||
- .ai/<PROJECT>/<LETTER>/logs/phase-4*.result.md
|
||||
- .ai/<PROJECT>/<LETTER>/logs/phase-5*.result.md
|
||||
- .ai/<PROJECT>/<LETTER>/logs/phase-6*.result.md
|
||||
|
||||
Your job:
|
||||
- Collect the union of repo file paths listed under "Touched files" in those result logs.
|
||||
- Keep only files inside the repository that currently exist and are textual project files: source, headers, build/config files, localization files, style files, and similar text assets.
|
||||
- Exclude `.ai/`, `out/`, binary files, and unrelated user files that were not touched by Codex in this task.
|
||||
- Rewrite each kept file so all line endings are CRLF.
|
||||
- If a kept file is UTF-8 or ASCII text, write it back as UTF-8 without BOM. Never add a UTF-8 BOM to source/config/project text files.
|
||||
- Preserve file content otherwise. Preserve whether the file ended with a trailing newline.
|
||||
|
||||
Rules:
|
||||
- Run this phase in the main session on Windows.
|
||||
- Do not modify files outside the touched-file set for the current task.
|
||||
- Do not rewrite binary files.
|
||||
- When scripting this phase, do not use writer APIs or defaults that emit UTF-8 with BOM.
|
||||
- If a file cannot be normalized safely, record it as a failure instead of silently skipping it.
|
||||
|
||||
When finished:
|
||||
1. Write `.ai/<PROJECT>/<LETTER>/logs/phase-7-line-endings.result.md`
|
||||
2. Include:
|
||||
- whether the phase completed
|
||||
- which files were normalized
|
||||
- which files were skipped and why
|
||||
- whether any UTF-8 BOMs were removed or verified absent
|
||||
- any failures that need to be mentioned in the final summary
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
When all phases, including build verification, code review, and Windows line ending normalization when applicable, are done:
|
||||
1. Read the final `plan.md` and report the summary to the user.
|
||||
2. Show which files were modified or created.
|
||||
3. Note any issues encountered during implementation.
|
||||
4. Summarize the code review iterations: how many rounds, what was found and fixed, or whether it was approved on the first pass.
|
||||
5. On Windows, mention the text-normalization result briefly: which project files were normalized, whether any BOMs were removed, or whether nothing needed changes.
|
||||
6. Calculate and display the total elapsed time since `$START_TIME` (format as `Xh Ym Zs`, omitting zero components).
|
||||
7. Remind the user of the project name so they can request follow-up tasks within the same project.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If any phase fails or gets stuck, follow the timeout and retry rules above. Do not close an agent solely because the final artifact is missing while its progress file is still advancing. For Phase 1, Phase 2, Phase 3, Phase 4, and Phase 6, do not rerun locally after delegated retries fail; ask the user instead.
|
||||
- If `context.md` or `plan.md` is not written properly by a phase, rerun that phase in a fresh subagent with more specific instructions.
|
||||
- If build errors persist after the build phase's attempts, report the remaining errors to the user.
|
||||
- If a review-fix phase introduces new build errors that it cannot resolve, report to the user.
|
||||
|
||||
## Prompt Delivery And Logs
|
||||
|
||||
For each phase:
|
||||
1. Write the full prompt to `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.prompt.md`
|
||||
2. Delegate by sending that prompt text to a fresh subagent, or use it as a same-session checklist only for the designated main-session phases or when delegation was unavailable from the start
|
||||
3. For delegated phases, expect a matching `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.progress.md` heartbeat while work is in flight
|
||||
4. Save a concise completion note to `.ai/<PROJECT>/<LETTER>/logs/phase-<name>.result.md`
|
||||
|
||||
For review iterations, include the iteration in the file name, for example:
|
||||
- `phase-6a-review-1.prompt.md`
|
||||
- `phase-6a-review-1.result.md`
|
||||
- `phase-6b-fix-1.prompt.md`
|
||||
- `phase-6b-fix-1.result.md`
|
||||
|
||||
## Subagent Pattern
|
||||
|
||||
Use this pattern conceptually for delegated phases:
|
||||
|
||||
1. Write the phase prompt file.
|
||||
2. Spawn a fresh subagent with the phase prompt, usually with `fork_context: false`.
|
||||
3. Require the agent to create the matching progress file early and refresh it sparingly: at natural milestones when possible, otherwise only after a longer quiet stretch such as roughly 5-10 minutes.
|
||||
4. Wait in 5-minute intervals when the next step is blocked on that phase, checking both the final artifact and the progress file on timeout.
|
||||
5. When the phase looks close to finishing, switch to 1-2 minute waits.
|
||||
6. Prefer filesystem mtime checks on the progress file first. If its mtime moved or the heartbeat counter increased, keep waiting; do not treat that as a stall.
|
||||
7. If neither the artifact nor the progress file moves, send one short follow-up to the same agent, then retry once with a fresh subagent before involving the user.
|
||||
8. Validate the expected artifact or code changes with small shell summaries and the completion checks above.
|
||||
9. Write the result log from the validated outcome and the compact reply block.
|
||||
|
||||
Do not replace this pattern with shell-launched `codex exec`.
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
name: task-think
|
||||
description: Orchestrate a multi-phase implementation workflow for this repository with artifact files under .ai/<project-name>/<letter>/ using Codex subagents instead of shell-spawned child processes. Use when the user wants one prompt to drive context gathering, planning, plan assessment, implementation, build verification, and review with persistent artifacts, clear phase handoffs, and a thin parent thread. Prefer spawn_agent/send_input/wait_agent, keep heavy pre-build work delegated when possible, and avoid pulling timed-out phases back into the main session.
|
||||
---
|
||||
|
||||
# Task Pipeline
|
||||
|
||||
Run a full implementation workflow with repository artifacts and clear phase boundaries.
|
||||
|
||||
## Inputs
|
||||
|
||||
Collect:
|
||||
- task description
|
||||
- optional project name (if missing, derive a short kebab-case name)
|
||||
- optional constraints (files, architecture, risk tolerance)
|
||||
- optional screenshot paths
|
||||
|
||||
If screenshots are attached in UI but not present as files, write a brief textual summary into the task artifacts before spawning fresh subagents so later phases can read the requirements without inheriting the whole parent thread.
|
||||
|
||||
## Overview
|
||||
|
||||
The workflow is organized around projects. Each project lives in `.ai/<project-name>/` and can contain multiple sequential tasks (labeled `a`, `b`, `c`, ... `z`).
|
||||
|
||||
Project structure:
|
||||
```text
|
||||
.ai/<project-name>/
|
||||
about.md # Single source of truth for the entire project
|
||||
a/ # First task
|
||||
context.md # Gathered codebase context for this task
|
||||
plan.md # Implementation plan
|
||||
review1.md # Code review documents (up to 3 iterations)
|
||||
review2.md
|
||||
review3.md
|
||||
logs/
|
||||
phase-*.prompt.md
|
||||
phase-*.progress.md
|
||||
phase-*.result.md
|
||||
b/ # Follow-up task
|
||||
context.md
|
||||
plan.md
|
||||
review1.md
|
||||
logs/
|
||||
...
|
||||
c/ # Another follow-up task
|
||||
...
|
||||
```
|
||||
|
||||
- `about.md` is the project-level blueprint: a single comprehensive document describing what this project does and how it works, written as if everything is already fully implemented. It contains no temporal state ("current state", "pending changes", "not yet implemented"). It is rewritten, not appended to, each time a new task starts, incorporating the new task's changes as if they were always part of the design.
|
||||
- Each task folder (`a/`, `b/`, ...) contains self-contained files for that task. The task's `context.md` carries all task-specific information: what specifically needs to change, the delta from the current codebase, gathered file references, and code patterns. Planning, implementation, and review phases should rely on the current task folder.
|
||||
|
||||
## Artifacts
|
||||
|
||||
Create and maintain:
|
||||
- `.ai/<project-name>/about.md`
|
||||
- `.ai/<project-name>/<letter>/context.md`
|
||||
- `.ai/<project-name>/<letter>/plan.md`
|
||||
- `.ai/<project-name>/<letter>/review<R>.md` (up to 3 review iterations)
|
||||
- `.ai/<project-name>/<letter>/logs/phase-<name>.prompt.md`
|
||||
- `.ai/<project-name>/<letter>/logs/phase-<name>.progress.md` for delegated phases
|
||||
- `.ai/<project-name>/<letter>/logs/phase-<name>.result.md`
|
||||
|
||||
Each `phase-<name>.result.md` should capture a concise outcome summary: whether the phase completed, which files it touched, and any follow-up notes or blockers.
|
||||
Each delegated `phase-<name>.progress.md` should act as a heartbeat: a tiny monotonic counter plus current step, files being read or edited, concrete findings so far, and the next checkpoint. It is not a final artifact; it exists so the parent can distinguish active research from a truly stuck subagent without rereading large context.
|
||||
|
||||
## Phases
|
||||
|
||||
Run these phases sequentially:
|
||||
|
||||
1. Phase 0: Setup - Record start time, detect follow-up vs new project, create directories.
|
||||
2. Phase 1: Context Gathering - Read codebase, write `about.md` and `context.md`. Use Phase 1F for follow-up tasks.
|
||||
3. Phase 2: Planning - Read context, write detailed `plan.md` with numbered steps grouped into phases.
|
||||
4. Phase 3: Plan Assessment - Review and refine the plan for correctness, completeness, code quality, and phase sizing.
|
||||
5. Phase 4: Implementation - Execute one implementation unit per plan phase.
|
||||
6. Phase 5: Build Verification - Build the project, fix any build errors. Skip if no source code was modified.
|
||||
7. Phase 6: Code Review Loop - Run review and fix iterations until approved or the iteration limit is reached.
|
||||
8. Phase 7: Windows Text Normalization - On Windows only, after review passes and before the final summary, normalize LF to CRLF for the text source/config files Codex edited in this task and ensure rewritten UTF-8 project files are saved without BOM.
|
||||
|
||||
Use the phase prompt templates in `PROMPTS.md`.
|
||||
|
||||
## Execution Mode
|
||||
|
||||
Use Codex subagents as the primary orchestration mechanism.
|
||||
|
||||
- When delegation is available, Phase 1, Phase 2, Phase 3, each Phase 4 implementation unit, and each Phase 6 review or review-fix pass must run in fresh subagents. Do not rerun those phases in the main session midstream just because a wait timed out or an artifact is missing.
|
||||
- Run Phase 7 in the main session on Windows because it depends on the final local file state and the exact touched-file set for the current task.
|
||||
- When any same-session helper rewrites Windows project text files, preserve CRLF and write UTF-8 without BOM. Avoid writer APIs or defaults that silently inject a UTF-8 BOM.
|
||||
- The main session may read `context.md` once after Phase 1 and `plan.md` once after Phase 3. After that, prefer narrow shell checks, file existence checks, and status-line reads instead of rereading full documents or diffs.
|
||||
- Prefer `worker` for phases that write files. Use `explorer` only for narrow read-only questions that unblock your next local step.
|
||||
- Keep `fork_context` off by default. Pass the phase prompt and explicit file paths instead of the whole thread unless the phase truly needs prior conversational context or thread-only attachments.
|
||||
- When the platform supports it, request `model: gpt-5.4` and `reasoning_effort: xhigh` for spawned phase agents. If overrides are unavailable, inherit the current session settings.
|
||||
- Write the exact phase prompt to the matching `logs/phase-<name>.prompt.md` file before you delegate. Use the same prompt file as a checklist if you later need to fall back to same-session execution.
|
||||
- For delegated phases, require an early `logs/phase-<name>.progress.md` heartbeat before deep work. The subagent should create or update it early, keep it tiny, and refresh it sparingly: preferably at natural milestones, and otherwise only after a longer quiet stretch such as roughly 5-10 minutes.
|
||||
- In every delegated prompt, require a compact final reply with only status, artifact paths, touched files, and blocker or `none`. Detailed reasoning belongs in `.ai/` artifacts, not in the chat reply.
|
||||
- After a subagent finishes, verify that the expected artifacts or code changes exist, then write a short result log in `logs/phase-<name>.result.md`.
|
||||
- For delegated phases, use `wait_agent` with a 5-minute timeout by default while a phase is still clearly in progress. Successful completion may wake earlier, so this does not add latency to finished phases.
|
||||
- When a phase looks close to completion — for example the final artifact has appeared, a build is in its final pass, or the agent said it is wrapping up — switch to 1-2 minute waits until it lands.
|
||||
- A timeout is not a failure; it only means no final status arrived yet. Do not treat short waits as stall detection for research-heavy phases.
|
||||
- On timeout, inspect the expected artifact, the phase progress file mtime, and the worktree for movement. Prefer mtime checks first; only reread the progress file when you need detail.
|
||||
- If the progress file mtime moved or its heartbeat counter increased since the previous check, treat that as active progress and wait again.
|
||||
- If no usable final artifact exists yet but the progress file is appearing or advancing, keep the same subagent alive. Progress-file movement does not count toward the retry limit.
|
||||
- If no usable final artifact exists yet and neither the expected artifact nor the progress file has moved since the previous blocked check, send one short follow-up asking the same subagent to refresh the progress file, finish the artifact, and return the compact status block, then wait again.
|
||||
- Only if the same subagent still shows no meaningful movement in either the expected artifact or the progress file after two full default waits and one follow-up should you close it and rerun that phase in a fresh subagent.
|
||||
- Use `wait_agent` only when the next step is blocked on the result. While the delegated phase runs, do small non-overlapping local tasks such as validating directory structure or preparing the next prompt file.
|
||||
- Build verification is critical-path work. Prefer running the build in the main session, and only delegate a bounded build-fix phase when there is a concrete reason.
|
||||
- If subagents are unavailable in the current environment, or current policy does not allow delegation from the start, run the phase in the main session using the same prompt files. Otherwise, do not switch a pre-build phase to same-session midstream. Never fall back to shell-spawned `codex exec` child processes from this skill.
|
||||
|
||||
## Verification Rules
|
||||
|
||||
- If build or test commands fail due to file locks or access-denied outputs (C1041, LNK1104), stop and ask the user to close locking processes before retrying.
|
||||
- Treat a delegated phase as complete only when the required artifact or status update exists on disk and matches the phase goals; do not rely on the chat reply alone.
|
||||
- Never claim completion without:
|
||||
- implemented code changes present
|
||||
- build attempt results recorded
|
||||
- review pass documented with any follow-up fixes
|
||||
- on Windows, if the task edited project source/config text files, a CRLF / no-BOM normalization pass recorded after review
|
||||
|
||||
## Completion Criteria
|
||||
|
||||
Mark complete only when:
|
||||
- All plan phases are done
|
||||
- Build verification is recorded
|
||||
- Review issues are addressed or explicitly deferred with rationale
|
||||
- On Windows, Codex-edited project source/config text files have been normalized to CRLF, any UTF-8 rewrites were saved without BOM, and the result is logged
|
||||
- Display total elapsed time since start (format: `Xh Ym Zs`, omitting zero components)
|
||||
- Remind the user of the project name so they can request follow-up tasks within the same project
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If any phase fails, times out, or gets stuck, follow the retry ladder from Execution Mode. Do not close an agent solely because the final artifact is missing while its progress file is still moving. After two delegated attempts remain blocked with no meaningful progress, report the issue to the user. Do not absorb the phase into the main session before build unless delegation was unavailable from the start.
|
||||
- If `context.md` or `plan.md` is not written properly by a phase, rerun that phase in a fresh subagent with more specific instructions. Do not repair it locally before build unless delegation was unavailable from the start.
|
||||
- If build errors persist after the build phase's attempts, report the remaining errors to the user.
|
||||
- If a review-fix phase introduces new build errors that it cannot resolve, report to the user.
|
||||
- If Phase 7 cannot safely normalize a touched file on Windows or remove an introduced UTF-8 BOM from a touched project text file, record the failure in the result log and report it in the final summary instead of silently skipping it.
|
||||
|
||||
## User Invocation
|
||||
|
||||
Use plain language with the skill name in the request, for example:
|
||||
|
||||
`Use local task-think skill with subagents: make sure FileLoadTask::process does not create or read QPixmap on background threads; use QImage with ARGB32_Premultiplied instead.`
|
||||
|
||||
For follow-up tasks on an existing project:
|
||||
|
||||
`Use local task-think skill with subagents: my-project also handle the case where the file is already cached`
|
||||
|
||||
If screenshots are relevant, include file paths in the same prompt when possible.
|
||||
@@ -1,57 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: true
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: true
|
||||
BeforeWhile: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBraces: Custom
|
||||
ColumnLimit: 120
|
||||
IncludeCategories:
|
||||
- Regex: '^<.*'
|
||||
Priority: 1
|
||||
- Regex: '^".*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 4
|
||||
InsertNewlineAtEOF: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 2
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
TabWidth: 4
|
||||
UseTab: Always
|
||||
...
|
||||
@@ -0,0 +1,306 @@
|
||||
---
|
||||
description: Generate an SVG icon from a design mockup using vectosolve vectorization
|
||||
allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Agent, AskUserQuestion, TodoWrite, mcp__vectosolve__vectorize
|
||||
---
|
||||
|
||||
# Icon - SVG Icon Generation from Design Mockup
|
||||
|
||||
You generate production-quality SVG icons for Telegram Desktop by vectorizing design mockup screenshots using the vectosolve MCP service, then post-processing the result to match the Telegram icon format.
|
||||
|
||||
**Arguments:** `$ARGUMENTS` = "$ARGUMENTS"
|
||||
|
||||
If `$ARGUMENTS` is empty, ask the user to describe the icon they want and paste a cropped screenshot of it.
|
||||
|
||||
## Overview
|
||||
|
||||
The workflow takes a cropped screenshot of an icon from a design mockup (grabbed from the clipboard), vectorizes it via the vectosolve MCP, then post-processes the SVG (recolor to white-on-transparent, restructure to minimal format, set 24x24 output size).
|
||||
|
||||
Working directory: `.ai/icon_{name}/` with iterations labeled by letter (`a/`, `b/`, ...), each containing `source.png`. Output SVGs are in the icon root: `a.svg`, `b.svg`, etc.
|
||||
|
||||
Follow-ups are supported: `/icon {icon_name} <description>` continues from where the previous run left off.
|
||||
|
||||
## Phase 0: Setup
|
||||
|
||||
**Record the current time** (using `date` or equivalent) as `$START_TIME`.
|
||||
|
||||
### Step 0a: Clipboard grab (MUST be the VERY FIRST action)
|
||||
|
||||
If there is an image attached to the user's message:
|
||||
|
||||
1. Generate a random 8-character hex string for `HASH` (use `openssl rand -hex 4` or similar).
|
||||
2. **IMMEDIATELY** — before any other processing — run this Bash command to save the clipboard image:
|
||||
```bash
|
||||
HASH=$(openssl rand -hex 4) && if [[ "$OSTYPE" == darwin* ]]; then bash .claude/grab_clipboard.sh ".ai/icon_${HASH}.png"; else powershell -ExecutionPolicy Bypass -File .claude/grab_clipboard.ps1 ".ai/icon_${HASH}.png"; fi
|
||||
```
|
||||
On macOS `.claude/grab_clipboard.sh` is used; on Windows `.claude/grab_clipboard.ps1`. Both grab the current clipboard image and save it to the specified path.
|
||||
|
||||
3. If the command fails (exit 1 / no image on clipboard):
|
||||
- Tell the user: **"Clipboard doesn't contain an image. Please copy the icon area first, then retry."** (On macOS: Cmd+Ctrl+Shift+4 to snip to clipboard; on Windows: Win+Shift+S.)
|
||||
- **STOP IMMEDIATELY. Do NOT continue.** You cannot use the image pasted in the conversation — it exists only as pixels in the chat, not as a file you can send to vectosolve. The clipboard grab is the ONLY way to get the image to disk. Do not attempt any workaround.
|
||||
|
||||
4. Read back the saved `.ai/icon_HASH.png` using the Read tool.
|
||||
5. Compare it visually with the image pasted in the conversation. They should depict the same thing.
|
||||
- If they look **completely different**: delete `.ai/icon_HASH.png` and fail:
|
||||
> "The clipboard image doesn't match what you pasted. Please re-copy and retry."
|
||||
- If they look the same (or close enough): proceed. Store the temp path.
|
||||
|
||||
If NO image is attached to the message, skip this step entirely.
|
||||
|
||||
### Step 0b: Fail-fast — verify vectosolve MCP
|
||||
|
||||
Check that the `mcp__vectosolve__vectorize` tool is available by looking at your available tools list. If it is NOT available, fail immediately with:
|
||||
|
||||
> vectosolve MCP is not configured. Set it up with:
|
||||
> ```
|
||||
> claude mcp add vectosolve --scope user -e VECTOSOLVE_API_KEY=vs_xxx -- npx @vectosolve/mcp
|
||||
> ```
|
||||
> Then restart Claude Code.
|
||||
|
||||
### Step 0c: Follow-up detection
|
||||
|
||||
Extract the first word/token from `$ARGUMENTS` (everything before the first space or newline). Call it `FIRST_TOKEN`.
|
||||
|
||||
Run these TWO commands using the Bash tool, **IN PARALLEL**:
|
||||
1. `ls .ai/` — to see all existing icon project names
|
||||
2. `ls .ai/icon_{FIRST_TOKEN}/context.md` — to check if this specific icon project exists
|
||||
|
||||
**Evaluate the results:**
|
||||
- If command 2 **succeeds** (context.md exists): this is a **follow-up**. The icon name is `FIRST_TOKEN`. The follow-up description is everything in `$ARGUMENTS` after `FIRST_TOKEN`.
|
||||
- If command 2 **fails** (not found): this is a **new icon**. The full `$ARGUMENTS` is the icon description.
|
||||
|
||||
### Step 0d: New icon setup
|
||||
|
||||
1. Parse `$ARGUMENTS` to determine:
|
||||
- **Icon description**: what the icon should depict
|
||||
- **Icon type**: default is `menu` (24x24 menu/button icon). User may specify otherwise.
|
||||
- **Target subfolder**: `menu/` by default, or another subfolder if specified.
|
||||
|
||||
2. Choose an icon file name:
|
||||
- Lowercase letters and underscores only — **NO hyphens**
|
||||
- Match existing naming conventions (check `Telegram/Resources/icons/{subfolder}/`)
|
||||
- Must NOT conflict with existing icons
|
||||
- Must NOT collide with existing `.ai/icon_{name}/` directories
|
||||
|
||||
3. Create `.ai/icon_{name}/` and `.ai/icon_{name}/a/`.
|
||||
|
||||
4. Write `.ai/icon_{name}/context.md` with:
|
||||
```
|
||||
## Icon: {icon_name}
|
||||
Type: {menu/other}
|
||||
Target: Telegram/Resources/icons/{subfolder}/{icon_name}.svg
|
||||
|
||||
## Original Request
|
||||
{full $ARGUMENTS text}
|
||||
|
||||
## Follow-ups
|
||||
(none yet)
|
||||
```
|
||||
|
||||
5. Set `LETTER` to `a`.
|
||||
|
||||
### Step 0e: Follow-up setup
|
||||
|
||||
1. Read `.ai/icon_{name}/context.md` to get the icon type, subfolder, and full history.
|
||||
2. Find the latest existing letter folder in `.ai/icon_{name}/` (highest letter).
|
||||
3. Set `LETTER` to the next letter after the latest.
|
||||
4. Create `.ai/icon_{name}/{LETTER}/`.
|
||||
5. Update `.ai/icon_{name}/context.md` — append the follow-up description to the `## Follow-ups` section:
|
||||
```
|
||||
### Follow-up (starting at letter {LETTER})
|
||||
{follow-up description}
|
||||
```
|
||||
|
||||
### Step 0f: Place source image
|
||||
|
||||
If a clipboard image was grabbed in Step 0a:
|
||||
1. Copy (or move) `.ai/icon_HASH.png` → `.ai/icon_{name}/source.png` (overwrite if exists — this is always the latest source).
|
||||
2. Copy it to `.ai/icon_{name}/{LETTER}/source.png` (archive per-iteration source).
|
||||
3. Delete the temp `.ai/icon_HASH.png` if it was copied (not moved).
|
||||
|
||||
If NO image was grabbed:
|
||||
- **New icon with no image**: Ask the user to provide a screenshot. STOP.
|
||||
- **Follow-up with no image**: The existing `source.png` in the icon root carries forward. Copy it to `.ai/icon_{name}/{LETTER}/source.png`. If no source.png exists at all, ask the user for an image.
|
||||
|
||||
### Step 0g: Verify renderer
|
||||
|
||||
Locate the render tool (`codegen_style` with `--render-svg` mode):
|
||||
|
||||
```bash
|
||||
if [[ "$OSTYPE" == darwin* ]]; then
|
||||
ls out/Telegram/codegen/codegen/style/Debug/codegen_style
|
||||
else
|
||||
ls out/Telegram/codegen/codegen/style/Debug/codegen_style.exe
|
||||
fi
|
||||
```
|
||||
|
||||
If missing, build it: `cmake --build out --config Debug --target codegen_style`
|
||||
|
||||
Test on a known good SVG (use the appropriate binary path for the OS):
|
||||
```bash
|
||||
CODEGEN=$(if [[ "$OSTYPE" == darwin* ]]; then echo out/Telegram/codegen/codegen/style/Debug/codegen_style; else echo out/Telegram/codegen/codegen/style/Debug/codegen_style.exe; fi)
|
||||
$CODEGEN --render-svg Telegram/Resources/icons/menu/tag_add.svg .ai/icon_{name}/test_render.png 512
|
||||
```
|
||||
|
||||
If works → delete test render, set `RENDER_AVAILABLE = true`. If fails → `RENDER_AVAILABLE = false`.
|
||||
|
||||
## Phase 1: Vectorize & Post-process
|
||||
|
||||
### Step 1a: Call vectosolve
|
||||
|
||||
Use the `mcp__vectosolve__vectorize` tool with `file_path` set to the **absolute path** of `.ai/icon_{name}/{LETTER}/source.png`.
|
||||
|
||||
**If this fails, STOP IMMEDIATELY.** Do NOT try to generate the SVG manually or by any other means. Report the error to the user and let them fix the issue (bad API key, no credits, network error, etc.).
|
||||
|
||||
Save the returned SVG content to `.ai/icon_{name}/{LETTER}/raw_vectosolve.svg`.
|
||||
|
||||
The MCP tool calls the vectosolve API ($0.20/call). The API key is stored in `~/.claude.json` MCP config (never in the repository).
|
||||
|
||||
### Step 1b: Post-process the SVG
|
||||
|
||||
The vectosolve SVG will have colors from the mockup, arbitrary dimensions, and possibly a non-square aspect ratio from a non-square screenshot crop. Post-processing fixes this by adjusting the **viewBox** — leave path coordinates untouched.
|
||||
|
||||
**Do NOT transform path coordinates.** Vectosolve's paths are correct — the only thing wrong is the framing. All geometry adjustments are done by manipulating the `viewBox` and the `width`/`height` attributes.
|
||||
|
||||
#### Sub-step 1: Read the request and determine parameters
|
||||
|
||||
Before touching the SVG, determine these from the user's request and context.md:
|
||||
|
||||
1. **Output size** (`OUT_W × OUT_H`): default is `24px × 24px` for menu icons. The user may request different dimensions (e.g., 36×36, 48×48, or non-square). Always check the request.
|
||||
2. **Content padding**: default is ~2px equivalent on each side at the output scale (so content fills roughly (OUT_W-4) × (OUT_H-4)). The user may request different padding or edge-to-edge.
|
||||
3. **Centering**: default is centered both horizontally and vertically. The user may request specific alignment (e.g., "align to bottom").
|
||||
|
||||
#### Sub-step 2: Parse the raw SVG
|
||||
|
||||
1. Extract the `viewBox`: `viewBox="VB_X VB_Y VB_W VB_H"` (typically `0 0 W H`).
|
||||
2. Identify ALL paths. Classify each:
|
||||
- **Background**: a rect or path spanning the full viewBox (first path that's a simple rectangle matching the viewBox bounds). **Remove it entirely.**
|
||||
- **Content**: the actual icon shapes. **Keep these, paths unchanged.**
|
||||
3. If paths have `transform="translate(TX,TY)"` attributes, that's fine — keep them as-is. The viewBox framing will work regardless.
|
||||
|
||||
#### Sub-step 3: Compute the content bounding box
|
||||
|
||||
Estimate the bounding box of the content paths (after removing the background). You can either:
|
||||
- Eyeball it from the path coordinates (look at first/last M commands and extremes of curves)
|
||||
- Or for precision, write a quick script to parse the paths and find min/max X/Y
|
||||
|
||||
Call the result: `CX_MIN, CY_MIN, CX_MAX, CY_MAX`. Content dimensions: `CW = CX_MAX - CX_MIN`, `CH = CY_MAX - CY_MIN`.
|
||||
|
||||
#### Sub-step 4: Compute the new viewBox
|
||||
|
||||
The viewBox determines what part of the SVG coordinate space maps to the output rectangle. By expanding the viewBox beyond the content bounds, we add padding. By making the viewBox aspect ratio match the output aspect ratio, we prevent stretching.
|
||||
|
||||
1. **Output aspect ratio**: `OUT_AR = OUT_W / OUT_H` (for 24×24 this is 1.0).
|
||||
2. **Padding in SVG coordinates**: we want ~2px padding at output scale. The scale factor is `OUT_W / VB_CONTENT_W` approximately, so padding in SVG coords = `2 * (CW / (OUT_W - 4))` (or similar — the exact formula depends on which dimension is dominant). Simpler approach: aim for content to occupy ~83% of the viewBox (≈ 20/24), so:
|
||||
- `PADDED_W = CW / 0.83`
|
||||
- `PADDED_H = CH / 0.83`
|
||||
3. **Match output aspect ratio**: the viewBox aspect ratio must equal `OUT_AR` to avoid stretching.
|
||||
- If `PADDED_W / PADDED_H > OUT_AR`: width is dominant → `VB_W = PADDED_W`, `VB_H = VB_W / OUT_AR`
|
||||
- If `PADDED_W / PADDED_H < OUT_AR`: height is dominant → `VB_H = PADDED_H`, `VB_W = VB_H * OUT_AR`
|
||||
- If equal: `VB_W = PADDED_W`, `VB_H = PADDED_H`
|
||||
4. **Center the content** in the new viewBox:
|
||||
- `VB_X = CX_MIN - (VB_W - CW) / 2`
|
||||
- `VB_Y = CY_MIN - (VB_H - CH) / 2`
|
||||
- (Adjust if the user requested non-centered alignment)
|
||||
|
||||
The new viewBox is: `viewBox="VB_X VB_Y VB_W VB_H"`.
|
||||
|
||||
#### Sub-step 5: Recolor to white-on-transparent
|
||||
|
||||
- Replace ALL `fill` color values (anything that isn't `none`) with `#FFFFFF`.
|
||||
- Remove ALL `stroke` and `stroke-width` attributes entirely.
|
||||
- Remove `opacity` attributes if present.
|
||||
|
||||
#### Sub-step 6: Determine path composition
|
||||
|
||||
Look at the icon's visual structure and decide how paths should combine:
|
||||
- **Outlined shape** (e.g., circle outline with something inside): combine outer + inner cutout into one `<path>` with `fill-rule="evenodd"`.
|
||||
- **Separate distinct parts** (e.g., magnifying glass + checkmark): keep as separate `<path>` elements.
|
||||
- **Filled shape with cutout** (e.g., filled circle with checkmark punched out): combine into one path with `fill-rule="evenodd"`.
|
||||
|
||||
#### Sub-step 7: Assemble final SVG
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="{OUT_W}px" height="{OUT_H}px" viewBox="{VB_X} {VB_Y} {VB_W} {VB_H}" xmlns="http://www.w3.org/2000/svg">
|
||||
<g stroke="none" fill="none" fill-rule="evenodd">
|
||||
<path d="..." fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</svg>
|
||||
```
|
||||
|
||||
- `width`/`height` = the output size from the request (default `24px`/`24px`).
|
||||
- `viewBox` = the computed viewBox from Sub-step 4. The SVG renderer maps this coordinate region to the output size.
|
||||
- Path `d` attributes are **unchanged** from vectosolve output (just background removed, colors replaced).
|
||||
- No `<title>`, `id`, `xmlns:xlink`, `version`, `class`, `style`, XML comments, `<metadata>`, or `preserveAspectRatio`.
|
||||
- No `<circle>`, `<rect>`, `<line>` — only `<path>`.
|
||||
|
||||
Write the final SVG to `.ai/icon_{name}/{LETTER}.svg`.
|
||||
|
||||
### Step 1c: Render
|
||||
|
||||
If `RENDER_AVAILABLE`:
|
||||
```bash
|
||||
$CODEGEN --render-svg ".ai/icon_{name}/{LETTER}.svg" ".ai/icon_{name}/render_{LETTER}.png" 512
|
||||
```
|
||||
|
||||
Read the render to visually verify the result.
|
||||
|
||||
## Phase 2: Review
|
||||
|
||||
After rendering, assess the result:
|
||||
|
||||
1. **Recognizable?** The icon should be clearly identifiable as the intended symbol.
|
||||
2. **Scale reasonable?** Should fill the space appropriately with ~2-3px padding.
|
||||
3. **Clean lines?** No broken paths, artifacts, or unwanted elements.
|
||||
4. **Correct colors?** All white on transparent (no leftover colors from the mockup).
|
||||
|
||||
If the result looks good → proceed to Phase 3 (Output).
|
||||
|
||||
If there are fixable issues (stray element, missed color, etc.) → fix the SVG directly, re-render, and re-check.
|
||||
|
||||
If the result is poor (vectosolve couldn't handle the input well) → report to the user and suggest:
|
||||
- Trying a cleaner/larger crop of the icon
|
||||
- Providing a different screenshot
|
||||
- Following up: `/icon {icon_name} <description of what to change>`
|
||||
|
||||
## Phase 3: Output
|
||||
|
||||
1. Read the `Target:` line from `.ai/icon_{name}/context.md` to get the output path.
|
||||
|
||||
2. Copy the final SVG to that target path (e.g., `Telegram/Resources/icons/menu/{icon_name}.svg`).
|
||||
|
||||
3. Update `.ai/icon_{name}/context.md` — append to the end:
|
||||
```
|
||||
## Latest Output
|
||||
Letter: {LETTER}
|
||||
Written to: {target_path}
|
||||
```
|
||||
|
||||
4. Report to the user:
|
||||
- Final icon file path
|
||||
- Number of vectosolve calls made (cost at $0.20/call)
|
||||
- Suggest verifying visually
|
||||
- Working directory `.ai/icon_{name}/` has all iterations
|
||||
- Elapsed time since `$START_TIME` (format `Xm Ys`)
|
||||
- Follow-up: `/icon {icon_name} <description of what to change>`
|
||||
|
||||
## Text-only Follow-ups (no new image)
|
||||
|
||||
When a follow-up has no attached image, the user wants to refine the existing SVG based on text feedback. In this case:
|
||||
|
||||
1. Skip Phase 1 (no vectosolve call needed).
|
||||
2. Read the latest SVG (`.ai/icon_{name}/{prev_letter}.svg`).
|
||||
3. Read the latest render if available.
|
||||
4. Apply the user's requested changes by editing the SVG directly.
|
||||
5. Save as `.ai/icon_{name}/{LETTER}.svg`.
|
||||
6. Render, review, and output as normal (Phases 1c → 3).
|
||||
|
||||
If the changes are too complex for manual SVG editing, suggest the user provide a new screenshot instead.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If clipboard grab fails → tell user to re-copy and retry.
|
||||
- If vectosolve returns an error → report it and suggest a different/cleaner screenshot.
|
||||
- If vectosolve returns SVG that can't be parsed → save raw output for debugging, report to user.
|
||||
- If the render helper fails → set `RENDER_AVAILABLE = false`, continue with SVG-only review.
|
||||
- If post-processing produces a broken SVG → fall back to the raw vectosolve output and do lighter cleanup.
|
||||
@@ -0,0 +1,122 @@
|
||||
---
|
||||
description: Plan and create a repetitive task automation (prompt.md + tasks.json pair)
|
||||
allowed-tools: Read, Write, Edit, Glob, Grep, Bash(mkdir:*), Bash(ls:*), AskUserQuestion
|
||||
---
|
||||
|
||||
# Task Planner - Create Automated Task Workflows
|
||||
|
||||
You are setting up a new **repetitive task automation** for Claude Code. The goal is to create a folder in `.ai/<featurename>/` containing:
|
||||
- `prompt.md` - Detailed instructions for the autonomous agent
|
||||
- `tasks.json` - List of tasks with completion tracking
|
||||
|
||||
This pair can then be executed via `.claude/iterate.ps1 <featurename>`.
|
||||
|
||||
## Your Workflow
|
||||
|
||||
### 1. Understand the Goal
|
||||
|
||||
First, understand what the user wants to automate. Ask clarifying questions using AskUserQuestion if needed:
|
||||
- What is the overall goal/feature being implemented?
|
||||
- What are the individual tasks involved?
|
||||
- Are there dependencies between tasks?
|
||||
- What files/areas of the codebase are involved?
|
||||
- Are there any reference examples or patterns to follow?
|
||||
|
||||
### 2. Choose a Feature Name
|
||||
|
||||
The `<featurename>` should be:
|
||||
- Short (1-2 words, lowercase, hyphen-separated)
|
||||
- Easy to type on command line
|
||||
- Descriptive of the work being done
|
||||
- Not already used in `.ai/`
|
||||
|
||||
Check existing folders:
|
||||
```bash
|
||||
ls .ai/
|
||||
```
|
||||
|
||||
Suggest a name to the user or let them specify one directly via $ARGUMENTS.
|
||||
|
||||
|
||||
### 3. Create the Folder and Files
|
||||
|
||||
Create `.ai/<featurename>/`:
|
||||
|
||||
**prompt.md** should include:
|
||||
- Overview of what we're doing
|
||||
- Architecture/context needed
|
||||
- Step-by-step instructions for each task type
|
||||
- Code patterns and examples
|
||||
- Build/test commands
|
||||
- Commit message format (see below)
|
||||
|
||||
### Commit Message Guidelines
|
||||
|
||||
All prompts should specify commit message length requirements:
|
||||
- **Soft limit**: ~50 characters (ideal length for first line)
|
||||
- **Hard limit**: 76 characters (must not exceed)
|
||||
|
||||
Example instruction for prompt.md:
|
||||
```
|
||||
## Commit Format
|
||||
|
||||
First line: Short summary ending with a dot (aim for ~50 chars, max 76 chars)
|
||||
|
||||
<Optional body with details, also ending with a dot.>
|
||||
|
||||
IMPORTANT: Never try to commit files in .ai/
|
||||
```
|
||||
|
||||
**tasks.json** format:
|
||||
```json
|
||||
{
|
||||
"tasks": [
|
||||
{
|
||||
"id": "task-id",
|
||||
"title": "Short task title",
|
||||
"description": "Detailed description of what to do",
|
||||
"started": false,
|
||||
"completed": false,
|
||||
"dependencies": ["other-task-id"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Iterate with the User
|
||||
|
||||
After creating initial files, the user may want to:
|
||||
- Add more tasks to tasks.json
|
||||
- Refine the prompt with more details
|
||||
- Add examples or patterns
|
||||
- Clarify instructions
|
||||
|
||||
Keep refining until the user is satisfied.
|
||||
|
||||
## Arguments
|
||||
|
||||
If `$ARGUMENTS` is provided, it's the feature name to use:
|
||||
- `$ARGUMENTS` = "$ARGUMENTS"
|
||||
|
||||
If empty, you'll need to determine/suggest a name based on the discussion.
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Settings Migration
|
||||
```
|
||||
/taskplanner settings-upgrade
|
||||
```
|
||||
Creates `.ai/settings-upgrade/` with prompt and tasks for migrating settings sections.
|
||||
|
||||
### Example 2: Open-ended
|
||||
```
|
||||
/taskplanner
|
||||
```
|
||||
Starts a conversation to understand what needs to be automated, then creates the appropriate folder.
|
||||
|
||||
## Starting Point
|
||||
|
||||
Let's begin! Please describe:
|
||||
1. What repetitive coding task do you want to automate?
|
||||
2. What is the end goal?
|
||||
3. Do you have initial tasks in mind, or should we discover them together?
|
||||
@@ -0,0 +1,136 @@
|
||||
---
|
||||
description: Learn from corrections — examine staged vs unstaged diffs and optionally distill insights into AGENTS.md or REVIEW.md
|
||||
allowed-tools: Read, Edit, Bash(git diff:*), Bash(git status:*), Bash(git log:*), Bash(ls:*), AskUserQuestion
|
||||
---
|
||||
|
||||
# Reflect — Learn from Corrections
|
||||
|
||||
You are a reflection agent. Your job is to examine the difference between what an AI agent produced (staged changes) and what the user corrected (unstaged changes), and determine whether any **general, reusable insight** can be extracted and added to the project's coding guidelines.
|
||||
|
||||
**CRITICAL: Use extended thinking ultrathink for your analysis. This requires deep, careful reasoning.**
|
||||
|
||||
## Arguments
|
||||
|
||||
`$ARGUMENTS` = "$ARGUMENTS"
|
||||
|
||||
If `$ARGUMENTS` is provided, it is a task name (project name from the `/task` workflow). This means the agent was working within `.ai/<task-name>/` and you should read the task context for deeper understanding of what the agent was trying to do.
|
||||
|
||||
If `$ARGUMENTS` is empty, skip the task context step — just work from the diffs alone.
|
||||
|
||||
## Context
|
||||
|
||||
The workflow is:
|
||||
1. An AI agent implemented something and its changes were staged (`git add`).
|
||||
2. The user reviewed and corrected the agent's work. These corrections are unstaged.
|
||||
3. You are now invoked to reflect on what went wrong and whether it reveals a pattern.
|
||||
|
||||
## Step 1: Gather the Diffs and Task Context
|
||||
|
||||
Run these commands in parallel:
|
||||
|
||||
```bash
|
||||
git diff --cached # What the agent wrote (staged)
|
||||
git diff # What the user corrected (unstaged, on top of staged)
|
||||
git status # Which files are involved
|
||||
```
|
||||
|
||||
If either diff is empty, tell the user and stop. Both diffs must be non-empty for reflection to be meaningful.
|
||||
|
||||
### Task context (only if `$ARGUMENTS` is non-empty)
|
||||
|
||||
The task name is `$ARGUMENTS`. Read the task's project context:
|
||||
|
||||
1. Read `.ai/$ARGUMENTS/about.md` — the project-level description of what this feature does.
|
||||
2. Find the latest task iteration folder: list `.ai/$ARGUMENTS/` and pick the folder with the highest letter (`a`, `b`, `c`, ...).
|
||||
3. Read `.ai/$ARGUMENTS/<latest-letter>/context.md` — the detailed implementation context the agent was working from.
|
||||
|
||||
This helps you distinguish between:
|
||||
- **Task-specific mistakes** — the agent misunderstood this particular feature's requirements or made a wrong choice within the specific problem. These are NOT documentation-worthy.
|
||||
- **General convention mistakes** — the agent did something that violates a pattern the codebase follows broadly, regardless of which feature is being implemented. These ARE potentially documentation-worthy.
|
||||
|
||||
Having the task context makes this distinction much sharper. Without it, you might mistake a task-specific correction for a general pattern or vice versa.
|
||||
|
||||
## Step 2: Read the Current Guidelines
|
||||
|
||||
Read both files:
|
||||
- `AGENTS.md` — development guidelines: build system, coding style, API usage patterns, UI styling, localization, rpl, architectural conventions, "how to do things"
|
||||
- `REVIEW.md` — mechanical style and formatting rules: brace placement, operator position, type checks, variable initialization, call formatting
|
||||
|
||||
Read them carefully. You need to know exactly what's already documented to avoid duplicates and detect contradictions.
|
||||
|
||||
## Step 3: Analyze the Corrections
|
||||
|
||||
Now think deeply. For each correction the user made, ask yourself:
|
||||
|
||||
1. **What did the agent do wrong?** Understand the specific mistake.
|
||||
2. **Why was it wrong?** Identify the underlying principle.
|
||||
3. **Is this already covered by AGENTS.md or REVIEW.md?** Check carefully:
|
||||
- If the existing rule's scope, title, and examples **clearly cover** this exact scenario and the agent just ignored it — that's not a documentation problem. Skip it.
|
||||
- If the existing rule **technically applies** but its scope is too narrow, its examples don't illustrate this usage pattern, or its wording would reasonably lead an agent to think it doesn't apply here — **the rule needs improvement**. Treat this as a potential insight (broaden the scope, add examples, adjust wording). A rule that agents repeatedly violate is an ineffective rule.
|
||||
4. **Is this specific to this particular task, or is it general?** Most corrections are task-specific ("wrong variable here", "this should call that function instead"). These are NOT documentation-worthy. Only patterns that would apply across many different tasks are worth capturing.
|
||||
5. **Would documenting this actually help a future agent?** Some things are too context-dependent or too obvious to be useful as a written rule. Be honest about this.
|
||||
|
||||
## Step 4: Decision
|
||||
|
||||
After analysis, you MUST reach one of these conclusions:
|
||||
|
||||
### Conclusion A: No actionable insight
|
||||
|
||||
The corrections are purely task-specific, or the existing documentation clearly and specifically covers the exact scenario and the agent simply ignored it. Say what the corrections were and why no doc changes are needed. Then **stop**.
|
||||
|
||||
### Conclusion B: New insight found
|
||||
|
||||
You can articulate a **concise, general rule** that:
|
||||
- Applies broadly (not just to this one task)
|
||||
- Is not already documented
|
||||
- Would genuinely help a future agent avoid the same class of mistake
|
||||
- Can be expressed in a few sentences with a clear code example
|
||||
|
||||
If you have a new insight, proceed to Step 5.
|
||||
|
||||
### Conclusion C: Existing rule needs improvement
|
||||
|
||||
A rule already exists in AGENTS.md or REVIEW.md, but its **scope is too narrow**, its **examples don't cover** the pattern the agent encountered, or its **wording** would reasonably lead an agent to think the rule doesn't apply. The agent's mistake is evidence the rule isn't effective.
|
||||
|
||||
This is NOT the same as Conclusion A. The test: would a careful agent, reading the existing rule, clearly know it applies to this specific situation? If no — the rule needs to be broadened, its examples expanded, or its title/scope adjusted. Proceed to Step 5.
|
||||
|
||||
**Common signs of an ineffective rule:**
|
||||
- The rule's title or scope restricts it to a context narrower than the actual principle (e.g., "in localization calls" when the pattern applies generally)
|
||||
- The examples only show one usage pattern, and the agent encountered a different one
|
||||
- The wording describes *what* to use but not *when* — so agents only apply it in situations that look like the examples
|
||||
|
||||
## Step 5: Categorize and Check for Contradictions
|
||||
|
||||
### Where does it belong?
|
||||
|
||||
- **REVIEW.md** — if it's a mechanical/style rule: formatting, naming, syntax preferences, call structure, brace/operator placement, type usage patterns. Rules that can be checked by looking at code locally without understanding the broader feature.
|
||||
- **AGENTS.md** — if it's an architectural/behavioral guideline: how to use APIs, where to place code, design patterns, build conventions, module organization, reactive patterns (rpl), localization usage, style system usage. Rules that require understanding the broader context.
|
||||
|
||||
### Does it contradict existing content?
|
||||
|
||||
Read the target file again carefully. Check if:
|
||||
1. The new insight **contradicts** an existing rule — if so, do NOT just append or just remove. Instead, use AskUserQuestion to present both the existing rule and the new insight to the user, explain the contradiction, and ask how to reconcile them.
|
||||
2. The new insight **overlaps** with an existing rule — if so, consider whether the existing rule should be extended/refined rather than adding a separate entry.
|
||||
3. The new insight is **complementary** — it adds something new without conflicting. This is the simplest case.
|
||||
|
||||
## Step 6: Propose the Change
|
||||
|
||||
**Do NOT silently edit the files.** First, present your proposed change to the user:
|
||||
|
||||
- Quote the exact text you want to add or modify
|
||||
- Explain which file and where in the file
|
||||
- Explain why this is general enough to document
|
||||
- If modifying existing text, show the before and after
|
||||
|
||||
Use AskUserQuestion to get the user's approval before making any edit.
|
||||
|
||||
Only after the user approves, apply the edit using the Edit tool.
|
||||
|
||||
## Rules
|
||||
|
||||
- **Keep docs lean and high-signal.** Don't add vague or overly specific rules. But don't default to inaction either — if the user had to manually fix something that a better-worded rule would have prevented, improving that rule is high-signal work.
|
||||
- **Never dump corrections verbatim.** The goal is distilled principles, not a changelog of mistakes.
|
||||
- **One insight per reflection, maximum.** If you think you see multiple insights, pick the strongest one. You can always run `/reflect` again next time.
|
||||
- **Keep the same style.** Match the formatting, tone, and level of detail of the target file. REVIEW.md uses specific before/after code examples. AGENTS.md uses explanatory sections with code snippets.
|
||||
- **Don't add "don't do X" rules.** Frame rules positively: "do Y" is better than "don't do X." Show the right way, not just the wrong way.
|
||||
- **No meta-commentary.** Don't add notes like "Added after reflection on..." — the rule should read as if it was always there.
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
description: Prepare changelog, set version, and commit a new release
|
||||
allowed-tools: Read, Bash, Edit, Grep, AskUserQuestion
|
||||
---
|
||||
|
||||
# Release — Changelog, Set Version, Commit
|
||||
|
||||
Full release flow: generate changelog entry, run `set_version`, and commit.
|
||||
|
||||
**Arguments:** `$ARGUMENTS` = "$ARGUMENTS"
|
||||
|
||||
Parse `$ARGUMENTS` for two optional parts (in any order):
|
||||
- A **version number** like `6.7` or `6.7.0` — if provided, use it as the new version exactly.
|
||||
- The word **"beta"** — if present, mark the release as beta.
|
||||
|
||||
If no version number is given, auto-increment the patch component (see step 2).
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Check git status is clean
|
||||
|
||||
Run `git status --porcelain`. If there are any uncommitted changes, **stop** and ask the user to commit or discard them before proceeding. Do not continue until status is clean.
|
||||
|
||||
### 2. Read the current changelog
|
||||
|
||||
Read `changelog.txt` from the repository root. Note the **latest version number** on the first line (e.g. `6.6.3 beta (12.03.26)`). Parse its major.minor.patch components.
|
||||
|
||||
### 3. Determine the new version number
|
||||
|
||||
**Important:** version numbers are shared across the beta and stable tracks — the sequence advances through both. The same `major.minor.patch` cannot be released as both beta and stable. A beta release "uses up" that number; the next stable must bump to a new patch.
|
||||
|
||||
- **If a version was provided in arguments**, use it directly (append `.0` if only major.minor was given). If the latest changelog entry already used this exact number (regardless of beta/stable), warn the user — they likely want a bumped patch.
|
||||
- **If no version was provided**, auto-increment from the latest changelog version:
|
||||
- If it was a beta, and the new release is **not** beta, bump the patch component by 1 (do **not** reuse the beta's number for stable).
|
||||
- If the new release is beta and the latest was also beta with the same major.minor, bump patch.
|
||||
- Otherwise bump the patch component by 1.
|
||||
- Present the chosen version to the user and ask for confirmation before proceeding. If the user suggests a different version, use that instead.
|
||||
|
||||
### 4. Fetch tags and determine the last release tag
|
||||
|
||||
Run `git fetch origin --tags` first to ensure all tags from the public repository are available locally. Then run `git tag --sort=-v:refname` and find the most recent `v*` tag. This is the baseline for the diff.
|
||||
|
||||
### 5. Collect commits
|
||||
|
||||
Run `git log <last-tag>..HEAD --oneline` to get all commits since the last release.
|
||||
|
||||
### 6. Write the changelog entry
|
||||
|
||||
Analyze every commit message. Group them mentally into features, improvements, and bug fixes. Then produce **brief, user-facing bullet points** following these rules:
|
||||
|
||||
- **Style:** Match the existing changelog tone exactly — short, imperative sentences starting with a verb (Fix, Add, Allow, Show, Improve, Support…). Keep the trailing periods (the existing changelog uses them).
|
||||
- **Brevity:** Each bullet should be one short sentence, around 80 characters when possible. No implementation details. No commit hashes.
|
||||
- **Selection:** Only include changes that matter to end users. Skip CI, build infra, submodule bumps, code style, refactors, and intermediate WIP commits. Collapse many related commits (e.g. a dozen image-editor commits) into one or two bullets.
|
||||
- **Ordering:** Features first, then improvements, then bug fixes.
|
||||
- **Quantity:** Aim for 4-12 bullets total depending on the amount of changes.
|
||||
|
||||
### 7. Format and insert into changelog.txt
|
||||
|
||||
Use this exact format (date is today in DD.MM.YY):
|
||||
|
||||
```
|
||||
<version> [beta ](DD.MM.YY)
|
||||
|
||||
- Bullet one.
|
||||
- Bullet two.
|
||||
```
|
||||
|
||||
Prepend the new entry at the very top of `changelog.txt`, separated by a blank line from the previous first entry. Use the Edit tool.
|
||||
|
||||
**Never delete or edit existing entries**, even if the new stable entry merges bullets from prior beta(s). Prior beta blocks remain as historical record for beta-track users.
|
||||
|
||||
**For stable releases spanning prior beta(s):** the entry should cover everything since the last **stable** release (not just since the last beta), including noteworthy beta-shipped features, trimmed as needed to stay within 4–12 bullets.
|
||||
|
||||
### 8. Wait for approval
|
||||
|
||||
After writing the entry to `changelog.txt` (step 7), tell the user the changelog has been updated and ask them to review it in the IDE. They can edit it directly and tell you to continue, or tell you what to change in chat. Do **not** print the full entry in chat — the file itself is the review surface.
|
||||
|
||||
**Do NOT proceed until the user explicitly approves.**
|
||||
|
||||
### 9. Run set_version
|
||||
|
||||
Once approved, run the `set_version` script from the repository root. On Windows:
|
||||
|
||||
```
|
||||
.\Telegram\build\set_version.bat <version_arg>
|
||||
```
|
||||
|
||||
Where `<version_arg>` is formatted as the `set_version` script expects:
|
||||
- Stable: `6.7.0` or `6.7`
|
||||
- Beta: `6.7.0.beta`
|
||||
|
||||
Verify the script exits successfully (exit code 0). If it fails, show the error and stop.
|
||||
|
||||
### 10. Commit
|
||||
|
||||
Stage all changes and create a commit. The commit message format:
|
||||
|
||||
**First line:**
|
||||
- For stable: `Version <major>.<minor>.` if patch is 0, otherwise `Version <major>.<minor>.<patch>.`
|
||||
- For beta: `Beta version <major>.<minor>.<patch>.`
|
||||
|
||||
**Then an empty line, then the changelog bullets.** Copy bullet lines from the changelog as-is. Only wrap lines that exceed 72 characters; shorter lines must stay on a single line. When wrapping is needed, break at logically correct places (between words/phrases) and indent continuation lines with two spaces.
|
||||
|
||||
Example commit message:
|
||||
```
|
||||
Beta version 6.6.3.
|
||||
|
||||
- Drawing tools in image editor
|
||||
(brush, marker, eraser, arrow).
|
||||
- Draw-to-reply button in media viewer.
|
||||
- Trim recorded voice messages.
|
||||
- Fix reorder freeze in chats list.
|
||||
```
|
||||
|
||||
Use a HEREDOC to pass the message to `git commit -a`.
|
||||
|
||||
### 11. Done
|
||||
|
||||
Run `git log -1` to show the resulting commit and confirm success.
|
||||
@@ -0,0 +1,506 @@
|
||||
---
|
||||
description: Implement a feature or fix using multi-agent workflow with fresh context at each phase
|
||||
allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Task, AskUserQuestion, TodoWrite
|
||||
---
|
||||
|
||||
# Task - Multi-Agent Implementation Workflow
|
||||
|
||||
You orchestrate a multi-phase implementation workflow that uses fresh agent spawns to work within context window limits on a large codebase.
|
||||
|
||||
**Arguments:** `$ARGUMENTS` = "$ARGUMENTS"
|
||||
|
||||
If `$ARGUMENTS` is provided, it's the task description. If empty, ask the user what they want implemented.
|
||||
|
||||
## Overview
|
||||
|
||||
The workflow is organized around **projects**. Each project lives in `.ai/<project-name>/` and can contain multiple sequential **tasks** (labeled `a`, `b`, `c`, ... `z`).
|
||||
|
||||
Project structure:
|
||||
```
|
||||
.ai/<project-name>/
|
||||
about.md # Single source of truth for the entire project
|
||||
a/ # First task
|
||||
context.md # Gathered codebase context for this task
|
||||
plan.md # Implementation plan
|
||||
review1.md # Code review documents (up to 3)
|
||||
review2.md
|
||||
review3.md
|
||||
b/ # Follow-up task
|
||||
context.md
|
||||
plan.md
|
||||
review1.md
|
||||
c/ # Another follow-up task
|
||||
...
|
||||
```
|
||||
|
||||
- `about.md` is the project-level blueprint — a single comprehensive document describing what this project does and how it works, written as if everything is already fully implemented. It contains no temporal state ("current state", "pending changes", "not yet implemented"). It is **rewritten** (not appended to) each time a new task starts, incorporating the new task's changes as if they were always part of the design.
|
||||
- Each task folder (`a/`, `b/`, ...) contains self-contained files for that task. The task's `context.md` carries all task-specific information: what specifically needs to change, the delta from the current codebase, gathered file references and code patterns. Planning, implementation, and review agents only read the current task's folder.
|
||||
|
||||
## Phase 0: Setup
|
||||
|
||||
**Record the current time now** (using `Get-Date` in PowerShell or equivalent) and store it as `$START_TIME`. You will use this at the end to display total elapsed time.
|
||||
|
||||
⚠️ **CRITICAL: Follow-up detection MUST happen FIRST, before anything else.**
|
||||
|
||||
### Step 0a: Follow-up detection (MANDATORY — do this BEFORE understanding the task)
|
||||
|
||||
Extract the first word/token from `$ARGUMENTS` (everything before the first space or newline). Call it `FIRST_TOKEN`.
|
||||
|
||||
Then run these TWO commands using the Bash tool, IN PARALLEL, right now:
|
||||
1. `ls .ai/` — to see all existing project names
|
||||
2. `ls .ai/<FIRST_TOKEN>/about.md` — to check if this specific project exists
|
||||
|
||||
**Evaluate the results:**
|
||||
- If command 2 **succeeds** (the file exists): this is a **follow-up task**. The project name is `FIRST_TOKEN`. The task description is everything in `$ARGUMENTS` AFTER `FIRST_TOKEN` (strip leading whitespace).
|
||||
- If command 2 **fails** (file not found): this is a **new project**. The full `$ARGUMENTS` is the task description.
|
||||
|
||||
**Do NOT proceed to step 0b until you have run these commands and determined follow-up vs new.**
|
||||
|
||||
### Step 0b: Project setup
|
||||
|
||||
**For new projects:**
|
||||
- Using the list from command 1, pick a unique short name (1-2 lowercase words, hyphen-separated) that doesn't collide with existing projects.
|
||||
- Create `.ai/<project-name>/` and `.ai/<project-name>/a/`.
|
||||
- Set current task letter = `a`.
|
||||
|
||||
**For follow-up tasks:**
|
||||
- Scan `.ai/<project-name>/` for existing task folders (`a/`, `b/`, ...). Find the latest one (highest letter).
|
||||
- The previous task letter = that highest letter.
|
||||
- The new task letter = next letter in sequence.
|
||||
- Create `.ai/<project-name>/<new-letter>/`.
|
||||
|
||||
Then proceed to Phase 1 (Context Gathering) in both cases. Follow-up tasks do NOT skip context gathering — they go through a modified version of it.
|
||||
|
||||
## Phase 1: Context Gathering
|
||||
|
||||
### For New Projects (task letter = `a`)
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure:
|
||||
|
||||
```
|
||||
You are a context-gathering agent for a large C++ codebase (Telegram Desktop).
|
||||
|
||||
TASK: <paste the user's task description here>
|
||||
|
||||
YOUR JOB: Read AGENTS.md, inspect the codebase, find ALL files and code relevant to this task, and write two documents.
|
||||
|
||||
Steps:
|
||||
1. Read AGENTS.md for project conventions and build instructions.
|
||||
2. Search the codebase for files, classes, functions, and patterns related to the task.
|
||||
3. Read all potentially relevant files. Be thorough - read more rather than less.
|
||||
4. For each relevant file, note:
|
||||
- File path
|
||||
- Relevant line ranges
|
||||
- What the code does and how it relates to the task
|
||||
- Key data structures, function signatures, patterns used
|
||||
5. Look for similar existing features that could serve as a reference implementation.
|
||||
6. Check api.tl if the task involves Telegram API.
|
||||
7. Check .style files if the task involves UI.
|
||||
8. Check lang.strings if the task involves user-visible text.
|
||||
|
||||
Write TWO files:
|
||||
|
||||
### File 1: .ai/<project-name>/about.md
|
||||
|
||||
NOTE: This file is NOT used by any agent in the current task. It exists solely as a starting point for a FUTURE follow-up task's context gatherer. No planning, implementation, or review agent will ever read it. Only the context-gathering agent of the next follow-up task reads about.md (together with the latest context.md) to produce a fresh context.md for that next task.
|
||||
|
||||
Write it as if the project is already fully implemented and working. It should contain:
|
||||
- **Project**: What this project does (feature description, goals, scope)
|
||||
- **Architecture**: High-level architectural decisions, which modules are involved, how they interact
|
||||
- **Key Design Decisions**: Important choices made about the approach
|
||||
- **Relevant Codebase Areas**: Which parts of the codebase this project touches, key types and APIs involved
|
||||
|
||||
Do NOT include temporal state like "Current State", "Pending Changes", "Not yet implemented", "TODO", or any other framing that distinguishes between "done" and "not done". Describe the project as a complete, coherent whole — as if everything is already working. This is a project overview, not a status tracker. Task-specific work belongs exclusively in context.md.
|
||||
|
||||
### File 2: .ai/<project-name>/a/context.md
|
||||
|
||||
This is the task-specific implementation context. This is the PRIMARY document — all downstream agents (planning, implementation, review) will read ONLY this file. It must be completely self-contained. It should contain:
|
||||
- **Task Description**: The full task restated clearly
|
||||
- **Relevant Files**: Every file path with line ranges and descriptions of what's there
|
||||
- **Key Code Patterns**: How similar things are done in the codebase (with code snippets)
|
||||
- **Data Structures**: Relevant types, structs, classes
|
||||
- **API Methods**: Any TL schema methods involved (copied from api.tl)
|
||||
- **UI Styles**: Any relevant style definitions
|
||||
- **Localization**: Any relevant string keys
|
||||
- **Build Info**: Build command and any special notes
|
||||
- **Reference Implementations**: Similar features that can serve as templates
|
||||
|
||||
Be extremely thorough. Another agent with NO prior context will read this file and must be able to understand everything needed to implement the task.
|
||||
```
|
||||
|
||||
After this agent completes, read both `about.md` and `a/context.md` to verify they were written properly.
|
||||
|
||||
### For Follow-up Tasks (task letter = `b`, `c`, ...)
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure:
|
||||
|
||||
```
|
||||
You are a context-gathering agent for a follow-up task on an existing project in a large C++ codebase (Telegram Desktop).
|
||||
|
||||
NEW TASK: <paste the follow-up task description here>
|
||||
|
||||
YOUR JOB: Read the existing project state, gather any additional context needed, and produce fresh documents for the new task.
|
||||
|
||||
Steps:
|
||||
1. Read AGENTS.md for project conventions and build instructions.
|
||||
2. Read .ai/<project-name>/about.md — this is the project-level blueprint describing everything done so far.
|
||||
3. Read .ai/<project-name>/<previous-letter>/context.md — this is the previous task's gathered context.
|
||||
4. Understand what has already been implemented by reading the actual source files referenced in about.md and the previous context.
|
||||
5. Based on the NEW TASK description, search the codebase for any ADDITIONAL files, classes, functions, and patterns that are relevant to the new task but not already covered.
|
||||
6. Read all newly relevant files thoroughly.
|
||||
|
||||
Write TWO files:
|
||||
|
||||
### File 1: .ai/<project-name>/about.md (REWRITE)
|
||||
|
||||
NOTE: This file is NOT used by any agent in the current task. It exists solely as a starting point for a FUTURE follow-up task's context gatherer. No planning, implementation, or review agent will ever read it. You are rewriting it now so that the next follow-up has an accurate project overview to start from.
|
||||
|
||||
REWRITE this file (not append). The new about.md must be a single coherent document that describes the project as if everything — including this new task's changes — is already fully implemented and working.
|
||||
|
||||
It should incorporate:
|
||||
- Everything from the old about.md that is still accurate and relevant
|
||||
- The new task's functionality described as part of the project (not as "changes to make")
|
||||
- Any changed design decisions or architectural updates from the new task requirements
|
||||
|
||||
It should NOT contain:
|
||||
- Any temporal state: "Current State", "Pending Changes", "TODO", "Not yet implemented"
|
||||
- History of how requirements changed between tasks
|
||||
- References to "the old approach" vs "the new approach"
|
||||
- Task-by-task changelog or timeline
|
||||
- Any distinction between "what was done before" and "what this task adds"
|
||||
- Information that contradicts the new task requirements (if the new task changes direction, the about.md should reflect the NEW direction as if it was always the plan)
|
||||
|
||||
Think of about.md as "the complete description of what this project does and how it works." Someone reading it should understand the full project as a finished product, without knowing it went through multiple tasks.
|
||||
|
||||
### File 2: .ai/<project-name>/<new-letter>/context.md
|
||||
|
||||
This is the PRIMARY document — all downstream agents (planning, implementation, review) will read ONLY this file. It must be completely self-contained. about.md will NOT be available to them.
|
||||
|
||||
It should contain:
|
||||
- **Task Description**: The new task restated clearly, with enough project background (from about.md and previous context.md) that an implementation agent can understand it without reading any other .ai/ files
|
||||
- **Relevant Files**: Every file path with line ranges relevant to THIS task (including files modified by previous tasks and any newly relevant files)
|
||||
- **Key Code Patterns**: How similar things are done in the codebase
|
||||
- **Data Structures**: Relevant types, structs, classes
|
||||
- **API Methods**: Any TL schema methods involved
|
||||
- **UI Styles**: Any relevant style definitions
|
||||
- **Localization**: Any relevant string keys
|
||||
- **Build Info**: Build command and any special notes
|
||||
- **Reference Implementations**: Similar features that can serve as templates
|
||||
|
||||
Be extremely thorough. Another agent with NO prior context will read ONLY this file and must be able to understand everything needed to implement the new task. Do NOT assume the reader has seen about.md or any previous task files. The context.md is the single source of truth for all downstream agents — it must include all relevant project background, not just the delta.
|
||||
```
|
||||
|
||||
After this agent completes, read both `about.md` and `<new-letter>/context.md` to verify they were written properly.
|
||||
|
||||
## Phase 2: Planning
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure:
|
||||
|
||||
```
|
||||
You are a planning agent. You must create a detailed implementation plan.
|
||||
|
||||
Read these files:
|
||||
- .ai/<project-name>/<letter>/context.md - Contains all gathered context for this task
|
||||
- Then read the specific source files referenced in context.md to understand the code deeply.
|
||||
|
||||
Think carefully about the implementation approach.
|
||||
|
||||
Create a detailed plan in: .ai/<project-name>/<letter>/plan.md
|
||||
|
||||
The plan.md should contain:
|
||||
|
||||
## Task
|
||||
<one-line summary>
|
||||
|
||||
## Approach
|
||||
<high-level description of the implementation approach>
|
||||
|
||||
## Files to Modify
|
||||
<list of files that will be created or modified>
|
||||
|
||||
## Files to Create
|
||||
<list of new files, if any>
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
Each step must be specific enough that an agent can execute it without ambiguity:
|
||||
- Exact file paths
|
||||
- Exact function names
|
||||
- What code to add/modify/remove
|
||||
- Where exactly in the file (after which function, in which class, etc.)
|
||||
|
||||
Number every step. Group steps into phases if there are more than ~8 steps.
|
||||
|
||||
### Phase 1: <name>
|
||||
1. <specific step>
|
||||
2. <specific step>
|
||||
...
|
||||
|
||||
### Phase 2: <name> (if needed)
|
||||
...
|
||||
|
||||
## Build Verification
|
||||
- Build command to run
|
||||
- Expected outcome
|
||||
|
||||
## Status
|
||||
- [ ] Phase 1: <name>
|
||||
- [ ] Phase 2: <name> (if applicable)
|
||||
- [ ] Build verification
|
||||
- [ ] Code review
|
||||
```
|
||||
|
||||
After this agent completes, read `plan.md` to verify it was written properly.
|
||||
|
||||
## Phase 3: Plan Assessment
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure:
|
||||
|
||||
```
|
||||
You are a plan assessment agent. Review and refine an implementation plan.
|
||||
|
||||
Read these files:
|
||||
- .ai/<project-name>/<letter>/context.md
|
||||
- .ai/<project-name>/<letter>/plan.md
|
||||
- Then read the actual source files referenced to verify the plan makes sense.
|
||||
|
||||
Carefully assess the plan:
|
||||
|
||||
1. **Correctness**: Are the file paths and line references accurate? Does the plan reference real functions and types?
|
||||
2. **Completeness**: Are there missing steps? Edge cases not handled?
|
||||
3. **Code quality**: Will the plan minimize code duplication? Does it follow existing codebase patterns from AGENTS.md?
|
||||
4. **Design**: Could the approach be improved? Are there better patterns already used in the codebase?
|
||||
5. **Phase sizing**: Each phase should be implementable by a single agent in one session. If a phase has more than ~8-10 substantive code changes, split it further.
|
||||
|
||||
Update plan.md with your refinements. Keep the same structure but:
|
||||
- Fix any inaccuracies
|
||||
- Add missing steps
|
||||
- Improve the approach if you found better patterns
|
||||
- Ensure phases are properly sized for single-agent execution
|
||||
- Add a line at the top of the Status section: `Phases: <N>` indicating how many implementation phases there are
|
||||
- Add `Assessed: yes` at the bottom of the file
|
||||
|
||||
If the plan is small enough for a single agent (roughly <=8 steps), mark it as a single phase.
|
||||
```
|
||||
|
||||
After this agent completes, read `plan.md` to verify it was assessed.
|
||||
|
||||
## Phase 4: Implementation
|
||||
|
||||
Now read `plan.md` yourself to understand the phases.
|
||||
|
||||
For each phase in the plan that is not yet marked as done, spawn an implementation agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are an implementation agent working on phase <N> of an implementation plan.
|
||||
|
||||
Read these files first:
|
||||
- .ai/<project-name>/<letter>/context.md - Full codebase context
|
||||
- .ai/<project-name>/<letter>/plan.md - Implementation plan
|
||||
|
||||
Then read the source files you'll be modifying.
|
||||
|
||||
YOUR TASK: Implement ONLY Phase <N> from the plan:
|
||||
<paste the specific phase steps here>
|
||||
|
||||
Rules:
|
||||
- Follow the plan precisely
|
||||
- Follow AGENTS.md coding conventions (no comments except complex algorithms, use auto, empty line before closing brace, etc.)
|
||||
- Do NOT modify .ai/ files except to update the Status section in plan.md
|
||||
- When done, update plan.md Status section: change `- [ ] Phase <N>: ...` to `- [x] Phase <N>: ...`
|
||||
- Do NOT work on other phases
|
||||
|
||||
When finished, report what you did and any issues encountered.
|
||||
```
|
||||
|
||||
After each implementation agent returns:
|
||||
1. Read `plan.md` to check the status was updated.
|
||||
2. If more phases remain, spawn the next implementation agent.
|
||||
3. If all phases are done, proceed to build verification.
|
||||
|
||||
## Phase 5: Build Verification
|
||||
|
||||
Only run this phase if the task involved modifying project source code (not just docs or config).
|
||||
|
||||
Spawn a build verification agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are a build verification agent.
|
||||
|
||||
Read these files:
|
||||
- .ai/<project-name>/<letter>/context.md
|
||||
- .ai/<project-name>/<letter>/plan.md
|
||||
|
||||
The implementation is complete. Your job is to build the project and fix any build errors.
|
||||
|
||||
Steps:
|
||||
1. Run (from repository root): cmake --build ./out --config Debug --target Telegram
|
||||
2. If the build succeeds, update plan.md: change `- [ ] Build verification` to `- [x] Build verification`
|
||||
3. If the build fails:
|
||||
a. Read the error messages carefully
|
||||
b. Read the relevant source files
|
||||
c. Fix the errors in accordance with the plan and AGENTS.md conventions
|
||||
d. Rebuild and repeat until the build passes
|
||||
e. Update plan.md status when done
|
||||
|
||||
Rules:
|
||||
- Only fix build errors, do not refactor or improve code
|
||||
- Follow AGENTS.md conventions
|
||||
- If build fails with file-locked errors (C1041, LNK1104), STOP and report - do not retry
|
||||
|
||||
When finished, report the build result.
|
||||
```
|
||||
|
||||
After the build agent returns, read `plan.md` to confirm the final status. Then proceed to Phase 6.
|
||||
|
||||
## Phase 6: Code Review Loop
|
||||
|
||||
After build verification passes, run up to 3 review-fix iterations to improve code quality. Set iteration counter `R = 1`.
|
||||
|
||||
### Review Loop
|
||||
|
||||
```
|
||||
LOOP:
|
||||
1. Spawn review agent (Step 6a) with iteration R
|
||||
2. Read review<R>.md verdict:
|
||||
- "APPROVED" → go to FINISH
|
||||
- Has improvement suggestions → spawn fix agent (Step 6b)
|
||||
3. After fix agent completes and build passes:
|
||||
R = R + 1
|
||||
If R > 3 → go to FINISH (stop iterating, accept current state)
|
||||
Otherwise → go to step 1
|
||||
|
||||
FINISH:
|
||||
- Update plan.md: change `- [ ] Code review` to `- [x] Code review`
|
||||
- Proceed to Completion
|
||||
```
|
||||
|
||||
### Step 6a: Code Review Agent
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are a code review agent for Telegram Desktop (C++ / Qt).
|
||||
|
||||
Read these files:
|
||||
- .ai/<project-name>/<letter>/context.md - Codebase context
|
||||
- .ai/<project-name>/<letter>/plan.md - Implementation plan
|
||||
- REVIEW.md - Style and formatting rules to enforce
|
||||
<if R > 1, also read:>
|
||||
- .ai/<project-name>/<letter>/review<R-1>.md - Previous review (to see what was already addressed)
|
||||
|
||||
Then run `git diff` to see all uncommitted changes made by the implementation. Implementation agents do not commit, so `git diff` shows exactly the current feature's changes.
|
||||
|
||||
Then read the modified source files in full to understand changes in context.
|
||||
|
||||
Perform a thorough code review.
|
||||
|
||||
REVIEW CRITERIA (in order of importance):
|
||||
|
||||
1. **Correctness and safety**: Obvious logic errors, missing null checks at API boundaries, potential crashes, use-after-free, dangling references, race conditions. This is the highest priority — bugs and safety issues must be caught first. Do NOT nitpick internal code that relies on framework guarantees.
|
||||
|
||||
2. **Dead code**: Any code added or left behind that is never called or used, within the scope of the changes. Unused variables, unreachable branches, leftover scaffolding.
|
||||
|
||||
3. **Redundant changes**: Changes in the diff that have no functional effect — moving declarations or code blocks to a different location without reason, reformatting untouched code, reordering includes or fields with no purpose. Every line in the diff should serve the feature. If a file appears in `git diff` but contains only no-op rearrangements, flag it for revert.
|
||||
|
||||
4. **Code duplication**: Unnecessary repetition of logic that should be shared. Look for near-identical blocks that differ only in minor details and could be unified.
|
||||
|
||||
5. **Wrong placement**: Code added to a module where it doesn't logically belong. If another existing module is a clearly better fit for the new code, flag it. Consider the existing module boundaries and responsibilities visible in context.md.
|
||||
|
||||
6. **Function decomposition**: For longer functions (roughly 50+ lines), consider whether a logical sub-task could be cleanly extracted into a separate function. This is NOT a hard rule — a 100-line function that flows naturally and isn't easily divisible is perfectly fine. But sometimes even a 20-line function contains a clear isolated subtask that reads better as two 10-line functions. The key is to think about it each time: does extracting improve readability and reduce cognitive load, or does it just scatter logic across call sites for no real benefit? Only suggest extraction when there's a genuinely self-contained piece of logic with a clear name and purpose.
|
||||
|
||||
7. **Module structure**: Only in exceptional cases — if a large amount of newly added code (hundreds of lines) is logically distinct from the rest of its host module, suggest extracting it into a new module. But do NOT suggest new modules lightly: every module adds significant build overhead due to PCH and heavy template usage. Only suggest this when the new code is both large enough AND logically separated enough to justify it. At the same time, don't let modules grow into multi-thousand-line monoliths either.
|
||||
|
||||
8. **Style compliance**: Verify adherence to REVIEW.md rules (empty line before closing brace, operators at start of continuation lines, minimize type checks with direct cast instead of is+as, no if-with-initializer when simpler alternatives exist) and AGENTS.md conventions (no unnecessary comments, `auto` usage, no hardcoded sizes — must use .style definitions), etc.
|
||||
|
||||
IMPORTANT GUIDELINES:
|
||||
- Review ONLY the changes made, not pre-existing code in the repository.
|
||||
- Be pragmatic. Don't suggest changes for the sake of it. Each suggestion should have a clear, concrete benefit.
|
||||
- Don't suggest adding comments, docstrings, or type annotations — the codebase style avoids these.
|
||||
- Don't suggest error handling for impossible scenarios or over-engineering.
|
||||
|
||||
Write your review to: .ai/<project-name>/<letter>/review<R>.md
|
||||
|
||||
The review document should contain:
|
||||
|
||||
## Code Review - Iteration <R>
|
||||
|
||||
## Summary
|
||||
<1-2 sentence overall assessment>
|
||||
|
||||
## Verdict: <APPROVED or NEEDS_CHANGES>
|
||||
|
||||
<If APPROVED, stop here. Everything looks good.>
|
||||
|
||||
<If NEEDS_CHANGES, continue with:>
|
||||
|
||||
## Changes Required
|
||||
|
||||
### <Issue 1 title>
|
||||
- **Category**: <dead code | duplication | wrong placement | function decomposition | module structure | style | correctness>
|
||||
- **File(s)**: <file paths>
|
||||
- **Problem**: <clear description of what's wrong>
|
||||
- **Fix**: <specific description of what to change>
|
||||
|
||||
### <Issue 2 title>
|
||||
...
|
||||
|
||||
Keep the list focused. Only include issues that genuinely improve the code. If you find yourself listing more than ~5-6 issues, prioritize the most impactful ones.
|
||||
|
||||
When finished, report your verdict clearly as: APPROVED or NEEDS_CHANGES.
|
||||
```
|
||||
|
||||
After the review agent returns, read `review<R>.md`. If the verdict is APPROVED, proceed to Completion. If NEEDS_CHANGES, spawn the fix agent.
|
||||
|
||||
### Step 6b: Review Fix Agent
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are a review fix agent. You implement improvements identified during code review.
|
||||
|
||||
Read these files:
|
||||
- .ai/<project-name>/<letter>/context.md - Codebase context
|
||||
- .ai/<project-name>/<letter>/plan.md - Original implementation plan
|
||||
- .ai/<project-name>/<letter>/review<R>.md - Code review with required changes
|
||||
|
||||
Then read the source files mentioned in the review.
|
||||
|
||||
YOUR TASK: Implement ALL changes listed in review<R>.md.
|
||||
|
||||
For each issue in the review:
|
||||
1. Read the relevant source file(s).
|
||||
2. Make the specified change.
|
||||
3. Verify the change makes sense in context.
|
||||
|
||||
After all changes are made:
|
||||
1. Build (from repository root): cmake --build ./out --config Debug --target Telegram
|
||||
2. If the build fails, fix build errors and rebuild until it passes.
|
||||
3. If build fails with file-locked errors (C1041, LNK1104), STOP and report - do not retry.
|
||||
|
||||
Rules:
|
||||
- Implement exactly the changes from the review, nothing more.
|
||||
- Follow AGENTS.md coding conventions.
|
||||
- Do NOT modify .ai/ files.
|
||||
|
||||
When finished, report what changes were made.
|
||||
```
|
||||
|
||||
After the fix agent returns, increment R and loop back to Step 6a (unless R > 3, in which case proceed to Completion).
|
||||
|
||||
## Completion
|
||||
|
||||
When all phases including build verification and code review are done:
|
||||
1. Read the final `plan.md` and report the summary to the user.
|
||||
2. Show which files were modified/created.
|
||||
3. Note any issues encountered during implementation.
|
||||
4. Summarize code review iterations: how many rounds, what was found and fixed, or if it was approved on first pass.
|
||||
5. Calculate and display the total elapsed time since `$START_TIME` (format as `Xh Ym Zs`, omitting zero components — e.g. `12m 34s` or `1h 5m 12s`).
|
||||
6. Remind the user of the project name so they can use `/task <project-name> <follow-up description>` for follow-up changes.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If any agent fails or gets stuck, report the issue to the user and ask how to proceed.
|
||||
- If context.md or plan.md is not written properly by an agent, re-spawn that agent with more specific instructions.
|
||||
- If build errors persist after the build agent's attempts, report the remaining errors to the user.
|
||||
- If a review fix agent introduces new build errors that it cannot resolve, report to the user.
|
||||
@@ -0,0 +1,656 @@
|
||||
---
|
||||
description: Implement a feature using multi-agent workflow, then iteratively test and fix it in-app
|
||||
allowed-tools: Read, Write, Edit, Glob, Grep, Bash, Task, AskUserQuestion, TodoWrite
|
||||
---
|
||||
|
||||
# WithTest - Multi-Agent Implementation + Testing Workflow
|
||||
|
||||
You orchestrate a multi-phase implementation workflow followed by an iterative testing/fixing loop. This is an extended version of `/task` that adds in-app programmatic testing after the build succeeds.
|
||||
|
||||
**Arguments:** `$ARGUMENTS` = "$ARGUMENTS"
|
||||
|
||||
If `$ARGUMENTS` is provided, it's the task description. If empty, ask the user what they want implemented.
|
||||
|
||||
## Overview
|
||||
|
||||
The workflow produces `.ai/<feature-name>/` containing:
|
||||
- `context.md` - Gathered codebase context relevant to the task
|
||||
- `plan.md` - Detailed implementation plan with phases and status
|
||||
- `testN.md` - Test plan for iteration N
|
||||
- `resultN.md` - Test result report for iteration N
|
||||
- `planN.md` - Fix plan for iteration N (if implementation bugs found)
|
||||
- `screenshots/` - Screenshots captured during test runs
|
||||
|
||||
Two major stages:
|
||||
1. **Implementation** (Phases 0-5) - same as `/task`
|
||||
2. **Testing Loop** (Phase 6) - iterative test-plan → test-do → test-run → test-check cycle
|
||||
|
||||
---
|
||||
|
||||
## STAGE 1: IMPLEMENTATION (Phases 0-5)
|
||||
|
||||
These phases are identical to the `/task` workflow.
|
||||
|
||||
### Phase 0: Setup
|
||||
|
||||
1. Understand the task from `$ARGUMENTS` or ask the user.
|
||||
2. **Follow-up detection:** Check if `$ARGUMENTS` starts with a task name (the first word/token before any whitespace or newline). Look for `.ai/<that-name>/` directory:
|
||||
- If `.ai/<that-name>/` exists AND contains both `context.md` and `plan.md`, this is a **follow-up task**. Read both files. The rest of `$ARGUMENTS` (after the task name) is the follow-up task description describing what additional changes are needed.
|
||||
- If no matching directory exists, this is a **new task** - proceed normally.
|
||||
3. For new tasks: check existing folders in `.ai/` to pick a unique short name (1-2 lowercase words, hyphen-separated) and create `.ai/<feature-name>/`.
|
||||
4. For follow-up tasks: the folder already exists, skip creation.
|
||||
|
||||
### Follow-up Task Flow
|
||||
|
||||
When a follow-up task is detected (existing `.ai/<name>/` with `context.md` and `plan.md`):
|
||||
|
||||
1. Skip Phase 1 (Context Gathering) - context already exists.
|
||||
2. Skip Phase 2 (Planning) - original plan already exists.
|
||||
3. Go directly to **Phase 2F (Follow-up Planning)** instead of Phase 3.
|
||||
|
||||
**Phase 2F: Follow-up Planning**
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt:
|
||||
|
||||
```
|
||||
You are a planning agent for a follow-up task on an existing implementation.
|
||||
|
||||
Read these files:
|
||||
- .ai/<feature-name>/context.md - Previously gathered codebase context
|
||||
- .ai/<feature-name>/plan.md - Previous implementation plan (already completed)
|
||||
|
||||
Then read the source files referenced in context.md and plan.md to understand what was already implemented.
|
||||
|
||||
FOLLOW-UP TASK: <paste the follow-up task description here>
|
||||
|
||||
The previous plan was already implemented and tested. Now there are follow-up changes needed.
|
||||
|
||||
YOUR JOB:
|
||||
1. Understand what was already done from plan.md (look at the completed phases).
|
||||
2. Read the actual source files to see the current state of the code.
|
||||
3. If context.md needs updates for the follow-up task (new files relevant, new patterns needed), update it with additional sections marked "## Follow-up Context (iteration 2)" or similar.
|
||||
4. Create a NEW follow-up plan. Update plan.md by:
|
||||
- Keep the existing content as history (do NOT delete it)
|
||||
- Add a new section at the end:
|
||||
|
||||
---
|
||||
## Follow-up Task
|
||||
<description>
|
||||
|
||||
## Follow-up Approach
|
||||
<high-level description>
|
||||
|
||||
## Follow-up Files to Modify
|
||||
<list>
|
||||
|
||||
## Follow-up Implementation Steps
|
||||
|
||||
### Phase F1: <name>
|
||||
1. <specific step>
|
||||
2. ...
|
||||
|
||||
### Phase F2: <name> (if needed)
|
||||
...
|
||||
|
||||
## Follow-up Status
|
||||
Phases: <N>
|
||||
- [ ] Phase F1: <name>
|
||||
- [ ] Phase F2: <name> (if applicable)
|
||||
- [ ] Build verification
|
||||
- [ ] Testing
|
||||
Assessed: yes
|
||||
|
||||
Reason carefully. The follow-up plan should be self-contained enough that an implementation agent can execute it by reading context.md and the updated plan.md.
|
||||
```
|
||||
|
||||
After this agent completes, read `plan.md` to verify the follow-up plan was written. Then proceed to Phase 4 (Implementation), using the follow-up phases (F1, F2, etc.) instead of the original phases. After implementation and build verification, proceed to Stage 2 (Testing Loop) as normal.
|
||||
|
||||
### New Task Flow
|
||||
|
||||
When this is a new task (no existing folder), proceed with Phases 1-5 as described below.
|
||||
|
||||
### Phase 1: Context Gathering
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure:
|
||||
|
||||
```
|
||||
You are a context-gathering agent for a large C++ codebase (Telegram Desktop).
|
||||
|
||||
TASK: <paste the user's task description here>
|
||||
|
||||
YOUR JOB: Read CLAUDE.md, inspect the codebase, find ALL files and code relevant to this task, and write a comprehensive context document.
|
||||
|
||||
Steps:
|
||||
1. Read CLAUDE.md for project conventions and build instructions.
|
||||
2. Search the codebase for files, classes, functions, and patterns related to the task.
|
||||
3. Read all potentially relevant files. Be thorough - read more rather than less.
|
||||
4. For each relevant file, note:
|
||||
- File path
|
||||
- Relevant line ranges
|
||||
- What the code does and how it relates to the task
|
||||
- Key data structures, function signatures, patterns used
|
||||
5. Look for similar existing features that could serve as a reference implementation.
|
||||
6. Check api.tl if the task involves Telegram API.
|
||||
7. Check .style files if the task involves UI.
|
||||
8. Check lang.strings if the task involves user-visible text.
|
||||
|
||||
Write your findings to: .ai/<feature-name>/context.md
|
||||
|
||||
The context.md should contain:
|
||||
- **Task Description**: The full task restated clearly
|
||||
- **Relevant Files**: Every file path with line ranges and descriptions of what's there
|
||||
- **Key Code Patterns**: How similar things are done in the codebase (with code snippets)
|
||||
- **Data Structures**: Relevant types, structs, classes
|
||||
- **API Methods**: Any TL schema methods involved (copied from api.tl)
|
||||
- **UI Styles**: Any relevant style definitions
|
||||
- **Localization**: Any relevant string keys
|
||||
- **Build Info**: Build command and any special notes
|
||||
- **Reference Implementations**: Similar features that can serve as templates
|
||||
|
||||
Be extremely thorough. Another agent with NO prior context will read this file and must be able to understand everything needed to implement the task.
|
||||
```
|
||||
|
||||
After this agent completes, read `context.md` to verify it was written properly.
|
||||
|
||||
### Phase 2: Planning
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure:
|
||||
|
||||
```
|
||||
You are a planning agent. You must create a detailed implementation plan.
|
||||
|
||||
Read these files:
|
||||
- .ai/<feature-name>/context.md - Contains all gathered context
|
||||
- Then read the specific source files referenced in context.md to understand the code deeply.
|
||||
|
||||
Think carefully about the implementation approach.
|
||||
|
||||
Create a detailed plan in: .ai/<feature-name>/plan.md
|
||||
|
||||
The plan.md should contain:
|
||||
|
||||
## Task
|
||||
<one-line summary>
|
||||
|
||||
## Approach
|
||||
<high-level description of the implementation approach>
|
||||
|
||||
## Files to Modify
|
||||
<list of files that will be created or modified>
|
||||
|
||||
## Files to Create
|
||||
<list of new files, if any>
|
||||
|
||||
## Implementation Steps
|
||||
|
||||
Each step must be specific enough that an agent can execute it without ambiguity:
|
||||
- Exact file paths
|
||||
- Exact function names
|
||||
- What code to add/modify/remove
|
||||
- Where exactly in the file (after which function, in which class, etc.)
|
||||
|
||||
Number every step. Group steps into phases if there are more than ~8 steps.
|
||||
|
||||
### Phase 1: <name>
|
||||
1. <specific step>
|
||||
2. <specific step>
|
||||
...
|
||||
|
||||
### Phase 2: <name> (if needed)
|
||||
...
|
||||
|
||||
## Build Verification
|
||||
- Build command to run
|
||||
- Expected outcome
|
||||
|
||||
## Status
|
||||
- [ ] Phase 1: <name>
|
||||
- [ ] Phase 2: <name> (if applicable)
|
||||
- [ ] Build verification
|
||||
- [ ] Testing
|
||||
```
|
||||
|
||||
After this agent completes, read `plan.md` to verify it was written properly.
|
||||
|
||||
### Phase 3: Plan Assessment
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`) with this prompt structure:
|
||||
|
||||
```
|
||||
You are a plan assessment agent. Review and refine an implementation plan.
|
||||
|
||||
Read these files:
|
||||
- .ai/<feature-name>/context.md
|
||||
- .ai/<feature-name>/plan.md
|
||||
- Then read the actual source files referenced to verify the plan makes sense.
|
||||
|
||||
Carefully assess the plan:
|
||||
|
||||
1. **Correctness**: Are the file paths and line references accurate? Does the plan reference real functions and types?
|
||||
2. **Completeness**: Are there missing steps? Edge cases not handled?
|
||||
3. **Code quality**: Will the plan minimize code duplication? Does it follow existing codebase patterns from CLAUDE.md?
|
||||
4. **Design**: Could the approach be improved? Are there better patterns already used in the codebase?
|
||||
5. **Phase sizing**: Each phase should be implementable by a single agent in one session. If a phase has more than ~8-10 substantive code changes, split it further.
|
||||
|
||||
Update plan.md with your refinements. Keep the same structure but:
|
||||
- Fix any inaccuracies
|
||||
- Add missing steps
|
||||
- Improve the approach if you found better patterns
|
||||
- Ensure phases are properly sized for single-agent execution
|
||||
- Add a line at the top of the Status section: `Phases: <N>` indicating how many implementation phases there are
|
||||
- Add `Assessed: yes` at the bottom of the file
|
||||
|
||||
If the plan is small enough for a single agent (roughly <=8 steps), mark it as a single phase.
|
||||
```
|
||||
|
||||
After this agent completes, read `plan.md` to verify it was assessed.
|
||||
|
||||
### Phase 4: Implementation
|
||||
|
||||
Now read `plan.md` yourself to understand the phases.
|
||||
|
||||
For each phase in the plan that is not yet marked as done, spawn an implementation agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are an implementation agent working on phase <N> of an implementation plan.
|
||||
|
||||
Read these files first:
|
||||
- .ai/<feature-name>/context.md - Full codebase context
|
||||
- .ai/<feature-name>/plan.md - Implementation plan
|
||||
|
||||
Then read the source files you'll be modifying.
|
||||
|
||||
YOUR TASK: Implement ONLY Phase <N> from the plan:
|
||||
<paste the specific phase steps here>
|
||||
|
||||
Rules:
|
||||
- Follow the plan precisely
|
||||
- Follow CLAUDE.md coding conventions (no comments except complex algorithms, use auto, empty line before closing brace, etc.)
|
||||
- Do NOT modify .ai/ files except to update the Status section in plan.md
|
||||
- When done, update plan.md Status section: change `- [ ] Phase <N>: ...` to `- [x] Phase <N>: ...`
|
||||
- Do NOT work on other phases
|
||||
|
||||
When finished, report what you did and any issues encountered.
|
||||
```
|
||||
|
||||
After each implementation agent returns:
|
||||
1. Read `plan.md` to check the status was updated.
|
||||
2. If more phases remain, spawn the next implementation agent.
|
||||
3. If all phases are done, proceed to build verification.
|
||||
|
||||
### Phase 5: Build Verification
|
||||
|
||||
Spawn a build verification agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are a build verification agent.
|
||||
|
||||
Read these files:
|
||||
- .ai/<feature-name>/context.md
|
||||
- .ai/<feature-name>/plan.md
|
||||
|
||||
The implementation is complete. Your job is to build the project and fix any build errors.
|
||||
|
||||
Steps:
|
||||
1. Run: cmake --build "c:\Telegram\tdesktop\out" --config Debug --target Telegram
|
||||
2. If the build succeeds, update plan.md: change `- [ ] Build verification` to `- [x] Build verification`
|
||||
3. If the build fails:
|
||||
a. Read the error messages carefully
|
||||
b. Read the relevant source files
|
||||
c. Fix the errors in accordance with the plan and CLAUDE.md conventions
|
||||
d. Rebuild and repeat until the build passes
|
||||
e. Update plan.md status when done
|
||||
|
||||
Rules:
|
||||
- Only fix build errors, do not refactor or improve code
|
||||
- Follow CLAUDE.md conventions
|
||||
- If build fails with file-locked errors (C1041, LNK1104), STOP and report - do not retry
|
||||
|
||||
When finished, report the build result.
|
||||
```
|
||||
|
||||
After the build agent returns, read `plan.md` to confirm build verification passed. If it did, proceed to Stage 2.
|
||||
|
||||
---
|
||||
|
||||
## STAGE 2: TESTING LOOP (Phase 6)
|
||||
|
||||
This stage iteratively tests the implementation in-app and fixes issues. It maintains an iteration counter `N` starting at 1.
|
||||
|
||||
**Key concept:** Since the project has tight coupling and no unit test infrastructure, we test by injecting `#ifdef _DEBUG` blocks into the app code that perform actions, write to `log.txt`, save screenshots, and call `Core::Quit()` when done. An agent then runs the app and observes the output.
|
||||
|
||||
### Git Submodule Awareness
|
||||
|
||||
Before ANY git operation (commit, stash, stash pop), the agent must:
|
||||
1. Run `git submodule status` to check for modified submodules.
|
||||
2. If submodules have changes, commit/stash those submodules FIRST, individually:
|
||||
```
|
||||
cd <submodule-path> && git add -A && git commit -m "[wip-N] test changes" && cd <repo-root>
|
||||
```
|
||||
or for stash:
|
||||
```
|
||||
cd <submodule-path> && git stash && cd <repo-root>
|
||||
```
|
||||
3. Then operate on the main repo.
|
||||
|
||||
### Step 6a: Test Plan (test-plan agent)
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are a test-planning agent for Telegram Desktop (C++ / Qt).
|
||||
|
||||
Read these files:
|
||||
- .ai/<feature-name>/context.md
|
||||
- .ai/<feature-name>/plan.md
|
||||
<if N > 1, also include:>
|
||||
- .ai/<feature-name>/result<N-1>.md - Previous test result
|
||||
<if a planN.md triggered this iteration:>
|
||||
- .ai/<feature-name>/plan<trigger>.md - Fix plan that was just implemented
|
||||
|
||||
CURRENT ITERATION: <N>
|
||||
|
||||
YOUR TASKS:
|
||||
|
||||
1. **Commit current implementation changes.**
|
||||
- Run `git submodule status` to check for modified submodules.
|
||||
- If any submodules are dirty, go into each one and commit:
|
||||
`cd <submodule> && git add -A && git commit -m "[wip-<N>]" && cd <repo-root>`
|
||||
- Then in main repo: `git add -A && git commit -m "[wip-<N>]"`
|
||||
- Do NOT add files in .ai/ to the commit.
|
||||
|
||||
2. <If N > 1> **Restore previous test code.**
|
||||
- Run `git submodule status` and `git stash list` in any dirty submodules to check for stashed test code.
|
||||
- Pop submodule stashes first: `cd <submodule> && git stash pop && cd <repo-root>`
|
||||
- Then pop main repo stash: `git stash pop`
|
||||
- Read the previous test<N-1>.md to understand what was tested before.
|
||||
- Decide: reuse/modify existing test code or start fresh.
|
||||
|
||||
3. **Plan the test code.**
|
||||
Carefully design test code that will verify the implementation works correctly.
|
||||
|
||||
The test code must:
|
||||
- Be wrapped in `#ifdef _DEBUG` blocks so it only runs in Debug builds
|
||||
- Be injected at appropriate points in the app lifecycle (e.g., after main window shows, after chats load, etc.)
|
||||
- Write progress and results to a log file. Use a dedicated path like:
|
||||
`QFile logFile("c:/Telegram/tdesktop/.ai/<feature-name>/test_log.txt");`
|
||||
Open with `QIODevice::Append | QIODevice::Text`, write with QTextStream, and flush after every write.
|
||||
- Save screenshots where visual verification is needed:
|
||||
`widget->grab().save("c:/Telegram/tdesktop/.ai/<feature-name>/screenshots/<name>.png");`
|
||||
Log each screenshot save: `"SCREENSHOT: <full-path>"`
|
||||
- Use `QTimer::singleShot(...)` or deferred calls to schedule test steps after UI events settle
|
||||
- Call `Core::Quit()` when all test steps complete, so the app exits cleanly
|
||||
- Log `"TEST_COMPLETE"` right before `Core::Quit()` so the test-run agent knows testing finished
|
||||
- Log `"TEST_STEP: <description>"` before each major step for progress tracking
|
||||
- Log `"TEST_RESULT: PASS: <what>"` or `"TEST_RESULT: FAIL: <what> - <details>"` for each check
|
||||
|
||||
Consider what needs testing:
|
||||
- Does the new UI appear correctly?
|
||||
- Do interactions work (clicks, navigation)?
|
||||
- Does data flow correctly?
|
||||
- Are there edge cases to verify?
|
||||
|
||||
4. **Write the test plan** to `.ai/<feature-name>/test<N>.md` containing:
|
||||
|
||||
## Test Iteration <N>
|
||||
## What We're Testing
|
||||
<description of what this test verifies>
|
||||
|
||||
## Test Steps
|
||||
1. <step>: what we do, what we expect, how we verify
|
||||
2. ...
|
||||
|
||||
## Code Injection Points
|
||||
- File: <path>, Location: <where in file>, Purpose: <what this block does>
|
||||
- ...
|
||||
|
||||
## Expected Log Output
|
||||
<example of what test_log.txt should contain if everything works>
|
||||
|
||||
## Expected Screenshots
|
||||
- <name>.png: should show <description>
|
||||
- ...
|
||||
|
||||
## Success Criteria
|
||||
- <criterion 1>
|
||||
- <criterion 2>
|
||||
- ...
|
||||
|
||||
When finished, report what test plan was created.
|
||||
```
|
||||
|
||||
### Step 6b: Test Implementation (test-do agent)
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are a test implementation agent for Telegram Desktop (C++ / Qt).
|
||||
|
||||
Read these files:
|
||||
- .ai/<feature-name>/context.md
|
||||
- .ai/<feature-name>/plan.md
|
||||
- .ai/<feature-name>/test<N>.md - The test plan to implement
|
||||
|
||||
YOUR TASK: Implement the test code described in test<N>.md.
|
||||
|
||||
Rules:
|
||||
- ALL test code MUST be inside `#ifdef _DEBUG` blocks
|
||||
- Place test code at the injection points specified in the test plan
|
||||
- Make sure the screenshots folder exists: create `.ai/<feature-name>/screenshots/` directory
|
||||
- Delete any old test_log.txt before the test starts (in code, at the first test step)
|
||||
- Use QTimer::singleShot for delayed operations to let the UI settle
|
||||
- Flush log writes immediately (don't buffer)
|
||||
- End with logging "TEST_COMPLETE" and calling Core::Quit()
|
||||
- Follow CLAUDE.md coding conventions
|
||||
- Make sure the code compiles: run `cmake --build "c:\Telegram\tdesktop\out" --config Debug --target Telegram`
|
||||
- If build fails, fix errors and rebuild until it passes
|
||||
- If build fails with file-locked errors (C1041, LNK1104), STOP and report
|
||||
|
||||
When finished, report what test code was added and where.
|
||||
```
|
||||
|
||||
### Step 6c: Test Run (test-run agent)
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are a test execution agent. You run the Telegram Desktop app and observe test output.
|
||||
|
||||
Read these files:
|
||||
- .ai/<feature-name>/test<N>.md - The test plan (so you know what to expect)
|
||||
|
||||
YOUR TASK: Run the built app and monitor test execution.
|
||||
|
||||
Steps:
|
||||
|
||||
1. **Prepare.**
|
||||
- Delete old test_log.txt if it exists: `del "c:\Telegram\tdesktop\docs\ai\work\<feature-name>\test_log.txt" 2>nul`
|
||||
- Ensure screenshots folder exists: `mkdir "c:\Telegram\tdesktop\docs\ai\work\<feature-name>\screenshots" 2>nul`
|
||||
|
||||
2. **Launch the app.**
|
||||
- Run in background: `start "" "c:\Telegram\tdesktop\out\Debug\Telegram.exe"`
|
||||
- Note the time of launch.
|
||||
|
||||
3. **Monitor test_log.txt in a polling loop.**
|
||||
- Every 5 seconds, read the log file to check for new output.
|
||||
- When you see `"SCREENSHOT: <path>"`, read the screenshot image file to visually verify it.
|
||||
- Track which TEST_STEP entries appear.
|
||||
- Track TEST_RESULT entries (PASS/FAIL).
|
||||
|
||||
4. **Detect completion or failure.**
|
||||
- **Success**: Log contains `"TEST_COMPLETE"` - the app should exit on its own shortly after.
|
||||
- **Crash**: The process disappears before `"TEST_COMPLETE"`. Check for crash dumps or error dialogs.
|
||||
- **Hang/Timeout**: If no new log output for 120 seconds and no `"TEST_COMPLETE"`, kill the process:
|
||||
`taskkill /IM Telegram.exe /F`
|
||||
- **No log at all**: If no test_log.txt appears within 60 seconds of launch, kill the process.
|
||||
|
||||
5. **After the process exits (or is killed), wait 5 seconds, then:**
|
||||
- Read the full final test_log.txt
|
||||
- Read all screenshot files saved during the test
|
||||
- Check for any leftover Telegram.exe processes: `tasklist /FI "IMAGENAME eq Telegram.exe"` and kill if needed
|
||||
|
||||
6. **Write the result report** to `.ai/<feature-name>/result<N>.md`:
|
||||
|
||||
## Test Result - Iteration <N>
|
||||
## Outcome: <PASS / FAIL / CRASH / TIMEOUT>
|
||||
|
||||
## Log Output
|
||||
<full contents of test_log.txt, or note that it was empty/missing>
|
||||
|
||||
## Screenshot Analysis
|
||||
- <name>.png: <description of what you see, whether it matches expectations from test<N>.md>
|
||||
- ...
|
||||
|
||||
## Test Results Summary
|
||||
- PASS: <list>
|
||||
- FAIL: <list>
|
||||
|
||||
## Issues Found
|
||||
<any problems observed, unexpected behavior, etc.>
|
||||
|
||||
## Raw Details
|
||||
<process exit code if available, timing information, any stderr output>
|
||||
|
||||
When finished, report the test outcome.
|
||||
```
|
||||
|
||||
After the test-run agent returns, read `result<N>.md`.
|
||||
|
||||
### Step 6d: Test Assessment (test-check agent)
|
||||
|
||||
Spawn an agent (Task tool, subagent_type=`general-purpose`):
|
||||
|
||||
```
|
||||
You are a test assessment agent. You analyze test results and decide next steps.
|
||||
|
||||
Read these files:
|
||||
- .ai/<feature-name>/context.md
|
||||
- .ai/<feature-name>/plan.md
|
||||
- .ai/<feature-name>/test<N>.md
|
||||
- .ai/<feature-name>/result<N>.md
|
||||
<if N > 1, also read previous test/result pairs for history>
|
||||
|
||||
Carefully analyze the test results.
|
||||
|
||||
DECIDE one of three outcomes:
|
||||
|
||||
### Outcome A: ALL TESTS PASS
|
||||
If all test results are PASS and screenshots look correct:
|
||||
1. Write to result<N>.md (append): `\n## Verdict: PASS`
|
||||
2. Report "ALL_TESTS_PASS" so the orchestrator knows to finish.
|
||||
|
||||
### Outcome B: TEST CODE NEEDS CHANGES
|
||||
If the test itself was flawed (wrong assertions, bad timing, insufficient waits, screenshot taken too early, wrong injection point, etc.) but the implementation seems correct:
|
||||
1. Describe what's wrong with the test and what to change.
|
||||
2. Make the changes directly to the test code in the source files.
|
||||
3. Rebuild: `cmake --build "c:\Telegram\tdesktop\out" --config Debug --target Telegram`
|
||||
4. If build fails with file-locked errors (C1041, LNK1104), STOP and report.
|
||||
5. Write the updated test description to `.ai/<feature-name>/test<N+1>.md` explaining what changed and why.
|
||||
6. Report "TEST_NEEDS_RERUN" so the orchestrator goes back to step 6c.
|
||||
|
||||
### Outcome C: IMPLEMENTATION HAS BUGS
|
||||
If the test results indicate actual bugs in the implementation (not test issues):
|
||||
1. Analyze what's wrong with the implementation.
|
||||
2. Write a fix plan to `.ai/<feature-name>/plan<N>.md`:
|
||||
|
||||
## Fix Plan - Iteration <N>
|
||||
## Problem
|
||||
<what the test revealed>
|
||||
|
||||
## Root Cause
|
||||
<analysis of why the implementation is wrong>
|
||||
|
||||
## Fix Steps
|
||||
1. <specific fix with file path, location, what to change>
|
||||
2. ...
|
||||
|
||||
3. Stash the test code (it will be restored later):
|
||||
- Run `git submodule status` and stash dirty submodules first:
|
||||
`cd <submodule> && git stash && cd <repo-root>`
|
||||
- Then: `git stash`
|
||||
4. Report "IMPLEMENTATION_NEEDS_FIX" so the orchestrator goes to re-implementation.
|
||||
|
||||
When finished, report your verdict clearly as one of: ALL_TESTS_PASS, TEST_NEEDS_RERUN, IMPLEMENTATION_NEEDS_FIX.
|
||||
```
|
||||
|
||||
### Orchestrator Loop Logic
|
||||
|
||||
After Phase 5 (build verification) succeeds, you (the orchestrator) run the testing loop:
|
||||
|
||||
```
|
||||
Set N = 1
|
||||
|
||||
LOOP:
|
||||
1. Spawn test-plan agent (Step 6a) with iteration N
|
||||
2. Spawn test-do agent (Step 6b) with iteration N
|
||||
3. Spawn test-run agent (Step 6c) with iteration N
|
||||
4. Spawn test-check agent (Step 6d) with iteration N
|
||||
5. Read the verdict:
|
||||
- "ALL_TESTS_PASS" → go to FINISH
|
||||
- "TEST_NEEDS_RERUN" →
|
||||
N = N + 1
|
||||
go to step 3 (skip 6a and 6b, test code was already updated by test-check)
|
||||
- "IMPLEMENTATION_NEEDS_FIX" →
|
||||
Spawn implementation fix agent (see below)
|
||||
N = N + 1
|
||||
go to step 1 (full restart: new commit, stash pop test code, etc.)
|
||||
6. Safety: if N > 5, stop and report to user - too many iterations.
|
||||
|
||||
FINISH:
|
||||
- Stash or revert all test code (#ifdef _DEBUG blocks):
|
||||
- git submodule status, stash submodules if dirty
|
||||
- git stash (to save test code separately, user may want it later)
|
||||
- Update plan.md: change `- [ ] Testing` to `- [x] Testing`
|
||||
- Report to user
|
||||
```
|
||||
|
||||
### Implementation Fix Agent
|
||||
|
||||
When test-check reports IMPLEMENTATION_NEEDS_FIX, spawn this agent:
|
||||
|
||||
```
|
||||
You are an implementation fix agent.
|
||||
|
||||
Read these files:
|
||||
- .ai/<feature-name>/context.md
|
||||
- .ai/<feature-name>/plan.md
|
||||
- .ai/<feature-name>/plan<N>.md - The fix plan from test assessment
|
||||
|
||||
Then read the source files mentioned in the fix plan.
|
||||
|
||||
YOUR TASK: Implement the fixes described in plan<N>.md.
|
||||
|
||||
Steps:
|
||||
1. Read and understand the fix plan.
|
||||
2. Make the specified code changes.
|
||||
3. Build: `cmake --build "c:\Telegram\tdesktop\out" --config Debug --target Telegram`
|
||||
4. Fix any build errors.
|
||||
5. If build fails with file-locked errors (C1041, LNK1104), STOP and report.
|
||||
|
||||
Rules:
|
||||
- Only make changes specified in the fix plan
|
||||
- Follow CLAUDE.md conventions
|
||||
- Do NOT touch test code or .ai/ files (except plan.md status if relevant)
|
||||
|
||||
When finished, report what was fixed.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Completion
|
||||
|
||||
When the testing loop finishes (ALL_TESTS_PASS or user stops it):
|
||||
1. Read the final `plan.md` and report full summary to the user.
|
||||
2. List all files modified/created by the implementation.
|
||||
3. Summarize test iterations: how many rounds, what was found and fixed.
|
||||
4. Note that test code is stashed (available via `git stash pop` if needed).
|
||||
5. Note any remaining concerns.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If any agent fails or gets stuck, report the issue to the user and ask how to proceed.
|
||||
- If context.md or plan.md is not written properly by an agent, re-spawn that agent with more specific instructions.
|
||||
- If build errors persist after agent attempts, report remaining errors to the user.
|
||||
- If the testing loop exceeds 5 iterations, stop and report - something fundamental may be wrong.
|
||||
- If the app crashes repeatedly, report to user - may need manual investigation.
|
||||
- If file-locked build errors occur at ANY point, stop immediately and ask user to close Telegram.exe.
|
||||
@@ -0,0 +1,11 @@
|
||||
param([string]$outPath)
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
$img = [System.Windows.Forms.Clipboard]::GetImage()
|
||||
if ($img) {
|
||||
$img.Save($outPath, [System.Drawing.Imaging.ImageFormat]::Png)
|
||||
Write-Host "Saved to $outPath"
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "No image on clipboard"
|
||||
exit 1
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
# Grab clipboard image on macOS and save as PNG.
|
||||
outPath="$1"
|
||||
if [ -z "$outPath" ]; then
|
||||
echo "Usage: grab_clipboard.sh <output.png>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
osascript -e '
|
||||
set theFile to POSIX file "'"$outPath"'"
|
||||
try
|
||||
set theImage to the clipboard as «class PNGf»
|
||||
on error
|
||||
return "no image"
|
||||
end try
|
||||
set fh to open for access theFile with write permission
|
||||
write theImage to fh
|
||||
close access fh
|
||||
return "ok"
|
||||
' 2>/dev/null | grep -q "ok"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Saved to $outPath"
|
||||
exit 0
|
||||
else
|
||||
echo "No image on clipboard"
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,343 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# Iterative Task Runner
|
||||
# Runs Claude Code in a loop to complete tasks from a taskplanner-created folder
|
||||
#
|
||||
# Usage: .\docs\ai\iterate.ps1 <featurename> [-MaxIterations N] [-Interactive] [-DryRun] [-SingleCommit] [-NoCommit]
|
||||
#
|
||||
# Arguments:
|
||||
# featurename Name of the folder in .ai/ containing prompt.md and tasks.json
|
||||
# -MaxIterations Maximum iterations before stopping (default: 50)
|
||||
# -Interactive Pause between iterations for user confirmation (default: auto/no pause)
|
||||
# -DryRun Show what would be executed without running
|
||||
# -SingleCommit Don't commit after each task, commit all changes at the end
|
||||
# -NoCommit Don't commit at all (no per-task commits, no final commit)
|
||||
|
||||
param(
|
||||
[Parameter(Position=0, Mandatory=$true)]
|
||||
[string]$FeatureName,
|
||||
|
||||
[int]$MaxIterations = 50,
|
||||
[switch]$Interactive,
|
||||
[switch]$DryRun,
|
||||
[switch]$SingleCommit,
|
||||
[switch]$NoCommit
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$RepoRoot = Resolve-Path (Join-Path $ScriptDir "..\..")
|
||||
$WorkDir = Join-Path $ScriptDir "work\$FeatureName"
|
||||
$PromptMd = Join-Path $WorkDir "prompt.md"
|
||||
$TasksJson = Join-Path $WorkDir "tasks.json"
|
||||
|
||||
$BuildOutputDir = Join-Path $RepoRoot "out\Debug"
|
||||
$TelegramExe = Join-Path $BuildOutputDir "Telegram.exe"
|
||||
$TelegramPdb = Join-Path $BuildOutputDir "Telegram.pdb"
|
||||
|
||||
function Format-Duration {
|
||||
param([int]$Seconds)
|
||||
|
||||
if ($Seconds -lt 60) {
|
||||
return "${Seconds}s"
|
||||
} elseif ($Seconds -lt 3600) {
|
||||
$min = [math]::Floor($Seconds / 60)
|
||||
$sec = $Seconds % 60
|
||||
return "${min}m ${sec}s"
|
||||
} else {
|
||||
$hr = [math]::Floor($Seconds / 3600)
|
||||
$min = [math]::Floor(($Seconds % 3600) / 60)
|
||||
$sec = $Seconds % 60
|
||||
return "${hr}h ${min}m ${sec}s"
|
||||
}
|
||||
}
|
||||
|
||||
function Test-BuildFilesUnlocked {
|
||||
$filesToCheck = @($TelegramExe, $TelegramPdb)
|
||||
|
||||
foreach ($file in $filesToCheck) {
|
||||
if (Test-Path $file) {
|
||||
try {
|
||||
Remove-Item $file -Force -ErrorAction Stop
|
||||
Write-Host "Removed: $file" -ForegroundColor DarkGray
|
||||
}
|
||||
catch {
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Red
|
||||
Write-Host " ERROR: Cannot delete build output" -ForegroundColor Red
|
||||
Write-Host " File is locked: $file" -ForegroundColor Red
|
||||
Write-Host "" -ForegroundColor Red
|
||||
Write-Host " Please close Telegram.exe and any" -ForegroundColor Red
|
||||
Write-Host " debugger, then try again." -ForegroundColor Red
|
||||
Write-Host "========================================" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
return $false
|
||||
}
|
||||
}
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
function Show-ClaudeStream {
|
||||
param([string]$Line)
|
||||
|
||||
try {
|
||||
$obj = $Line | ConvertFrom-Json -ErrorAction Stop
|
||||
|
||||
switch ($obj.type) {
|
||||
"assistant" {
|
||||
if ($obj.message.content) {
|
||||
foreach ($block in $obj.message.content) {
|
||||
if ($block.type -eq "text") {
|
||||
Write-Host $block.text -ForegroundColor White
|
||||
}
|
||||
elseif ($block.type -eq "tool_use") {
|
||||
$summary = ""
|
||||
if ($block.input) {
|
||||
if ($block.input.file_path) {
|
||||
$summary = $block.input.file_path
|
||||
} elseif ($block.input.pattern) {
|
||||
$summary = $block.input.pattern
|
||||
} elseif ($block.input.command) {
|
||||
$cmd = $block.input.command
|
||||
if ($cmd.Length -gt 60) { $cmd = $cmd.Substring(0, 60) + "..." }
|
||||
$summary = $cmd
|
||||
} else {
|
||||
$inputStr = $block.input | ConvertTo-Json -Compress -Depth 1
|
||||
if ($inputStr.Length -gt 60) { $inputStr = $inputStr.Substring(0, 60) + "..." }
|
||||
$summary = $inputStr
|
||||
}
|
||||
}
|
||||
Write-Host "[Tool: $($block.name)] $summary" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"user" {
|
||||
# Tool results - skip verbose output
|
||||
}
|
||||
"result" {
|
||||
Write-Host "`n--- Session Complete ---" -ForegroundColor Cyan
|
||||
if ($obj.cost_usd) {
|
||||
Write-Host "Cost: `$$($obj.cost_usd)" -ForegroundColor DarkCyan
|
||||
}
|
||||
}
|
||||
"system" {
|
||||
# System messages - skip
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
# Not valid JSON, skip
|
||||
}
|
||||
}
|
||||
|
||||
# Verify feature folder exists
|
||||
if (-not (Test-Path $WorkDir)) {
|
||||
Write-Error "Feature folder not found: $WorkDir`nRun '/taskplanner $FeatureName' first to create it."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Verify required files exist
|
||||
foreach ($file in @($PromptMd, $TasksJson)) {
|
||||
if (-not (Test-Path $file)) {
|
||||
Write-Error "Required file not found: $file"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
if ($SingleCommit -or $NoCommit) {
|
||||
$AfterImplementation = @"
|
||||
- Mark the task completed in tasks.json ("completed": true)
|
||||
- If new tasks emerged, add them to tasks.json
|
||||
"@
|
||||
$CommitRule = "- Do NOT commit changes after task is done, just mark it as done in tasks.json. Commit will be done when all tasks are complete, separately."
|
||||
} else {
|
||||
$AfterImplementation = @"
|
||||
- Mark the task completed in tasks.json ("completed": true)
|
||||
- Commit your changes
|
||||
- If new tasks emerged, add them to tasks.json
|
||||
"@
|
||||
$CommitRule = ""
|
||||
}
|
||||
|
||||
$Prompt = @"
|
||||
You are an autonomous coding agent working on: $FeatureName
|
||||
|
||||
Read these files for context:
|
||||
- .ai/$FeatureName/prompt.md - Detailed instructions and architecture
|
||||
- .ai/$FeatureName/tasks.json - Task list with completion status
|
||||
|
||||
Do exactly ONE task per iteration.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Read tasks.json and find the most suitable task to implement (it can be first uncompleted task or it can be some task in the middle, if it is better suited to be implemented right now, respecting dependencies)
|
||||
2. Plan the implementation carefully
|
||||
3. Implement that ONE task only
|
||||
4. After successful implementation:
|
||||
$AfterImplementation
|
||||
|
||||
## Critical Rules
|
||||
|
||||
- Only mark a task complete if you verified the work is done (build passes, etc.)
|
||||
- If stuck, document the issue in the task's notes field and move on
|
||||
- Do ONE task per iteration, then stop
|
||||
- NEVER try to commit files in .ai/
|
||||
$CommitRule
|
||||
|
||||
## Completion Signal
|
||||
|
||||
If ALL tasks in tasks.json have "completed": true, output exactly:
|
||||
===ALL_TASKS_COMPLETE===
|
||||
"@
|
||||
|
||||
$CommitPrompt = @"
|
||||
You are an autonomous coding agent. All tasks for "$FeatureName" are now complete.
|
||||
|
||||
Your job: Create a single commit with all the changes.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Run git status to see all modified files
|
||||
2. Run git diff to review the changes
|
||||
3. Create a commit with a short summary (aim for ~50 chars, max 76 chars) describing what was implemented
|
||||
4. The commit message should describe the overall feature/fix, not list individual changes
|
||||
|
||||
## Critical Rules
|
||||
|
||||
- NEVER try to commit files in .ai/
|
||||
- Use a concise commit message that captures the essence of the work done
|
||||
"@
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host " Iterative Task Runner" -ForegroundColor Cyan
|
||||
Write-Host " Feature: $FeatureName" -ForegroundColor Cyan
|
||||
Write-Host " Max iterations: $MaxIterations" -ForegroundColor Cyan
|
||||
Write-Host " Mode: $(if ($Interactive) { 'Interactive' } else { 'Auto' })" -ForegroundColor Cyan
|
||||
Write-Host " Commit: $(if ($NoCommit) { 'None' } elseif ($SingleCommit) { 'Single (at end)' } else { 'Per task' })" -ForegroundColor Cyan
|
||||
Write-Host " Working directory: $RepoRoot" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
if ($DryRun) {
|
||||
Write-Host "[DRY RUN] Would execute with prompt:" -ForegroundColor Yellow
|
||||
Write-Host $Prompt
|
||||
Write-Host ""
|
||||
Write-Host "Feature folder: $WorkDir" -ForegroundColor Yellow
|
||||
Write-Host "Prompt file: $PromptMd" -ForegroundColor Yellow
|
||||
Write-Host "Tasks file: $TasksJson" -ForegroundColor Yellow
|
||||
exit 0
|
||||
}
|
||||
|
||||
Push-Location $RepoRoot
|
||||
|
||||
$ScriptStartTime = Get-Date
|
||||
$IterationTimes = @()
|
||||
|
||||
try {
|
||||
for ($i = 1; $i -le $MaxIterations; $i++) {
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Yellow
|
||||
Write-Host " Iteration $i of $MaxIterations" -ForegroundColor Yellow
|
||||
Write-Host "========================================" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
if (-not (Test-BuildFilesUnlocked)) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
$IterationStartTime = Get-Date
|
||||
|
||||
claude --dangerously-skip-permissions --verbose -p $Prompt --output-format stream-json 2>&1 | ForEach-Object {
|
||||
Show-ClaudeStream $_
|
||||
}
|
||||
|
||||
$IterationEndTime = Get-Date
|
||||
$IterationDuration = [int]($IterationEndTime - $IterationStartTime).TotalSeconds
|
||||
$IterationTimes += $IterationDuration
|
||||
Write-Host "Iteration time: $(Format-Duration $IterationDuration)" -ForegroundColor DarkCyan
|
||||
|
||||
# Check task status after each run
|
||||
$tasks = Get-Content $TasksJson | ConvertFrom-Json
|
||||
$incomplete = @($tasks.tasks | Where-Object { -not $_.completed })
|
||||
$inProgress = @($tasks.tasks | Where-Object { $_.started -and -not $_.completed })
|
||||
|
||||
if ($incomplete.Count -eq 0) {
|
||||
if ($SingleCommit -and -not $NoCommit) {
|
||||
$i++
|
||||
if ($i -le $MaxIterations) {
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Yellow
|
||||
Write-Host " Final commit iteration" -ForegroundColor Yellow
|
||||
Write-Host "========================================" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
$CommitStartTime = Get-Date
|
||||
|
||||
claude --dangerously-skip-permissions --verbose -p $CommitPrompt --output-format stream-json 2>&1 | ForEach-Object {
|
||||
Show-ClaudeStream $_
|
||||
}
|
||||
|
||||
$CommitEndTime = Get-Date
|
||||
$CommitDuration = [int]($CommitEndTime - $CommitStartTime).TotalSeconds
|
||||
$IterationTimes += $CommitDuration
|
||||
Write-Host "Commit time: $(Format-Duration $CommitDuration)" -ForegroundColor DarkCyan
|
||||
} else {
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Red
|
||||
Write-Host " Max iterations reached before commit" -ForegroundColor Red
|
||||
Write-Host " Run manually: git add . && git commit" -ForegroundColor Red
|
||||
Write-Host "========================================" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
$TotalTime = [int]((Get-Date) - $ScriptStartTime).TotalSeconds
|
||||
$AvgTime = if ($IterationTimes.Count -gt 0) { [int](($IterationTimes | Measure-Object -Sum).Sum / $IterationTimes.Count) } else { 0 }
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host " ALL TASKS COMPLETE!" -ForegroundColor Green
|
||||
Write-Host " Feature: $FeatureName" -ForegroundColor Green
|
||||
Write-Host " Iterations: $($IterationTimes.Count)" -ForegroundColor Green
|
||||
Write-Host " Total time: $(Format-Duration $TotalTime)" -ForegroundColor Green
|
||||
Write-Host " Avg per iteration: $(Format-Duration $AvgTime)" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Remaining tasks: $($incomplete.Count)" -ForegroundColor Cyan
|
||||
if ($inProgress.Count -gt 0) {
|
||||
Write-Host "In progress: $($inProgress[0].title)" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
if ($Interactive) {
|
||||
Write-Host "Press Enter to continue, Ctrl+C to stop..." -ForegroundColor Cyan
|
||||
Read-Host
|
||||
} else {
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
}
|
||||
|
||||
$TotalTime = [int]((Get-Date) - $ScriptStartTime).TotalSeconds
|
||||
$AvgTime = if ($IterationTimes.Count -gt 0) { [int](($IterationTimes | Measure-Object -Sum).Sum / $IterationTimes.Count) } else { 0 }
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Red
|
||||
Write-Host " Max iterations ($MaxIterations) reached" -ForegroundColor Red
|
||||
Write-Host " Check tasks.json for remaining tasks" -ForegroundColor Red
|
||||
Write-Host " Total time: $(Format-Duration $TotalTime)" -ForegroundColor Red
|
||||
Write-Host " Avg per iteration: $(Format-Duration $AvgTime)" -ForegroundColor Red
|
||||
Write-Host "========================================" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
# Add directories or file patterns to ignore during indexing (e.g. foo/ or *.csv)
|
||||
Telegram/ThirdParty/
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "CentOS",
|
||||
"image": "tdesktop:centos_env",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"C_Cpp.intelliSenseEngine": "disabled",
|
||||
"cmake.generator": "Ninja Multi-Config",
|
||||
"cmake.buildDirectory": "${workspaceFolder}/out",
|
||||
"cmake.copyCompileCommands": "${workspaceFolder}/compile_commands.json"
|
||||
},
|
||||
"extensions": [
|
||||
"ms-vscode.cpptools-extension-pack",
|
||||
"llvm-vs-code-extensions.vscode-clangd",
|
||||
"TheQtCompany.qt",
|
||||
"ms-python.python",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"eamodio.gitlens"
|
||||
]
|
||||
}
|
||||
},
|
||||
"capAdd": [
|
||||
"SYS_PTRACE"
|
||||
],
|
||||
"securityOpt": [
|
||||
"seccomp=unconfined"
|
||||
],
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/usr/src/tdesktop,type=bind,consistency=cached",
|
||||
"workspaceFolder": "/usr/src/tdesktop"
|
||||
}
|
||||
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for reporting issues of Telegram Desktop!
|
||||
Thanks for reporting issues of AyuGram Desktop!
|
||||
|
||||
To make it easier for us to help you please enter detailed information below.
|
||||
- type: textarea
|
||||
@@ -39,12 +39,9 @@ body:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Version of Telegram Desktop
|
||||
label: Version of AyuGram Desktop
|
||||
description: >
|
||||
Please note we don't support versions from Linux distro repositories.
|
||||
If you need support for these versions, **please contact your distro maintainer**
|
||||
or your distro bugtracker.
|
||||
**Don't use 'latest'**, specify actual version, **that's a reason to close your issue**.
|
||||
**Don't use 'latest'**, specify actual version.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
@@ -52,11 +49,10 @@ body:
|
||||
label: Installation source
|
||||
multiple: false
|
||||
options:
|
||||
- Static binary from official website
|
||||
- Microsoft Store
|
||||
- Mac App Store
|
||||
- Flatpak
|
||||
- Snap
|
||||
- Binary from GitHub / @AyuGramReleases channel
|
||||
- Arch Linux (ayugram-desktop / ayugram-desktop-git)
|
||||
- Arch Linux (ayugram-desktop-bin)
|
||||
- flatpak by 0FL01
|
||||
- Other (unofficial) source
|
||||
validations:
|
||||
required: true
|
||||
@@ -65,9 +61,7 @@ body:
|
||||
label: Crash ID
|
||||
description: >
|
||||
If you're reporting a crash, please enter the crash ID from the crash reporter
|
||||
opening on the next launch after crash. **You have to enable beta versions
|
||||
installation in Settings -> Advanced for the reporter to appear.**
|
||||
You don't have to wait for a beta version to arrive.
|
||||
opening on the next launch after crash.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Logs
|
||||
|
||||
@@ -7,5 +7,5 @@ contact_links:
|
||||
url: https://bugs.telegram.org
|
||||
about: Any bug report or feature request not about Telegram Desktop.
|
||||
- name: Question
|
||||
url: https://t.me/TelegramDesktopTalk
|
||||
url: https://t.me/ayugramchat
|
||||
about: Ask a question.
|
||||
|
||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 161 KiB |
|
After Width: | Height: | Size: 142 KiB |
@@ -1,6 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -0,0 +1,328 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Convert changelog.txt to a static HTML page for GitHub Pages."""
|
||||
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import html
|
||||
from pathlib import Path
|
||||
|
||||
MONTHS = [
|
||||
"", "January", "February", "March", "April", "May", "June",
|
||||
"July", "August", "September", "October", "November", "December",
|
||||
]
|
||||
|
||||
VERSION_RE = re.compile(
|
||||
r"^(\d+\.\d+(?:\.\d+)?)\s*" # version number
|
||||
r"(?:(alpha|beta|dev|stable)\s*)?" # optional tag
|
||||
r"\((\d{2})\.(\d{2})\.(\d{2,4})\)$" # date (DD.MM.YY or DD.MM.YYYY)
|
||||
)
|
||||
|
||||
|
||||
def parse_date(day: str, month: str, year: str) -> tuple[str, str, str]:
|
||||
"""Return (sort_key, raw_display, full_display) from DD, MM, YY strings."""
|
||||
y = int(year)
|
||||
if y < 100:
|
||||
y += 2000
|
||||
m = int(month)
|
||||
d = int(day)
|
||||
sort_key = f"{y:04d}-{m:02d}-{d:02d}"
|
||||
raw_display = f"{day}.{month}.{year}"
|
||||
full_display = f"{d} {MONTHS[m]} {y}"
|
||||
return sort_key, raw_display, full_display
|
||||
|
||||
|
||||
def parse_changelog(text: str) -> list[dict]:
|
||||
entries = []
|
||||
current = None
|
||||
|
||||
for raw_line in text.splitlines():
|
||||
line = raw_line.rstrip()
|
||||
m = VERSION_RE.match(line)
|
||||
if m:
|
||||
if current:
|
||||
entries.append(current)
|
||||
version, tag, day, month, year = m.groups()
|
||||
sort_key, raw_date, full_date = parse_date(day, month, year)
|
||||
current = {
|
||||
"version": version,
|
||||
"tag": tag or "",
|
||||
"date": raw_date,
|
||||
"full_date": full_date,
|
||||
"sort_key": sort_key,
|
||||
"lines": [],
|
||||
}
|
||||
elif current is not None:
|
||||
# Skip blank lines at the start
|
||||
if not line and not current["lines"]:
|
||||
continue
|
||||
# Skip stray artifact lines
|
||||
if line.strip() in ("),", "),"):
|
||||
continue
|
||||
current["lines"].append(line)
|
||||
|
||||
if current:
|
||||
entries.append(current)
|
||||
|
||||
# Trim trailing blank lines from each entry
|
||||
for entry in entries:
|
||||
while entry["lines"] and not entry["lines"][-1]:
|
||||
entry["lines"].pop()
|
||||
|
||||
return entries
|
||||
|
||||
|
||||
def render_entry(entry: dict) -> str:
|
||||
version = html.escape(entry["version"])
|
||||
tag = entry["tag"]
|
||||
date = html.escape(entry["date"])
|
||||
anchor = f"v{version}"
|
||||
|
||||
tag_html = ""
|
||||
if tag and tag not in ("stable",):
|
||||
tag_html = f' {html.escape(tag)}'
|
||||
|
||||
parts = [
|
||||
f'<article class="entry" id="{anchor}">',
|
||||
f' <h2><a class="anchor" href="#{anchor}"></a>'
|
||||
f'{version}{tag_html}'
|
||||
f' <time>{date}</time></h2>',
|
||||
]
|
||||
|
||||
in_list = False
|
||||
for line in entry["lines"]:
|
||||
stripped = line.lstrip()
|
||||
if stripped.startswith("- ") or stripped.startswith("\u2014 "):
|
||||
# Bullet point (- or em dash)
|
||||
if not in_list:
|
||||
parts.append(" <ul>")
|
||||
in_list = True
|
||||
bullet_text = stripped[2:]
|
||||
parts.append(f" <li>{html.escape(bullet_text)}</li>")
|
||||
else:
|
||||
if in_list:
|
||||
parts.append(" </ul>")
|
||||
in_list = False
|
||||
if stripped:
|
||||
parts.append(f" <p>{html.escape(stripped)}</p>")
|
||||
|
||||
if in_list:
|
||||
parts.append(" </ul>")
|
||||
|
||||
parts.append("</article>")
|
||||
return "\n".join(parts)
|
||||
|
||||
|
||||
def build_html(entries: list[dict]) -> str:
|
||||
count = len(entries)
|
||||
first_date = entries[-1]["full_date"] if entries else ""
|
||||
latest_version = entries[0]["version"] if entries else ""
|
||||
|
||||
entries_html = "\n\n".join(render_entry(e) for e in entries)
|
||||
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Version history</title>
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="icon32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="icon16.png">
|
||||
<style>
|
||||
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
|
||||
body {{
|
||||
font: 12px / 18px "Lucida Grande", "Lucida Sans Unicode", Arial,
|
||||
Helvetica, Verdana, sans-serif;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
}}
|
||||
header {{
|
||||
background: #1d98dc;
|
||||
color: #fff;
|
||||
padding: 2rem 1.5rem;
|
||||
text-align: center;
|
||||
}}
|
||||
header h1 {{ font-size: 18px; font-weight: 700; }}
|
||||
header p {{ opacity: .85; margin-top: 4px; font-size: 12px; }}
|
||||
.container {{
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 15px;
|
||||
}}
|
||||
.search-box {{
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
background: #fff;
|
||||
padding: 8px 0 12px;
|
||||
}}
|
||||
.search-box input {{
|
||||
width: 100%;
|
||||
padding: 6px 10px;
|
||||
font: 12px / 18px "Lucida Grande", "Lucida Sans Unicode", Arial,
|
||||
Helvetica, Verdana, sans-serif;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
outline: none;
|
||||
}}
|
||||
.search-box input:focus {{ border-color: #1d98dc; }}
|
||||
.entry {{
|
||||
padding: 14px 0 4px;
|
||||
scroll-margin-top: 48px;
|
||||
}}
|
||||
.entry h2 {{
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 22px;
|
||||
margin-bottom: 6px;
|
||||
position: relative;
|
||||
}}
|
||||
.entry h2 .anchor {{
|
||||
position: absolute;
|
||||
left: -24px;
|
||||
top: 0;
|
||||
width: 24px;
|
||||
height: 22px;
|
||||
display: block;
|
||||
opacity: 0;
|
||||
transition: opacity .15s;
|
||||
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 16 16'%3E%3Cpath fill='%23168acd' d='M7.775 3.275a.75.75 0 0 0 1.06 1.06l1.25-1.25a2 2 0 1 1 2.83 2.83l-2.5 2.5a2 2 0 0 1-2.83 0 .75.75 0 0 0-1.06 1.06 3.5 3.5 0 0 0 4.95 0l2.5-2.5a3.5 3.5 0 0 0-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 0 1 0-2.83l2.5-2.5a2 2 0 0 1 2.83 0 .75.75 0 0 0 1.06-1.06 3.5 3.5 0 0 0-4.95 0l-2.5 2.5a3.5 3.5 0 0 0 4.95 4.95l1.25-1.25a.75.75 0 0 0-1.06-1.06l-1.25 1.25a2 2 0 0 1-2.83 0z'/%3E%3C/svg%3E") 0 center / 18px no-repeat;
|
||||
cursor: pointer;
|
||||
}}
|
||||
.entry h2:hover .anchor {{ opacity: .6; }}
|
||||
.entry h2 .anchor:hover {{ opacity: 1; }}
|
||||
.entry h2 time {{
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #999;
|
||||
margin-left: 6px;
|
||||
}}
|
||||
.entry ul {{
|
||||
margin: 0 0 4px 8px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}}
|
||||
.entry li {{
|
||||
padding: 2px 0 2px 16px;
|
||||
position: relative;
|
||||
color: #333;
|
||||
}}
|
||||
.entry li::before {{
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 9px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #009be1;
|
||||
}}
|
||||
.entry p {{
|
||||
margin: 4px 0;
|
||||
color: #555;
|
||||
font-style: italic;
|
||||
}}
|
||||
.hidden {{ display: none; }}
|
||||
footer {{
|
||||
text-align: center;
|
||||
padding: 24px 15px;
|
||||
font-size: 11px;
|
||||
color: #999;
|
||||
}}
|
||||
footer a {{ color: #168acd; text-decoration: none; }}
|
||||
footer a:hover {{ text-decoration: underline; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<h1>Version history</h1>
|
||||
<p>{count} releases since {first_date} · latest: {latest_version}</p>
|
||||
</header>
|
||||
|
||||
<div class="container">
|
||||
<div class="search-box">
|
||||
<input type="text" id="search" placeholder="Search versions and changes\u2026"
|
||||
autocomplete="off" spellcheck="false">
|
||||
</div>
|
||||
|
||||
<div id="entries">
|
||||
{entries_html}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
Auto-generated from
|
||||
<a href="https://github.com/telegramdesktop/tdesktop/blob/dev/changelog.txt">changelog.txt</a>.
|
||||
Source code is published under
|
||||
<a href="https://github.com/telegramdesktop/tdesktop">GPL v3</a>.
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
(function() {{
|
||||
var input = document.getElementById('search');
|
||||
var entries = document.querySelectorAll('.entry');
|
||||
var timer;
|
||||
input.addEventListener('input', function() {{
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function() {{
|
||||
var q = input.value.toLowerCase().trim();
|
||||
entries.forEach(function(el) {{
|
||||
if (!q) {{
|
||||
el.classList.remove('hidden');
|
||||
}} else {{
|
||||
el.classList.toggle('hidden', el.textContent.toLowerCase().indexOf(q) === -1);
|
||||
}}
|
||||
}});
|
||||
}}, 150);
|
||||
}});
|
||||
|
||||
// Anchor links: copy URL on click
|
||||
document.addEventListener('click', function(e) {{
|
||||
var anchor = e.target.closest('.anchor');
|
||||
if (!anchor) return;
|
||||
e.preventDefault();
|
||||
var url = location.origin + location.pathname + anchor.getAttribute('href');
|
||||
history.replaceState(null, '', anchor.getAttribute('href'));
|
||||
if (navigator.clipboard) {{
|
||||
navigator.clipboard.writeText(url);
|
||||
}}
|
||||
}});
|
||||
}})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
def main():
|
||||
repo = Path(__file__).resolve().parent.parent.parent
|
||||
src = repo / "changelog.txt"
|
||||
if len(sys.argv) > 1:
|
||||
src = Path(sys.argv[1])
|
||||
|
||||
out = repo / "docs" / "changelog" / "index.html"
|
||||
if len(sys.argv) > 2:
|
||||
out = Path(sys.argv[2])
|
||||
|
||||
text = src.read_text(encoding="utf-8")
|
||||
entries = parse_changelog(text)
|
||||
html_content = build_html(entries)
|
||||
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
out.write_text(html_content, encoding="utf-8")
|
||||
|
||||
# Copy favicon files from resources
|
||||
icons_src = repo / "Telegram" / "Resources" / "art"
|
||||
for name in ("icon16.png", "icon32.png"):
|
||||
icon = icons_src / name
|
||||
if icon.exists():
|
||||
shutil.copy2(icon, out.parent / name)
|
||||
|
||||
print(f"Generated {out} ({len(entries)} entries, {out.stat().st_size:,} bytes)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,124 +0,0 @@
|
||||
name: Linux.
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
- '.github/**'
|
||||
- '!.github/workflows/linux.yml'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
- 'Telegram/SourceFiles/platform/mac/**'
|
||||
- 'Telegram/Telegram/**'
|
||||
- 'Telegram/configure.bat'
|
||||
- 'Telegram/Telegram.plist'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
- '.github/**'
|
||||
- '!.github/workflows/linux.yml'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/Resources/winrc/**'
|
||||
- 'Telegram/SourceFiles/platform/win/**'
|
||||
- 'Telegram/SourceFiles/platform/mac/**'
|
||||
- 'Telegram/Telegram/**'
|
||||
- 'Telegram/configure.bat'
|
||||
- 'Telegram/Telegram.plist'
|
||||
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
name: Rocky Linux 8
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
defines:
|
||||
- ""
|
||||
- "DESKTOP_APP_DISABLE_X11_INTEGRATION"
|
||||
|
||||
env:
|
||||
UPLOAD_ARTIFACT: "true"
|
||||
|
||||
steps:
|
||||
- name: Get repository name.
|
||||
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Clone.
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
path: ${{ env.REPO_NAME }}
|
||||
|
||||
- name: First set up.
|
||||
run: |
|
||||
echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
|
||||
docker pull ghcr.io/$GITHUB_REPOSITORY/centos_env
|
||||
docker tag ghcr.io/$GITHUB_REPOSITORY/centos_env tdesktop:centos_env
|
||||
|
||||
- name: Telegram Desktop build.
|
||||
run: |
|
||||
cd $REPO_NAME
|
||||
|
||||
DEFINE=""
|
||||
if [ -n "${{ matrix.defines }}" ]; then
|
||||
DEFINE="-D ${{ matrix.defines }}=ON"
|
||||
echo Define from matrix: $DEFINE
|
||||
echo "ARTIFACT_NAME=Telegram_${{ matrix.defines }}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "ARTIFACT_NAME=Telegram" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
docker run --rm \
|
||||
-v $PWD:/usr/src/tdesktop \
|
||||
-e CONFIG=Debug \
|
||||
tdesktop:centos_env \
|
||||
/usr/src/tdesktop/Telegram/build/docker/centos_env/build.sh \
|
||||
-D CMAKE_C_FLAGS_DEBUG="" \
|
||||
-D CMAKE_CXX_FLAGS_DEBUG="" \
|
||||
-D CMAKE_C_FLAGS="-Werror" \
|
||||
-D CMAKE_CXX_FLAGS="-Werror" \
|
||||
-D CMAKE_EXE_LINKER_FLAGS="-s" \
|
||||
-D TDESKTOP_API_TEST=ON \
|
||||
-D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF \
|
||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF \
|
||||
$DEFINE
|
||||
|
||||
- name: Check.
|
||||
run: |
|
||||
filePath="$REPO_NAME/out/Debug/Telegram"
|
||||
if test -f "$filePath"; then
|
||||
echo "Build successfully done! :)"
|
||||
|
||||
size=$(stat -c %s "$filePath")
|
||||
echo "File size of ${filePath}: ${size} Bytes."
|
||||
else
|
||||
echo "Build error, output file does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Move artifact.
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
run: |
|
||||
cd $REPO_NAME/out/Debug
|
||||
sudo mkdir artifact
|
||||
sudo mv {Telegram,Updater} artifact/
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
name: Upload artifact.
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_NAME }}
|
||||
path: ${{ env.REPO_NAME }}/out/Debug/artifact/
|
||||
@@ -1,201 +0,0 @@
|
||||
name: Windows.
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
- '.github/**'
|
||||
- '!.github/workflows/win.yml'
|
||||
- 'lib/xdg/**'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/docker/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/SourceFiles/platform/linux/**'
|
||||
- 'Telegram/SourceFiles/platform/mac/**'
|
||||
- 'Telegram/Telegram/**'
|
||||
- 'Telegram/configure.sh'
|
||||
- 'Telegram/Telegram.plist'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**.md'
|
||||
- 'changelog.txt'
|
||||
- 'LEGAL'
|
||||
- 'LICENSE'
|
||||
- '.github/**'
|
||||
- '!.github/workflows/win.yml'
|
||||
- 'lib/xdg/**'
|
||||
- 'snap/**'
|
||||
- 'Telegram/build/docker/**'
|
||||
- 'Telegram/Resources/uwp/**'
|
||||
- 'Telegram/SourceFiles/platform/linux/**'
|
||||
- 'Telegram/SourceFiles/platform/mac/**'
|
||||
- 'Telegram/Telegram/**'
|
||||
- 'Telegram/configure.sh'
|
||||
- 'Telegram/Telegram.plist'
|
||||
|
||||
jobs:
|
||||
|
||||
windows:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
arch: [Win32, x64]
|
||||
generator: ["", "Ninja Multi-Config"]
|
||||
|
||||
env:
|
||||
UPLOAD_ARTIFACT: "true"
|
||||
ONLY_CACHE: "false"
|
||||
PREPARE_PATH: "Telegram/build/prepare/prepare.py"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
|
||||
steps:
|
||||
- name: Prepare directories.
|
||||
run: |
|
||||
mkdir %userprofile%\TBuild\Libraries
|
||||
mklink /d %GITHUB_WORKSPACE%\TBuild %userprofile%\TBuild
|
||||
echo TBUILD=%GITHUB_WORKSPACE%\TBuild>>%GITHUB_ENV%
|
||||
|
||||
- name: Get repository name.
|
||||
shell: bash
|
||||
run: echo "REPO_NAME=${GITHUB_REPOSITORY##*/}" >> $GITHUB_ENV
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||
name: Native Tools Command Prompt.
|
||||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
- name: Clone.
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
path: ${{ env.TBUILD }}\${{ env.REPO_NAME }}
|
||||
|
||||
- name: Set up environment paths.
|
||||
shell: bash
|
||||
run: |
|
||||
echo "CACHE_KEY=$(sha256sum $TBUILD/$REPO_NAME/$PREPARE_PATH | awk '{ print $1 }')" >> $GITHUB_ENV
|
||||
|
||||
echo "Configurate git for cherry-picks."
|
||||
git config --global user.email "you@example.com"
|
||||
git config --global user.name "Sample"
|
||||
|
||||
- name: NuGet sources.
|
||||
run: |
|
||||
nuget sources Disable -Name "Microsoft Visual Studio Offline Packages"
|
||||
nuget sources Add -Source https://api.nuget.org/v3/index.json & exit 0
|
||||
|
||||
- name: ThirdParty cache.
|
||||
id: cache-third-party
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.TBUILD }}\ThirdParty
|
||||
key: ${{ runner.OS }}-${{ matrix.arch }}-third-party-${{ env.CACHE_KEY }}
|
||||
restore-keys: ${{ runner.OS }}-${{ matrix.arch }}-third-party-
|
||||
|
||||
- name: Libraries cache.
|
||||
id: cache-libs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.TBUILD }}\Libraries
|
||||
key: ${{ runner.OS }}-${{ matrix.arch }}-libs-${{ env.CACHE_KEY }}
|
||||
restore-keys: ${{ runner.OS }}-${{ matrix.arch }}-libs-
|
||||
|
||||
- name: Libraries.
|
||||
env:
|
||||
GYP_MSVS_OVERRIDE_PATH: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\'
|
||||
GYP_MSVS_VERSION: 2022
|
||||
run: |
|
||||
cd %TBUILD%
|
||||
%REPO_NAME%\Telegram\build\prepare\win.bat skip-release silent
|
||||
|
||||
- name: Read configuration matrix.
|
||||
shell: bash
|
||||
run: |
|
||||
ARTIFACT_NAME="Telegram"
|
||||
|
||||
ARCH=""
|
||||
if [ -n "${{ matrix.arch }}" ]; then
|
||||
case "${{ matrix.arch }}" in
|
||||
Win32) ARCH="x86";;
|
||||
*) ARCH="${{ matrix.arch }}";;
|
||||
esac
|
||||
echo "Architecture from matrix: $ARCH"
|
||||
ARTIFACT_NAME="${ARTIFACT_NAME}_${{ matrix.arch }}"
|
||||
fi
|
||||
|
||||
GENERATOR=""
|
||||
if [ -n "${{ matrix.generator }}" ]; then
|
||||
GENERATOR="-G \"${{ matrix.generator }}\""
|
||||
echo "Generator from matrix: $GENERATOR"
|
||||
ARTIFACT_NAME="${ARTIFACT_NAME}_${{ matrix.generator }}"
|
||||
fi
|
||||
echo "TDESKTOP_BUILD_GENERATOR=$GENERATOR" >> $GITHUB_ENV
|
||||
|
||||
[ -n "$GENERATOR" ] && ARCH=""
|
||||
echo "TDESKTOP_BUILD_ARCH=$ARCH" >> $GITHUB_ENV
|
||||
|
||||
DEFINE=""
|
||||
if [ -n "${{ matrix.defines }}" ]; then
|
||||
DEFINE="-D ${{ matrix.defines }}=ON"
|
||||
echo "Define from matrix: $DEFINE"
|
||||
ARTIFACT_NAME="${ARTIFACT_NAME}_${{ matrix.defines }}"
|
||||
fi
|
||||
echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV
|
||||
|
||||
echo "ARTIFACT_NAME=$ARTIFACT_NAME" >> $GITHUB_ENV
|
||||
|
||||
API="-D TDESKTOP_API_TEST=ON"
|
||||
if [ $GITHUB_REF == 'refs/heads/nightly' ]; then
|
||||
echo "Use the open credentials."
|
||||
API="-D TDESKTOP_API_ID=611335 -D TDESKTOP_API_HASH=d524b414d21f4d37f08684c1df41ac9c"
|
||||
fi
|
||||
echo "TDESKTOP_BUILD_API=$API" >> $GITHUB_ENV
|
||||
|
||||
- name: Free up some disk space.
|
||||
run: |
|
||||
cd %TBUILD%
|
||||
del /S Libraries\*.pdb
|
||||
del /S Libraries\*.pch
|
||||
del /S Libraries\*.obj
|
||||
|
||||
- name: Telegram Desktop build.
|
||||
if: env.ONLY_CACHE == 'false'
|
||||
run: |
|
||||
cd %TBUILD%\%REPO_NAME%\Telegram
|
||||
|
||||
call configure.bat ^
|
||||
%TDESKTOP_BUILD_GENERATOR% ^
|
||||
%TDESKTOP_BUILD_ARCH% ^
|
||||
%TDESKTOP_BUILD_API% ^
|
||||
-D CMAKE_C_FLAGS="/WX" ^
|
||||
-D CMAKE_CXX_FLAGS="/WX" ^
|
||||
-D DESKTOP_APP_DISABLE_AUTOUPDATE=OFF ^
|
||||
-D DESKTOP_APP_DISABLE_CRASH_REPORTS=OFF ^
|
||||
-D DESKTOP_APP_NO_PDB=ON ^
|
||||
%TDESKTOP_BUILD_DEFINE%
|
||||
|
||||
cmake --build ..\out --config Debug --parallel
|
||||
|
||||
- name: Move artifact.
|
||||
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
|
||||
run: |
|
||||
set OUT=%TBUILD%\%REPO_NAME%\out\Debug
|
||||
mkdir artifact
|
||||
move %OUT%\Telegram.exe artifact/
|
||||
move %OUT%\Updater.exe artifact/
|
||||
- uses: actions/upload-artifact@v4
|
||||
name: Upload artifact.
|
||||
if: (env.UPLOAD_ARTIFACT == 'true') || (github.ref == 'refs/heads/nightly')
|
||||
with:
|
||||
name: ${{ env.ARTIFACT_NAME }}
|
||||
path: artifact\
|
||||
@@ -19,6 +19,8 @@ Release/
|
||||
ipch/
|
||||
.vs/
|
||||
.vscode/
|
||||
.cache/
|
||||
compile_commands.json
|
||||
|
||||
/Telegram/log.txt
|
||||
/Telegram/data
|
||||
@@ -52,5 +54,22 @@ stage
|
||||
.idea/
|
||||
cmake-build-debug/
|
||||
|
||||
# Local configuration files
|
||||
settings.local.json
|
||||
*.local.json
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Cursor IDE local settings (but keep .cursor/rules/)
|
||||
.cursor/*
|
||||
!.cursor/rules/
|
||||
|
||||
# AI work folder (session-specific, not for version control)
|
||||
.ai
|
||||
|
||||
# Generated changelog page (built by CI, deployed to GitHub Pages)
|
||||
/docs/changelog/
|
||||
|
||||
# Project specific
|
||||
Telegram/SourceFiles/_other/packer_private.h
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
[submodule "Telegram/ThirdParty/libtgvoip"]
|
||||
path = Telegram/ThirdParty/libtgvoip
|
||||
url = https://github.com/telegramdesktop/libtgvoip
|
||||
[submodule "Telegram/ThirdParty/GSL"]
|
||||
path = Telegram/ThirdParty/GSL
|
||||
url = https://github.com/Microsoft/GSL.git
|
||||
@@ -76,9 +73,6 @@
|
||||
[submodule "Telegram/lib_webview"]
|
||||
path = Telegram/lib_webview
|
||||
url = https://github.com/desktop-app/lib_webview.git
|
||||
[submodule "Telegram/ThirdParty/jemalloc"]
|
||||
path = Telegram/ThirdParty/jemalloc
|
||||
url = https://github.com/jemalloc/jemalloc
|
||||
[submodule "Telegram/ThirdParty/dispatch"]
|
||||
path = Telegram/ThirdParty/dispatch
|
||||
url = https://github.com/apple/swift-corelibs-libdispatch
|
||||
@@ -97,3 +91,9 @@
|
||||
[submodule "Telegram/ThirdParty/xdg-desktop-portal"]
|
||||
path = Telegram/ThirdParty/xdg-desktop-portal
|
||||
url = https://github.com/flatpak/xdg-desktop-portal.git
|
||||
[submodule "Telegram/lib_translate"]
|
||||
path = Telegram/lib_translate
|
||||
url = https://github.com/desktop-app/lib_translate
|
||||
[submodule "Telegram/lib_icu"]
|
||||
path = Telegram/lib_icu
|
||||
url = https://github.com/AyuGram/lib_icu.git
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
# Agent Guide for Telegram Desktop
|
||||
|
||||
This guide defines repository-wide instructions for coding agents working with the Telegram Desktop codebase.
|
||||
|
||||
Avoid building the project.
|
||||
|
||||
If you're asked to create a Pull Request, then clearly state in PR description that it was AI generated.
|
||||
|
||||
# Development Guidelines
|
||||
|
||||
## Coding Style
|
||||
|
||||
**Do NOT write comments in code:**
|
||||
|
||||
This is important! Do not write single-line comments that describe what the next line does - they are bloat. Comments are allowed ONLY to describe complex algorithms in detail, when the explanation requires at least 4-5 lines. Self-documenting code with clear variable and function names is preferred.
|
||||
|
||||
```cpp
|
||||
// BAD - don't do this:
|
||||
// Get the user's name
|
||||
auto name = user->name();
|
||||
// Check if premium
|
||||
if (user->isPremium()) {
|
||||
|
||||
// GOOD - no comments needed, code is self-explanatory:
|
||||
auto name = user->name();
|
||||
if (user->isPremium()) {
|
||||
|
||||
// ACCEPTABLE - complex algorithm explanation (4+ lines):
|
||||
// The algorithm works by first collecting all visible messages
|
||||
// in the viewport, then calculating their intersection with
|
||||
// the clip rectangle. Messages are grouped by date headers,
|
||||
// and we need to account for sticky headers that may overlap
|
||||
// with the first message in each group.
|
||||
```
|
||||
|
||||
**Style and formatting rules** are in `REVIEW.md` — see that file for empty-line-before-closing-brace, operator placement in multi-line expressions, if-with-initializer, and other mechanical style rules.
|
||||
|
||||
**Use `auto` for type deduction:**
|
||||
|
||||
Prefer `auto` (or `const auto`, `const auto &`) instead of explicit types:
|
||||
|
||||
```cpp
|
||||
// Prefer this:
|
||||
auto currentTitle = tr::lng_settings_title(tr::now);
|
||||
auto nameProducer = GetNameProducer();
|
||||
|
||||
// Instead of this:
|
||||
QString currentTitle = tr::lng_settings_title(tr::now);
|
||||
rpl::producer<QString> nameProducer = GetNameProducer();
|
||||
```
|
||||
|
||||
## API Usage
|
||||
|
||||
### API Schema Files
|
||||
|
||||
API definitions use [TL Language](https://core.telegram.org/mtproto/TL):
|
||||
|
||||
1. **`Telegram/SourceFiles/mtproto/scheme/mtproto.tl`** - MTProto protocol (encryption, auth, etc.)
|
||||
2. **`Telegram/SourceFiles/mtproto/scheme/api.tl`** - Telegram API (messages, users, chats, etc.)
|
||||
|
||||
### Making API Requests
|
||||
|
||||
Standard pattern using `api()`, generated `MTP...` types, and callbacks:
|
||||
|
||||
```cpp
|
||||
api().request(MTPnamespace_MethodName(
|
||||
MTP_flags(flags_value),
|
||||
MTP_inputPeer(peer),
|
||||
MTP_string(messageText),
|
||||
MTP_long(randomId),
|
||||
MTP_vector<MTPMessageEntity>()
|
||||
)).done([=](const MTPResponseType &result) {
|
||||
// Handle successful response
|
||||
|
||||
// Multiple constructors - use .match() or check type:
|
||||
result.match([&](const MTPDuser &data) {
|
||||
// use data.vfirst_name().v
|
||||
}, [&](const MTPDuserEmpty &data) {
|
||||
// handle empty user
|
||||
});
|
||||
|
||||
// Single constructor - use .data() shortcut:
|
||||
const auto &data = result.data();
|
||||
// use data.vmessages().v
|
||||
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
// Handle API error
|
||||
if (error.type() == u"FLOOD_WAIT_X"_q) {
|
||||
// Handle flood wait
|
||||
}
|
||||
}).handleFloodErrors().send();
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
- Always refer to `api.tl` for method signatures and return types
|
||||
- Use generated `MTP...` types for parameters (`MTP_int`, `MTP_string`, etc.)
|
||||
- For multiple constructors, use `.match()` or check `.type()` against `mtpc_` constants then call `.c_constructorName()`:
|
||||
```cpp
|
||||
// Using match:
|
||||
result.match([&](const MTPDuser &data) { ... }, [&](const MTPDuserEmpty &data) { ... });
|
||||
// Or explicit type check:
|
||||
if (result.type() == mtpc_user) {
|
||||
const auto &data = result.c_user(); // asserts on type mismatch
|
||||
}
|
||||
```
|
||||
- For single constructors, use `.data()` shortcut
|
||||
- Include `.handleFloodErrors()` before `.send()` in rare cases where you want special case flood error handling
|
||||
- Silently ignore HTTP 406 errors in UI: the server uses 406 to mean "show nothing to the user". Guard toasts with `MTP::IgnoreError(error)` or use `MTP::ShowErrorFallback(show, error)` (both in `mtproto/mtproto_response.h`) which shows `error.type()` as a toast unless the error should be ignored.
|
||||
|
||||
## UI Styling
|
||||
|
||||
### Style Files
|
||||
|
||||
UI styles are defined in `.style` files using custom syntax:
|
||||
|
||||
```style
|
||||
using "ui/basic.style";
|
||||
using "ui/widgets/widgets.style";
|
||||
|
||||
MyButtonStyle {
|
||||
textPadding: margins;
|
||||
icon: icon;
|
||||
height: pixels;
|
||||
}
|
||||
|
||||
defaultButton: MyButtonStyle {
|
||||
textPadding: margins(10px, 15px, 10px, 15px);
|
||||
icon: icon{{ "gui/icons/search", iconColor }};
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
primaryButton: MyButtonStyle(defaultButton) {
|
||||
icon: icon{{ "gui/icons/check", iconColor }};
|
||||
}
|
||||
```
|
||||
|
||||
**Built-in types:**
|
||||
- `int` - Integer numbers (e.g., `maxLines: 3;`)
|
||||
- `bool` - Boolean values (e.g., `useShadow: true;`)
|
||||
- `pixels` - Pixel values with `px` suffix (e.g., `10px`)
|
||||
- `color` - Named colors from `ui/colors.palette`
|
||||
- `icon` - Inline icon definition: `icon{{ "path/stem", color }}`
|
||||
- `margins` - Four values: `margins(top, right, bottom, left)`
|
||||
- `size` - Two values: `size(width, height)`
|
||||
- `point` - Two values: `point(x, y)`
|
||||
- `align` - Alignment: `align(center)`, `align(left)`
|
||||
- `font` - Font: `font(14px semibold)`
|
||||
- `double` - Floating point
|
||||
|
||||
**Multi-part icons** (layers drawn bottom-up):
|
||||
```style
|
||||
myComplexIcon: icon{
|
||||
{ "gui/icons/background", iconBgColor },
|
||||
{ "gui/icons/foreground", iconFgColor }
|
||||
};
|
||||
```
|
||||
|
||||
**Borders** are typically separate fields, not a single property:
|
||||
```style
|
||||
chatInput {
|
||||
border: 1px; // width
|
||||
borderFg: defaultInputFieldBorder; // color
|
||||
}
|
||||
```
|
||||
|
||||
**Never hardcode sizes in code:**
|
||||
|
||||
The app supports different interface scale options. Style `px` values are automatically scaled at runtime, but raw integer constants in code are not. Never use hardcoded numbers for margins, paddings, spacing, sizes, coordinates, or any other dimensional values. Always define them in `.style` files and reference via `st::`.
|
||||
|
||||
```cpp
|
||||
// BAD - breaks at non-100% interface scale:
|
||||
p.drawText(10, 20, text);
|
||||
widget->setFixedHeight(48);
|
||||
auto margin = 8;
|
||||
auto iconSize = QSize(24, 24);
|
||||
|
||||
// GOOD - define in .style file and reference:
|
||||
p.drawText(st::myWidgetTextLeft, st::myWidgetTextTop, text);
|
||||
widget->setFixedHeight(st::myWidgetHeight);
|
||||
auto margin = st::myWidgetMargin;
|
||||
auto iconSize = st::myWidgetIconSize;
|
||||
```
|
||||
|
||||
**Duration constants**: Animation durations should NOT go in `.style` files, this is a legacy approach. Prefer `constexpr auto kName = crl::time(N)` in an anonymous namespace in the relevant `.cpp` file.
|
||||
|
||||
### Usage in Code
|
||||
|
||||
```cpp
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
// Access style members
|
||||
int height = st::primaryButton.height;
|
||||
const style::icon &icon = st::primaryButton.icon;
|
||||
style::margins padding = st::primaryButton.textPadding;
|
||||
|
||||
// Use in painting
|
||||
void MyWidget::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
p.fillRect(rect(), st::chatInput.backgroundColor);
|
||||
}
|
||||
```
|
||||
|
||||
## Localization
|
||||
|
||||
### String Definitions
|
||||
|
||||
Strings are defined in `Telegram/Resources/langs/lang.strings`:
|
||||
|
||||
```
|
||||
"lng_settings_title" = "Settings";
|
||||
"lng_confirm_delete_item" = "Are you sure you want to delete {item_name}?";
|
||||
"lng_files_selected#one" = "{count} file selected";
|
||||
"lng_files_selected#other" = "{count} files selected";
|
||||
```
|
||||
|
||||
### Usage in Code
|
||||
|
||||
**Immediate (current value):**
|
||||
|
||||
```cpp
|
||||
auto currentTitle = tr::lng_settings_title(tr::now);
|
||||
|
||||
auto currentConfirmation = tr::lng_confirm_delete_item(
|
||||
tr::now,
|
||||
lt_item_name, currentItemName);
|
||||
|
||||
auto filesText = tr::lng_files_selected(tr::now, lt_count, count);
|
||||
```
|
||||
|
||||
**Reactive (rpl::producer):**
|
||||
|
||||
```cpp
|
||||
auto titleProducer = tr::lng_settings_title();
|
||||
|
||||
auto confirmationProducer = tr::lng_confirm_delete_item(
|
||||
lt_item_name,
|
||||
std::move(itemNameProducer));
|
||||
|
||||
auto filesTextProducer = tr::lng_files_selected(
|
||||
lt_count,
|
||||
countProducer | tr::to_count());
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
- Pass `tr::now` as first argument for immediate `QString`
|
||||
- Omit `tr::now` for reactive `rpl::producer<QString>`
|
||||
- Placeholders use `lt_tag_name, value` pattern
|
||||
- For `{count}`: immediate uses `int`, reactive uses `rpl::producer<float64>` with `| tr::to_count()`
|
||||
- Move producers with `std::move` when passing to placeholders
|
||||
- Rich text projectors — these `tr::` helpers serve double duty: as the **last argument** (projector) they set the return type to `TextWithEntities`, and as **placeholder values** they wrap individual substitutions in formatting. Always prefer them over `Ui::Text::Bold()`, `Ui::Text::RichLangValue`, etc. — see REVIEW.md for the full mapping.
|
||||
- `tr::marked` — basic projection, converts `QString` to `TextWithEntities`
|
||||
- `tr::rich` — interprets `**bold**`/`__italic__` markup in the string
|
||||
- `tr::bold`, `tr::italic`, `tr::underline` — wrap text in that formatting
|
||||
- `tr::link` — wrap as a clickable link
|
||||
- `tr::url(u"https://..."_q)` — returns a projection that converts text to a link pointing to the given URL; can be passed to `rpl::map` or directly to a `tr::lng_...` call
|
||||
```cpp
|
||||
// As last argument (projector):
|
||||
auto title = tr::lng_export_progress_title(tr::now, tr::bold);
|
||||
auto text = tr::lng_proxy_incorrect_secret(tr::now, tr::rich);
|
||||
// As placeholder value wrapper + projector:
|
||||
auto desc = tr::lng_some_key(
|
||||
tr::now,
|
||||
lt_name,
|
||||
tr::bold(userName),
|
||||
lt_group,
|
||||
tr::bold(groupName),
|
||||
tr::rich);
|
||||
// Nested tr::lng as placeholder:
|
||||
auto linked = tr::lng_settings_birthday_contacts(
|
||||
lt_link,
|
||||
tr::lng_settings_birthday_contacts_link(tr::url(link)),
|
||||
tr::marked);
|
||||
```
|
||||
|
||||
## RPL (Reactive Programming Library)
|
||||
|
||||
### Core Concepts
|
||||
|
||||
**Producers** represent streams of values over time:
|
||||
|
||||
```cpp
|
||||
auto intProducer = rpl::single(123); // Emits single value
|
||||
auto lifetime = rpl::lifetime(); // Manages subscription lifetime
|
||||
```
|
||||
|
||||
### Starting Pipelines
|
||||
|
||||
```cpp
|
||||
std::move(counter) | rpl::on_next([=](int value) {
|
||||
qDebug() << "Received: " << value;
|
||||
}, lifetime);
|
||||
|
||||
// Without lifetime parameter - MUST store returned lifetime:
|
||||
auto subscriptionLifetime = std::move(counter) | rpl::on_next([=](int value) {
|
||||
// process value
|
||||
});
|
||||
```
|
||||
|
||||
### Transforming Producers
|
||||
|
||||
```cpp
|
||||
auto strings = std::move(ints) | rpl::map([](int value) {
|
||||
return QString::number(value * 2);
|
||||
});
|
||||
|
||||
auto evenInts = std::move(ints) | rpl::filter([](int value) {
|
||||
return (value % 2 == 0);
|
||||
});
|
||||
```
|
||||
|
||||
### Combining Producers
|
||||
|
||||
**`rpl::combine`** - combines latest values (lambdas receive unpacked arguments):
|
||||
|
||||
```cpp
|
||||
auto combined = rpl::combine(countProducer, textProducer);
|
||||
|
||||
std::move(combined) | rpl::on_next([=](int count, const QString &text) {
|
||||
qDebug() << "Count=" << count << ", Text=" << text;
|
||||
}, lifetime);
|
||||
```
|
||||
|
||||
**`rpl::merge`** - merges producers of same type:
|
||||
|
||||
```cpp
|
||||
auto merged = rpl::merge(sourceA, sourceB);
|
||||
|
||||
std::move(merged) | rpl::on_next([=](QString &&value) {
|
||||
qDebug() << "Merged value: " << value;
|
||||
}, lifetime);
|
||||
```
|
||||
|
||||
**Other pipeline starters** — besides `rpl::on_next`, there are:
|
||||
- `rpl::on_error([=](Error &&e) { ... }, lifetime)` — handle errors
|
||||
- `rpl::on_done([=] { ... }, lifetime)` — handle stream completion
|
||||
- `rpl::on_next_error_done(nextCb, errorCb, doneCb, lifetime)` — handle all three
|
||||
|
||||
The `Error` template parameter defaults to `rpl::no_error`: `rpl::producer<Type, Error = no_error>`.
|
||||
|
||||
**Key points:**
|
||||
- Explicitly `std::move` producers when starting pipelines
|
||||
- Pass `rpl::lifetime` to `on_...` methods or store returned lifetime
|
||||
- Use `rpl::duplicate(producer)` to reuse a producer multiple times
|
||||
- Combined producers automatically unpack tuples in lambdas (works with `rpl::map`, `rpl::filter`, and `rpl::on_next`)
|
||||
@@ -0,0 +1,3 @@
|
||||
# Claude Code Pointer
|
||||
|
||||
Read `AGENTS.md` and treat it as the canonical repository-wide instructions.
|
||||
@@ -4,15 +4,7 @@
|
||||
# For license and copyright information please follow this link:
|
||||
# https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
if (APPLE)
|
||||
# target_precompile_headers with COMPILE_LANGUAGE restriction.
|
||||
cmake_minimum_required(VERSION 3.23)
|
||||
else()
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
endif()
|
||||
if (POLICY CMP0149)
|
||||
cmake_policy(SET CMP0149 NEW)
|
||||
endif()
|
||||
cmake_minimum_required(VERSION 3.25...3.31)
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
@@ -20,19 +12,27 @@ include(cmake/validate_special_target.cmake)
|
||||
include(cmake/version.cmake)
|
||||
desktop_app_parse_version(Telegram/build/version)
|
||||
|
||||
set(project_langs C CXX)
|
||||
if (APPLE)
|
||||
list(APPEND project_langs OBJC OBJCXX)
|
||||
elseif (LINUX)
|
||||
list(APPEND project_langs ASM)
|
||||
if (NOT DEFINED CMAKE_CONFIGURATION_TYPES)
|
||||
set(configuration_types_init 1)
|
||||
endif()
|
||||
|
||||
project(Telegram
|
||||
LANGUAGES ${project_langs}
|
||||
LANGUAGES C CXX
|
||||
VERSION ${desktop_app_version_cmake}
|
||||
DESCRIPTION "AyuGram Desktop"
|
||||
HOMEPAGE_URL "https://ayugram.one"
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
enable_language(OBJC OBJCXX)
|
||||
endif()
|
||||
|
||||
if (configuration_types_init
|
||||
AND CMAKE_CONFIGURATION_TYPES
|
||||
AND NOT MinSizeRel IN_LIST CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES};MinSizeRel" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Telegram)
|
||||
|
||||
get_filename_component(third_party_loc "Telegram/ThirdParty" REALPATH)
|
||||
@@ -47,9 +47,7 @@ include(cmake/variables.cmake)
|
||||
include(cmake/nice_target_sources.cmake)
|
||||
include(cmake/target_compile_options_if_exists.cmake)
|
||||
include(cmake/target_link_frameworks.cmake)
|
||||
include(cmake/target_link_optional_libraries.cmake)
|
||||
include(cmake/target_link_options_if_exists.cmake)
|
||||
include(cmake/target_link_static_libraries.cmake)
|
||||
include(cmake/init_target.cmake)
|
||||
include(cmake/generate_target.cmake)
|
||||
include(cmake/nuget.cmake)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
Copyright (c) 2014-2025 The Telegram Desktop Authors.
|
||||
Copyright (c) 2014-2026 The Telegram Desktop Authors.
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
- Кастомизация шрифта
|
||||
- Режим Стримера
|
||||
- Локальный телеграм премиум
|
||||
- Переводчик
|
||||
- Превью медиа и быстрая реакция при сильном нажатии на тачпад (macOS)
|
||||
- Улучшенный вид
|
||||
|
||||
@@ -18,11 +19,18 @@
|
||||
|
||||
<h3>
|
||||
<details>
|
||||
<summary>Скриншоты настроек</summary>
|
||||
<img src='.github/demos/demo1.png' width='268'>
|
||||
<img src='.github/demos/demo2.png' width='268'>
|
||||
<img src='.github/demos/demo3.png' width='268'>
|
||||
<img src='.github/demos/demo4.png' width='268'>
|
||||
<summary>Превью</summary>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src='.github/demos/demo1.png' width='268' alt='Preferences'></td>
|
||||
<td><img src='.github/demos/demo2.png' width='268' alt='AyuGram Options'></td>
|
||||
<td><img src='.github/demos/demo3.png' width='268' alt='Message Filters'></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src='.github/demos/demo4.png' width='268' alt='Appearance'></td>
|
||||
<td><img src='.github/demos/demo5.png' width='268' alt='Chats'></td>
|
||||
</tr>
|
||||
</table>
|
||||
</details>
|
||||
</h3>
|
||||
|
||||
@@ -30,10 +38,10 @@
|
||||
|
||||
### Windows
|
||||
|
||||
#### Официальный вариант
|
||||
#### Официальная версия
|
||||
|
||||
Вы можете скачать готовый бинарный файл со вкладки [Releases](https://github.com/AyuGram/AyuGramDesktop/releases) или из
|
||||
[Телеграм чата](https://t.me/ayugramchat/12788).
|
||||
[Телеграм канала](https://t.me/AyuGramReleases).
|
||||
|
||||
#### Winget
|
||||
|
||||
@@ -55,19 +63,66 @@ scoop install ayugram
|
||||
|
||||
### macOS
|
||||
|
||||
#### Официальная версия
|
||||
|
||||
Вы можете скачать подписанный пакет со вкладки [Releases](https://github.com/AyuGram/AyuGramDesktop/releases).
|
||||
|
||||
#### Homebrew
|
||||
|
||||
```bash
|
||||
brew install --cask ayugram
|
||||
```
|
||||
|
||||
### Arch Linux
|
||||
|
||||
Вы можете установить `ayugram-desktop` из [AUR](https://aur.archlinux.org/packages?O=0&K=ayugram).
|
||||
#### Из исходников (рекомендованный способ)
|
||||
|
||||
Установите `ayugram-desktop` из [AUR](https://aur.archlinux.org/packages/ayugram-desktop).
|
||||
|
||||
#### Готовые бинарники
|
||||
|
||||
Установите `ayugram-desktop-bin` из [AUR](https://aur.archlinux.org/packages/ayugram-desktop-bin).
|
||||
|
||||
Примечание: данный пакет собирается не нами.
|
||||
|
||||
### NixOS
|
||||
|
||||
Попробуйте [этот репозиторий](https://github.com/ayugram-port/ayugram-desktop).
|
||||
#### Флейк (рекомендуется)
|
||||
|
||||
Установите `ayugram-desktop` из [ndfined-crp/ayugram-desktop](https://github.com/ndfined-crp/ayugram-desktop)
|
||||
|
||||
#### Nixpkgs
|
||||
|
||||
Установите `ayugram-desktop` из [nixpkgs](https://search.nixos.org/packages?channel=unstable&show=ayugram-desktop)
|
||||
|
||||
### ALT Linux
|
||||
|
||||
[Sisyphus](https://packages.altlinux.org/en/sisyphus/srpms/ayugram-desktop/)
|
||||
|
||||
### Gentoo Linux
|
||||
|
||||
Инструкцию по установке можно найти в [этом репозитории](https://codeberg.org/OverLessArtem/ayugram-ebuild-gentoo).
|
||||
|
||||
### Void Linux
|
||||
Инструкцию по установке можно найти в [этом репозитории](https://codeberg.org/OverLessArtem/ayugram-template-void)
|
||||
|
||||
### EPM
|
||||
|
||||
`epm play ayugram`
|
||||
|
||||
### Fedora
|
||||
|
||||
Из репозитория [RPM Fusion](https://admin.rpmfusion.org/pkgdb/package/free/ayugram-desktop/).
|
||||
|
||||
```bash
|
||||
dnf install ayugram-desktop
|
||||
```
|
||||
|
||||
### Любой другой Линукс дистрибутив
|
||||
|
||||
Следуйте [официальному руководству](https://github.com/AyuGram/AyuGramDesktop/blob/dev/docs/building-linux.md).
|
||||
Flatpak: https://github.com/0FL01/AyuGramDesktop-flatpak
|
||||
|
||||
Или следуйте [официальному руководству](https://github.com/AyuGram/AyuGramDesktop/blob/dev/docs/building-linux.md).
|
||||
|
||||
### Примечания для Windows
|
||||
|
||||
@@ -101,3 +156,7 @@ scoop install ayugram
|
||||
### Иконки
|
||||
|
||||
- [Solar Icon Set](https://www.figma.com/community/file/1166831539721848736)
|
||||
|
||||
### Боты
|
||||
|
||||
- [TelegramDB](https://t.me/tgdatabase) для получения юзернейма по ID (до закрытия бесплатной версии 2 апреля 2026)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
- Font customization
|
||||
- Streamer mode
|
||||
- Local Telegram Premium
|
||||
- Translator
|
||||
- Media preview & quick reaction on force click (macOS)
|
||||
- Enhanced appearance
|
||||
|
||||
@@ -19,11 +20,18 @@ And many more. Check out our [Documentation](https://docs.ayugram.one/desktop/).
|
||||
|
||||
<h3>
|
||||
<details>
|
||||
<summary>Preferences screenshots</summary>
|
||||
<img src='.github/demos/demo1.png' width='268'>
|
||||
<img src='.github/demos/demo2.png' width='268'>
|
||||
<img src='.github/demos/demo3.png' width='268'>
|
||||
<img src='.github/demos/demo4.png' width='268'>
|
||||
<summary>Preview</summary>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src='.github/demos/demo1.png' width='268' alt='Preferences'></td>
|
||||
<td><img src='.github/demos/demo2.png' width='268' alt='AyuGram Options'></td>
|
||||
<td><img src='.github/demos/demo3.png' width='268' alt='Message Filters'></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src='.github/demos/demo4.png' width='268' alt='Appearance'></td>
|
||||
<td><img src='.github/demos/demo5.png' width='268' alt='Chats'></td>
|
||||
</tr>
|
||||
</table>
|
||||
</details>
|
||||
</h3>
|
||||
|
||||
@@ -34,7 +42,7 @@ And many more. Check out our [Documentation](https://docs.ayugram.one/desktop/).
|
||||
#### Official
|
||||
|
||||
You can download prebuilt Windows binary from [Releases tab](https://github.com/AyuGram/AyuGramDesktop/releases) or from
|
||||
the [Telegram topic](https://t.me/ayugramchat/12788).
|
||||
the [Telegram channel](https://t.me/AyuGramReleases).
|
||||
|
||||
#### Winget
|
||||
|
||||
@@ -56,19 +64,66 @@ build by yourself.
|
||||
|
||||
### macOS
|
||||
|
||||
#### Official
|
||||
|
||||
You can download prebuilt macOS package from [Releases tab](https://github.com/AyuGram/AyuGramDesktop/releases).
|
||||
|
||||
#### Homebrew
|
||||
|
||||
```bash
|
||||
brew install --cask ayugram
|
||||
```
|
||||
|
||||
### Arch Linux
|
||||
|
||||
You can install `ayugram-desktop` from [AUR](https://aur.archlinux.org/packages?O=0&K=ayugram).
|
||||
#### From source (recommended)
|
||||
|
||||
Install `ayugram-desktop` from [AUR](https://aur.archlinux.org/packages/ayugram-desktop).
|
||||
|
||||
#### Prebuilt binaries
|
||||
|
||||
Install `ayugram-desktop-bin` from [AUR](https://aur.archlinux.org/packages/ayugram-desktop-bin).
|
||||
|
||||
Note: these binaries aren't officially maintained by us.
|
||||
|
||||
### NixOS
|
||||
|
||||
See [this repository](https://github.com/ayugram-port/ayugram-desktop) for installation manual.
|
||||
#### Flake (recommended)
|
||||
|
||||
Install `ayugram-desktop` from [ndfined-crp/ayugram-desktop](https://github.com/ndfined-crp/ayugram-desktop)
|
||||
|
||||
#### Nixpkgs
|
||||
|
||||
Install `ayugram-desktop` from [nixpkgs](https://search.nixos.org/packages?channel=unstable&show=ayugram-desktop)
|
||||
|
||||
### ALT Linux
|
||||
|
||||
[Sisyphus](https://packages.altlinux.org/en/sisyphus/srpms/ayugram-desktop/)
|
||||
|
||||
### Gentoo Linux
|
||||
|
||||
See [this repository](https://codeberg.org/OverLessArtem/ayugram-ebuild-gentoo) for installation manual.
|
||||
|
||||
### Void Linux
|
||||
See [this repository](https://codeberg.org/OverLessArtem/ayugram-template-void) for installation manual.
|
||||
|
||||
### EPM
|
||||
|
||||
`epm play ayugram`
|
||||
|
||||
### Fedora
|
||||
|
||||
From [RPM Fusion](https://admin.rpmfusion.org/pkgdb/package/free/ayugram-desktop/) repository.
|
||||
|
||||
```bash
|
||||
dnf install ayugram-desktop
|
||||
```
|
||||
|
||||
### Any other Linux distro
|
||||
|
||||
Follow the [official guide](https://github.com/AyuGram/AyuGramDesktop/blob/dev/docs/building-linux.md).
|
||||
Flatpak: https://github.com/0FL01/AyuGramDesktop-flatpak
|
||||
|
||||
Or follow the [official guide](https://github.com/AyuGram/AyuGramDesktop/blob/dev/docs/building-linux.md).
|
||||
|
||||
### Remarks for Windows
|
||||
|
||||
@@ -98,7 +153,12 @@ Enjoy using **AyuGram**? Consider sending us a tip!
|
||||
- [JSON for Modern C++](https://github.com/nlohmann/json)
|
||||
- [SQLite](https://github.com/sqlite/sqlite)
|
||||
- [sqlite_orm](https://github.com/fnc12/sqlite_orm)
|
||||
- [androidx sources](https://github.com/androidx/androidx)
|
||||
|
||||
### Icons
|
||||
|
||||
- [Solar Icon Set](https://www.figma.com/community/file/1166831539721848736)
|
||||
|
||||
### Bots
|
||||
|
||||
- [TelegramDB](https://t.me/tgdatabase) for username lookup by ID (until closing free inline mode at 2 April 2026)
|
||||
|
||||
@@ -0,0 +1,514 @@
|
||||
# Code Review Style Guide
|
||||
|
||||
This file contains style and formatting rules that the review subagent must check and fix. These are mechanical issues that should always be caught during code review.
|
||||
|
||||
## Empty line before closing brace
|
||||
|
||||
Always add an empty line before the closing brace of a **class** (which has one or more sections like `public:` / `private:`). Plain **structs** with just data members do NOT get a trailing empty line — they are compact: `struct Foo { data lines; };`.
|
||||
|
||||
```cpp
|
||||
// BAD:
|
||||
class MyClass {
|
||||
public:
|
||||
void foo();
|
||||
|
||||
private:
|
||||
int _value = 0;
|
||||
};
|
||||
|
||||
// GOOD:
|
||||
class MyClass {
|
||||
public:
|
||||
void foo();
|
||||
|
||||
private:
|
||||
int _value = 0;
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
## Multi-line expressions — operators at the start of continuation lines
|
||||
|
||||
When splitting an expression across multiple lines, place operators (like `&&`, `||`, `;`, `+`, etc.) at the **beginning** of continuation lines, not at the end of the previous line. This makes it immediately obvious from the left edge whether a line is a continuation or new code.
|
||||
|
||||
```cpp
|
||||
// BAD - continuation looks like scope code:
|
||||
if (const auto &lottie = animation->lottie;
|
||||
lottie && lottie->valid() && lottie->framesCount() > 1) {
|
||||
lottie->animate([=] {
|
||||
|
||||
// GOOD - semicolon at start signals continuation:
|
||||
if (const auto &lottie = animation->lottie
|
||||
; lottie && lottie->valid() && lottie->framesCount() > 1) {
|
||||
lottie->animate([=] {
|
||||
|
||||
// BAD - trailing && makes next line look like independent code:
|
||||
if (veryLongExpression() &&
|
||||
anotherLongExpression() &&
|
||||
anotherOne()) {
|
||||
doSomething();
|
||||
|
||||
// GOOD - leading && clearly marks continuation:
|
||||
if (veryLongExpression()
|
||||
&& anotherLongExpression()
|
||||
&& anotherOne()) {
|
||||
doSomething();
|
||||
```
|
||||
|
||||
## Minimize type checks — prefer direct cast over is + as
|
||||
|
||||
Don't check a type and then cast — just cast and check for null. `asUser()` already returns `nullptr` when the peer is not a user, so calling `isUser()` first is redundant. The same applies to `asChannel()`, `asChat()`, etc.
|
||||
|
||||
```cpp
|
||||
// BAD - redundant isUser() check, then asUser():
|
||||
if (peer && peer->isUser()) {
|
||||
peer->asUser()->setNoForwardFlags(
|
||||
|
||||
// GOOD - just cast and null-check:
|
||||
if (const auto user = peer->asUser()) {
|
||||
user->setNoForwardFlags(
|
||||
```
|
||||
|
||||
When you need a specific subtype, look up the specific subtype directly instead of loading a generic type and then casting:
|
||||
|
||||
```cpp
|
||||
// BAD - loads generic peer, then casts:
|
||||
if (const auto peer = session().data().peerLoaded(peerId)
|
||||
; peer && peer->isUser()) {
|
||||
peer->asUser()->setNoForwardFlags(
|
||||
|
||||
// GOOD - look up the specific subtype directly:
|
||||
const auto userId = peerToUser(peerId);
|
||||
if (const auto user = session().data().userLoaded(userId)) {
|
||||
user->setNoForwardFlags(
|
||||
```
|
||||
|
||||
Avoid C++17 `if` with initializer (`;` inside the condition) when the code can be written more clearly with simple nested `if` statements or by extracting the value beforehand:
|
||||
|
||||
```cpp
|
||||
// BAD - complex if-with-initializer:
|
||||
if (const auto peer = session().data().peerLoaded(peerId)
|
||||
; peer && peer->isUser()) {
|
||||
|
||||
// GOOD - simple nested ifs when direct lookup isn't available:
|
||||
if (const auto peer = session().data().peerLoaded(peerId)) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
|
||||
## Always initialize variables of basic types
|
||||
|
||||
Never leave variables of basic types (`int`, `float`, `bool`, pointers, etc.) uninitialized. Custom types with constructors are fine — they initialize themselves. But for any basic type, always provide a default value (`= 0`, `= false`, `= nullptr`, etc.). This applies especially to class fields, where uninitialized members are a persistent source of bugs.
|
||||
|
||||
The only exception is performance-critical hot paths where you can prove no read-from-uninitialized-memory occurs. For class fields there is no such exception — always initialize.
|
||||
|
||||
```cpp
|
||||
// BAD:
|
||||
int _bulletLeft;
|
||||
int _bulletTop;
|
||||
bool _expanded;
|
||||
SomeType *_pointer;
|
||||
|
||||
// GOOD:
|
||||
int _bulletLeft = 0;
|
||||
int _bulletTop = 0;
|
||||
bool _expanded = false;
|
||||
SomeType *_pointer = nullptr;
|
||||
```
|
||||
|
||||
## Use tr:: projections for TextWithEntities
|
||||
|
||||
Inside `tr::lng_...()` calls, always use the `tr::` projection helpers instead of their `Ui::Text::` equivalents. The `tr::` helpers are shorter and work uniformly as both placeholder wrappers and final projectors.
|
||||
|
||||
| Instead of | Use |
|
||||
|---|---|
|
||||
| `Ui::Text::Bold(x)` | `tr::bold(x)` |
|
||||
| `Ui::Text::Italic(x)` | `tr::italic(x)` |
|
||||
| `Ui::Text::RichLangValue` | `tr::rich` |
|
||||
| `Ui::Text::WithEntities` | `tr::marked` |
|
||||
|
||||
```cpp
|
||||
// BAD - verbose Ui::Text:: functions:
|
||||
tr::lng_some_key(
|
||||
tr::now,
|
||||
lt_name,
|
||||
Ui::Text::Bold(name),
|
||||
lt_group,
|
||||
Ui::Text::Bold(group),
|
||||
Ui::Text::RichLangValue)
|
||||
|
||||
// GOOD - concise tr:: helpers:
|
||||
tr::lng_some_key(
|
||||
tr::now,
|
||||
lt_name,
|
||||
tr::bold(name),
|
||||
lt_group,
|
||||
tr::bold(group),
|
||||
tr::rich)
|
||||
```
|
||||
|
||||
Also use `tr::marked()` as the standard way to create `TextWithEntities` — not just as a projector:
|
||||
|
||||
```cpp
|
||||
// BAD - verbose constructor:
|
||||
auto text = TextWithEntities();
|
||||
auto text = TextWithEntities{ u"hello"_q };
|
||||
auto text = TextWithEntities().append(u"hello"_q);
|
||||
|
||||
// GOOD - concise:
|
||||
auto text = tr::marked();
|
||||
auto text = tr::marked(u"hello"_q);
|
||||
```
|
||||
|
||||
## Multi-line calls — one argument per line
|
||||
|
||||
When a function call doesn't fit on one line, put each argument on its own line. Don't group "logical pairs" on the same line — it creates inconsistent line lengths and makes diffs noisier.
|
||||
|
||||
```cpp
|
||||
// BAD - pairs of arguments sharing lines:
|
||||
tr::lng_some_key(
|
||||
tr::now,
|
||||
lt_name, tr::bold(name),
|
||||
lt_group, tr::bold(group),
|
||||
tr::rich)
|
||||
|
||||
// GOOD - one argument per line:
|
||||
tr::lng_some_key(
|
||||
tr::now,
|
||||
lt_name,
|
||||
tr::bold(name),
|
||||
lt_group,
|
||||
tr::bold(group),
|
||||
tr::rich)
|
||||
|
||||
// Single-line is fine when everything fits:
|
||||
auto text = tr::lng_settings_title(tr::now);
|
||||
```
|
||||
|
||||
## std::optional access — avoid value()
|
||||
|
||||
Do not call `std::optional::value()` because it throws an exception that is not available on older macOS targets. Use `has_value()`, `value_or()`, `operator bool()`, or `operator*` instead.
|
||||
|
||||
## Sort includes alphabetically, nested folders first
|
||||
|
||||
After the file's own header, sort `#include` directives alphabetically with two special rules:
|
||||
|
||||
1. **Nested folders before files** in the same directory — like Finder / File Explorer (folders first, then files). E.g. `ui/controls/button.h` sorts before `ui/abstract_button.h`.
|
||||
2. **Style includes (`styles/style_*.h`) always go last**, separated from the rest.
|
||||
|
||||
```cpp
|
||||
// BAD - arbitrary order, style mixed in:
|
||||
#include "media/audio/media_audio.h"
|
||||
#include "styles/style_media_player.h"
|
||||
#include "data/data_document.h"
|
||||
#include "apiwrap.h"
|
||||
|
||||
// GOOD - alphabetical, folders first, styles last:
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_document.h"
|
||||
#include "media/audio/media_audio.h"
|
||||
|
||||
#include "styles/style_media_player.h"
|
||||
```
|
||||
|
||||
## Use C++17 nested namespace syntax
|
||||
|
||||
Use `namespace A::B {` instead of nesting `namespace A { namespace B {`. The closing comment mirrors the opening: `} // namespace A::B`.
|
||||
|
||||
```cpp
|
||||
// BAD - old-style nesting:
|
||||
namespace Media {
|
||||
namespace Player {
|
||||
...
|
||||
} // namespace Player
|
||||
} // namespace Media
|
||||
|
||||
// GOOD - C++17 nested:
|
||||
namespace Media::Player {
|
||||
...
|
||||
} // namespace Media::Player
|
||||
```
|
||||
|
||||
## Merge consecutive branches with identical bodies
|
||||
|
||||
When two or more consecutive `if` / `else if` branches execute the same code, combine their conditions into a single branch.
|
||||
|
||||
```cpp
|
||||
// BAD - duplicated body:
|
||||
if (!document) {
|
||||
finalize();
|
||||
return;
|
||||
}
|
||||
if (!document->isSong()) {
|
||||
finalize();
|
||||
return;
|
||||
}
|
||||
|
||||
// GOOD - combined:
|
||||
if (!document || !document->isSong()) {
|
||||
finalize();
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
## Use base::take for read-and-reset
|
||||
|
||||
When you need to read a variable's current value and reset it in one step, use `base::take(var)` instead of manually copying and clearing. `base::take` returns the old value and resets the variable to its default-constructed state.
|
||||
|
||||
```cpp
|
||||
// BAD - manual read + reset:
|
||||
if (_playing) {
|
||||
_listenedMs += crl::now() - _playStartedAt;
|
||||
_playing = false;
|
||||
}
|
||||
|
||||
// GOOD:
|
||||
if (base::take(_playing)) {
|
||||
_listenedMs += crl::now() - _playStartedAt;
|
||||
}
|
||||
|
||||
// BAD - copy fields then clear them one by one:
|
||||
const auto document = _document;
|
||||
const auto contextId = _contextId;
|
||||
_document = nullptr;
|
||||
_listenedMs = 0;
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
// GOOD - take everything upfront, then validate:
|
||||
const auto document = base::take(_document);
|
||||
const auto contextId = base::take(_contextId);
|
||||
const auto duration = static_cast<int>(base::take(_listenedMs) / 1000);
|
||||
if (!document || duration <= 0) {
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
## Don't wrap tr:: lang keys in rpl::single
|
||||
|
||||
`tr::lng_*()` (without `tr::now`) already returns an `rpl::producer`. Wrapping a snapshot in `rpl::single()` defeats live language switching — the value is captured once and never updates. Just call the lang key without `tr::now`.
|
||||
|
||||
```cpp
|
||||
// BAD - frozen snapshot, won't update on language change:
|
||||
rpl::single(tr::lng_ai_compose_title(tr::now))
|
||||
|
||||
// GOOD - live producer that updates automatically:
|
||||
tr::lng_ai_compose_title()
|
||||
```
|
||||
|
||||
## Extract method definitions from local classes
|
||||
|
||||
When defining local classes (e.g. in anonymous namespaces), keep the class body compact — only declarations. Put all method definitions **after** all class definitions. This avoids unnecessary nesting inside the class body and keeps methods at the same indentation level as free functions.
|
||||
|
||||
```cpp
|
||||
// BAD - methods defined inline, adding a nesting level:
|
||||
class MyWidget final : public Ui::RpWidget {
|
||||
public:
|
||||
MyWidget(QWidget *parent)
|
||||
: RpWidget(parent) {
|
||||
// ... 20 lines of setup
|
||||
}
|
||||
|
||||
void setActive(bool active) {
|
||||
_active = active;
|
||||
update();
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override {
|
||||
// ... 30 lines of painting
|
||||
}
|
||||
|
||||
private:
|
||||
bool _active = false;
|
||||
|
||||
};
|
||||
|
||||
// GOOD - class is a compact declaration, methods defined after:
|
||||
class MyWidget final : public Ui::RpWidget {
|
||||
public:
|
||||
MyWidget(QWidget *parent, QString label);
|
||||
|
||||
void setActive(bool active);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
bool _active = false;
|
||||
|
||||
};
|
||||
|
||||
MyWidget::MyWidget(QWidget *parent, QString label)
|
||||
: RpWidget(parent) {
|
||||
// ... 20 lines of setup
|
||||
}
|
||||
|
||||
void MyWidget::setActive(bool active) {
|
||||
_active = active;
|
||||
update();
|
||||
}
|
||||
|
||||
void MyWidget::paintEvent(QPaintEvent *e) {
|
||||
// ... 30 lines of painting
|
||||
}
|
||||
```
|
||||
|
||||
When there are multiple local classes, put **all class definitions first**, then **all method definitions** after. This keeps the declarations readable as an overview.
|
||||
|
||||
## Use RAII for resource cleanup
|
||||
|
||||
When working with raw resources (Win32 HANDLEs, file descriptors, COM objects), use `gsl::finally` or a dedicated RAII wrapper for cleanup instead of calling release functions manually. Manual cleanup breaks when early returns are added later.
|
||||
|
||||
```cpp
|
||||
// BAD - manual cleanup, fragile with early returns:
|
||||
const auto snapshot = CreateToolhelp32Snapshot(...);
|
||||
if (snapshot != INVALID_HANDLE_VALUE) {
|
||||
// ... logic that might grow early returns ...
|
||||
CloseHandle(snapshot);
|
||||
}
|
||||
|
||||
// GOOD - RAII guard, cleanup runs on any exit path:
|
||||
const auto snapshot = CreateToolhelp32Snapshot(...);
|
||||
if (snapshot == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
const auto guard = gsl::finally([&] {
|
||||
CloseHandle(snapshot);
|
||||
});
|
||||
// ... logic, early returns are safe ...
|
||||
```
|
||||
|
||||
## Extract substantial logic from lambdas
|
||||
|
||||
When a lambda grows beyond a few lines of self-contained logic, extract it into a named function (free function in anonymous namespace, or a private method). Lambdas should primarily be glue — captures, dispatch, short transforms. This applies when the lambda's captures are minimal and can easily become function parameters. When a lambda captures many variables from its surrounding context, it may be cleaner to keep it inline.
|
||||
|
||||
```cpp
|
||||
// BAD - substantial logic buried in a lambda:
|
||||
crl::async([=] {
|
||||
auto found = false;
|
||||
auto pe = PROCESSENTRY32();
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
const auto snapshot = CreateToolhelp32Snapshot(...);
|
||||
if (snapshot != INVALID_HANDLE_VALUE) {
|
||||
for (...) {
|
||||
if (/* match */) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CloseHandle(snapshot);
|
||||
}
|
||||
crl::on_main(weak, [=] { handle(found); });
|
||||
});
|
||||
|
||||
// GOOD - logic extracted, lambda is just glue:
|
||||
crl::async([=] {
|
||||
const auto found = FindRunningReader();
|
||||
crl::on_main(weak, [=] { handle(found); });
|
||||
});
|
||||
```
|
||||
|
||||
## Data-driven matching over chained conditions
|
||||
|
||||
When comparing a value against multiple known constants, store them in a collection and loop instead of chaining `||` conditions. Easier to extend, less repetition, and reads as data rather than logic.
|
||||
|
||||
```cpp
|
||||
// BAD - repetitive chain, hard to extend:
|
||||
if (_wcsicmp(name, L"Narrator.exe") == 0
|
||||
|| _wcsicmp(name, L"nvda.exe") == 0
|
||||
|| _wcsicmp(name, L"jfw.exe") == 0
|
||||
|| _wcsicmp(name, L"Zt.exe") == 0) {
|
||||
|
||||
// GOOD - data-driven, easy to extend:
|
||||
const auto list = std::array{
|
||||
L"Narrator.exe",
|
||||
L"nvda.exe",
|
||||
L"jfw.exe",
|
||||
L"Zt.exe",
|
||||
};
|
||||
for (const auto &entry : list) {
|
||||
if (_wcsicmp(name, entry) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Use !isHidden() for logic checks, not isVisible()
|
||||
|
||||
When you call `show()` / `hide()` / `setVisible()` on a widget and later branch on that state, always check `!isHidden()` (the widget's own flag) — never `isVisible()`. `isVisible()` returns `true` only when the widget **and every ancestor** are visible, so it silently returns `false` during parent show-animations, before the parent is laid out, etc. `isHidden()` reflects exactly the flag you set.
|
||||
|
||||
```cpp
|
||||
// BAD — breaks when parent is still animating / not yet shown:
|
||||
child->setVisible(true);
|
||||
// ... later, in resizeGetHeight or similar:
|
||||
if (child->isVisible()) { // false if parent isn't visible yet!
|
||||
child->moveToRight(x, y, w);
|
||||
}
|
||||
|
||||
// GOOD — checks the widget's own state:
|
||||
if (!child->isHidden()) {
|
||||
child->moveToRight(x, y, w);
|
||||
}
|
||||
```
|
||||
|
||||
The same applies to any logic that depends on a previous `show()`/`hide()` call: skip blocks, layout branches, opacity decisions, etc.
|
||||
|
||||
## Consolidate make_state calls into a single State struct
|
||||
|
||||
Every `make_state` is a separate heap allocation. When a function needs multiple pieces of lambda-captured mutable state, define a local `struct State` with all fields and call `make_state<State>()` once, then capture the resulting pointer everywhere.
|
||||
|
||||
```cpp
|
||||
// BAD - two allocations:
|
||||
const auto shown = lifetime.make_state<bool>(false);
|
||||
const auto count = lifetime.make_state<int>(0);
|
||||
|
||||
// GOOD - one allocation:
|
||||
struct State {
|
||||
bool shown = false;
|
||||
int count = 0;
|
||||
};
|
||||
const auto state = lifetime.make_state<State>();
|
||||
```
|
||||
|
||||
## Use trailing return type when the return type doesn't fit on one line
|
||||
|
||||
When a function's return type is long enough that the declaration would need a line break between the return type and the function name, use trailing return type syntax (`auto ... -> Type`) to keep the function name on the opening line.
|
||||
|
||||
```cpp
|
||||
// BAD - return type orphaned on its own line:
|
||||
not_null<HistoryView::Controls::ComposeAiButton*>
|
||||
SetupCaptionAiButton(SetupCaptionAiButtonArgs &&args);
|
||||
|
||||
// GOOD - trailing return type keeps name visible:
|
||||
auto SetupCaptionAiButton(SetupCaptionAiButtonArgs &&args)
|
||||
-> not_null<HistoryView::Controls::ComposeAiButton*>;
|
||||
```
|
||||
|
||||
## Mind data structure sizes and alignment
|
||||
|
||||
When adding fields to a class or struct, consider the memory layout. A standalone `bool` between two pointer-sized fields wastes 7 bytes to alignment padding. Review new fields for packing opportunities:
|
||||
|
||||
- If the struct already has bitfields, pack new boolean flags as `: 1` members rather than standalone `bool`.
|
||||
- If alignment leaves a gap (e.g., an `int` followed by a pointer), consider whether a new small field can fill it.
|
||||
- For classes instantiated in large quantities (per-message, per-element, per-row), every wasted byte is multiplied thousands of times.
|
||||
|
||||
```cpp
|
||||
// BAD - standalone bool adds 8 bytes (1 + 7 padding) before the next pointer:
|
||||
mutable bool _myFlag = false;
|
||||
mutable std::unique_ptr<Foo> _foo;
|
||||
|
||||
// GOOD - packed into existing bitfield group, no extra bytes:
|
||||
mutable uint32 _myFlag : 1 = 0;
|
||||
```
|
||||
|
||||
## Static member functions use PascalCase
|
||||
|
||||
Non-static member functions use camelCase (`startBatch`, `finalize`). Static member functions use PascalCase (`ShouldTrack`, `Parse`, `Create`), matching the convention for free functions.
|
||||
|
||||
```cpp
|
||||
// BAD - camelCase for static method:
|
||||
[[nodiscard]] static bool shouldTrack(not_null<HistoryItem*> item);
|
||||
|
||||
// GOOD - PascalCase for static method:
|
||||
[[nodiscard]] static bool ShouldTrack(not_null<HistoryItem*> item);
|
||||
```
|
||||
|
Before Width: | Height: | Size: 8.5 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg width="1200" height="1200" viewBox="0 0 1200 1200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1177_97)">
|
||||
<rect width="1200" height="1200" rx="600" fill="#9570FF"/>
|
||||
<g opacity="0.07">
|
||||
<path d="M806.896 -279.064C785.598 -313.026 733.108 -291.661 741.582 -252.479L1066.32 1248.94C1069.88 1265.41 1084.45 1277.16 1101.31 1277.16H1718.15C1746.29 1277.16 1763.42 1246.19 1748.47 1222.35L806.896 -279.064Z" fill="white"/>
|
||||
<path d="M669.079 1606.13C669.079 1640.4 712.592 1655.08 733.354 1627.82L935.184 1362.81C941.526 1354.48 943.905 1343.8 941.696 1333.57L739.866 399.014C730.809 357.077 669.079 363.667 669.079 406.57L669.079 1606.13Z" fill="white"/>
|
||||
<path d="M392.104 -279.064C413.403 -313.026 465.892 -291.661 457.418 -252.479L132.68 1248.94C129.117 1265.41 114.546 1277.16 97.692 1277.16H-519.146C-547.286 1277.16 -564.423 1246.19 -549.473 1222.35L392.104 -279.064Z" fill="white"/>
|
||||
<path d="M529.921 1606.13C529.921 1640.4 486.408 1655.08 465.646 1627.82L263.816 1362.81C257.474 1354.48 255.095 1343.8 257.304 1333.57L459.134 399.014C468.191 357.077 529.921 363.667 529.921 406.57V1606.13Z" fill="white"/>
|
||||
</g>
|
||||
<path d="M672.345 264.951C664.864 253.017 646.428 260.525 649.404 274.293L763.463 801.88C764.715 807.668 769.833 811.799 775.752 811.799H992.407C1002.29 811.799 1008.31 800.915 1003.06 792.538L672.345 264.951Z" fill="white"/>
|
||||
<path d="M623.939 927.397C623.939 939.438 639.222 944.597 646.514 935.018L717.404 841.895C719.631 838.969 720.467 835.214 719.691 831.618L648.801 503.223C645.62 488.487 623.939 490.802 623.939 505.878L623.939 927.397Z" fill="white"/>
|
||||
<path d="M526.655 264.951C534.136 253.017 552.572 260.525 549.596 274.293L435.537 801.88C434.285 807.668 429.167 811.799 423.248 811.799H206.593C196.709 811.799 190.69 800.915 195.941 792.538L526.655 264.951Z" fill="white"/>
|
||||
<path d="M575.061 927.397C575.061 939.438 559.778 944.597 552.486 935.018L481.596 841.895C479.369 838.969 478.533 835.214 479.309 831.618L550.199 503.223C553.38 488.487 575.061 490.802 575.061 505.878V927.397Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1177_97">
|
||||
<rect width="1200" height="1200" rx="600" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,82 @@
|
||||
<svg width="1200" height="1200" viewBox="0 0 1200 1200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1177_56)">
|
||||
<rect width="1200" height="1200" rx="600" fill="#FDFDFD"/>
|
||||
<path d="M806.896 -279.064C785.598 -313.026 733.108 -291.661 741.582 -252.479L1066.32 1248.94C1069.88 1265.41 1084.45 1277.16 1101.31 1277.16H1718.15C1746.29 1277.16 1763.42 1246.19 1748.47 1222.35L806.896 -279.064Z" fill="url(#paint0_radial_1177_56)" fill-opacity="0.04"/>
|
||||
<path d="M669.079 1606.13C669.079 1640.4 712.592 1655.08 733.354 1627.82L935.184 1362.81C941.526 1354.48 943.905 1343.8 941.696 1333.57L739.866 399.014C730.809 357.077 669.079 363.667 669.079 406.57L669.079 1606.13Z" fill="url(#paint1_radial_1177_56)" fill-opacity="0.04"/>
|
||||
<path d="M392.104 -279.064C413.403 -313.026 465.892 -291.661 457.418 -252.479L132.68 1248.94C129.117 1265.41 114.546 1277.16 97.692 1277.16H-519.146C-547.286 1277.16 -564.423 1246.19 -549.473 1222.35L392.104 -279.064Z" fill="url(#paint2_radial_1177_56)" fill-opacity="0.04"/>
|
||||
<path d="M529.921 1606.13C529.921 1640.4 486.408 1655.08 465.646 1627.82L263.816 1362.81C257.474 1354.48 255.095 1343.8 257.304 1333.57L459.134 399.014C468.191 357.077 529.921 363.667 529.921 406.57V1606.13Z" fill="url(#paint3_radial_1177_56)" fill-opacity="0.04"/>
|
||||
<path d="M672.345 264.951C664.864 253.017 646.428 260.525 649.404 274.293L763.463 801.88C764.715 807.668 769.833 811.799 775.752 811.799H992.407C1002.29 811.799 1008.31 800.915 1003.06 792.538L672.345 264.951Z" fill="url(#paint4_radial_1177_56)"/>
|
||||
<path d="M623.939 927.397C623.939 939.438 639.222 944.597 646.514 935.018L717.404 841.895C719.631 838.969 720.467 835.214 719.691 831.618L648.801 503.223C645.62 488.487 623.939 490.802 623.939 505.878L623.939 927.397Z" fill="url(#paint5_radial_1177_56)"/>
|
||||
<path d="M526.655 264.951C534.136 253.017 552.572 260.525 549.596 274.293L435.537 801.88C434.285 807.668 429.167 811.799 423.248 811.799H206.593C196.709 811.799 190.69 800.915 195.941 792.538L526.655 264.951Z" fill="url(#paint6_radial_1177_56)"/>
|
||||
<path d="M575.061 927.397C575.061 939.438 559.778 944.597 552.486 935.018L481.596 841.895C479.369 838.969 478.533 835.214 479.309 831.618L550.199 503.223C553.38 488.487 575.061 490.802 575.061 505.878V927.397Z" fill="url(#paint7_radial_1177_56)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<radialGradient id="paint0_radial_1177_56" cx="0" cy="0" r="1" gradientTransform="matrix(755.281 3220.39 -3836.69 634.576 -633.706 -1346.76)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#1BA1E3"/>
|
||||
<stop offset="0.0001" stop-color="#1BA1E3"/>
|
||||
<stop offset="0.300221" stop-color="#5489D6"/>
|
||||
<stop offset="0.545524" stop-color="#9B72CB"/>
|
||||
<stop offset="0.825372" stop-color="#D96570"/>
|
||||
<stop offset="1" stop-color="#F49C46"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint1_radial_1177_56" cx="0" cy="0" r="1" gradientTransform="matrix(755.281 3220.39 -3836.69 634.576 -633.706 -1346.76)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#1BA1E3"/>
|
||||
<stop offset="0.0001" stop-color="#1BA1E3"/>
|
||||
<stop offset="0.300221" stop-color="#5489D6"/>
|
||||
<stop offset="0.545524" stop-color="#9B72CB"/>
|
||||
<stop offset="0.825372" stop-color="#D96570"/>
|
||||
<stop offset="1" stop-color="#F49C46"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint2_radial_1177_56" cx="0" cy="0" r="1" gradientTransform="matrix(755.281 3220.39 -3836.69 634.576 -633.706 -1346.76)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#1BA1E3"/>
|
||||
<stop offset="0.0001" stop-color="#1BA1E3"/>
|
||||
<stop offset="0.300221" stop-color="#5489D6"/>
|
||||
<stop offset="0.545524" stop-color="#9B72CB"/>
|
||||
<stop offset="0.825372" stop-color="#D96570"/>
|
||||
<stop offset="1" stop-color="#F49C46"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint3_radial_1177_56" cx="0" cy="0" r="1" gradientTransform="matrix(755.281 3220.39 -3836.69 634.576 -633.706 -1346.76)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#1BA1E3"/>
|
||||
<stop offset="0.0001" stop-color="#1BA1E3"/>
|
||||
<stop offset="0.300221" stop-color="#5489D6"/>
|
||||
<stop offset="0.545524" stop-color="#9B72CB"/>
|
||||
<stop offset="0.825372" stop-color="#D96570"/>
|
||||
<stop offset="1" stop-color="#F49C46"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint4_radial_1177_56" cx="0" cy="0" r="1" gradientTransform="matrix(274.644 1185.23 -1411.16 229.793 166.356 -110.23)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#22B1F8"/>
|
||||
<stop offset="0.242027" stop-color="#1BA1E3"/>
|
||||
<stop offset="0.381789" stop-color="#5489D6"/>
|
||||
<stop offset="0.648677" stop-color="#9B72CB"/>
|
||||
<stop offset="0.866975" stop-color="#D96570"/>
|
||||
<stop offset="1" stop-color="#F49C46"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint5_radial_1177_56" cx="0" cy="0" r="1" gradientTransform="matrix(274.644 1185.23 -1411.16 229.793 166.356 -110.23)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#22B1F8"/>
|
||||
<stop offset="0.242027" stop-color="#1BA1E3"/>
|
||||
<stop offset="0.381789" stop-color="#5489D6"/>
|
||||
<stop offset="0.648677" stop-color="#9B72CB"/>
|
||||
<stop offset="0.866975" stop-color="#D96570"/>
|
||||
<stop offset="1" stop-color="#F49C46"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint6_radial_1177_56" cx="0" cy="0" r="1" gradientTransform="matrix(274.644 1185.23 -1411.16 229.793 166.356 -110.23)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#22B1F8"/>
|
||||
<stop offset="0.242027" stop-color="#1BA1E3"/>
|
||||
<stop offset="0.381789" stop-color="#5489D6"/>
|
||||
<stop offset="0.648677" stop-color="#9B72CB"/>
|
||||
<stop offset="0.866975" stop-color="#D96570"/>
|
||||
<stop offset="1" stop-color="#F49C46"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint7_radial_1177_56" cx="0" cy="0" r="1" gradientTransform="matrix(274.644 1185.23 -1411.16 229.793 166.356 -110.23)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#22B1F8"/>
|
||||
<stop offset="0.242027" stop-color="#1BA1E3"/>
|
||||
<stop offset="0.381789" stop-color="#5489D6"/>
|
||||
<stop offset="0.648677" stop-color="#9B72CB"/>
|
||||
<stop offset="0.866975" stop-color="#D96570"/>
|
||||
<stop offset="1" stop-color="#F49C46"/>
|
||||
</radialGradient>
|
||||
<clipPath id="clip0_1177_56">
|
||||
<rect width="1200" height="1200" rx="600" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
@@ -0,0 +1,20 @@
|
||||
<svg width="1200" height="1200" viewBox="0 0 1200 1200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1177_50)">
|
||||
<rect width="1200" height="1200" rx="600" fill="#2B2242"/>
|
||||
<g opacity="0.07">
|
||||
<path d="M806.896 -279.064C785.598 -313.026 733.108 -291.661 741.582 -252.479L1066.32 1248.94C1069.88 1265.41 1084.45 1277.16 1101.31 1277.16H1718.15C1746.29 1277.16 1763.42 1246.19 1748.47 1222.35L806.896 -279.064Z" fill="#C3AEFF"/>
|
||||
<path d="M669.079 1606.13C669.079 1640.4 712.592 1655.08 733.354 1627.82L935.184 1362.81C941.526 1354.48 943.905 1343.8 941.696 1333.57L739.866 399.014C730.809 357.077 669.079 363.667 669.079 406.57L669.079 1606.13Z" fill="#C3AEFF"/>
|
||||
<path d="M392.104 -279.064C413.403 -313.026 465.892 -291.661 457.418 -252.479L132.68 1248.94C129.117 1265.41 114.546 1277.16 97.692 1277.16H-519.146C-547.286 1277.16 -564.423 1246.19 -549.473 1222.35L392.104 -279.064Z" fill="#C3AEFF"/>
|
||||
<path d="M529.921 1606.13C529.921 1640.4 486.408 1655.08 465.646 1627.82L263.816 1362.81C257.474 1354.48 255.095 1343.8 257.304 1333.57L459.134 399.014C468.191 357.077 529.921 363.667 529.921 406.57V1606.13Z" fill="#C3AEFF"/>
|
||||
</g>
|
||||
<path d="M672.345 264.951C664.864 253.017 646.428 260.525 649.404 274.293L763.463 801.88C764.715 807.668 769.833 811.799 775.752 811.799H992.407C1002.29 811.799 1008.31 800.915 1003.06 792.538L672.345 264.951Z" fill="#C3AEFF"/>
|
||||
<path d="M623.939 927.397C623.939 939.438 639.222 944.597 646.514 935.018L717.404 841.895C719.631 838.969 720.467 835.214 719.691 831.618L648.801 503.223C645.62 488.487 623.939 490.802 623.939 505.878L623.939 927.397Z" fill="#DCCFFF"/>
|
||||
<path d="M526.655 264.951C534.136 253.017 552.572 260.525 549.596 274.293L435.537 801.88C434.285 807.668 429.167 811.799 423.248 811.799H206.593C196.709 811.799 190.69 800.915 195.941 792.538L526.655 264.951Z" fill="#F5F5F5"/>
|
||||
<path d="M575.061 927.397C575.061 939.438 559.778 944.597 552.486 935.018L481.596 841.895C479.369 838.969 478.533 835.214 479.309 831.618L550.199 503.223C553.38 488.487 575.061 490.802 575.061 505.878V927.397Z" fill="#F5F5F5"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_1177_50">
|
||||
<rect width="1200" height="1200" rx="600" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 17 KiB |