{"id":484321,"date":"2026-06-19T15:14:13","date_gmt":"2026-06-19T15:14:13","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=484321"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=484321","title":{"rendered":"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Rust \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e GPUI"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<h2>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435<\/h2>\n<p>\u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0441\u0430\u043c\u043e\u0433\u043e \u0438 \u0434\u043b\u044f \u043c\u043e\u0438\u0445 \u0442\u043e\u0432\u0430\u0440\u0438\u0449\u0435\u0439 \u043f\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0437\u0434\u0435\u0441\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0435 \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u044e \u043d\u0430 \u0438\u0441\u0442\u0438\u043d\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u0438 \u043a\u0430\u043a \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443. \u041e\u0434\u043d\u0430\u043a\u043e \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0434\u043b\u044f \u043c\u043d\u043e\u0433\u0438\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u043b\u043e\u0436\u0438\u0442\u044c \u044d\u0442\u0443 \u0440\u0430\u0431\u043e\u0442\u0443, \u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435 \u0447\u0442\u043e \u044f \u043d\u0435 \u0441\u043c\u043e\u0433 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442\u044c \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0438\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u043f\u0440\u043e GPUI, \u0434\u0430 \u0438 \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u0438\u0445 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e. \u042f \u043e\u0442\u043a\u0440\u044b\u0442 \u043a \u043e\u0442\u0437\u044b\u0432\u0430\u043c, \u0441\u043e\u0432\u0435\u0442\u0430\u043c, \u043a\u0440\u0438\u0442\u0438\u043a\u0435, \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432\u0430\u0448\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u0435\u0441\u043b\u0438 \u0431\u0443\u0434\u0443\u0442 \u0445\u043e\u0440\u043e\u0448\u0438\u0435 \u0441\u043e\u0432\u0435\u0442\u044b, \u0442\u043e \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c. \u041f\u0440\u0438\u044f\u0442\u043d\u043e\u0433\u043e \u0447\u0442\u0435\u043d\u0438\u044f!<\/p>\n<h2>\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h2>\n<p>GPUI \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u044b\u043c \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c UI \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u043d\u0430 Rust c GPU \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435\u043c \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0441\u043e\u0437\u0434\u0430\u0432\u0448\u0438\u0445 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u043a\u043e\u0434\u0430 Zed, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u0430\u043a \u0440\u0430\u0437 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0434\u043b\u044f UI \u0447\u0430\u0441\u0442\u0438. \u0414\u0430\u043d\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0432\u044b\u0448\u0435\u043b \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0433\u043e API \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0439, \u0432\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u0445, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0412\u044b \u043c\u043e\u0433\u043b\u0438 \u043d\u0430\u0442\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0430\u0445 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0432 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u0441\u0442\u0430\u0440\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438, \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0435\u0449\u0451 \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u041e\u043d \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u0430\u043a\u0438\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043a\u0430\u043a macOS, Windows, Linux \u0438 FreeBSD. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432\u0435\u0440\u0441\u0438\u044f <code>0.2.2<\/code>.<\/p>\n<p>\u0414\u043b\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f GPUI \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 pet-\u043f\u0440\u043e\u0435\u043a\u0442. \u041e\u043d \u0438\u0437 \u0441\u0435\u0431\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u0434\u043e\u0441\u043a\u0443 \u043e \u0441\u0442\u0435\u043d\u0434\u0430\u0445 \u0438\u0437 \u0414\u0436\u043e\u0414\u0436\u043e: \u0438\u043c\u044f, \u0444\u043e\u0442\u043e \u0438 \u043b\u0435\u043f\u0435\u0441\u0442\u043a\u043e\u0432\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0438\u0441\u044c \u0432 \u0430\u043d\u0438\u043c\u0435. \u0422\u0430\u043a\u0436\u0435 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u0444\u0438\u0447\u0438 \u043f\u043e \u0432\u044b\u0431\u043e\u0440\u0443 \u0442\u0435\u043c\u044b \u0438 \u044f\u0437\u044b\u043a\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<p>\u041d\u0438\u0436\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u043f\u043e \u0441\u0430\u043c\u043e\u0439 GPUI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c\u0438: <br \/> <a href=\"https:\/\/github.com\/hedge-ops\/gpui-tutorial\" rel=\"noopener noreferrer nofollow\">\u041c\u0438\u043d\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b<\/a> <br \/> <a href=\"https:\/\/github.com\/zed-industries\/zed\/tree\/main\/crates\/gpui\" rel=\"noopener noreferrer nofollow\">\u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a> <br \/> <a href=\"https:\/\/docs.rs\/gpui\/latest\/gpui\/index.html\" rel=\"noopener noreferrer nofollow\">\u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/a> <br \/> <a href=\"https:\/\/github.com\/zed-industries\/awesome-gpui\/blob\/main\/README.md\" rel=\"noopener noreferrer nofollow\">\u0421\u0431\u043e\u0440\u043d\u0438\u043a \u0440\u0430\u0437\u043d\u044b\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043f\u043e GPUI, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043f\u0440\u043e\u0435\u043a\u0442\u044b<\/a><\/p>\n<h2>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u044b\u043b\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u0430 \u043b\u0443\u043a\u043e\u0432\u0438\u0447\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0432\u044b\u0448\u043b\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439:<\/p>\n<pre><code>\u251c\u2500\u2500 Cargo.toml                # \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Workspace\u251c\u2500\u2500 assets\/                   # \u0410\u0441\u0441\u0435\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u2502   \u251c\u2500\u2500 data\/                 # \u0411\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445\u2502   \u251c\u2500\u2500 icons\/                # \u0418\u043a\u043e\u043d\u043a\u0438\u2502   \u251c\u2500\u2500 images\/               # \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u2502   \u2514\u2500\u2500 locales\/              # \u0424\u0430\u0439\u043b\u044b \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438\u2514\u2500\u2500 crates\/    \u251c\u2500\u2500 app\/                  # \u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f GPUI    \u2502   \u2514\u2500\u2500 src\/main.rs    \u251c\u2500\u2500 core\/                 # \u042f\u0434\u0440\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430    \u2502   \u2514\u2500\u2500 src\/    \u2502       \u251c\u2500\u2500 types\/        # \u041e\u0431\u0449\u0438\u0435 \u0442\u0438\u043f\u044b \u0438 enum'\u044b    \u2502       \u251c\u2500\u2500 models\/       # \u0427\u0438\u0441\u0442\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430    \u2502       \u251c\u2500\u2500 repositories\/ # \u0422\u0440\u0435\u0439\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438    \u2502       \u251c\u2500\u2500 services\/     # \u0421\u0435\u0440\u0432\u0438\u0441\u044b \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438    \u2502       \u2514\u2500\u2500 lib.rs    \u251c\u2500\u2500 infrastructure\/       # \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b    \u2502   \u2514\u2500\u2500 src\/    \u2502       \u251c\u2500\u2500 dtos\/         # \u0422\u0440\u0430\u043d\u0441\u0444\u0435\u0440\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0434\u0430\u043d\u043d\u044b\u0445    \u2502       \u251c\u2500\u2500 mappers\/      # \u041f\u0435\u0440\u0435\u0432\u043e\u0434\u044b \u043c\u0435\u0436\u0434\u0443 DTO \u0438 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438    \u2502       \u251c\u2500\u2500 repositories\/ # \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432    \u2502       \u251c\u2500\u2500 file\/         # \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438    \u2502       \u2514\u2500\u2500 lib.rs    \u251c\u2500\u2500 di\/                   # \u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439     \u2502   \u2514\u2500\u2500 src\/    \u2502       \u251c\u2500\u2500 dependency_injector.rs    \u2502       \u2514\u2500\u2500 lib.rs    \u2514\u2500\u2500 ui\/                   # UI \u0441\u043b\u043e\u0439        \u2514\u2500\u2500 src\/            \u251c\u2500\u2500 shared\/   # \u041e\u0431\u0449\u0438\u0435 UI-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b            \u251c\u2500\u2500 features\/     # \u0411\u043e\u043b\u044c\u0448\u0438\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0438\u0447\u0438, \u044d\u043a\u0440\u0430\u043d\u044b, \u043e\u043a\u043d\u0430            \u251c\u2500\u2500 locale.rs     # \u041c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438            \u251c\u2500\u2500 theme.rs      # \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0442\u0435\u043c \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u044f            \u2514\u2500\u2500 lib.rs<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041b\u0443\u043a\u043e\u0432\u0438\u0447\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u0432\u0438\u0434\u043e\u0432 \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0439\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0442\u0430\u043a\u0436\u0435 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u0447\u0438\u0441\u0442\u0430\u044f \u0438 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f. \u041f\u0440\u0438\u043d\u0446\u0438\u043f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0438 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u0432 \u043d\u0438\u0445 \u0432\u043e \u0432\u0441\u0435\u0445 \u0441\u0445\u043e\u0436\u0438, \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u0438\u0445 \u043f\u0440\u0430\u0432\u0438\u043b.<\/p>\n<p>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043a\u0430\u043a \u0443\u0436\u0435 \u0441\u0442\u0430\u043b\u0430 \u044f\u0441\u043d\u043e \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u043b\u043e\u0451\u0432, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0441\u043b\u043e\u0451\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0433\u043e, \u043e\u0434\u043d\u0430\u043a\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043e \u0441\u043b\u043e\u0435, \u0432\u043d\u0435\u0448\u043d\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0433\u043e. \u0412 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0412\u044b \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0435 \u0438 \u0442\u043e\u0447\u043d\u044b\u0435, \u0447\u0435\u043c \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043f\u0440\u043e\u0439\u0434\u0443\u0441\u044c \u043b\u0438\u0448\u044c \u0432\u0441\u043a\u043e\u043b\u044c\u0437\u044c.<\/p>\n<h3>\u042f\u0434\u0440\u043e<\/h3>\n<p>\u0412 \u044f\u0434\u0440\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u044d\u0442\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 UI \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u042f\u0434\u0440\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u043c \u0441\u043b\u043e\u0435\u043c, \u0432\u043e\u043a\u0440\u0443\u0433 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0442\u0440\u043e\u044f\u0442\u0441\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0441\u043b\u043e\u0438. \u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u0438\u0437 \u0447\u0435\u0433\u043e \u043e\u043d \u0441\u043e\u0441\u0442\u043e\u0438\u0442.<\/p>\n<h4>\u041c\u043e\u0434\u0435\u043b\u0438<\/h4>\n<p>\u041c\u043e\u0434\u0435\u043b\u044c (\u0438\u043b\u0438 \u0436\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c) \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043b\u0438\u0448\u044c \u043f\u043e\u043b\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u043d\u0430 \u043d\u0435\u0441\u0451\u0442, \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u044d\u0442\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u0414\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u0441\u044f, \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043e \u0432\u043d\u0435\u0448\u043d\u0435\u043c \u0441\u043b\u043e\u0435, \u0434\u0430\u0436\u0435 \u043e \u0442\u043e\u043c, \u043e\u0442\u043a\u0443\u0434\u0430 \u0431\u0435\u0440\u0443\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0435\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f. \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0433\u043e \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>types<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0442\u0438\u043f\u044b \u0438 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f, \u043f\u0440\u0438\u0437\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435.<\/p>\n<h4>\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/h4>\n<p>\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432 \u044f\u0434\u0440\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0442\u0440\u0435\u0439\u0442\u043e\u043c (\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u043a\u0430\u043a\u0438\u0435 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u0441 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u0445 \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u0438 \u0442\u043e\u043c\u0443 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435.<\/p>\n<h4>\u0421\u0435\u0440\u0432\u0438\u0441\u044b<\/h4>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441\u044b \u0432 \u044f\u0434\u0440\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u0441\u043b\u043e\u0435\u043c, \u0438\u043c\u0435\u043d\u043d\u043e \u0441 \u043d\u0438\u043c\u0438 UI \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043d\u0443\u0436\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u043a\u0430\u043a \u0443\u0436\u0435 \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0441\u0435\u0440\u0432\u0438\u0441, \u043e\u0431\u0449\u0430\u044f\u0441\u044c \u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u043b\u043e\u0451\u0432 \u0441 \u044f\u0434\u0440\u043e\u043c.<\/p>\n<h3>\u0418\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/h3>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0442\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0434\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0438 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432.<\/p>\n<h4>DTO<\/h4>\n<p>DTO (Data Transfer Object) <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u0441\u0443\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043b\u0438\u0448\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438\u0437 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u043b\u0443\u0436\u0430\u0442 \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u044d\u0442\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432. \u041e\u043d\u0438 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043e\u0431\u043b\u0430\u0434\u0430\u044e\u0442 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<h4>\u041c\u0430\u043f\u043f\u0435\u0440\u044b<\/h4>\n<p>\u041c\u0430\u043f\u043f\u0435\u0440 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u043c \u043b\u0438\u0448\u044c 2 \u0437\u0430\u0434\u0430\u0447\u0438 <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 DTO \u0432 \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e.<\/p>\n<h4>\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/h4>\n<p>\u0418\u043c\u0435\u043d\u043d\u043e \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0440\u0435\u0439\u0442\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0438\u0437 \u044f\u0434\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u0430 \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0440\u0435\u0439\u0442\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u0432 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a \u0440\u0430\u0437\u043d\u044b\u043c \u0431\u0430\u0437\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<h4>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/h4>\n<p>\u0412 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0435 \u0437\u0430 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0445 (\u0411\u0414, \u0444\u0430\u0439\u043b\u044b, API \u0438 \u0442\u0434.), \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 (Gateway, API \u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0442\u0434.), \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439 \u0438 \u043f\u0440\u043e\u0447\u0435\u0433\u043e \u0440\u043e\u0434\u0430 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u043e\u0432. \u0412 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u043c\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u0442\u0430\u043a\u043e\u0439 \u0441\u043b\u043e\u0439 <code>file<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438.<\/p>\n<h3>DI<\/h3>\n<p>DI (Dependency Injection) \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438\u0437\u0432\u043d\u0435. \u0412\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u044f\u0437\u044b\u043a\u0430\u0445 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445 DI \u043e\u0431\u044b\u0447\u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0438 \u0448\u0438\u0440\u043e\u043a\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u0432 \u043c\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043e\u043d \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0449\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u043b\u0438\u0448\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0438\u043c.<\/p>\n<h3>UI<\/h3>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043b\u043e\u0435\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 UI \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0434\u043b\u044f \u0441\u043b\u043e\u044f \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0438\u0437 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u043c \u0441\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u0430 MV* (MVC, MVP, MVVM), \u043e\u0434\u043d\u0430\u043a\u043e \u0434\u043b\u044f GPUI \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u043d\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434. \u041c\u043d\u0435 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e, \u0435\u0441\u0442\u044c \u043b\u0438 \u0443 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u0430\u043b \u0435\u043c\u0443 \u0441\u0432\u043e\u0439 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435: <code>State-Entity-View<\/code>. \u0427\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u044e \u0435\u0451 \u0441\u0443\u0442\u044c, \u0441\u0435\u0439\u0447\u0430\u0441 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442.<\/p>\n<h4>\u0422\u0435\u043c\u0430<\/h4>\n<p>\u0412 <code>theme.rs<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0435\u043c\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 UI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0446\u0432\u0435\u0442, \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u0438 \u0442\u0434, \u043d\u043e \u0438 \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0442\u0435\u043c, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0434\u043b\u044f \u0438\u0445 \u0441\u043c\u0435\u043d\u044b.<\/p>\n<h4>\u041b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h4>\n<p>\u0412 <code>locale.rs<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u043c\u0438 \u043f\u0430\u043a\u0435\u0442\u0430\u043c\u0438, \u0432 \u043c\u043e\u0451\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u044b\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b <code>ftl<\/code> (Fluent Translation List). \u041e\u043d\u0430 \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u044f\u0437\u044b\u043a \u0438 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u044b \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0432 UI.<\/p>\n<h4>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/h4>\n<p>\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>shared<\/code> \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c\u0441\u044f \u0442\u0435 UI \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u044b \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445, \u044d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c <strong><em>\u043e\u0431\u0449\u0438\u043c\u0438<\/em><\/strong>.<\/p>\n<h4>\u0424\u0438\u0447\u0438<\/h4>\n<p>\u0421\u0430\u043c\u044b\u043c \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u043f\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f <code>features<\/code>. \u042f \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0440\u044f\u0434 \u043f\u0440\u0430\u0432\u0438\u043b \u043f\u043e \u0435\u0451 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u043e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0432 \u043a\u0440\u0443\u043f\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u0441\u0438\u043b\u044c\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438 \u0438 \u0438\u0437\u043b\u0438\u0448\u043d\u0438\u043c\u0438 \u0434\u043b\u044f \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<p>\u041d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u043e\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>features<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u043a\u0440\u0430\u043d, \u043e\u043a\u043d\u043e \u0438\u043b\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 \u0441\u043b\u043e\u0436\u043d\u0443\u044e \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0435\u0435 \u043e\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u042d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c <strong><em>\u0444\u0438\u0447\u0430\u043c\u0438<\/em><\/strong>. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0437 \u044d\u0442\u0438\u0445 <strong><em>\u0444\u0438\u0447<\/em><\/strong> \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430:<\/p>\n<pre><code>specific_feature\/             # \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0444\u0438\u0447\u0430\u251c\u2500\u2500 components\/               # \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0444\u0438\u0447\u0438\u251c\u2500\u2500 state.rs                  # \u041b\u043e\u0433\u0438\u043a\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c\u251c\u2500\u2500 view.rs                   # \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0444\u0438\u0447\u0438\u2514\u2500\u2500 mod.rs<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/h3>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u043e\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0442\u0435 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 UI \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043b\u043e\u0433\u0438\u043a\u0430 \u0434\u043b\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439 \u0441 \u043d\u0438\u043c\u0438.<\/p>\n<h3>\u0412\u0438\u0434<\/h3>\n<p>\u0417\u0434\u0435\u0441\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u043f\u043e\u043b\u044f \u0442\u0438\u043f\u043e\u0432 <code>gpui::Entity&lt;SpecificFeatureState&gt;<\/code> \u0438 <code>Subscription<\/code> \u0438 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u0442\u0440\u0435\u0439\u0442 <code>Render<\/code>.<\/p>\n<p>\u0422\u0438\u043f <code>gpui::Entity&lt;T&gt;<\/code> \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u0441\u0438\u043b\u044c\u043d\u044b\u0439, \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f GPUI \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0438 \u043f\u0440\u0438\u043d\u044f\u0442\u0438\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439. \u0422\u0438\u043f <code>Subscription<\/code>, \u043a\u0430\u043a \u044f\u0441\u043d\u043e \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u043e\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u0430\u044f GPUI. \u0422\u0440\u0435\u0439\u0442 <code>Render<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>render<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0438\u0441\u0443\u0435\u0442 view \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.<\/p>\n<h3>\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/h3>\n<p>\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>specific_feature\/components<\/code> \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u043b\u0438\u0441\u044c \u0442\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432 <code>specific_feature<\/code>, \u044d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u043c\u0438<\/em><\/strong>. \u0414\u043b\u044f <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/em><\/strong> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/p>\n<pre><code>components\/\u251c\u2500\u2500 multiple_component_1\/\u251c\u2500\u2500 multiple_component_2\/\u251c\u2500\u2500 ...\u251c\u2500\u2500 single_component_1.rs\u251c\u2500\u2500 single_component_2.rs\u251c\u2500\u2500 ...\u2514\u2500\u2500 mod.rs<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c <code>single_component_*.rs<\/code> \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u044e\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0430\u043a\u0440\u043e\u0441 <code>IntoElement<\/code>. \u0414\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d \u0442\u0440\u0435\u0439\u0442 <code>RenderOnce<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u043d\u0435\u0434\u043e\u043b\u0433\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442.<\/p>\n<p>\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>multiple_component_*<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u0435\u0445 <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/em><\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0430\u043c\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u0441\u0435\u0431\u044f \u0435\u0449\u0451 \u0441\u043b\u043e\u0439 <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/em><\/strong>. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u044d\u0442\u0438\u0445 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f:<\/p>\n<pre><code>multiple_component_*\/\u251c\u2500\u2500 components\/\u251c\u2500\u2500 multiple_component_*.rs\u2514\u2500\u2500 mod.rs<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c <code>multiple_component_*.rs<\/code> \u043f\u043e\u0434\u043e\u0431\u043d\u043e <code>single_component_*.rs<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 <code>IntoElement<\/code> \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/em><\/strong> \u0441 \u0442\u0435\u043c \u043b\u0438\u0448\u044c \u043e\u0442\u043b\u0438\u0447\u0438\u0435\u043c, \u0447\u0442\u043e \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0441\u0432\u043e\u0438 <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b 2-\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/em><\/strong>. \u0414\u043b\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>components<\/code> \u0437\u0434\u0435\u0441\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0447\u0442\u043e \u0438 \u0440\u0430\u043d\u0435\u0435, \u0438 \u0442\u0430\u043a \u0434\u043e <img decoding=\"async\" class=\"formula inline\" source=\"n\" alt=\"n\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7\/7b\/7b8\/7b8b965ad4bca0e41ab51de7b31363a1.svg\" width=\"12\" height=\"12\" data-width=\"1.357\" data-height=\"1.025\" data-vertical-align=\"-0.025\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7\/7b\/7b8\/7b8b965ad4bca0e41ab51de7b31363a1.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7\/7b\/7b8\/7b8b965ad4bca0e41ab51de7b31363a1.svg 781w\" loading=\"lazy\" decode=\"async\"\/>-\u043e\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430 \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u0412\u0441\u0435 \u044d\u0442\u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/em><\/strong> \u0442\u0430\u043a\u0436\u0435 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f <strong><em>\u043e\u0431\u0449\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/em><\/strong>.<\/p>\n<h3>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h3>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u0432\u0441\u0451 \u044d\u0442\u043e \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442\u0441\u044f \u0432 <code>app\/src\/main.rs<\/code>, \u0433\u0434\u0435 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>main<\/code> \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u0431\u043e\u0440\u043a\u0430 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<h2>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>\u0412 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0443 \u043d\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0444\u0430\u0439\u043b\u043e\u0432:<\/p>\n<pre><code>.\u251c\u2500\u2500 assets\/\u251c\u2500\u2500 crates\/\u251c\u2500\u2500 Cargo.lock\u2514\u2500\u2500 Cargo.toml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 Cargo.toml \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u044b <code>workspace<\/code> \u0438 <code>workspace.dependencies<\/code>. \u0412 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 <code>workspace<\/code> \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u043a\u0440\u0435\u0439\u0442\u043e\u0432 \u0438 \u043a\u0440\u0435\u0439\u0442 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430:<\/p>\n<pre><code>[workspace]members = [\"crates\/app\", \"crates\/core\", \"crates\/di\", \"crates\/infrastructure\", \"crates\/ui\"]default-members = [\"crates\/app\"]resolver = \"2\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 <code>workspace.dependencies<\/code> \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0435\u043c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u0440\u0435\u0439\u0442\u044b:<\/p>\n<pre><code>[workspace.dependencies]app = { path = \"crates\/app\" }core = { path = \"crates\/core\" }di = { path = \"crates\/di\" }infrastructure = { path = \"crates\/infrastructure\" }ui = { path = \"crates\/ui\" }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0410 \u0437\u0430\u0442\u0435\u043c \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<pre><code>gpui = \"0.2.2\"gpui-component = \"0.5.1\"serde = { version = \"1.0\", features = [\"derive\"] }csv = \"1.3.1\"anyhow = \"1.0\"fluent-templates = \"0.14\" unic-langid = \"0.9\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 Cargo.toml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>[workspace]members = [\"crates\/app\", \"crates\/core\", \"crates\/di\", \"crates\/infrastructure\", \"crates\/ui\"]default-members = [\"crates\/app\"]resolver = \"2\"[workspace.dependencies]jojo_stand_viewer = { path = \"crates\/app\" }core = { path = \"crates\/core\" }di = { path = \"crates\/di\" }infrastructure = { path = \"crates\/infrastructure\" }ui = { path = \"crates\/ui\" }gpui = \"0.2.2\"gpui-component = \"0.5.1\"serde = { version = \"1.0\", features = [\"derive\"] }csv = \"1.3.1\"anyhow = \"1.0\"fluent-templates = \"0.14\" unic-langid = \"0.9\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u0410\u0441\u0441\u0435\u0442\u044b<\/h3>\n<p>\u0412 <code>assets<\/code> \u0443 \u043c\u0435\u043d\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:<\/p>\n<pre><code>assets\/\u251c\u2500\u2500 data\/\u2502   \u2514\u2500\u2500 jojo-stands.csv\u251c\u2500\u2500 icons\/\u2502   \u251c\u2500\u2500 language.svg\u2502   \u2514\u2500\u2500 theme.svg\u251c\u2500\u2500 images\/\u2502   \u251c\u2500\u2500 Achtung Baby.png\u2502   \u251c\u2500\u2500 Aerosmith.png\u2502   \u2514\u2500\u2500 ...\u2514\u2500\u2500 locales\/    \u251c\u2500\u2500 en.ftl    \u2514\u2500\u2500 ru.ftl<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0441\u0442\u043e\u0438\u0442 \u043b\u0438\u0448\u044c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b <code>csv<\/code> \u0438 <code>ftl<\/code> \u0444\u0430\u0439\u043b\u043e\u0432: <br \/> <code>jojo-stands.csv<\/code>:<\/p>\n<pre><code>Stand,PWR,SPD,RNG,PER,PRC,DEVAnubis,B,B,E,A,E,CAtum,D,C,D,B,D,D...<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>en.ftl<\/code>:<\/p>\n<pre><code>stand_list = Stand listpower = Powerspeed = Speedrange = Rangepower_persistence = Power Persistenceprecision = Precisiondevelopment_potential = Development Potential<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>ru.ftl<\/code>:<\/p>\n<pre><code>stand_list = \u0421\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0435\u043d\u0434\u043e\u0432power = \u0421\u0438\u043b\u0430speed = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044crange = \u0414\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044cpower_persistence = \u0412\u044b\u043d\u043e\u0441\u043b\u0438\u0432\u043e\u0441\u0442\u044cprecision = \u0422\u043e\u0447\u043d\u043e\u0441\u0442\u044cdevelopment_potential = \u041f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b \u0420\u0430\u0437\u0432\u0438\u0442\u0438\u044f<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u0430\u0442\u0430\u0441\u0435\u0442 <code>jojo-stands.csv<\/code> \u044f \u043d\u0430\u0448\u0451\u043b <a href=\"https:\/\/www.kaggle.com\/datasets\/dsfelix\/jojo-stands-stats?select=jojo-stands.csv\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<h3>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u0440\u0435\u0439\u0442\u044b<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0441\u0430\u043c\u043e\u0439 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043a \u0441\u0430\u043c\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u0441\u0435\u0433\u043e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043c\u044b \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435.<\/p>\n<h4>\u042f\u0434\u0440\u043e<\/h4>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 core\/Cargo.toml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>[package]name = \"core\"version = \"1.2.0\"edition = \"2024\"[dependencies]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u0422\u0438\u043f\u044b<\/h3>\n<p>\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>types<\/code> \u0443 \u043c\u0435\u043d\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u043b\u0438\u0448\u044c \u043e\u0434\u043d\u043e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 <code>Rank<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a \u0441\u0442\u0435\u043d\u0434\u043e\u0432:<\/p>\n<pre><code class=\"rust\">#[derive(Debug, Clone, Copy)]pub enum Rank {    None,    E,    D,    C,    B,    A,    Infinite,}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0431\u044b\u043b\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u0432 \u0442\u0438\u043f\u044b <code>u8<\/code> \u0438 <code>String<\/code>:<\/p>\n<pre><code class=\"rust\">    pub fn to_u8(&amp;self) -&gt; u8 {        match self {            Rank::None =&gt; 0,            Rank::E =&gt; 1,            Rank::D =&gt; 2,            Rank::C =&gt; 3,            Rank::B =&gt; 4,            Rank::A =&gt; 5,            Rank::Infinite =&gt; 6        }    }    pub fn to_string(&amp;self) -&gt; String {        match self {            Rank::None =&gt; String::from(\"None\"),            Rank::E =&gt; String::from(\"E\"),            Rank::D =&gt; String::from(\"D\"),            Rank::C =&gt; String::from(\"C\"),            Rank::B =&gt; String::from(\"B\"),            Rank::A =&gt; String::from(\"A\"),            Rank::Infinite =&gt; String::from(\"Infinite\")        }    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 core\/src\/types\/rank.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">\/\/\/ Represents the statistical rank of a Stand's attribute in JoJo's Bizarre Adventure.\/\/\/ \/\/\/ Used to classify capabilities such as Power, Speed, Range, Power Persistence, Precision, and Developmental Potential.#[derive(Debug, Clone, Copy)]pub enum Rank {    None,    E,    D,    C,    B,    A,    Infinite,}impl Rank {    \/\/\/ Converts the rank into a numeric value.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `u8` integer mapping from 0 (None) to 6 (Infinite) representing the attribute level.    pub fn to_u8(&amp;self) -&gt; u8 {        match self {            Rank::None =&gt; 0,            Rank::E =&gt; 1,            Rank::D =&gt; 2,            Rank::C =&gt; 3,            Rank::B =&gt; 4,            Rank::A =&gt; 5,            Rank::Infinite =&gt; 6        }    }    \/\/\/ Converts the rank into a `String`.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A heap-allocated `String` containing the official text name of the rank.    pub fn to_string(&amp;self) -&gt; String {        match self {            Rank::None =&gt; String::from(\"None\"),            Rank::E =&gt; String::from(\"E\"),            Rank::D =&gt; String::from(\"D\"),            Rank::C =&gt; String::from(\"C\"),            Rank::B =&gt; String::from(\"B\"),            Rank::A =&gt; String::from(\"A\"),            Rank::Infinite =&gt; String::from(\"Infinite\")        }    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u041c\u043e\u0434\u0435\u043b\u0438<\/h3>\n<p>\u0412 \u043c\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043e\u0434\u043d\u0430 \u043c\u043e\u0434\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0441\u0442\u0435\u043d\u0434. \u0412 \u043f\u043e\u043b\u044f\u0445 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0438\u043c\u0435\u043d\u0438 \u0438 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0430\u0445 \u0441\u0442\u0435\u043d\u0434\u0430:<\/p>\n<pre><code class=\"rust\">#[derive(Debug, Clone)]pub struct StandModel {    name: String,    power: Rank,    speed: Rank,    range: Rank,    power_persistence: Rank,    precision: Rank,    development_potential: Rank}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e \u0441\u0432\u043e\u0435\u043c\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0443 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435, \u0442\u043e \u043a\u0430\u043a \u0442\u0430\u043a\u043e\u0432\u043e\u0439 \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0438 \u0443 \u043c\u043e\u0434\u0435\u043b\u0438 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f, \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440, \u0433\u0435\u0442\u0442\u0435\u0440\u044b \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e:<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 core\/src\/models\/stand.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use crate::types::Rank;\/\/\/ Represents a Stand with its name and statistical attributes.#[derive(Debug, Clone)]pub struct StandModel {    name: String,    power: Rank,    speed: Rank,    range: Rank,    power_persistence: Rank,    precision: Rank,    development_potential: Rank}impl StandModel {    \/\/\/ Creates a new instance of a `StandModel` with the specified name and attributes.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `name` - The unique name of the Stand.    \/\/\/ * `power` - The Power rank.    \/\/\/ * `speed` - The Speed rank.    \/\/\/ * `range` - The Range rank.    \/\/\/ * `power_persistence` - The Power Persistence rank.    \/\/\/ * `precision` - The Precision rank.    \/\/\/ * `development_potential` - The Developmental Potential rank.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An initialized `StandModel` instance containing the provided attributes.    pub fn new(        name: String,        power: Rank,        speed: Rank,        range: Rank,        power_persistence: Rank,        precision: Rank,        development_potential: Rank    ) -&gt; Self {        StandModel {            name,            power,            speed,            range,            power_persistence,            precision,            development_potential        }    }    \/\/\/ Returns a string slice referencing the Stand's name.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A string slice (`&amp;str`) referencing the heap-allocated name of the Stand.    pub fn name(&amp;self) -&gt; &amp;str {        &amp;self.name    }    \/\/\/ Returns the Stand's Power rank.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `Rank` enum representing the Stand's power level.    pub fn power(&amp;self) -&gt; Rank {        self.power    }    \/\/\/ Returns the Stand's Speed rank.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `Rank` enum representing the Stand's speed level.    pub fn speed(&amp;self) -&gt; Rank {        self.speed    }    \/\/\/ Returns the Stand's Range rank.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `Rank` enum representing the Stand's maximum operational distance.    pub fn range(&amp;self) -&gt; Rank {        self.range    }    \/\/\/ Returns the Stand's Power Persistence rank.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `Rank` enum representing the Stand's ability to maintain its state over time.    pub fn power_persistence(&amp;self) -&gt; Rank {        self.power_persistence    }    \/\/\/ Returns the Stand's Precision rank.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `Rank` enum representing the Stand's accuracy and combat control.    pub fn precision(&amp;self) -&gt; Rank {        self.precision    }    \/\/\/ Returns the Stand's Developmental Potential rank.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `Rank` enum representing the Stand's capacity to evolve or manifest new skills.    pub fn development_potential(&amp;self) -&gt; Rank {        self.development_potential    }}impl Default for StandModel {    \/\/\/ Creates a default placeholder state when no Stand is currently selected.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `StandModel` instance with the name \"No selected\" and all attributes set to `Rank::None`.    fn default() -&gt; Self {        StandModel {            name: String::from(\"No selected\"),            power: Rank::None,            speed: Rank::None,            range: Rank::None,            power_persistence: Rank::None,            precision: Rank::None,            development_potential: Rank::None        }    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/h3>\n<p>\u0423 \u043c\u0435\u043d\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d \u0442\u0440\u0435\u0439\u0442 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u0441\u0442\u0435\u043d\u0434\u043e\u0432 \u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043f\u043e \u0438\u043c\u0435\u043d\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 core\/src\/repositories\/stand.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use crate::models::StandModel;\/\/\/ A thread-safe repository trait defining data access operations for Stands.pub trait StandRepository: Send + Sync {    \/\/\/ Retrieves all available Stands from the storage source.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `Vec&lt;StandModel&gt;` containing a collection of all stored Stand models.    fn get_all(&amp;self) -&gt; Vec&lt;StandModel&gt;;    \/\/\/ Retrieves a specific Stand model by its unique name identifier.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `name` - A string slice referencing the unique name of the Stand to search for.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An `Option&lt;StandModel&gt;` containing `Some(StandModel)` if a match is found, or `None` if it does not exist.    fn get_by_name(&amp;self, name: &amp;str) -&gt; Option&lt;StandModel&gt;;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u0421\u0435\u0440\u0432\u0438\u0441\u044b<\/h3>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b UI \u043c\u043e\u0433 \u043a\u0430\u043a-\u043b\u0438\u0431\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u0442\u0435\u043d\u0434\u0430\u0445, \u043d\u0443\u0436\u0435\u043d \u0441\u0435\u0440\u0432\u0438\u0441. \u0421\u0435\u0440\u0432\u0438\u0441 \u0438\u043c\u0435\u0435\u0442 \u043f\u043e\u043b\u0435 \u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0438 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430:<\/p>\n<pre><code class=\"rust\">pub struct StandService {    stand_repository: Arc&lt;dyn StandRepository&gt;,}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u043c\u044b\u0441\u043b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0438\u0445 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"rust\">    pub fn get_all(&amp;self) -&gt; Vec&lt;StandModel&gt; {        self.stand_repository.get_all()    }    pub fn get_by_name(&amp;self, name: &amp;str) -&gt; Option&lt;StandModel&gt; {        self.stand_repository.get_by_name(name)    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 core\/src\/services\/stand.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use std::sync::Arc;use crate::repositories::StandRepository;use crate::models::StandModel;\/\/\/ A service layer structural component providing high-level business logic operations for Stands.pub struct StandService {    stand_repository: Arc&lt;dyn StandRepository&gt;,}impl StandService {    \/\/\/ Creates a new instance of a `StandService` injected with a thread-safe repository implementation.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `stand_repository` - An atomically reference-counted pointer (`Arc`) wrapping a dynamic `StandRepository` trait object.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An initialized `StandService` instance.    pub fn new(stand_repository: Arc&lt;dyn StandRepository&gt;) -&gt; Self {        Self {             stand_repository         }    }    \/\/\/ Fetches a complete collection of all stored Stand models via the underlying repository.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `Vec&lt;StandModel&gt;` containing all available Stands.    pub fn get_all(&amp;self) -&gt; Vec&lt;StandModel&gt; {        self.stand_repository.get_all()    }    \/\/\/ Fetches a specific Stand model by its unique name identifier via the underlying repository.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `name` - A string slice referencing the unique name of the Stand.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An `Option&lt;StandModel&gt;` containing `Some(StandModel)` if found, or `None` if no match exists.    pub fn get_by_name(&amp;self, name: &amp;str) -&gt; Option&lt;StandModel&gt; {        self.stand_repository.get_by_name(name)    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h4>\u0418\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/h4>\n<p>\u041c\u044b \u0443\u0436\u0435 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0438 \u0441 \u044f\u0434\u0440\u043e\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u0435\u043c \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u043c\u0435\u043b\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043a \u0441\u043b\u043e\u044e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 infrastructure\/Cargo.toml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>[package]name = \"infrastructure\"version = \"1.2.0\"edition = \"2024\"[dependencies]core.workspace = trueserde.workspace = truecsv.workspace = true<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>DTO<\/h3>\n<p>\u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0443 \u043c\u0435\u043d\u044f \u0438\u043c\u0435\u0435\u0442\u0441\u044f 2 DTO \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0434\u043b\u044f \u0442\u0438\u043f\u0430 <code>Rank<\/code> \u0438 \u0434\u043b\u044f CSV \u0441\u0442\u0440\u043e\u043a\u0438.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u0440\u0430\u043d\u0433\u0430, \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e CSV \u0444\u0430\u0439\u043b\u0430 \u0438 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438\u0445 \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043d\u0430\u043c \u0432\u0438\u0434\u0435, \u0442\u043e \u0435\u0441\u0442\u044c \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c:<\/p>\n<pre><code class=\"rust\">impl&lt;'de&gt; Deserialize&lt;'de&gt; for RankDto {    fn deserialize&lt;D&gt;(deserializer: D) -&gt; Result&lt;Self, D::Error&gt;    where        D: serde::Deserializer&lt;'de&gt;    {        let s = String::deserialize(deserializer)?;        Ok(RankDto::from(s.as_str()))    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 infrastructure\/src\/dtos\/rank.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use serde::{Serialize, Deserialize};\/\/\/ A Data Transfer Object (DTO) representing a Stand's statistical rank during serialization and deserialization.#[derive(Debug, Clone, Copy, Serialize)]pub enum RankDto {    None,    E,    D,    C,    B,    A,    Infi}impl From&lt;&amp;str&gt; for RankDto {    \/\/\/ Maps a raw string slice representation of a rank into a matching `RankDto` variant.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `s` - A raw string slice parsed from the data source.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The corresponding `RankDto` variant, defaulting to `RankDto::None` if the input string is unrecognized.    fn from(s: &amp;str) -&gt; Self {        match s {            \"None\" =&gt; RankDto::None,            \"E\" =&gt; RankDto::E,            \"D\" =&gt; RankDto::D,            \"C\" =&gt; RankDto::C,            \"B\" =&gt; RankDto::B,            \"A\" =&gt; RankDto::A,            \"Infi\" =&gt; RankDto::Infi,            _ =&gt; RankDto::None,        }    }}impl&lt;'de&gt; Deserialize&lt;'de&gt; for RankDto {    fn deserialize&lt;D&gt;(deserializer: D) -&gt; Result&lt;Self, D::Error&gt;    where        D: serde::Deserializer&lt;'de&gt;    {        let s = String::deserialize(deserializer)?;        Ok(RankDto::from(s.as_str()))    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u043b\u044f CSV \u0441\u0442\u0440\u043e\u043a\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u043e\u043b\u044f \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e CSV \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<pre><code class=\"rust\">#[derive(Debug, Clone, Serialize, Deserialize)]pub struct StandDto {    #[serde(rename = \"Stand\")]    stand: String,    #[serde(rename = \"PWR\")]    pwr: RankDto,    #[serde(rename = \"SPD\")]    spd: RankDto,    #[serde(rename = \"RNG\")]    rng: RankDto,    #[serde(rename = \"PER\")]    per: RankDto,    #[serde(rename = \"PRC\")]    prc: RankDto,    #[serde(rename = \"DEV\")]    dev: RankDto}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 infrastructure\/src\/dtos\/stand.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use serde::{Serialize, Deserialize};use super::RankDto;\/\/\/ A Data Transfer Object (DTO) used for flat-file deserialization and serialization of Stand records.#[derive(Debug, Clone, Serialize, Deserialize)]pub struct StandDto {    #[serde(rename = \"Stand\")]    stand: String,    #[serde(rename = \"PWR\")]    pwr: RankDto,    #[serde(rename = \"SPD\")]    spd: RankDto,    #[serde(rename = \"RNG\")]    rng: RankDto,    #[serde(rename = \"PER\")]    per: RankDto,    #[serde(rename = \"PRC\")]    prc: RankDto,    #[serde(rename = \"DEV\")]    dev: RankDto}impl StandDto {    \/\/\/ Creates a new instance of a `StandDto` with explicit raw transfer components.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `stand` - The raw name string of the Stand.    \/\/\/ * `pwr` - The mapped raw power rank token.    \/\/\/ * `spd` - The mapped raw speed rank token.    \/\/\/ * `rng` - The mapped raw range rank token.    \/\/\/ * `per` - The mapped raw persistence rank token.    \/\/\/ * `prc` - The mapped raw precision rank token.    \/\/\/ * `dev` - The mapped raw development potential rank token.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An initialized `StandDto` transfer state payload container.    pub fn new(        stand: String,        pwr: RankDto,        spd: RankDto,        rng: RankDto,        per: RankDto,        prc: RankDto,        dev: RankDto    ) -&gt; Self {        StandDto {            stand,            pwr,            spd,            rng,            per,            prc,            dev        }    }    \/\/\/ Accesses the raw name of the Stand.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A string slice referencing the internal name identifier.    pub fn stand(&amp;self) -&gt; &amp;str {        &amp;self.stand    }    \/\/\/ Accesses the raw short power rank data token.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `RankDto` enumeration token value for power.    pub fn power(&amp;self) -&gt; RankDto {        self.pwr    }    \/\/\/ Accesses the raw short speed rank data token.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `RankDto` enumeration token value for speed.    pub fn speed(&amp;self) -&gt; RankDto {        self.spd    }    \/\/\/ Accesses the raw short range rank data token.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `RankDto` enumeration token value for range.    pub fn range(&amp;self) -&gt; RankDto {        self.rng    }    \/\/\/ Accesses the raw short power persistence rank data token.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `RankDto` enumeration token value for power persistence.    pub fn power_persistence(&amp;self) -&gt; RankDto {        self.per    }    \/\/\/ Accesses the raw short precision rank data token.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `RankDto` enumeration token value for precision.    pub fn precision(&amp;self) -&gt; RankDto {        self.prc    }    \/\/\/ Accesses the raw short developmental potential rank data token.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The `RankDto` enumeration token value for developmental potential.    pub fn development_potential(&amp;self) -&gt; RankDto {        self.dev    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u041c\u0430\u043f\u043f\u0435\u0440\u044b<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0442\u0440\u0435\u0439\u0442 <code>Mapper<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u0432 \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u0432 DTO.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 infrastructure\/src\/mappers\/mapper.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">\/\/\/ A generic data mapping abstraction layer used to convert data structures between different architectural layers.\/\/\/\/\/\/ Typically implemented within the infrastructure layer to decouple core domain models from external Data Transfer Objects (DTOs).\/\/\/\/\/\/ # Type Parameters\/\/\/\/\/\/ * `Model` - The core domain model representing business logic rules.\/\/\/ * `Dto` - The data transfer representation..pub trait Mapper&lt;Model, Dto&gt; {    \/\/\/ Maps a core domain model reference into its data transfer object counterpart.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `model` - A shared reference (`&amp;Model`) to the core entity being converted.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An instance of the corresponding `Dto`.    fn to_dto(model: &amp;Model) -&gt; Dto;    \/\/\/ Maps a data transfer object reference back into its core domain model representation.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `dto` - A shared reference (`&amp;Dto`) to the data transfer object layout being converted.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An instance of the corresponding core `Model`.    fn to_model(dto: &amp;Dto) -&gt; Model;}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<p>\u0410 \u0434\u0430\u043b\u0435\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043c\u0430\u043f\u043f\u0435\u0440\u044b \u0434\u043b\u044f \u0440\u0430\u043d\u0433\u0430 \u0438 \u0441\u0442\u0435\u043d\u0434\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 infrastructure\/src\/mappers\/rank.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use core::types::Rank;use crate::dtos::RankDto;use super::mapper::Mapper;\/\/\/ A stateless mapping utility responsible for converting between domain `Rank` enums and infrastructure `RankDto` representations.pub struct RankMapper;impl Mapper&lt;Rank, RankDto&gt; for RankMapper {    \/\/\/ Maps a domain `Rank` reference into its infrastructure-specific `RankDto` counterpart.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `model` - A shared reference to the domain `Rank` enum variant.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The corresponding `RankDto` enum variant used for transfer layouts.    fn to_dto(model: &amp;Rank) -&gt; RankDto {        match model {            Rank::None =&gt; RankDto::None,            Rank::E =&gt; RankDto::E,            Rank::D =&gt; RankDto::D,            Rank::C =&gt; RankDto::C,            Rank::B =&gt; RankDto::B,            Rank::A =&gt; RankDto::A,            Rank::Infinite =&gt; RankDto::Infi        }    }    \/\/\/ Maps an infrastructure `RankDto` reference back into its domain `Rank` representation.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `dto` - A shared reference to the `RankDto` data serialization variant.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The corresponding core domain `Rank` enum variant.    fn to_model(dto: &amp;RankDto) -&gt; Rank {        match dto {            RankDto::None =&gt; Rank::None,            RankDto::E =&gt; Rank::E,            RankDto::D =&gt; Rank::D,            RankDto::C =&gt; Rank::C,            RankDto::B =&gt; Rank::B,            RankDto::A =&gt; Rank::A,            RankDto::Infi =&gt; Rank::Infinite        }    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 infrastructure\/src\/mappers\/stand.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use core::models::StandModel;use crate::dtos::StandDto;use super::mapper::Mapper;use crate::mappers::RankMapper;\/\/\/ A stateless mapping utility responsible for converting between complex domain `StandModel` structures and flattened infrastructure `StandDto` data layers.pub struct StandMapper;impl Mapper&lt;StandModel, StandDto&gt; for StandMapper {    \/\/\/ Maps a domain `StandModel` reference into its infrastructure-specific serialized `StandDto` layout.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `model` - A shared reference to the domain `StandModel`.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A fully initialized `StandDto` instance containing mapped attribute transfer tokens.    fn to_dto(model: &amp;StandModel) -&gt; StandDto {        StandDto::new(            String::from(model.name()),            RankMapper::to_dto(&amp;model.power()),            RankMapper::to_dto(&amp;model.speed()),            RankMapper::to_dto(&amp;model.range()),            RankMapper::to_dto(&amp;model.power_persistence()),            RankMapper::to_dto(&amp;model.precision()),            RankMapper::to_dto(&amp;model.development_potential())        )    }    \/\/\/ Maps a raw infrastructure `StandDto` data transfer record back into a domain `StandModel`.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `dto` - A shared reference to the deserialized external `StandDto` data block.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A core domain `StandModel` instance.    fn to_model(dto: &amp;StandDto) -&gt; StandModel {        StandModel::new(            String::from(dto.stand()),            RankMapper::to_model(&amp;dto.power()),            RankMapper::to_model(&amp;dto.speed()),            RankMapper::to_model(&amp;dto.range()),            RankMapper::to_model(&amp;dto.power_persistence()),            RankMapper::to_model(&amp;dto.precision()),            RankMapper::to_model(&amp;dto.development_potential())        )    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438<\/h3>\n<p>\u0417\u0434\u0435\u0441\u044c \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e CSV \u0444\u0430\u0439\u043b\u0430. \u0414\u043b\u044f \u0435\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u043a\u0440\u0435\u0439\u0442\u043e\u043c <code>csv<\/code>, \u0447\u0442\u043e\u0431\u044b \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043c\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 infrastructure\/src\/repositories\/csv_stand.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use std::error::Error;use std::fs::File;use std::io::BufReader;use csv::Reader;use core::models::StandModel;use core::repositories::StandRepository;use crate::dtos::StandDto;use crate::mappers::{Mapper,StandMapper};use crate::file::PathManager;pub struct CsvStandRepository {    items: Vec&lt;StandModel&gt;,}\/\/\/ An implementation of `StandRepository` that loads and caches data from a flat CSV file.impl CsvStandRepository {    \/\/\/ Initializes the repository by parsing records from a CSV file.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `path_manager` - A shared reference to the utility managing environment file paths.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `Result` containing the initialized `CsvStandRepository` state on success, or a dynamic wrapper of any IO\/Parsing error.    pub fn new(path_manager: &amp;PathManager) -&gt; Result&lt;Self, Box&lt;dyn Error&gt;&gt; {        let mut items = Vec::new();        let path = path_manager.csv_path();        let file = File::open(path)?;        let reader = BufReader::new(file);        let mut rdr = Reader::from_reader(reader);        for result in rdr.deserialize() {            let record: StandDto = result?;            items.push(StandMapper::to_model(&amp;record));        }        Ok(Self { items })    }}impl StandRepository for CsvStandRepository {    \/\/\/ Returns a cloned snapshot collection of all cached domain models.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `Vec&lt;StandModel&gt;` populated with copies of the Stand entities.    fn get_all(&amp;self) -&gt; Vec&lt;StandModel&gt; {        self.items.clone()    }    \/\/\/ Searches for a specific Stand by its unique string name in the local cached vector.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `name` - A string slice referencing the Stand's unique lookup key.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An `Option&lt;StandModel&gt;` containing a cloned model instance if matched, or `None`.    fn get_by_name(&amp;self, name: &amp;str) -&gt; Option&lt;StandModel&gt; {        self.items.iter().find(|s| s.name() == name).cloned()    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438<\/h3>\n<p>\u0412 \u0441\u0432\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0443\u0442\u044f\u043c\u0438 \u0444\u0430\u0439\u043b\u043e\u0432 <code>PathManager<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u0443\u0442\u0435\u0439 \u043a \u0430\u0441\u0441\u0435\u0442\u0430\u043c. \u0422\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u044c \u0443 \u043c\u0435\u043d\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043c\u043d\u043e\u0433\u043e \u0438\u043a\u043e\u043d\u043e\u043a, \u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c <code>IconManager<\/code>, \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u0435\u0434\u0436\u043c\u0435\u043d\u0442\u0430 \u0438\u043a\u043e\u043d\u043a\u0430\u043c\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 infrastructure\/src\/file\/path_manager.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use std::path::{Path, PathBuf};\/\/\/ A utility structure responsible for managing component file paths across the application asset space.\/\/\/\/\/\/ It constructs and verifies path locations for static data, icons, and dynamic stand images.pub struct PathManager {    assets_dir: PathBuf,    csv_path: PathBuf}impl PathManager {    \/\/\/ Constructs a new `PathManager` by combining a base directory with specific resource names.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `base_dir` - An object that implements `AsRef&lt;Path&gt;` serving as the root directory of the project.    \/\/\/ * `assets_dir_name` - The subfolder name string holding static resources.    \/\/\/ * `csv_name` - The base name of the database file without the extension.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An initialized `PathManager` with calculated asset and database directory trees.    pub fn new(base_dir: impl AsRef&lt;Path&gt;, assets_dir_name: &amp;str, csv_name: &amp;str) -&gt; Self {        let base_dir = base_dir.as_ref().to_path_buf();        let assets_dir = base_dir.join(assets_dir_name);        let csv_filename = format!(\"{}.csv\", csv_name);        let csv_path = assets_dir.join(\"data\").join(csv_filename);        PathManager {            assets_dir,            csv_path        }    }    \/\/\/ Accesses the root path of the asset directory tree.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A shared reference to a `Path` pointing to the application's root asset directory.    pub fn assets_dir(&amp;self) -&gt; &amp;Path {        &amp;self.assets_dir    }    \/\/\/ Accesses the designated CSV flat-file path.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A shared reference to a `Path` pointing directly to the target CSV database file.    pub fn csv_path(&amp;self) -&gt; &amp;Path {        &amp;self.csv_path    }    \/\/\/ Resolves the absolute runtime path for a requested Stand profile image.    \/\/\/    \/\/\/ If the specific image file does not exist on disk, it falls back to a default placeholder image.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `path` - A string slice referencing the relative path\/filename of the stand image.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `PathBuf` container holding the verified image file path or the \"unknown.png\" fallback location.    pub fn image_path(&amp;self, path: &amp;str) -&gt; PathBuf {        let image_path =  self.assets_dir.join(\"images\").join(path);        if image_path.exists() {            image_path        } else {            self.assets_dir.join(\"images\").join(\"unknown.png\")        }    }    \/\/\/ Resolves the file path for graphical asset icons.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `path` - A string slice referencing the relative path or file descriptor of the icon.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `PathBuf` holding the absolute directory layout path for the icon file.    pub fn icon_path(&amp;self, path: &amp;str) -&gt; PathBuf {        self.assets_dir.join(\"icons\").join(path)    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h4>DI<\/h4>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u0432\u0441\u0451 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0434\u043b\u044f \u043b\u043e\u0433\u0438\u043a\u0438 \u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043a DI.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 di\/Cargo.toml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>[package]name = \"di\"version = \"1.2.0\"edition = \"2024\"[dependencies]core.workspace = trueinfrastructure.workspace = truegpui.workspace = true<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<p>\u041c\u043e\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 <code>DependencyInjector<\/code> \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 <code>PathManager<\/code> \u0438 <code>StandService<\/code> \u0438 \u0434\u0430\u0451\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0438\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u043c, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0438\u0437 \u043a\u0430\u0436\u0434\u043e\u0433\u043e UI-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.<\/p>\n<pre><code class=\"rust\">    pub fn init(base_dir: impl AsRef&lt;Path&gt;) -&gt; Result&lt;Self, Box&lt;dyn std::error::Error&gt;&gt; {        let path_manager = Arc::new(PathManager::new(base_dir, \"assets\", \"jojo-stands\"));        let csv_stand_repository = CsvStandRepository::new(&amp;path_manager)?;        let stand_repository: Arc&lt;dyn StandRepository&gt; = Arc::new(csv_stand_repository);        let stand_service = Arc::new(StandService::new(stand_repository));        Ok(Self {            path_manager,            stand_service        })    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f <code>DependencyInjector<\/code> \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f <code>gpui::Global<\/code>, \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0432 GPUI \u043c\u043e\u0433 \u0435\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0433\u043e \u0438\u0437 \u043b\u044e\u0431\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u0433\u0434\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442.<\/p>\n<pre><code class=\"rust\">impl Global for DependencyInjector {}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0442\u0435\u043c, \u0447\u0442\u043e \u043c\u043d\u0435 \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0434\u0435\u0441\u044c \u043c\u043d\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0442\u043e \u0432 DI \u0441\u043b\u043e\u0435 \u0443 \u043c\u0435\u043d\u044f \u0432\u0441\u0435\u0433\u043e \u043e\u0434\u043d\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043e\u0434\u043d\u0430\u043a\u043e \u0435\u0441\u043b\u0438 \u0443 \u0412\u0430\u0441 \u043a\u0440\u0443\u043f\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442, \u0433\u0434\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440, \u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u0435\u0435, \u0435\u0441\u043b\u0438 \u0412\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u0442\u0435 \u043f\u043e\u0434\u043c\u043e\u0434\u0443\u043b\u0438, \u0433\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u0441\u043b\u043e\u0451\u0432, \u0438 \u043f\u043e\u0442\u043e\u043c \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u0435 \u0432\u0441\u0435 \u044d\u0442\u0438 \u043f\u043e\u0434\u043c\u043e\u0434\u0443\u043b\u0438 \u0432 <code>DependencyInjector<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 di\/src\/dependency_injector.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use std::sync::Arc;use std::path::Path;use gpui::Global;use core::repositories::StandRepository;use core::services::StandService;use infrastructure::file::PathManager;use infrastructure::repositories::CsvStandRepository;\/\/\/ A centralized dependency injection container that manages the application's global state lifetimes.pub struct DependencyInjector {    path_manager: Arc&lt;PathManager&gt;,    stand_service: Arc&lt;StandService&gt;,}impl Global for DependencyInjector {}impl DependencyInjector {    \/\/\/ Initializes the entire application dependency graph by assembling infrastructure and core service layers.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `base_dir` - An object implementing `AsRef&lt;Path&gt;` that points to the application's root execution directory.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `Result` containing the fully wired `DependencyInjector` container on success, or an IO\/parsing startup error wrapped in a `Box`.    pub fn init(base_dir: impl AsRef&lt;Path&gt;) -&gt; Result&lt;Self, Box&lt;dyn std::error::Error&gt;&gt; {        let path_manager = Arc::new(PathManager::new(base_dir, \"assets\", \"jojo-stands\"));        let csv_stand_repository = CsvStandRepository::new(&amp;path_manager)?;        let stand_repository: Arc&lt;dyn StandRepository&gt; = Arc::new(csv_stand_repository);        let stand_service = Arc::new(StandService::new(stand_repository));        Ok(Self {            path_manager,            stand_service        })    }    \/\/\/ Provides a thread-safe, reference-counted clone of the `PathManager` service.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An `Arc&lt;PathManager&gt;` pointer managing asset paths.    pub fn path_manager(&amp;self) -&gt; Arc&lt;PathManager&gt; {        self.path_manager.clone()    }    \/\/\/ Provides a thread-safe, reference-counted clone of the `StandService`.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An `Arc&lt;StandService&gt;` pointer used for performing application operations.    pub fn stand_service(&amp;self) -&gt; Arc&lt;StandService&gt; {        self.stand_service.clone()    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h4>UI<\/h4>\n<p>\u041c\u044b \u0443\u0436\u0435 \u043d\u0430 \u0444\u0438\u043d\u0438\u0448\u043d\u043e\u0439 \u043f\u0440\u044f\u043c\u043e\u0439! \u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0443 \u043c\u0435\u043d\u044f \u0443\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0447\u0430\u0441\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 ui\/Cargo.toml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>[package]name = \"ui\"version = \"1.2.0\"edition = \"2024\"[dependencies]core.workspace = trueinfrastructure.workspace = truedi.workspace = truegpui.workspace = truegpui-component.workspace = truefluent-templates.workspace = trueunic-langid.workspace = true<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u0422\u0435\u043c\u0430<\/h3>\n<p>\u0412 \u0441\u0432\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u043b\u0438\u0448\u044c 2 \u0442\u0435\u043c\u044b: \u0441\u0432\u0435\u0442\u043b\u0430\u044f \u0438 \u0442\u0451\u043c\u043d\u0430\u044f. \u042f \u0441\u043e\u0437\u0434\u0430\u043b \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u044d\u0442\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439.<\/p>\n<pre><code class=\"rust\">#[derive(Clone)]enum ThemeMode {    Light,    Dark}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b <code>Theme<\/code> \u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0446\u0432\u0435\u0442\u043e\u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u0447\u0430\u0441\u0442\u0435\u0439 UI \u0438 \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u0442\u0435\u043c\u0435.<\/p>\n<pre><code class=\"rust\">#[derive(Clone)]pub struct Theme {    mode: ThemeMode,    pub background_color: u32,    pub text_color: u32,    pub button_color: u32,    pub button_hover_color: u32,    pub grid_color: u32,    pub polygon_color: u32,    pub polygon_opacity: u8,    pub radar_text_color: Hsla,}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0431\u044b\u043b\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b <code>light<\/code> \u0438 <code>dark<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430\u043c\u0438, \u0441\u043e\u0437\u0434\u0430\u044e\u0449\u0438\u043c\u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0441 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043c\u0435\u043d\u044b \u0442\u0435\u043c\u044b. \u0417\u0434\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 <code>cx<\/code>. \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>cx.set_global(new_theme)<\/code> \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0442\u0438\u043f\u0430 <code>Theme<\/code> \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 <code>new_theme<\/code>. \u0410 <code>cx.refresh_windows()<\/code> \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0432\u0441\u0435 \u043e\u043a\u043d\u0430, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u0440\u0430\u043d\u0435\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438.<\/p>\n<pre><code class=\"rust\">    pub fn toggle_theme(&amp;self, cx: &amp;mut App) {        let current = cx.global::&lt;Self&gt;().clone();        let new_theme = match current.mode {            ThemeMode::Light =&gt; Self::dark(),            ThemeMode::Dark =&gt; Self::light(),        };        cx.set_global(new_theme);        cx.refresh_windows();    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 ui\/src\/theme.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use gpui::{App, Global, Hsla, hsla};\/\/\/ Represents the active visual mode of the application's user interface.#[derive(Clone)]enum ThemeMode {    Light,    Dark}\/\/\/ A comprehensive styling configuration containing color palettes and opacity settings for the UI.#[derive(Clone)]pub struct Theme {    mode: ThemeMode,    pub background_color: u32,    pub text_color: u32,    pub button_color: u32,    pub button_hover_color: u32,    pub grid_color: u32,    pub polygon_color: u32,    pub polygon_opacity: u8,    pub radar_text_color: Hsla,}impl Global for Theme {}impl Theme {    \/\/\/ Constructs a predefined dark theme configuration matching low-light environment palettes.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `Theme` instance initialized with dark background colors and high-contrast text markers.    pub fn dark() -&gt; Self {        Self {            mode: ThemeMode::Dark,            background_color: 0x1e1e1e,            text_color: 0xffffff,            button_color: 0x2d2d2d,            button_hover_color: 0x37373d,            grid_color: 0x9d9d9d,            polygon_color: 0xff830f,            polygon_opacity: 120,            radar_text_color: hsla(0.0, 1.0, 0.99, 1.0),        }    }    \/\/\/ Constructs a predefined light theme configuration matching high-luminance environment palettes.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A `Theme` instance initialized with light background colors and readable dark accents.    pub fn light() -&gt; Self {        Self {            mode: ThemeMode::Light,            background_color: 0xffffff,            text_color: 0x1e1e1e,            button_color: 0xdadada,            button_hover_color: 0xb7b7b7,            grid_color: 0xafa9a9,            polygon_color: 0xff830f,            polygon_opacity: 120,            radar_text_color: hsla(0.0, 0.0, 0.0, 1.0),        }    }    \/\/\/ Toggles the global application theme between Light and Dark modes.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `cx` - A mutable reference to the GPUI `App` context.    pub fn toggle_theme(&amp;self, cx: &amp;mut App) {        let current = cx.global::&lt;Self&gt;().clone();        let new_theme = match current.mode {            ThemeMode::Light =&gt; Self::dark(),            ThemeMode::Dark =&gt; Self::light(),        };        cx.set_global(new_theme);        cx.refresh_windows();    }}impl Default for Theme {    fn default() -&gt; Self {        Self::dark()    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u041b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h3>\n<p>\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 <code>ftl<\/code> \u044f \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0441\u044f \u043a\u0440\u0435\u0439\u0442\u0430\u043c\u0438 <code>fluent_templates<\/code> \u0438 <code>unic_langid<\/code>.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0432\u044b\u0437\u0432\u0430\u043b \u043c\u0430\u043a\u0440\u043e\u0441 <code>static_loader<\/code>, \u043e\u043d \u043d\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0432\u0441\u0435 fluent \u0440\u0435\u0441\u0443\u0440\u0441\u044b \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u0434\u0430\u0451\u0442 \u044f\u0437\u044b\u043a \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.<\/p>\n<pre><code class=\"rust\">static_loader! {    pub static LOCALES = {        locales: \"..\/..\/assets\/locales\",        fallback_language: \"en\",    };}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u044f\u0437\u044b\u043a \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0442\u0440\u0435\u0439\u0442 <code>gpui::Global<\/code>.<\/p>\n<pre><code class=\"rust\">#[derive(Clone)]pub struct Locale {    pub language: LanguageIdentifier,}impl Global for Locale {}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u043a\u043b\u044e\u0447\u0443 \u0438\u0437 <code>ftl<\/code> \u0444\u0430\u0439\u043b\u0443 \u0438 \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0441\u043c\u0435\u043d\u044b \u044f\u0437\u044b\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0445\u043e\u0436 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441 \u0441\u043c\u0435\u043d\u043e\u0439 \u0442\u0435\u043c\u044b.<\/p>\n<pre><code class=\"rust\">pub fn translate(&amp;self, key: &amp;str) -&gt; String {        LOCALES.try_lookup(&amp;self.language, key)            .unwrap_or_else(|| {                println!(\"[Localization Warning] Key '{}' not found!\", key);                key.to_string()             })    }    pub fn toggle_language(&amp;self, cx: &amp;mut gpui::App) {        let locale = cx.global::&lt;Self&gt;().clone();                let new_language = if locale.language == langid!(\"ru\") {            langid!(\"en\")        } else {            langid!(\"ru\")        };        cx.set_global(Locale { language: new_language });        cx.refresh_windows();    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430, \u0434\u0430\u0431\u044b \u043d\u0435 \u043f\u0440\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445 \u043e\u0433\u0440\u043e\u043c\u043d\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u043a\u043e\u0434\u0430, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u0432 UI, \u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0441 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u043e\u043c <code>tr(cx, \"key\")<\/code>.<\/p>\n<pre><code class=\"rust\">pub fn tr(cx: &amp;gpui::App, key: &amp;str) -&gt; gpui::SharedString {    cx.global::&lt;Locale&gt;().translate(key).into()}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 ui\/src\/locale.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use gpui::Global;use fluent_templates::{Loader, static_loader};use unic_langid::{langid, LanguageIdentifier};static_loader! {    pub static LOCALES = {        locales: \"..\/..\/assets\/locales\",        fallback_language: \"en\",    };}\/\/\/ A global localization manager responsible for translating UI strings and managing the application language state.#[derive(Clone)]pub struct Locale {    pub language: LanguageIdentifier,}impl Global for Locale {}impl Locale {    \/\/\/ Constructs a new `Locale` manager initialized with English (\"en\") as the default language.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An initialized `Locale` state instance.    pub fn new() -&gt; Self {        Self {            language: langid!(\"en\"),        }    }    \/\/\/ Looks up a localization translation resource string matching the provided key identifier.    \/\/\/    \/\/\/ If the key is missing in the primary and fallback languages, it prints a warning to the console and safely returns the raw key string to avoid UI crashes.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `key` - A string slice referencing the unique translation key.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A resolved heap-allocated `String` translation text.    pub fn translate(&amp;self, key: &amp;str) -&gt; String {        LOCALES.try_lookup(&amp;self.language, key)            .unwrap_or_else(|| {                println!(\"[Localization Warning] Key '{}' not found!\", key);                key.to_string()             })    }    \/\/\/ Toggles the active application language between Russian and English layouts.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `cx` - A mutable reference to the global GPUI `App` application instance context.    pub fn toggle_language(&amp;self, cx: &amp;mut gpui::App) {        let locale = cx.global::&lt;Self&gt;().clone();                let new_language = if locale.language == langid!(\"ru\") {            langid!(\"en\")        } else {            langid!(\"ru\")        };        cx.set_global(Locale { language: new_language });        cx.refresh_windows();    }}\/\/\/ A short global utility helper function used to fetch localized strings swiftly.\/\/\/\/\/\/ # Arguments\/\/\/\/\/\/ * `cx` - A shared reference to the GPUI application lifecycle state context.\/\/\/ * `key` - The unique translation dictionary lookup identifier key token.\/\/\/\/\/\/ # Returns\/\/\/\/\/\/ * A thread-safe, immutable `SharedString` compatible with GPUI primitive rendering components.pub fn tr(cx: &amp;gpui::App, key: &amp;str) -&gt; gpui::SharedString {    cx.global::&lt;Locale&gt;().translate(key).into()}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u041e\u0431\u0449\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/h3>\n<p>\u041d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u044f \u0431\u043e\u043b\u044c\u0448\u0435 \u0431\u0443\u0434\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u0430\u043c\u043e\u0433\u043e GPUI \u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u043f\u0440\u043e \u0441\u0430\u043c \u043c\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442. \u0415\u0441\u043b\u0438 \u0412\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043e\u0441\u0442\u0430\u0432\u0448\u0443\u044e\u0441\u044f \u0447\u0430\u0441\u0442\u044c \u043c\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e, \u0442\u043e \u0432 \u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u043e\u0441\u0442\u0430\u0432\u043b\u044e \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 GitHub \u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c.<\/p>\n<p>\u0412 \u043c\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d \u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u043e\u0431\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442: \u043a\u043d\u043e\u043f\u043a\u0430 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u042f \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u043c\u043e\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u043c\u043e\u0436\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043b\u0438\u0431\u043e \u0442\u0435\u043a\u0441\u0442, \u043b\u0438\u0431\u043e SVG \u0438\u043a\u043e\u043d\u043a\u0443 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.<\/p>\n<pre><code class=\"rust\">pub enum ButtonContentType {    Text(SharedString),    Icon(String, f32),}#[derive(IntoElement)]pub struct Button {    id: ElementId,    content_type: ButtonContentType,    on_click: Option&lt;Box&lt;dyn Fn(&amp;ClickEvent, &amp;mut Window, &amp;mut App) + 'static&gt;&gt;,    modifier: Option&lt;Box&lt;dyn FnOnce(Stateful&lt;Div&gt;) -&gt; Stateful&lt;Div&gt; + 'static&gt;&gt;}impl Button {    pub fn on_click(mut self, on_click: impl Fn(&amp;ClickEvent, &amp;mut Window, &amp;mut App) + 'static) -&gt; Self {        self.on_click = Some(Box::new(on_click));        self    }    pub fn style_modifier(mut self, modifier: impl FnOnce(Stateful&lt;Div&gt;) -&gt; Stateful&lt;Div&gt; + 'static) -&gt; Self {        self.modifier = Some(Box::new(modifier));        self    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043a\u043d\u043e\u043f\u043a\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c, \u0442\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0442\u0440\u0435\u0439\u0442 <code>RenderOnce<\/code>. \u0422\u043e, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043d\u0430\u0448 UI-\u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043c\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0437 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <code>render<\/code>.<\/p>\n<pre><code class=\"rust\">impl RenderOnce for Button {    fn render(self, _window: &amp;mut Window, cx: &amp;mut App) -&gt; impl IntoElement {<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <code>window<\/code> \u043d\u0443\u0436\u043d\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u043a\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, <code>cx<\/code> \u043c\u044b \u0443\u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0438 \u0440\u0430\u043d\u0435\u0435, \u043a\u043e\u0433\u0434\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u043b\u0438 \u0442\u0435\u043c\u0443 \u0438 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u044d\u0442\u043e \u043d\u0430\u0448 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u0446\u0438\u044f <code>cx.global::&lt;G&gt;()<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0442\u0438\u043f\u0430 <code>G<\/code>.<\/p>\n<p>\u0421\u0442\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0441\u0430, \u043f\u043e \u0441\u043b\u043e\u0432\u0430\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u044b Zed, \u0432\u0434\u043e\u0445\u043d\u043e\u0432\u043b\u0435\u043d\u0430 API Tailwind CSS, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0412\u044b \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u043d\u0438\u043c \u0438\u043b\u0438 \u0441 \u043e\u0431\u044b\u0447\u043d\u044b\u043c\u0438 CSS \u0438 HTML, \u0442\u043e \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0412\u0430\u043c \u0437\u043d\u0430\u043a\u043e\u043c.<\/p>\n<p>\u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0431\u0443\u0434\u0443\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f\u043c\u0438 <code>Div<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439, \u043a\u0430\u043a \u0438 \u0432 HTML, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u043c \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u0422\u0430\u043a\u0436\u0435 \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u0447\u0442\u043e \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043c\u0432\u0430\u044e\u0442 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c, \u0434\u043e\u043b\u0436\u043d\u044b \u043e\u0431\u043b\u0430\u0434\u0430\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 <code>id<\/code>. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u0440\u043e \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u044f \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0443, \u043c\u043d\u043e\u0433\u0438\u0435 \u0438\u0437 \u043d\u0438\u0445 \u043f\u043e\u043d\u044f\u0442\u043d\u044b \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e, \u0434\u0430 \u0438 \u0432 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043e\u043d\u0438 \u0432\u0441\u0435 \u0445\u043e\u0440\u043e\u0448\u043e \u0438 \u043f\u043d\u0442\u044f\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u044b.<\/p>\n<pre><code class=\"rust\">        div()            .id(self.id)            .flex()            .items_center()            .justify_center()            .cursor_pointer()            .rounded_md()            .p_2()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>when_some<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432 \u043d\u0435\u0433\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043b\u0438, \u0435\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430.<\/p>\n<pre><code class=\"rust\">            .when_some(self.modifier, |this, modifier| {                modifier(this)            })            .when_some(self.on_click, |this, on_click| {                this.on_click(move |evt, window, cx| (on_click)(evt, window, cx))            })<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u0435\u0442\u043e\u0434 <code>modifier<\/code> \u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0442\u0438\u043b\u0438 \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043a\u0438, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"rust\">button(    \"some-id\",     ButtonContentType::Text(\"Text\")).style_modifier(move |style| {    style        .w_full()        .h(px(40.0))        .bg(rgb(0x000000))        \/\/ \u0418 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0438\u043b\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u0434\u0430\u0434\u0438\u0442\u0435})<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>child<\/code> \u043d\u0443\u0436\u0435\u043d, \u0434\u0430\u0431\u044b \u0437\u0430\u0434\u0430\u0442\u044c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u0438\u043c\u043d\u0435\u043d\u043d\u043e \u0432 \u043d\u0451\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 UI-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430. \u0415\u0441\u043b\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443, \u0442\u043e \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u043d \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u043c\u0438 \u0441\u0442\u0438\u043b\u044f\u043c\u0438 \u0442\u0435\u043a\u0441\u0442\u0430.<\/p>\n<pre><code class=\"rust\">div()    .child(\"Text\")    .child(        div()    )<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u044f \u0434\u0443\u043c\u0430\u044e, \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u043e, \u0435\u0441\u043b\u0438 \u0434\u043b\u044f <strong><em>\u043e\u0431\u0449\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/em><\/strong> \u0432\u043c\u0435\u0441\u0442\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 <code>new<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0443\u044e \u0444\u0430\u0431\u0440\u0438\u0447\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c UI \u0432 \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u043e\u043c \u0438 \u043e\u0431\u0449\u0435\u043c \u0432\u0438\u0434\u0435, \u043d\u043e \u0438 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c <strong><em>\u043e\u0431\u0449\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/em><\/strong> \u043e\u0442 <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445<\/em><\/strong>.<\/p>\n<pre><code class=\"rust\">pub fn button(id: impl Into&lt;ElementId&gt;, content_type: ButtonContentType) -&gt; Button {    Button {         id: id.into(),        content_type,        on_click: None,        modifier: None    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 ui\/src\/shared\/button.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use gpui::{    SharedString, IntoElement, ElementId, ClickEvent,    Window, App, Stateful, Div, RenderOnce, InteractiveElement,    Styled, StatefulInteractiveElement, ParentElement,    div, svg, px, rgb,    prelude::FluentBuilder};use di::DependencyInjector;use crate::Theme;\/\/\/ Defines the visual and structural payload inside the custom UI button.pub enum ButtonContentType {    Text(SharedString),    Icon(String, f32),}\/\/\/ A highly reusable, composable, and customizable stateful component built on top of GPUI primitives.\/\/\/\/\/\/ It supports fluid functional styling adjustments via custom modifier closures and lifecycle interaction event hooks.#[derive(IntoElement)]pub struct Button {    id: ElementId,    content_type: ButtonContentType,    on_click: Option&lt;Box&lt;dyn Fn(&amp;ClickEvent, &amp;mut Window, &amp;mut App) + 'static&gt;&gt;,    modifier: Option&lt;Box&lt;dyn FnOnce(Stateful&lt;Div&gt;) -&gt; Stateful&lt;Div&gt; + 'static&gt;&gt;}impl Button {    \/\/\/ Registers an asynchronous interaction callback executed whenever the user dispatches a pointer click event.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `on_click` - A closure triggered on execution, mutating the parent frame architecture states.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The updated `Button` builder instance.    pub fn on_click(mut self, on_click: impl Fn(&amp;ClickEvent, &amp;mut Window, &amp;mut App) + 'static) -&gt; Self {        self.on_click = Some(Box::new(on_click));        self    }    \/\/\/ Appends external decorative style overrides onto the baseline layout wrapper tree state.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `modifier` - A closure taking ownership of the existing stateful element, returning the stylized version.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * The updated `Button` builder instance.    pub fn style_modifier(mut self, modifier: impl FnOnce(Stateful&lt;Div&gt;) -&gt; Stateful&lt;Div&gt; + 'static) -&gt; Self {        self.modifier = Some(Box::new(modifier));        self    }}impl RenderOnce for Button {    fn render(self, _window: &amp;mut Window, cx: &amp;mut App) -&gt; impl IntoElement {        let path_manager = cx.global::&lt;DependencyInjector&gt;().path_manager();        let theme = cx.global::&lt;Theme&gt;();        div()            .id(self.id)            .flex()            .items_center()            .justify_center()            .cursor_pointer()            .rounded_md()            .p_2()            .when_some(self.modifier, |this, modifier| {                modifier(this)            })            .when_some(self.on_click, |this, on_click| {                this.on_click(move |evt, window, cx| (on_click)(evt, window, cx))            })            .child(match self.content_type {                ButtonContentType::Text(text) =&gt; div().child(text).into_any_element(),                ButtonContentType::Icon(icon, size) =&gt; {                    let path = path_manager                        .icon_path(&amp;icon)                        .to_string_lossy()                        .into_owned();                    svg()                        .size(px(size))                        .path(path)                        .text_color(rgb(theme.text_color))                        .into_any_element()                },            })    }}\/\/\/ A global functional initialization helper used to generate standalone standard interactive `Button` primitives.\/\/\/\/\/\/ # Arguments\/\/\/\/\/\/ * `id` - A unique identifier token compatible with GPUI element state matching rules.\/\/\/ * `content_type` - The state token describing what information payload the button displays internally.\/\/\/\/\/\/ # Returns\/\/\/\/\/\/ * A baseline configured `Button` component struct instance.pub fn button(id: impl Into&lt;ElementId&gt;, content_type: ButtonContentType) -&gt; Button {    Button {         id: id.into(),        content_type,        on_click: None,        modifier: None    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u0424\u0438\u0447\u0438<\/h3>\n<p>\u041a\u0430\u043a \u0443\u0436\u0435 \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u043d\u0435\u0435, \u043a <strong><em>\u0444\u0438\u0447\u0430\u043c<\/em><\/strong> \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f \u043e\u043a\u043d\u0430, \u044d\u043a\u0440\u0430\u043d\u044b \u0438 \u0442\u0435 UI-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 \u0441\u043b\u043e\u0436\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043c\u0435\u043d\u044f\u0435\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0432\u0438\u0434 \u043f\u0440\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u043d\u0438\u043c. \u041d\u0430\u0441\u0447\u0451\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0433\u043e\u0432\u0440\u0438\u0442\u044c \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435. \u041a \u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0412\u0430\u043c \u043c\u043e\u0433\u043b\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043a \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438 <strong><em>\u0444\u0438\u0447<\/em><\/strong>, \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u0441\u043c\u0435\u043d\u044b \u0442\u0435\u043c\u044b. \u0422\u0430\u043a \u043a\u0430\u043a \u043f\u043e\u043b\u044f \u0442\u0435\u043c\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u0432\u0441\u0435\u0433\u043e \u044d\u043a\u0440\u0430\u043d\u0430, \u0442\u043e \u0434\u0430\u043d\u043d\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c\u0443 \u043a\u043d\u043e\u043f\u043a\u0443, \u043d\u043e \u0438 \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435, \u0432 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0447\u0435\u043c \u0434\u0430\u043d\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c<\/em><\/strong> \u044d\u043a\u0440\u0430\u043d\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0436\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <strong><em>\u0444\u0438\u0447\u0435\u0439<\/em><\/strong>.<\/p>\n<p>\u0412 \u043c\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043e\u0434\u043d\u0430 <strong><em>\u0444\u0438\u0447\u0430<\/em><\/strong> <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u044d\u0442\u043e \u0433\u043b\u0430\u0432\u043d\u044b\u0439, \u0438 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439, \u044d\u043a\u0440\u0430\u043d. \u0415\u0441\u043b\u0438 \u0431\u044b \u044f \u0445\u043e\u0442\u0435\u043b \u0435\u0449\u0451 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442, \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0438\u0441\u043a\u0430, \u0442\u043e \u043f\u0430\u043d\u0435\u043b\u044c \u0441 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u043c \u043f\u043e\u043b\u0435\u043c \u0438 \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u043a\u043d\u043e\u043f\u043e\u043a \u0431\u044b\u043b\u043e \u0431\u044b <strong><em>\u0444\u0438\u0447\u0435\u0439<\/em><\/strong>, \u0442\u0430\u043a \u043a\u0430\u043a \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c \u043f\u043e\u043b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439\u0441\u044f \u0442\u0435\u043a\u0441\u0442, \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0435\u043d\u0434\u043e\u0432. \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 <strong><em>\u0444\u0438\u0447\u0438<\/em><\/strong> \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a\u043e \u0432\u0441\u0435\u043c\u0443 \u044d\u043a\u0440\u0430\u043d\u0443, \u043e\u043d\u0438 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0436\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <strong><em>\u0444\u0438\u0447\u0438<\/em><\/strong>.<\/p>\n<h3>\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/h3>\n<p><strong><em>\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/em><\/strong> \u0434\u043e\u043b\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0441\u0435\u0431\u0435 \u043f\u043e\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b \u0434\u043b\u044f <strong><em>\u0444\u0438\u0447\u0438<\/em><\/strong>, \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u0435\u0439. \u0422\u043e \u0431\u0438\u0448\u044c \u043e\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043e\u0442\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043e \u043e\u0442 UI, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043b\u0438\u0448\u044c \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0438 \u043b\u043e\u0433\u0438\u043a\u0443. <strong><em>\u0412\u0438\u0434<\/em><\/strong> \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 <strong><em>\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/em><\/strong><\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 ui\/src\/features\/main_screen\/state.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use std::sync::Arc;use core::services::StandService;use core::models::StandModel;\/\/\/ Represents the presentation and interactive state container for the main screen.pub struct MainScreenState {    stand_service: Arc&lt;StandService&gt;,    stands: Vec&lt;StandModel&gt;,    selected_stand_name: Option&lt;String&gt;,}impl MainScreenState {    \/\/\/ Constructs a new `MainScreenState`, instantly pre-fetching the available record sets.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `stand_service` - A thread-safe shared reference pointer to the core `StandService` instance.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An initialized state machine payload with no initial selection targeted.    pub fn new(stand_service: Arc&lt;StandService&gt;) -&gt; Self {        let stands = stand_service.get_all();        Self {            stand_service,            stands,            selected_stand_name: None        }    }    \/\/\/ Provides a slice reference of all pre-cached `StandModel` entities.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * A slice sequence containing compiled model payloads.    pub fn stands(&amp;self) -&gt; &amp;[StandModel] {        &amp;self.stands    }    \/\/\/ Exposes a shared reference to the unique identifier string of the currently active selection.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An `Option` reference wrapping the selected target item name key.    pub fn selected_stand_name(&amp;self) -&gt; &amp;Option&lt;String&gt; {        &amp;self.selected_stand_name    }    \/\/\/ Resolves and fetches the full model payload corresponding to the active user selection state identifier.    \/\/\/    \/\/\/ It queries the business service layer dynamically based on the stored text key index.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * `Some(StandModel)` if an identity key is selected and verified by the repository backend, or `None`.    pub fn selected_stand(&amp;self) -&gt; Option&lt;StandModel&gt; {        let selected_name = self.selected_stand_name.clone();        match selected_name {            None =&gt; None,            Some(name) =&gt; match self.stand_service.get_by_name(&amp;name.as_str()) {                None =&gt; None,                Some(stand) =&gt; Some(stand)            }        }    }    \/\/\/ Mutates the selection index parameters to target a new focused record entry point.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `name` - The concrete string name identity token representing the newly focused model item.    pub fn select_stand(&amp;mut self, name: String) {        self.selected_stand_name = Some(name);    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u0412\u0438\u0434<\/h3>\n<p>\u0412\u0438\u0434 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u043f\u043e\u043b\u044f\u043c\u0438 \u0442\u0438\u043f\u043e\u0432 <code>gpui::Entity&lt;SomeState&gt;<\/code> \u0438 <code>gpui::Subscription<\/code>. <code>Entity<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u043e\u0441\u043b\u043e\u0439\u043a\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 <strong><em>\u0432\u0438\u0434\u043e\u043c<\/em><\/strong> \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f <strong><em>\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/em><\/strong>. \u0410 <code>Subscription<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043a\u0435\u043d\u043e\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0441\u0432\u044f\u0437\u044c, \u043f\u043e\u043a\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.<\/p>\n<pre><code class=\"rust\">pub struct MainScreen {    entity: Entity&lt;MainScreenState&gt;,    _subscription: Subscription}impl MainScreen {    pub fn new(entity: Entity&lt;MainScreenState&gt;, cx: &amp;mut Context&lt;Self&gt;) -&gt; Self {        let _subscription = cx.observe(&amp;entity, |_, _, cx| cx.notify());        MainScreen {            entity,            _subscription        }    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>cx.observe()<\/code> \u043a\u0430\u043a \u0440\u0430\u0437 \u0438 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <code>Subscription<\/code>, \u0430 <code>cx.notify()<\/code> \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u0442 <strong><em>\u0432\u0438\u0434<\/em><\/strong>, \u0447\u0442\u043e <code>Entity<\/code> \u0438\u0437\u043c\u0435\u043d\u0451\u043d.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u0442\u043e\u0438\u0442 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c, \u0447\u0442\u043e \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c <code>Entity<\/code> \u0438\u043b\u0438 <strong><em>\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435<\/em><\/strong> \u0432\u043e <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/em><\/strong>, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0438\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u043b\u0438\u0448\u044c \u0441\u0430\u043c <strong><em>\u0432\u0438\u0434<\/em><\/strong>, \u0432\u043e <strong><em>\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/em><\/strong> \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u0430\u043c\u0438 \u043f\u043e\u043b\u044f <strong><em>\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/em><\/strong> \u0438 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u044f \u0441 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u0432 <strong><em>\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/em><\/strong>.<\/p>\n<pre><code class=\"rust\">.child(    Sidebar::new(stands.to_vec(), move |stand_name, _window, cx| {        state_clone.update(cx, |state, _cx| {            state.select_stand(stand_name);         });    }))<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 ui\/src\/features\/main_screen\/view.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use gpui::{    Entity, Subscription, Render, Window, Context,    IntoElement, Styled, ParentElement,    div, rgb};use super::MainScreenState;use super::components::Sidebar;use super::components::StandInfo;use crate::Theme;\/\/\/ The UI view container component representing the main screen.pub struct MainScreen {    entity: Entity&lt;MainScreenState&gt;,    _subscription: Subscription}impl MainScreen {    \/\/\/ Constructs a new `MainScreen` instance and binds a change observation listener.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `entity` - An encapsulated GPUI `Entity` holding the reactive model state data logic.    \/\/\/ * `cx` - A mutable reference to the view's current operational execution context.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An initialized view layout node subscribing to state events.    pub fn new(entity: Entity&lt;MainScreenState&gt;, cx: &amp;mut Context&lt;Self&gt;) -&gt; Self {        let _subscription = cx.observe(&amp;entity, |_, _, cx| cx.notify());        MainScreen {            entity,            _subscription        }    }}impl Render for MainScreen {    fn render(&amp;mut self, _window: &amp;mut Window, cx: &amp;mut Context&lt;Self&gt;) -&gt; impl IntoElement {        let state = self.entity.read(cx);        let stands = state.stands();        let state_clone = self.entity.clone();        let selected_stand = state.selected_stand();        let theme = cx.global::&lt;Theme&gt;();        div()            .size_full()            .flex()            .bg(rgb(theme.background_color))            .text_color(rgb(theme.text_color))            .child(                Sidebar::new(stands.to_vec(), move |stand_name, _window, cx| {                    state_clone.update(cx, |state, _cx| {                        state.select_stand(stand_name);                     });                })            )            .child(                StandInfo::new(selected_stand)            )    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h3>\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/h3>\n<p>\u0412 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u044f \u0431\u0443\u0434\u0443 \u043f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0435 \u043f\u0440\u043e \u0441\u0430\u043c \u043f\u0440\u043e\u0435\u043a\u0442, \u0430 \u0443\u0436\u0435 \u043f\u0440\u043e \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 GPUI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043d\u043e\u044e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0438\u0441\u044c. \u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0441\u0441\u043e\u043c\u0442\u043e\u0440\u0435\u0442\u044c \u0432\u0441\u0451 \u044d\u0442\u043e \u0434\u0435\u043b\u043e \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e, \u0442\u043e \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430.<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u043c\u043e\u043c\u0435\u043d\u0442, \u043a\u043e\u0433\u0434\u0430 \u043f\u044b\u0442\u0430\u043b\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043a\u0440\u043e\u043b\u043b \u0432 GPUI, \u044f \u043d\u0430\u0442\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u043a\u0440\u0435\u0439\u0442 <code>gpui-component<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u0438 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u0430\u043c \u0441\u043a\u0440\u043e\u043b\u043b. \u0412\u043e\u0442 <a href=\"https:\/\/longbridge.github.io\/gpui-component\/\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0430<\/a> \u043d\u0430 \u043d\u0435\u0433\u043e. \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043a\u0440\u043e\u043b\u043b\u0430 \u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b \u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 <code>Stateful&lt;Div&gt;<\/code> \u043c\u0435\u0442\u043e\u0434 <code>overflow_y_scroll()<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u043d\u0433\u0430 \u043f\u043e \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438.<\/p>\n<pre><code class=\"rust\">v_flex()    .id(\"stand_list\")    .overflow_y_scroll()<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c, \u043e \u0447\u0451\u043c \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c, <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> <code>Canvas<\/code>. \u042d\u0442\u043e\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044f\u043c\u0438 \u043d\u0438\u0437\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e\u0439 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438, \u0447\u0442\u043e \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043b\u0435\u043f\u0435\u0441\u0442\u043a\u043e\u0432\u043e\u0439 \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u044b. \u0424\u0443\u043d\u043a\u0446\u0438\u044f <code>canvas<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 <code>Canvas<\/code>, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 2 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u044f: <code>prepaint<\/code> \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438, \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439 \u0438 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439; <code>paint<\/code> \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0443\u0436\u0435 \u0441\u0430\u043c\u043e\u0439 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u043e\u0439.<\/p>\n<pre><code class=\"rust\">canvas(    |bounds: Bounds&lt;Pixels&gt;, window: &amp;mut Window, cx: &amp;mut App| {},    move |bounds: Bounds&lt;Pixels&gt;, _, window: &amp;mut Window, cx: &amp;mut App| {})<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>Bounds<\/code> \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0443\u044e \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432 \u0434\u0432\u0443\u043c\u0435\u0440\u043d\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435, \u0437\u0430\u0434\u0430\u0432\u0430\u0435\u043c\u0443\u044e \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u043e\u0439 \u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c. \u0414\u043e \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043d\u0438\u0433\u0434\u0435 \u043d\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0438 <code>Window<\/code>, \u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0430\u0441\u0442\u0430\u043b \u0435\u0433\u043e \u0447\u0430\u0441, \u0442\u0430\u043a \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>window.paint_path(path, rgb(color))<\/code> \u0440\u0438\u0441\u0443\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u0446\u0432\u0435\u0442\u043e\u043c. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0443\u0442\u0438, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u043a\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 <code>PathBuilder<\/code>. \u041c\u0435\u0442\u043e\u0434 <code>PathBuilder::stroke(px(1.0))<\/code> \u0433\u043e\u0432\u043e\u0440\u0438\u0442, \u0447\u0442\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u043b\u0438\u043d\u0438\u044f\u043c\u0438 \u0448\u0438\u0440\u0438\u043d\u043e\u0439 \u0432 1 \u043f\u0438\u043a\u0441\u0435\u043b\u044c, <code>PathBuilder::fill()<\/code> \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u0447\u0442\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0433\u0440\u0430\u043d\u0438\u0446\u0435\u0439 \u0434\u043b\u044f \u0437\u0430\u043b\u0438\u0442\u043e\u0439 \u0444\u0438\u0433\u0443\u0440\u044b.<\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>move_to(point)<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0442\u043e\u0447\u043a\u0443 \u0432 \u0437\u0430\u0434\u0430\u043d\u043d\u0443\u044e. <code>line_to(point)<\/code> \u0441\u0442\u0440\u043e\u0438\u0442 \u043b\u0438\u043d\u0438\u044e \u043e\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0442\u043e\u0447\u043a\u0438 \u0434\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0439. \u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c, \u043a\u0430\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b\u0430 \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043a\u0440\u044b\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u043e\u0434\u043f\u0443\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <code>builder.close()<\/code>.<\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <code>paint_glyph<\/code>.<\/p>\n<pre><code class=\"rust\">window.paint_glyph(point: Point&lt;Pixels&gt;, font_id: FontId, glyph_id: GlyphId, font_size: Pixels, color: Hsla)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0413\u043b\u0438\u0444 <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0435 \u043e\u0447\u0435\u0440\u0442\u0430\u043d\u0438\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u0430 \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u0441\u0442\u0438\u043b\u044f \u0442\u0435\u043a\u0441\u0442\u0430. \u0422\u0443\u0442 <code>point<\/code> <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u044d\u0442\u043e \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b, \u0433\u0434\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0433\u043b\u0438\u0444, <code>font_id<\/code> <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0448\u0440\u0438\u0444\u0442\u0430, <code>glyph_id<\/code> <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0433\u043b\u0438\u0444\u0430, <code>font_size<\/code> <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u0440\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430, <code>text_color<\/code> <img decoding=\"async\" class=\"formula inline\" source=\"-\" alt=\"-\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg\" width=\"12\" height=\"12\" data-width=\"1.76\" data-height=\"1.505\" data-vertical-align=\"-0.186\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/formulas\/3\/33\/336\/336d5ebc5436534e61d16e63ddfca327.svg 781w\" loading=\"lazy\" decode=\"async\"\/> \u0446\u0432\u0435\u0442 \u0433\u043b\u0438\u0444\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 HSLA.<\/p>\n<h4>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h4>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u0437\u0430\u043f\u0443\u0441\u043a\u0443 \u0432\u0441\u0435\u0433\u043e, \u0447\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043b\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 app\/Cargo.toml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>[package]name = \"app\"version = \"1.2.0\"edition = \"2021\"publish = false[[bin]]name = \"app\"path = \"src\/main.rs\"[dependencies]di.workspace = trueui.workspace = truegpui.workspace = truegpui-component.workspace = trueanyhow.workspace = true<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0440\u0435\u0430\u043b\u043c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u0442 \u0438 \u043a\u044d\u0448\u0438\u0440\u0443\u0435\u0442 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044b. \u042f \u044d\u0442\u0443 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0438\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u0431\u0435\u0437 \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b SVG \u0444\u0430\u0439\u043b\u044b \u043d\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u044e\u0442\u0441\u044f.<\/p>\n<pre><code class=\"rust\">struct Assets;impl AssetSource for Assets {    fn load(&amp;self, path: &amp;str) -&gt; Result&lt;Option&lt;Cow&lt;'static, [u8]&gt;&gt;&gt; {        std::fs::read(path)            .map(Into::into)            .map_err(Into::into)            .map(Some)    }    fn list(&amp;self, _path: &amp;str) -&gt; Result&lt;Vec&lt;SharedString&gt;&gt; {        Ok(vec![])    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <code>Application::new().with_assets(Assets{})<\/code>. \u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 <code>run<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435. \u0412 \u043d\u0451\u043c \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0447\u0435\u0440\u0435\u0437 <code>cx.set_global(global_struct)<\/code>. \u041d\u0430\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u043a \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>cx.open_window()<\/code>, \u0433\u0434\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u0438 \u043e\u043a\u043d\u0430 \u0438 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u044d\u043a\u0440\u0430\u043d.<\/p>\n<pre><code class=\"rust\">fn main() {    let base_dir = std::env::current_dir().unwrap();    let di = DependencyInjector::init(&amp;base_dir).unwrap();    let stand_service = di.stand_service();    Application::new().with_assets(Assets{}).run(move |cx: &amp;mut App| {        cx.set_global(gpui_component::Theme::default());        cx.set_global(di);        cx.set_global(Theme::default());        cx.set_global(Locale::new());        let main_state = cx.new(|_cx| {            MainScreenState::new(stand_service)        });        cx.open_window(            gpui::WindowOptions::default(),            |_, cx| {                cx.new(|cx| {                    MainScreen::new(main_state, cx)                })            },        ).unwrap();    });}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<details class=\"spoiler\">\n<summary>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 app\/src\/main.rs<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use gpui::{    AssetSource, SharedString, Application, App, AppContext};use std::borrow::Cow;use anyhow::Result;use di::DependencyInjector;use ui::{    MainScreenState, MainScreen, Theme, locale::Locale};\/\/\/ An application asset provider responsible for bridging GPUI's resource management layer with external storage locations.struct Assets;impl AssetSource for Assets {    \/\/\/ Dynamically loads a resource binary payload from the local filesystem based on its relative path string.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `path` - A string slice indicating the unique lookup destination route of the target asset.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * `Ok(Some(Cow::Owned))` containing the raw file byte array vector data if found,    \/\/\/   `Ok(None)` if the resource file doesn't exist, or an IO `Err` if a filesystem error occurs.    fn load(&amp;self, path: &amp;str) -&gt; Result&lt;Option&lt;Cow&lt;'static, [u8]&gt;&gt;&gt; {        std::fs::read(path)            .map(Into::into)            .map_err(Into::into)            .map(Some)    }    \/\/\/ Scans a directory path and indexes all nested asset identities inside it.    \/\/\/    \/\/\/ Currently stubbed to return an empty collection since the framework accesses targeted     \/\/\/ media assets explicitly by their exact paths via the `load` method.    \/\/\/    \/\/\/ # Arguments    \/\/\/    \/\/\/ * `_path` - A root directory path token slice where the recursive scanning would begin.    \/\/\/    \/\/\/ # Returns    \/\/\/    \/\/\/ * An empty vector array wrapped in a successful `Result`.    fn list(&amp;self, _path: &amp;str) -&gt; Result&lt;Vec&lt;SharedString&gt;&gt; {        Ok(vec![])    }}fn main() {    let base_dir = std::env::current_dir().unwrap();    let di = DependencyInjector::init(&amp;base_dir).unwrap();    let stand_service = di.stand_service();    Application::new().with_assets(Assets{}).run(move |cx: &amp;mut App| {        cx.set_global(gpui_component::Theme::default());        cx.set_global(di);        cx.set_global(Theme::default());        cx.set_global(Locale::new());        let main_state = cx.new(|_cx| {            MainScreenState::new(stand_service)        });        cx.open_window(            gpui::WindowOptions::default(),            |_, cx| {                cx.new(|cx| {                    MainScreen::new(main_state, cx)                })            },        ).unwrap();    });}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<\/div>\n<\/details>\n<h2>\u0418\u0442\u043e\u0433<\/h2>\n<p>\u041e\u0431\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<pre><code>.\u251c\u2500\u2500 assets\u2502   \u251c\u2500\u2500 data\u2502   \u2502   \u2514\u2500\u2500 jojo-stands.csv\u2502   \u251c\u2500\u2500 icons\u2502   \u2502   \u251c\u2500\u2500 language.svg\u2502   \u2502   \u2514\u2500\u2500 theme.svg\u2502   \u251c\u2500\u2500 images\u2502   \u2502   \u251c\u2500\u2500 'Achtung Baby.png'\u2502   \u2502   \u251c\u2500\u2500 Aerosmith.png\u2502   \u2502   \u251c\u2500\u2500 ...\u2502   \u2514\u2500\u2500 locales\u2502       \u251c\u2500\u2500 en.ftl\u2502       \u2514\u2500\u2500 ru.ftl\u251c\u2500\u2500 Cargo.lock\u251c\u2500\u2500 Cargo.toml\u2514\u2500\u2500 crates    \u251c\u2500\u2500 app    \u2502   \u251c\u2500\u2500 Cargo.toml    \u2502   \u2514\u2500\u2500 src    \u2502       \u2514\u2500\u2500 main.rs    \u251c\u2500\u2500 core    \u2502   \u251c\u2500\u2500 Cargo.toml    \u2502   \u2514\u2500\u2500 src    \u2502       \u251c\u2500\u2500 lib.rs    \u2502       \u251c\u2500\u2500 models    \u2502       \u2502   \u251c\u2500\u2500 mod.rs    \u2502       \u2502   \u2514\u2500\u2500 stand.rs    \u2502       \u251c\u2500\u2500 repositories    \u2502       \u2502   \u251c\u2500\u2500 mod.rs    \u2502       \u2502   \u2514\u2500\u2500 stand.rs    \u2502       \u251c\u2500\u2500 services    \u2502       \u2502   \u251c\u2500\u2500 mod.rs    \u2502       \u2502   \u2514\u2500\u2500 stand.rs    \u2502       \u2514\u2500\u2500 types    \u2502           \u251c\u2500\u2500 mod.rs    \u2502           \u2514\u2500\u2500 rank.rs    \u251c\u2500\u2500 di    \u2502   \u251c\u2500\u2500 Cargo.toml    \u2502   \u2514\u2500\u2500 src    \u2502       \u251c\u2500\u2500 dependency_injector.rs    \u2502       \u2514\u2500\u2500 lib.rs    \u251c\u2500\u2500 infrastructure    \u2502   \u251c\u2500\u2500 Cargo.toml    \u2502   \u2514\u2500\u2500 src    \u2502       \u251c\u2500\u2500 dtos    \u2502       \u2502   \u251c\u2500\u2500 mod.rs    \u2502       \u2502   \u251c\u2500\u2500 rank.rs    \u2502       \u2502   \u2514\u2500\u2500 stand.rs    \u2502       \u251c\u2500\u2500 file    \u2502       \u2502   \u251c\u2500\u2500 mod.rs    \u2502       \u2502   \u2514\u2500\u2500 path_manager.rs    \u2502       \u251c\u2500\u2500 lib.rs    \u2502       \u251c\u2500\u2500 mappers    \u2502       \u2502   \u251c\u2500\u2500 mapper.rs    \u2502       \u2502   \u251c\u2500\u2500 mod.rs    \u2502       \u2502   \u251c\u2500\u2500 rank.rs    \u2502       \u2502   \u2514\u2500\u2500 stand.rs    \u2502       \u2514\u2500\u2500 repositories    \u2502           \u251c\u2500\u2500 csv_stand.rs    \u2502           \u2514\u2500\u2500 mod.rs    \u2514\u2500\u2500 ui        \u251c\u2500\u2500 Cargo.toml        \u2514\u2500\u2500 src            \u251c\u2500\u2500 features            \u2502   \u251c\u2500\u2500 main_screen            \u2502   \u2502   \u251c\u2500\u2500 components            \u2502   \u2502   \u2502   \u251c\u2500\u2500 mod.rs            \u2502   \u2502   \u2502   \u251c\u2500\u2500 sidebar.rs            \u2502   \u2502   \u2502   \u2514\u2500\u2500 stand_info            \u2502   \u2502   \u2502       \u251c\u2500\u2500 components            \u2502   \u2502   \u2502       \u2502   \u251c\u2500\u2500 mod.rs            \u2502   \u2502   \u2502       \u2502   \u251c\u2500\u2500 radar_chart.rs            \u2502   \u2502   \u2502       \u2502   \u2514\u2500\u2500 stand_image.rs            \u2502   \u2502   \u2502       \u251c\u2500\u2500 mod.rs            \u2502   \u2502   \u2502       \u2514\u2500\u2500 stand_info.rs            \u2502   \u2502   \u251c\u2500\u2500 mod.rs            \u2502   \u2502   \u251c\u2500\u2500 state.rs            \u2502   \u2502   \u2514\u2500\u2500 view.rs            \u2502   \u2514\u2500\u2500 mod.rs            \u251c\u2500\u2500 lib.rs            \u251c\u2500\u2500 locale.rs            \u251c\u2500\u2500 shared            \u2502   \u251c\u2500\u2500 button.rs            \u2502   \u2514\u2500\u2500 mod.rs            \u2514\u2500\u2500 theme.rs<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u043e\u0436\u0435\u043c \u0441\u043c\u0435\u043b\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0447\u0435\u0440\u0435\u0437 <code>cargo run<\/code>, \u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443: <\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/a45\/52d\/1b2\/a4552d1b232625b9a89881019282145a.png\" alt=\"\u041e\u043a\u043d\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/\/post_images\/a45\/52d\/1b2\/a4552d1b232625b9a89881019282145a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/\/post_images\/a45\/52d\/1b2\/a4552d1b232625b9a89881019282145a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041e\u043a\u043d\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/figcaption><\/div>\n<\/figure>\n<p>\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0447\u0442\u0435\u043d\u0438\u0435!<\/p>\n<p><a href=\"https:\/\/github.com\/ToniTrum\/JoJo_Stands_Viewer\" rel=\"noopener noreferrer nofollow\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c<\/a><\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1049714\/\">https:\/\/habr.com\/ru\/articles\/1049714\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u0438\u0441\u043b\u043e\u0432\u0438\u0435\u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0441\u0430\u043c\u043e\u0433\u043e \u0438 \u0434\u043b\u044f \u043c\u043e\u0438\u0445 \u0442\u043e\u0432\u0430\u0440\u0438\u0449\u0435\u0439 \u043f\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0437\u0434\u0435\u0441\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043d\u0435 \u043f\u0440\u0435\u0442\u0435\u043d\u0434\u0443\u044e \u043d\u0430 \u0438\u0441\u0442\u0438\u043d\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u0438 \u043a\u0430\u043a \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0443. \u041e\u0434\u043d\u0430\u043a\u043e \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u0434\u043b\u044f \u043c\u043d\u043e\u0433\u0438\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u043b\u043e\u0436\u0438\u0442\u044c \u044d\u0442\u0443 \u0440\u0430\u0431\u043e\u0442\u0443, \u0442\u0435\u043c \u0431\u043e\u043b\u0435\u0435 \u0447\u0442\u043e \u044f \u043d\u0435 \u0441\u043c\u043e\u0433 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442\u044c \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0438\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u043f\u0440\u043e GPUI, \u0434\u0430 \u0438 \u043d\u0430 \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c \u0438\u0445 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e. \u042f \u043e\u0442\u043a\u0440\u044b\u0442 \u043a \u043e\u0442\u0437\u044b\u0432\u0430\u043c, \u0441\u043e\u0432\u0435\u0442\u0430\u043c, \u043a\u0440\u0438\u0442\u0438\u043a\u0435, \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0432\u0430\u0448\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u0435\u0441\u043b\u0438 \u0431\u0443\u0434\u0443\u0442 \u0445\u043e\u0440\u043e\u0448\u0438\u0435 \u0441\u043e\u0432\u0435\u0442\u044b, \u0442\u043e \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c. \u041f\u0440\u0438\u044f\u0442\u043d\u043e\u0433\u043e \u0447\u0442\u0435\u043d\u0438\u044f!\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435GPUI \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0431\u044b\u0441\u0442\u0440\u044b\u043c \u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c UI \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u043d\u0430 Rust c GPU \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435\u043c \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0441\u043e\u0437\u0434\u0430\u0432\u0448\u0438\u0445 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u043a\u043e\u0434\u0430 Zed, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u0430\u043a \u0440\u0430\u0437 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0434\u043b\u044f UI \u0447\u0430\u0441\u0442\u0438. \u0414\u0430\u043d\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0432\u044b\u0448\u0435\u043b \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0433\u043e API \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0439, \u0432\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u0445, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0412\u044b \u043c\u043e\u0433\u043b\u0438 \u043d\u0430\u0442\u043a\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0440\u0430\u0445 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0432 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u043c \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430 \u0431\u043e\u043b\u0435\u0435 \u0441\u0442\u0430\u0440\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438, \u0438\u0437-\u0437\u0430 \u0447\u0435\u0433\u043e \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0435\u0449\u0451 \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u041e\u043d \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0442\u0430\u043a\u0438\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043a\u0430\u043a macOS, Windows, Linux \u0438 FreeBSD. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0432\u0435\u0440\u0441\u0438\u044f 0.2.2.\u0414\u043b\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f GPUI \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 pet-\u043f\u0440\u043e\u0435\u043a\u0442. \u041e\u043d \u0438\u0437 \u0441\u0435\u0431\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043f\u0440\u043e\u0441\u0442\u0443 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u0434\u043e\u0441\u043a\u0443 \u043e \u0441\u0442\u0435\u043d\u0434\u0430\u0445 \u0438\u0437 \u0414\u0436\u043e\u0414\u0436\u043e: \u0438\u043c\u044f, \u0444\u043e\u0442\u043e \u0438 \u043b\u0435\u043f\u0435\u0441\u0442\u043a\u043e\u0432\u0430\u044f \u0434\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u043b\u0438\u0441\u044c \u0432 \u0430\u043d\u0438\u043c\u0435. \u0422\u0430\u043a\u0436\u0435 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0431\u0443\u0434\u0443\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u044b \u0444\u0438\u0447\u0438 \u043f\u043e \u0432\u044b\u0431\u043e\u0440\u0443 \u0442\u0435\u043c\u044b \u0438 \u044f\u0437\u044b\u043a\u0430 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.\u041d\u0438\u0436\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u043f\u043e \u0441\u0430\u043c\u043e\u0439 GPUI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c\u0438:  \u041c\u0438\u043d\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b  \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439  \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f  \u0421\u0431\u043e\u0440\u043d\u0438\u043a \u0440\u0430\u0437\u043d\u044b\u0445 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043f\u043e GPUI, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u043f\u0440\u043e\u0435\u043a\u0442\u044b\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0414\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u044b\u043b\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u0430 \u043b\u0443\u043a\u043e\u0432\u0438\u0447\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430, \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0432\u044b\u0448\u043b\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439:\u251c\u2500\u2500 Cargo.toml                # \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Workspace\u251c\u2500\u2500 assets\/                   # \u0410\u0441\u0441\u0435\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u2502   \u251c\u2500\u2500 data\/                 # \u0411\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445\u2502   \u251c\u2500\u2500 icons\/                # \u0418\u043a\u043e\u043d\u043a\u0438\u2502   \u251c\u2500\u2500 images\/               # \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u2502   \u2514\u2500\u2500 locales\/              # \u0424\u0430\u0439\u043b\u044b \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438\u2514\u2500\u2500 crates\/    \u251c\u2500\u2500 app\/                  # \u0422\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430, \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f GPUI    \u2502   \u2514\u2500\u2500 src\/main.rs    \u251c\u2500\u2500 core\/                 # \u042f\u0434\u0440\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430    \u2502   \u2514\u2500\u2500 src\/    \u2502       \u251c\u2500\u2500 types\/        # \u041e\u0431\u0449\u0438\u0435 \u0442\u0438\u043f\u044b \u0438 enum&#8217;\u044b    \u2502       \u251c\u2500\u2500 models\/       # \u0427\u0438\u0441\u0442\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430    \u2502       \u251c\u2500\u2500 repositories\/ # \u0422\u0440\u0435\u0439\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438    \u2502       \u251c\u2500\u2500 services\/     # \u0421\u0435\u0440\u0432\u0438\u0441\u044b \u0434\u043b\u044f \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438    \u2502       \u2514\u2500\u2500 lib.rs    \u251c\u2500\u2500 infrastructure\/       # \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u0432 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b    \u2502   \u2514\u2500\u2500 src\/    \u2502       \u251c\u2500\u2500 dtos\/         # \u0422\u0440\u0430\u043d\u0441\u0444\u0435\u0440\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0434\u0430\u043d\u043d\u044b\u0445    \u2502       \u251c\u2500\u2500 mappers\/      # \u041f\u0435\u0440\u0435\u0432\u043e\u0434\u044b \u043c\u0435\u0436\u0434\u0443 DTO \u0438 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438    \u2502       \u251c\u2500\u2500 repositories\/ # \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432    \u2502       \u251c\u2500\u2500 file\/         # \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438    \u2502       \u2514\u2500\u2500 lib.rs    \u251c\u2500\u2500 di\/                   # \u0412\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439     \u2502   \u2514\u2500\u2500 src\/    \u2502       \u251c\u2500\u2500 dependency_injector.rs    \u2502       \u2514\u2500\u2500 lib.rs    \u2514\u2500\u2500 ui\/                   # UI \u0441\u043b\u043e\u0439        \u2514\u2500\u2500 src\/            \u251c\u2500\u2500 shared\/   # \u041e\u0431\u0449\u0438\u0435 UI-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b            \u251c\u2500\u2500 features\/     # \u0411\u043e\u043b\u044c\u0448\u0438\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0438\u0447\u0438, \u044d\u043a\u0440\u0430\u043d\u044b, \u043e\u043a\u043d\u0430            \u251c\u2500\u2500 locale.rs     # \u041c\u0435\u043d\u0435\u0434\u0436\u0435\u0440 \u043b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438            \u251c\u2500\u2500 theme.rs      # \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0442\u0435\u043c \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u044f            \u2514\u2500\u2500 lib.rs\u041b\u0443\u043a\u043e\u0432\u0438\u0447\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u0432\u0438\u0434\u043e\u0432 \u043c\u043d\u043e\u0433\u043e\u0441\u043b\u043e\u0439\u043d\u043e\u0439 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0442\u0430\u043a\u0436\u0435 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u0447\u0438\u0441\u0442\u0430\u044f \u0438 \u0433\u0435\u043a\u0441\u0430\u0433\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f. \u041f\u0440\u0438\u043d\u0446\u0438\u043f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0438 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u0432 \u043d\u0438\u0445 \u0432\u043e \u0432\u0441\u0435\u0445 \u0441\u0445\u043e\u0436\u0438, \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u0438\u0445 \u043f\u0440\u0430\u0432\u0438\u043b.\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u043a\u0430\u043a \u0443\u0436\u0435 \u0441\u0442\u0430\u043b\u0430 \u044f\u0441\u043d\u043e \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u043b\u043e\u0451\u0432, \u0433\u0434\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0441\u043b\u043e\u0451\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 \u043d\u0435\u0433\u043e, \u043e\u0434\u043d\u0430\u043a\u043e \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043e \u0441\u043b\u043e\u0435, \u0432\u043d\u0435\u0448\u043d\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0433\u043e. \u0412 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0412\u044b \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0441\u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0435 \u0438 \u0442\u043e\u0447\u043d\u044b\u0435, \u0447\u0435\u043c \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043f\u0440\u043e\u0439\u0434\u0443\u0441\u044c \u043b\u0438\u0448\u044c \u0432\u0441\u043a\u043e\u043b\u044c\u0437\u044c.\u042f\u0434\u0440\u043e\u0412 \u044f\u0434\u0440\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430 \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u044d\u0442\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 UI \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u042f\u0434\u0440\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u043c \u0441\u043b\u043e\u0435\u043c, \u0432\u043e\u043a\u0440\u0443\u0433 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0441\u0442\u0440\u043e\u044f\u0442\u0441\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0441\u043b\u043e\u0438. \u0420\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u0438\u0437 \u0447\u0435\u0433\u043e \u043e\u043d \u0441\u043e\u0441\u0442\u043e\u0438\u0442.\u041c\u043e\u0434\u0435\u043b\u0438\u041c\u043e\u0434\u0435\u043b\u044c (\u0438\u043b\u0438 \u0436\u0435 \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044c) \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043b\u0438\u0448\u044c \u043f\u043e\u043b\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u043d\u0430 \u043d\u0435\u0441\u0451\u0442, \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u044d\u0442\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438. \u0414\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u0441\u044f, \u043d\u0435 \u0437\u043d\u0430\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043e \u0432\u043d\u0435\u0448\u043d\u0435\u043c \u0441\u043b\u043e\u0435, \u0434\u0430\u0436\u0435 \u043e \u0442\u043e\u043c, \u043e\u0442\u043a\u0443\u0434\u0430 \u0431\u0435\u0440\u0443\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0435\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f. \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0433\u043e \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f types, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0442\u0438\u043f\u044b \u0438 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f, \u043f\u0440\u0438\u0437\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0432 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0435.\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0432 \u044f\u0434\u0440\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0442\u0440\u0435\u0439\u0442\u043e\u043c (\u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u043a\u0430\u043a\u0438\u0435 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0438 \u0441 \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u0445 \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u0438 \u0442\u043e\u043c\u0443 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435.\u0421\u0435\u0440\u0432\u0438\u0441\u044b\u0421\u0435\u0440\u0432\u0438\u0441\u044b \u0432 \u044f\u0434\u0440\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u0441\u043b\u043e\u0435\u043c, \u0438\u043c\u0435\u043d\u043d\u043e \u0441 \u043d\u0438\u043c\u0438 UI \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043d\u0443\u0436\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438 \u043a\u0430\u043a \u0443\u0436\u0435 \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0441\u0435\u0440\u0432\u0438\u0441, \u043e\u0431\u0449\u0430\u044f\u0441\u044c \u0441 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u043c, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434\u044b \u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u043b\u043e\u0451\u0432 \u0441 \u044f\u0434\u0440\u043e\u043c.\u0418\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u0414\u0430\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u0442\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0434\u043b\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u044f \u0438 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432.DTODTO (Data Transfer Object)  \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u0441\u0443\u0442 \u0432 \u0441\u0435\u0431\u0435 \u043b\u0438\u0448\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438\u0437 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u043b\u0443\u0436\u0430\u0442 \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u044d\u0442\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u0432. \u041e\u043d\u0438 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043e\u0431\u043b\u0430\u0434\u0430\u044e\u0442 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0434\u0435\u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.\u041c\u0430\u043f\u043f\u0435\u0440\u044b\u041c\u0430\u043f\u043f\u0435\u0440 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0449\u0438\u043c \u043b\u0438\u0448\u044c 2 \u0437\u0430\u0434\u0430\u0447\u0438  \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 DTO \u0432 \u043c\u043e\u0434\u0435\u043b\u044c \u0438 \u043e\u0431\u0440\u0430\u0442\u043d\u043e.\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438\u0418\u043c\u0435\u043d\u043d\u043e \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0440\u0435\u0439\u0442\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0438\u0437 \u044f\u0434\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d\u0430 \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0440\u0435\u0439\u0442\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0435\u0432 \u0432 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435, \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a \u0440\u0430\u0437\u043d\u044b\u043c \u0431\u0430\u0437\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0445.\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b\u0412 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0435 \u0437\u0430 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0445 (\u0411\u0414, \u0444\u0430\u0439\u043b\u044b, API \u0438 \u0442\u0434.), \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 (Gateway, API \u043a\u043b\u0438\u0435\u043d\u0442 \u0438 \u0442\u0434.), \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u0435\u0439 \u0438 \u043f\u0440\u043e\u0447\u0435\u0433\u043e \u0440\u043e\u0434\u0430 \u0430\u0434\u0430\u043f\u0442\u0435\u0440\u043e\u0432. \u0412 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u043c\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u0442\u0430\u043a\u043e\u0439 \u0441\u043b\u043e\u0439 file, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0444\u0430\u0439\u043b\u0430\u043c\u0438.DIDI (Dependency Injection) \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0438\u0437\u0432\u043d\u0435. \u0412\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u044f\u0437\u044b\u043a\u0430\u0445 \u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445 DI \u043e\u0431\u044b\u0447\u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0438 \u0448\u0438\u0440\u043e\u043a\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u0432 \u043c\u043e\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043e\u043d \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0449\u0435, \u0442\u0430\u043a \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u043b\u0438\u0448\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0438\u043c.UI\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c \u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043b\u043e\u0435\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 UI \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0412\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 \u0434\u043b\u044f \u0441\u043b\u043e\u044f \u043f\u0440\u0435\u0437\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0438\u0437 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u043e\u043c \u0441\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u0430 MV* (MVC, MVP, MVVM), \u043e\u0434\u043d\u0430\u043a\u043e \u0434\u043b\u044f GPUI \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u043d\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434. \u041c\u043d\u0435 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e, \u0435\u0441\u0442\u044c \u043b\u0438 \u0443 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u043a\u0430\u043a\u043e\u0435-\u0442\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u0430\u043b \u0435\u043c\u0443 \u0441\u0432\u043e\u0439 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435: State-Entity-View. \u0427\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u044e \u0435\u0451 \u0441\u0443\u0442\u044c, \u0441\u0435\u0439\u0447\u0430\u0441 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b \u0434\u043b\u044f \u043f\u0440\u043e\u0435\u043a\u0442.\u0422\u0435\u043c\u0430\u0412 theme.rs \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0435\u043c\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0414\u0430\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 UI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0446\u0432\u0435\u0442, \u043e\u0442\u0441\u0442\u0443\u043f\u044b \u0438 \u0442\u0434, \u043d\u043e \u0438 \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0442\u0435\u043c, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0434\u043b\u044f \u0438\u0445 \u0441\u043c\u0435\u043d\u044b.\u041b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f\u0412 locale.rs \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u043c\u0438 \u043f\u0430\u043a\u0435\u0442\u0430\u043c\u0438, \u0432 \u043c\u043e\u0451\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u044b\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b ftl (Fluent Translation List). \u041e\u043d\u0430 \u0445\u0440\u0430\u043d\u0438\u0442 \u0432 \u0441\u0435\u0431\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u044f\u0437\u044b\u043a \u0438 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u043d\u0443\u0436\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u044b \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0432 UI.\u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 shared \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c\u0441\u044f \u0442\u0435 UI \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u044b \u0432 \u0440\u0430\u0437\u043d\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445, \u044d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043e\u0431\u0449\u0438\u043c\u0438.\u0424\u0438\u0447\u0438\u0421\u0430\u043c\u044b\u043c \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u043f\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f features. \u042f \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b \u0440\u044f\u0434 \u043f\u0440\u0430\u0432\u0438\u043b \u043f\u043e \u0435\u0451 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u043e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0432 \u043a\u0440\u0443\u043f\u043d\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u0441\u0438\u043b\u044c\u043d\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438 \u0438 \u0438\u0437\u043b\u0438\u0448\u043d\u0438\u043c\u0438 \u0434\u043b\u044f \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430.\u041d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u043b\u043e\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 features \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u044d\u043a\u0440\u0430\u043d, \u043e\u043a\u043d\u043e \u0438\u043b\u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 \u0441\u043b\u043e\u0436\u043d\u0443\u044e \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f, \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0435\u0435 \u043e\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u042d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0444\u0438\u0447\u0430\u043c\u0438. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0437 \u044d\u0442\u0438\u0445 \u0444\u0438\u0447 \u0441\u0442\u0440\u043e\u0438\u0442\u0441\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430:specific_feature\/             # \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0444\u0438\u0447\u0430\u251c\u2500\u2500 components\/               # \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0444\u0438\u0447\u0438\u251c\u2500\u2500 state.rs                  # \u041b\u043e\u0433\u0438\u043a\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c\u251c\u2500\u2500 view.rs                   # \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0444\u0438\u0447\u0438\u2514\u2500\u2500 mod.rs\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u043e\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0442\u0435 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 UI \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043b\u043e\u0433\u0438\u043a\u0430 \u0434\u043b\u044f \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439 \u0441 \u043d\u0438\u043c\u0438.\u0412\u0438\u0434\u0417\u0434\u0435\u0441\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u043f\u043e\u043b\u044f \u0442\u0438\u043f\u043e\u0432 gpui::Entity&lt;SpecificFeatureState&gt; \u0438 Subscription \u0438 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u0442\u0440\u0435\u0439\u0442 Render.\u0422\u0438\u043f gpui::Entity&lt;T&gt; \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u0441\u0438\u043b\u044c\u043d\u044b\u0439, \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f GPUI \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0438 \u043f\u0440\u0438\u043d\u044f\u0442\u0438\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439. \u0422\u0438\u043f Subscription, \u043a\u0430\u043a \u044f\u0441\u043d\u043e \u0438\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u043e\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u0430\u044f GPUI. \u0422\u0440\u0435\u0439\u0442 Render \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 render, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0438\u0441\u0443\u0435\u0442 view \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 specific_feature\/components \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u043b\u0438\u0441\u044c \u0442\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432 specific_feature, \u044d\u0442\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u043c\u0438. \u0414\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430:components\/\u251c\u2500\u2500 multiple_component_1\/\u251c\u2500\u2500 multiple_component_2\/\u251c\u2500\u2500 &#8230;\u251c\u2500\u2500 single_component_1.rs\u251c\u2500\u2500 single_component_2.rs\u251c\u2500\u2500 &#8230;\u2514\u2500\u2500 mod.rs\u0417\u0434\u0435\u0441\u044c single_component_*.rs \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u044e\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0430\u043a\u0440\u043e\u0441 IntoElement. \u0414\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d \u0442\u0440\u0435\u0439\u0442 RenderOnce, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u043d\u0435\u0434\u043e\u043b\u0433\u043e\u0436\u0438\u0432\u0443\u0449\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442.\u0414\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 multiple_component_* \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0442\u0435\u0445 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0430\u043c\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u0441\u0435\u0431\u044f \u0435\u0449\u0451 \u0441\u043b\u043e\u0439 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u044d\u0442\u0438\u0445 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0439 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f:multiple_component_*\/\u251c\u2500\u2500 components\/\u251c\u2500\u2500 multiple_component_*.rs\u2514\u2500\u2500 mod.rs\u0417\u0434\u0435\u0441\u044c multiple_component_*.rs \u043f\u043e\u0434\u043e\u0431\u043d\u043e single_component_*.rs \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 IntoElement \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441 \u0442\u0435\u043c \u043b\u0438\u0448\u044c \u043e\u0442\u043b\u0438\u0447\u0438\u0435\u043c, \u0447\u0442\u043e \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u0441\u0430\u043c\u043e\u0433\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0441\u0432\u043e\u0438 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b 2-\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-484321","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484321","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=484321"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/484321\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=484321"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=484321"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=484321"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}