{"id":320054,"date":"2021-03-22T15:01:10","date_gmt":"2021-03-22T15:01:10","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=320054"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=320054","title":{"rendered":"\u041f\u043e\u0433\u0440\u0443\u0436\u0435\u043d\u0438\u0435 \u0432 JetBrains Space Applicaitons"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440.<\/p>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e JetBrains \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043b\u0438 \u0441\u0432\u043e\u0439 \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c<a href=\"https:\/\/jetbrains.com\/space\" rel=\"noopener noreferrer nofollow\"> <u>Space<\/u><\/a>, \u043e \u0447\u0435\u043c \u0431\u044b\u043b \u0441\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439<a href=\"https:\/\/habr.com\/en\/company\/jetbrains\/blog\/478866\/\" rel=\"noopener noreferrer nofollow\"> <u>\u043f\u043e\u0441\u0442 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435<\/u><\/a>. \u041f\u0440\u043e\u0448\u043b\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u0443\u0436\u0435 \u043f\u043e\u0440\u0430 \u0431\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0435\u0433\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u043a \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0435\u0447\u044c \u043f\u043e\u0439\u0434\u0435\u0442 \u043e<a href=\"https:\/\/www.jetbrains.com\/help\/space\/applications.html\" rel=\"noopener noreferrer nofollow\"> <u>Space Applications<\/u><\/a>.<\/p>\n<p>Space Applications &#8212; \u044d\u0442\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0435\u0439. Applications \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0435\u0451 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 Space. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 &#8212; Application \u043d\u0435\u043b\u044c\u0437\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f Space. \u0414\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043c\u0435\u0436\u0434\u0443 Space \u0438 Application \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0439 Endpoint, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c Endpoint URI &#8212; \u0430\u0434\u0440\u0435\u0441 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 Space \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Space HTTP API.<\/p>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0438\u0434\u043e\u0432 Applications:<\/p>\n<h4>Chatbot<\/h4>\n<figure class=\"float full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/675\/429\/733\/675429733c3afe43898bfb2b2cf96186.png\" width=\"889\" height=\"750\"><figcaption><\/figcaption><\/figure>\n<p>C\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0447\u0430\u0442\u0431\u043e\u0442, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u043c \u0441 \u043d\u0438\u043c \u0447\u0430\u0442\u0435. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u0441\u0442\u0443\u043f\u0430\u0435\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Telegram. \u041d\u0435\u043b\u044c\u0437\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u043e\u0442\u0430 \u0432 \u043a\u0430\u043d\u0430\u043b (\u0433\u0440\u0443\u043f\u043f\u043e\u0432\u043e\u0439 \u0447\u0430\u0442), \u0430 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u043e\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043d\u043e\u043f\u043a\u0438.  <\/p>\n<\/p>\n<h4>Slash commands<\/h4>\n<figure class=\"float full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/24a\/cbe\/fc5\/24acbefc572753015688f713e28b1e32.png\" alt=\"\" title=\"\" width=\"882\" height=\"317\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u0430\u043d\u0430\u043b\u0430 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0434\u0430\u043d\u044b \u0440\u0430\u0437\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0438 \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 &#171;\/&#187;, \u0435\u043c\u0443 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0447\u0430\u0442\u0431\u043e\u0442\u043e\u0432.    <\/p>\n<h4>Client applications<\/h4>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b Space, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0442 \u043d\u0435\u0433\u043e \u0440\u0430\u0437\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438\u043b\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438 \u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c\/\u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0442\u044c issues, \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043e\u0441\u0442\u044b \u0432 \u043a\u0430\u043d\u0430\u043b \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435.<\/p>\n<\/p>\n<h4>Custom menus<\/h4>\n<figure class=\"float full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/853\/054\/8be\/8530548be574f98f6e604b3b445cdc69.png\" width=\"1007\" height=\"503\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u0435\u043d\u044e \u043d\u043e\u0432\u044b\u043c\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 api \u0434\u043b\u044f \u043d\u0438\u0445 \u0435\u0449\u0435 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d.<\/p>\n<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0438\u043f\u043e\u0432 Applications. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0431\u043e\u0442\u0430, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u043a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0431\u0438\u043b\u0434\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 CI\/CD \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0435\u0440\u043d\u0435\u0442\u0441\u044f \u0432 \u043e\u0431\u0449\u0438\u0439 \u043a\u0430\u043d\u0430\u043b.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 Application \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c. \u0414\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 Administration menu. \u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u043c\u0438 \u043f\u0440\u0430\u0432\u0430\u043c\u0438 \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043b\u0430\u0434\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u043b\u043e \u0434\u043e\u0441\u0442\u0443\u043f \u0442\u043e\u043b\u044c\u043a\u043e \u043a \u0442\u0435\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043c\u0438 \u044f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u044b.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/738\/e1d\/c3b\/738e1dc3b0a8cf093895aa45935c4267.png\" width=\"1076\" height=\"378\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432 \u0442\u0430\u0431\u0435 Authentication \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 Authentication flows, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0438\u043f\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u0440\u0430\u0442\u043a\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a:<\/p>\n<ul>\n<li>\n<p>Client Credentials Flow &#8212; \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 client id \u0438 client secret. \u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043e\u0442 \u0441\u0432\u043e\u0435\u0433\u043e \u043b\u0438\u0446\u0430 \u0438 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>Authorization Code Flow &#8212; \u043b\u043e\u0433\u0438\u043d\u0438\u043c\u0441\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 Space, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u043e\u0434 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0447\u0442\u043e\u0431\u044b \u0438\u0437 \u043d\u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043e\u0442 \u043b\u0438\u0446\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.  <\/p>\n<\/li>\n<li>\n<p>Implicit Flow &#8212; \u0438\u0434\u0435\u044f \u0442\u0430\u0436\u0435, \u0447\u0442\u043e \u0438 Authorization Code Flow, \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430.<\/p>\n<\/li>\n<\/ul>\n<h2>Client application<\/h2>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b Space, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0440\u0430\u0437\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e: \u043a\u0430\u043d\u0430\u043b\u044b, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438, \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u0438 \u0442.\u0434.&nbsp;<\/p>\n<details class=\"spoiler\">\n<summary>build.gradle.kts<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">repositories {     mavenCentral()     maven(\"https:\/\/kotlin.bintray.com\/kotlinx\")     maven(\"https:\/\/maven.pkg.jetbrains.space\/public\/p\/space\/maven\") }  dependencies {     implementation(kotlin(\"stdlib\"))      \/\/ Space api sdk     \/\/ https:\/\/www.jetbrains.com\/help\/space\/space-sdk.html     val space_version = \"61400-beta\"     implementation(\"org.jetbrains:space-sdk-jvm:$space_version\")      \/\/ Ktor (http client)     \/\/ https:\/\/github.com\/ktorio\/ktor     val ktor_version = \"1.4.3\"     implementation(\"io.ktor:ktor-client-core:$ktor_version\")     implementation(\"io.ktor:ktor-client-core-jvm:$ktor_version\")     implementation(\"io.ktor:ktor-client-cio:$ktor_version\") } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Client Credentials Flow:<\/p>\n<pre><code class=\"kotlin\">private const val spaceInstanceUrl = \"https:\/\/makentoshe.jetbrains.space\"  val spaceClient = SpaceHttpClient(HttpClient(CIO)).withServiceAccountTokenSource(     ClientCredentialsFlow.clientId, ClientCredentialsFlow.clientSecret, spaceInstanceUrl )  object ClientCredentialsFlow {      const val clientId: String = TODO(\u201cPut your client_id here\u201d)      const val clientSecret: String = TODO(\u201cPut your client_secret here\u201d)  } <\/code><\/pre>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<pre><code class=\"kotlin\">\/\/ There are some examples of retrieving several data from the Space instance. \/\/ We can process this info as we want - create analytics, office dashboards, and so on. fun main() = runBlocking {     val channels = spaceClient.chats.channels.listAllChannels(\"\").data     println(\"Channels: ${channels.map { \"${it.name}(${it.channelId})\" }}\")      \/\/ View application rights allows to see all applications     \/\/ If rights were not accepted - the application can see only itself.     val applications = spaceClient.applications.getAllApplications(\"\")     println(\"Applications: ${applications.map { \"${it.name}(${it.id})\" }}\")      \/\/ Works only with View member profile rights     val profiles = spaceClient.teamDirectory.profiles.getAllProfiles().data     println(\"Profiles: ${profiles.map { \"${it.username}(${it.id})\" }}\")      \/\/ Works only with View project parameters rights     \/\/ These rights can be managed for selected projects or for whole projects at one time.     val projects = spaceClient.projects.getAllProjects().data     println(\"Projects: ${projects.map { \"${it.name}(${it.id})\" }}\")                  \/\/ Works only with Project Issues: View issues rights     val issues = projects.firstOrNull()?.let { getProjectIssues(it) }     println(\"Issues: ${issues?.map { \"${it.title}(${it.id})\" }} \") }  private suspend fun getProjectIssues(project: PR_Project): List&lt;Issue&gt; {     return spaceClient.projects.planning.issues.getAllIssues(         project = ProjectIdentifier.Id(project.id),         assigneeId = emptyList(),         statuses = emptyList(),         sorting = IssuesSorting.CREATED,         descending = true     ).data } <\/code><\/pre>\n<details class=\"spoiler\">\n<summary>Output<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>Channels: [Booruchan(4UHs4I3yyno1), general(10xDLp0yqy4w), Habrachan(4HyHLw3SnO9Y), Sipichan(15A2hA1RpAsp)] Applications: [client(2czEkY3AIaV0), chatbot(d3Q8Z0UeVCF)] Profiles: [Makentoshe(2iqI4p3gzufl)] Projects: [Booruchan(qN0K31awqo6), Habrachan(1tJHqn2A76Yf), Sipichan(35BreB35gvdA)] Issues: [Add custom Run Configuration and support ngrok startup(3S09oT4JHvpC), Add Client template for Space plugin with Gradle (atQRe1SIklB), Add Blank template for Space application plugin support for Gradle(4REln04HAo5k)]<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0430\u0432 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c\u0441\u044f. \u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 .data. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 Batch, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u0438 \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043d\u0430\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043b\u044e\u0447 \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u043d\u0430\u0431\u043e\u0440\u0443, \u0438 \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u041f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u0441\u0442\u043e\u0438\u0442 \u044d\u0442\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c, \u043e\u0434\u043d\u0430\u043a\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044f \u043e\u043f\u0443\u0449\u0435\u043d\u0430.<\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u0430 <a href=\"https:\/\/github.com\/Makentoshe\/sipichan-client\" rel=\"noopener noreferrer nofollow\">github <\/a>\u0438 \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f.<\/p>\n<h2>Chatbot + slash command application<\/h2>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 Applications, \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u043c\u0438, \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438. \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0445\u043e\u0441\u0442\u0438\u0442\u044c\u0441\u044f \u043d\u0430\u0448 \u0431\u043e\u0442. \u041c\u044b \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 HTTP \u043a\u043b\u0438\u0435\u043d\u0442 Ktor, \u0442\u0430\u043a \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0430 \u043d\u0435\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0434\u043b\u044f Ktor \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0443\u0449\u0435\u043d\u043e, \u043d\u043e \u0435\u0441\u0442\u044c<a href=\"https:\/\/ktor.io\/docs\/a-ktor-application.html\" rel=\"noopener noreferrer nofollow\"> <u>\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/u><\/a>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0435\u0440\u0435\u0442\u044c\u0441\u044f.<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u043e\u0434\u043d\u0438\u043c\u0435\u043c \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0435\u0433\u043e URL, \u0447\u0442\u043e\u0431\u044b Space \u043c\u043e\u0433 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u041f\u043e\u043a\u0443\u043f\u0430\u0442\u044c \u0445\u043e\u0441\u0442, \u0438\u043b\u0438 \u0438\u0441\u043a\u0430\u0442\u044c \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u043d\u0435 \u043a\u043e\u043c\u0438\u043b\u044c\u0444\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043f\u043e\u0439\u0434\u0435\u043c \u043e\u0431\u0445\u043e\u0434\u043d\u044b\u043c \u043f\u0443\u0442\u0435\u043c &#8212; \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0443\u043d\u043d\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441. \u0412 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f ngrok, \u043e\u0434\u043d\u0430\u043a\u043e \u043b\u0438\u0447\u043d\u043e \u044f \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e localtunnel, \u0438\u0437-\u0437\u0430 \u0435\u0433\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441.<\/p>\n<pre><code class=\"bash\">\/\/ localtunnel npx localtunnel --port 8080 --subdomain makentoshe \/\/ ngrok ngrok http 8080<\/code><\/pre>\n<p>\u0412 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c URL &#8212; \u044d\u0442\u043e \u043a\u0430\u043a \u0440\u0430\u0437 \u0442\u043e, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e.<\/p>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 Applications \u0432 \u043d\u0430\u0448\u0435\u043c Space. \u0412 \u0442\u0430\u0431\u0435 Endpoint \u0432 \u043f\u043e\u043b\u0435 Endpoint URI \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0430\u0448 url. \u0414\u043b\u044f \u043c\u0435\u043d\u044f \u044d\u0442\u043e <code>https:\/\/makentoshe.loca.lt\/api\/chatbot<\/code>. \u041f\u0440\u043e \u0442\u043e, \u0437\u0430\u0447\u0435\u043c \u043d\u0443\u0436\u0435\u043d <code>\/api\/chatbot<\/code> \u0431\u0443\u0434\u0435\u0442 \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/426\/2e5\/d2b\/4262e5d2bb640325094d2ebc92e9e450.png\" width=\"1453\" height=\"815\"><figcaption><\/figcaption><\/figure>\n<p>\u0412 \u0442\u043e\u043c \u0436\u0435 \u0442\u0430\u0431\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0432\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0432\u0435\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b:  <\/p>\n<ul>\n<li>\n<p>Verification token &#8212; \u044d\u0442\u043e\u0442 \u0442\u043e\u043a\u0435\u043d \u043a\u043b\u0430\u0434\u0435\u0442\u0441\u044f \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0442 Space. \u041d\u0430\u043c \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u044d\u0442\u0438 \u0442\u043e\u043a\u0435\u043d\u044b, \u0438 \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442 &#8212; \u043c\u044b \u043e\u0431\u0449\u0430\u0435\u043c\u0441\u044f \u0441 \u043d\u0430\u0448\u0438\u043c Space. <\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440 \u043e\u0442\u0432\u0435\u0442\u0430 \u0441 Verification token<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">{       \"className\": \"ListCommandsPayload\",       \"accessToken\": \"\",       \"verificationToken\": \"d415ca5965b37f4f0cac59fd33de7b94e396284e897d0fb8a070d0a5e1b7f2d3\",       \"userId\": \"2kawvQ4F6GM6\" }<\/code><\/pre>\n<\/div>\n<\/details>\n<ul>\n<li>\n<p>Signing key &#8212; \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u043c\u0435\u0442\u043e\u0434. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0445\u0435\u0448, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043b\u0430\u0434\u0435\u0442\u0441\u044f \u0432 \u0435\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a. \u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0445\u0435\u0448, \u0438 \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442 &#8212; \u0432\u0441\u0435 \u043e\u043a. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0431 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0435 &#8212; <a href=\"https:\/\/www.jetbrains.com\/help\/space\/verify-space-in-application.html#verifying-requests-using-a-signing-key\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440 \u043e\u0442\u0432\u0435\u0442\u0430 \u0441 Signing key<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>POST \/api\/chatbot HTTP\/1.1 Host: 12345abcdef.ngrok.io User-Agent: Space (61355) Ktor http-client Content-Length: 163 Accept: *\/* Accept-Charset: UTF-8 Content-Type: application\/json X-Forwarded-For: 123.456.123.456 X-Forwarded-Proto: https X-Space-Signature: 2aa8cba6217a28686de0ca8dcfe2a1d0795e343d744a0c5307308e43777593a5 X-Space-Timestamp: 1607623492912 Accept-Encoding: gzip  {\"className\":\"ListCommandsPayload\",\"accessToken\":\"\",\"verificationToken\":\"d415ca5965b37f4f0cac59fd33de7b94e396284e897d0fb8a070d0a5e1b7f2d3\",\"userId\":\"2kawvQ4F6GM6\"}<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u044b \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u043e\u0431\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0438 \u0431\u0443\u0434\u0435\u043c \u0441\u0432\u0435\u0440\u044f\u0442\u044c \u0438 \u0445\u0435\u0448\u0438, \u0438 \u0442\u043e\u043a\u0435\u043d\u044b.<\/p>\n<pre><code class=\"kotlin\">object Endpoint {      const val verificationToken: String = TODO(\"Place your verification_token\")     const val signingKey: String = TODO(\"Place your signing_key\")      fun verify(payload: ApplicationPayload): Boolean {         return payload.verifyWithToken(verificationToken)     }      fun verify(timestamp: String, signature: String, body: String): Boolean {         val hmacSha256 = Mac.getInstance(\"HmacSHA256\")         hmacSha256.init(SecretKeySpec(signingKey.toByteArray(), \"HmacSHA256\"))         val hash = hmacSha256.doFinal(\"$timestamp:$body\".toByteArray()).toHexString()         return hash == signature     }      private fun ByteArray.toHexString() = joinToString(\"\") { (0xFF and it.toInt()).toString(16).padStart(2, '0') } }  <\/code><\/pre>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c Routing. \u042d\u0442\u043e \u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 Endpoint \u0434\u043b\u044f Space, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u043c\u0443 \u0431\u043e\u0442\u0443.<\/p>\n<pre><code class=\"kotlin\">@Suppress(\"unused\") \/\/ Referenced in application.conf @kotlin.jvm.JvmOverloads fun Application.module(testing: Boolean = false) {     install(Routing) {         chatbot()     } }  fun Routing.chatbot() {     post(\"api\/chatbot\") {         val receiveBody = call.receiveText()          val timestamp = call.request.headers[\"x-space-timestamp\"]             ?: return@post call.respond(HttpStatusCode.BadRequest)         val signature = call.request.headers[\"x-space-signature\"]             ?: return@post call.respond(HttpStatusCode.BadRequest)         if (!Endpoint.verify(timestamp, signature, receiveBody)) {             return@post call.respond(HttpStatusCode.Unauthorized)         }          val payload = readPayload(receiveBody)         if (!Endpoint.verify(payload)) {             return@post call.respond(HttpStatusCode.Unauthorized)         } \t\t\t\t         try {             processChatbotPayload(payload)         } catch (unknownCommand: IllegalStateException) {             LoggerFactory.getLogger(\"Chatbot\").error(unknownCommand.message)         }      } } <\/code><\/pre>\n<p>\u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043f\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0430\u0434\u0440\u0435\u0441\u0443, \u043f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u0438\u0448\u0435\u043b \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0442 \u043d\u0430\u0448\u0435\u0433\u043e Space. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a &#8212; \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c 401 Unauthorized.<\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0431\u043e\u0442\u0443 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 payload. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 5 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0439 ApplicationPayload:<\/p>\n<ul>\n<li>\n<p>MessagePayload &#8212; \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u043c, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043e\u0431\u044b\u0447\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435.<\/p>\n<\/li>\n<li>\n<p>ListCommandsPayload &#8212; \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u043c, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 &#171;\/&#187; \u0438 \u0437\u0430\u0442\u0435\u043c \u0432\u0432\u043e\u0434\u0438\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043f\u043e\u0441\u0438\u043c\u0432\u043e\u043b\u044c\u043d\u043e. \u0417\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u0441\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043c\u0430\u043d\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0432 \u0432\u0438\u0434\u0435 json. \u041d\u0430 \u0432\u0432\u043e\u0434 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0438\u043c\u0432\u043e\u043b\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 Payload.<\/p>\n<\/li>\n<li>\n<p>MessageActionPayload &#8212; \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443. \u041a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0438\u0437 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f. \u0412\u0441\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0431\u0443\u0434\u0443\u0442 &#171;\u0441\u0442\u0435\u0440\u0442\u044b&#187;(\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0438\u0445 actionId \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439).<\/p>\n<\/li>\n<li>\n<p>MenuActionPayload &#8212; \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u0442 \u043d\u0430 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0430 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u043c\u0435\u043d\u044e (ProjectMenu, LocationMenu, ChannelMessageMenu, ChannelAttachmentMenu \u0438 \u0442.\u0434.). \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d.<\/p>\n<\/li>\n<li>\n<p>ListMenuExtensionsPayload &#8212; \u0438\u043c\u0435\u0435\u0442 \u0442\u0443 \u0436\u0435 \u0438\u0434\u0435\u044e, \u0447\u0442\u043e \u0438 ListCommandsPayload, \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043c\u0435\u043d\u044e. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u0432\u0441\u0435 \u0435\u0449\u0435 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"kotlin\"> private suspend fun PipelineContext&lt;*, ApplicationCall&gt;.processChatbotPayload(payload: ApplicationPayload) {     when (payload) {         is MessagePayload -&gt; {             processChatbotMessagePayload(payload)         }         is MessageActionPayload -&gt; {             processChatbotMessageActionPayload(payload)         }         is ListCommandsPayload -&gt; {             processChatbotListCommandsPayload(payload)         }     } }<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 &#8212; \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u043e\u0442\u0443 \u043d\u0430\u0434\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c. \u041a\u043e\u043c\u0430\u043d\u0434\u0443 \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0434\u043d\u0438\u043c \u0434\u0430\u0442\u0430 \u043a\u043b\u0430\u0441\u0441\u043e\u043c:  <\/p>\n<pre><code class=\"kotlin\">data class Command(     val name: String,     val info: String,     val action: suspend (payload: MessagePayload) -&gt; Unit ) {        fun toCommandDetail() = CommandDetail(name, info) }<\/code><\/pre>\n<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0438 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434\u044b: <\/p>\n<ul>\n<li>\n<p>help &#8212; \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u0430\u043d\u0434;<\/p>\n<\/li>\n<li>\n<p>echo &#8212; \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e;<\/p>\n<\/li>\n<li>\n<p>interactive &lt;type&gt; &#8212; \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, button.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"kotlin\">object Commands {      val help = Command(         \"help\",         \"Show this help\",     ) { payload -&gt;         val context = HelpContext.from(payload)         printToChat(context, message {             section {                 text(                     \"\"\"Help message:                     name - Show this help                     ${echo.name} - ${echo.info}                     ${interactive.name} - ${interactive.info}                 \t\t\"\"\".trimIndent()                 )             }         })     }      val echo = Command(         \"echo\",         \"Echoing the input string\",     ) { payload -&gt;         val context = EchoContext.from(payload)         val body = context.message.body         printToChat(context, message = if (body is ChatMessage.Text) {             message { section { text(body.text) } }         } else {             message { section { text(\"Skip the Block body\") } }         })     }      val interactive = Command(         \"interactive\",         \"Displaying available message interactive elements\"     ) { payload -&gt;        \/\/ TODO finish later     }      val list = listOf(help, echo, interactive)      val commands: Commands         get() = Commands(list.map { it.toCommandDetail() }) } <\/code><\/pre>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0445 help \u0438 echo. \u0418\u0437 <code>ApplicationPayload <\/code>\u043a\u0430\u0436\u0434\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0437\u0432\u043b\u0435\u0447\u044c \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0438\u0445 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 Context, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0441\u0430\u043c\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c. \u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043d\u0430\u043c \u0430\u043a\u043a\u0443\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435.<\/p>\n<details class=\"spoiler\">\n<summary>Context.kt<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">interface UserContext {     val userId: String }  fun userContext(applicationPayload: ApplicationPayload) = object: UserContext {     override val userId = applicationPayload.userId ?: throw IllegalArgumentException(\"Payload does not contains user id\") }  data class EchoContext(override val userId: String, val message: MessageContext) : UserContext {      companion object {          fun from(payload: ApplicationPayload): EchoContext? = when (payload) {             is MessagePayload -&gt; from(payload)             else -&gt; null         }          fun from(payload: MessagePayload): EchoContext {             return EchoContext(payload.userId, payload.message)         }     } }  data class HelpContext(override val userId: String): UserContext {      companion object {          fun from(payload: ApplicationPayload): HelpContext {             return HelpContext(payload.userId!!)         }     } }  data class InteractiveContext(override val userId: String): UserContext {      companion object {          fun from(payload: ApplicationPayload): InteractiveContext {             return InteractiveContext(payload.userId!!)         }     } } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043d\u0430\u0448 <code>userId<\/code> \u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043e\u043f\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0438\u0445 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0432 \u0447\u0430\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442 \u0431\u043e\u0442. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043f\u0438\u0448\u0435\u043c   \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>printToChat<\/code>. <\/p>\n<pre><code class=\"kotlin\">suspend fun printToChat(context: UserContext, message: ChatMessage) {     val member = ProfileIdentifier.Id(context.userId)     spaceClient.chats.messages.sendMessage(MessageRecipient.Member(member), message) }<\/code><\/pre>\n<p>\u041b\u044e\u0431\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 Space \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u0432 \u0432\u0438\u0434\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 <code>ChatMessage<\/code>. \u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f sealed \u0438 \u0438\u043c\u0435\u0435\u0442 2 \u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u0430: <code>ChatMessage.Text<\/code> \u0438 <code>ChatMessage.Block<\/code>.  <\/p>\n<p><code>ChatMessage.Text<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u043c markdown.&nbsp;<\/p>\n<pre><code class=\"kotlin\">ChatMessage.Text(   \"\"\"   **bold**   `code`   *italic*   @{2iqI4p3gzufl, Maksim Hvostov}    @{2iqI4p3gzufl, Makentoshe}    @{2iqI4p3gzufl, any string may be replaced with my name}    [\\#general](im\/group\/10xDLp0yqy4w)    &gt;quote   \"\"\".trimIndent() )<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>Output<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"float\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e3f\/f2b\/0b8\/e3ff2b0b8aec841403f5f95726227790.png\" width=\"289\" height=\"290\"><figcaption><\/figcaption><\/figure>\n<\/div>\n<\/details>\n<p><code>ChatMessage.Block<\/code> \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0437\u0431\u0438\u0442\u044b \u043d\u0430 \u0441\u0435\u043a\u0446\u0438\u0438, \u0438\u043c\u0435\u0442\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u0438, \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0435\u0433\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 DSL, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c. \u0412\u0441\u0451 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>message <\/code>&#8212; \u044d\u0442\u043e \u043a\u043e\u0440\u0435\u043d\u044c \u043d\u0430\u0448\u0435\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0443\u043a\u0430\u0437\u0430\u0442\u044c:<\/p>\n<ul>\n<li>\n<p><code>MessageOutline <\/code>&#8212; \u044d\u0442\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u044c \u043f\u043e\u0434 \u0438\u043c\u0435\u043d\u0435\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044f \u0438, \u043f\u043e \u0436\u0435\u043b\u0430\u043d\u0438\u044e, \u0438\u043a\u043e\u043d\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0441\u0442\u0440\u043e\u043a\u0443. \u041a\u0430\u043a\u043e\u0439 \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u044d\u0442\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u043a\u0430 \u043d\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u043c\u0435\u0441\u0442\u043e \u0438\u043a\u043e\u043d\u043a\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c <code>null<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>MessageStyle <\/code>&#8212; \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0446\u0432\u0435\u0442\u0430 \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438, \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441\u043e \u0441\u0442\u0438\u043b\u0435\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043b\u044f \u0447\u0435\u0433\u043e \u043d\u0443\u0436\u043d\u0430 <code>messageData <\/code>\u044f \u043f\u043e\u043a\u0430 \u0442\u0430\u043a \u0438 \u043d\u0435 \u043f\u043e\u043d\u044f\u043b. \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0431\u044b\u043b\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e \u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0438 \u043d\u0430\u0448\u0435\u043c\u0443 \u0431\u043e\u0442\u0443, \u044d\u0442\u043e \u043f\u043e\u043b\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 <code>null<\/code>.<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"kotlin\">message { \tthis.outline = MessageOutline(null, \"Outline text\")   this.style = MessageStyle.PRIMARY  \tsection { \t\tthis.text(\"Primary message\") \t} }<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>Outputs<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"float\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/51c\/776\/8f2\/51c7768f2cb7938789be52f373dca62a.png\" width=\"476\" height=\"518\"><figcaption><\/figcaption><\/figure>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043b\u0438\u0431\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0441\u0435\u043a\u0446\u0438\u044e \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>section<\/code>, \u043b\u0438\u0431\u043e \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>divide<\/code>.<\/p>\n<p>\u0412 \u0441\u0435\u043a\u0446\u0438\u0438 \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b:<\/p>\n<ul>\n<li>\n<p>\u043e\u0431\u044b\u0447\u043d\u043e\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u0442\u043e\u0434 <code>text<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 \u0441 \u0442\u0435\u0433\u043e\u043c, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c.<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 \u0441 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u0441\u043f\u0440\u0430\u0432\u0430 \u043e\u0442 \u0441\u0435\u043a\u0446\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435 \u0441 \u0438\u043a\u043e\u043d\u043a\u043e\u0439, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u043f\u044f\u0442\u044c \u0436\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u0430.<\/p>\n<\/li>\n<li>\n<p><code>footer <\/code>\u0438 <code>header<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u201c\u043f\u043e\u043b\u0435&nbsp; &nbsp; \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u201d \u0447\u0435\u0440\u0435\u0437 <code>fields<\/code><\/p>\n<\/li>\n<li>\n<p>\u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043d\u043e\u043f\u043a\u0430.<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u0430\u043a \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442:&nbsp;<\/p>\n<pre><code class=\"kotlin\">message {     this.outline = MessageOutline(null, \"Outline text\")     this.style = MessageStyle.PRIMARY      section {         this.header = \"Section header\"         this.footer = \"Section footer\"         this.text(\"Plain text\")     }     divider()     section {         header = \"This tag may indicate something not good\"         this.textWithTag(\"Text with tag\", \"error tag\", MessageStyle.ERROR)     }     section {         this.text(\"Plain text just to fill some space.\")         this.textWithImage(\"Text with image\", \"https:\/\/www.jetbrains.com\/space\/img\/feedback-section\/video-preview.png\")     }     section {         this.textWithIcon(\"Text with icon\", \"\", MessageStyle.WARNING)     }     section {         header = \"Fields\"         this.fields {             this.field(\"field1\", \"value1\")             this.field(\"field2\", \"value2\")             this.field(\"field3\", \"value3\")             this.field(\"field4\", \"value4\")         }         this.controls {             this.button(\"Disabled button without any action\", PostMessageAction(\"\", \"\"), disabled = true)         }     } }<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>Output<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d4f\/28e\/a8d\/d4f28ea8d2dc02272149b2346347be6a.png\" width=\"1206\" height=\"719\"><figcaption><\/figcaption><\/figure>\n<\/div>\n<\/details>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 interaction \u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435.<\/p>\n<pre><code class=\"kotlin\">val interactive = Command(         \"interactive\",         \"Displaying available message interactive elements\"     ) { payload -&gt;         val context = InteractiveContext.from(payload)         val arguments = payload.commandArguments()         if (arguments == null || arguments.isBlank()) {             return@Command printToChat(context, message {                 section {                     text(\"Specify one of the selected ui elements:\\nbutton\")                 }             })         }          printToChat(context, message {             section {                 header = \"Available message interactive elements\"                 controls {                     when (arguments) {                         \"button\" -&gt; {                             val primaryAction = PostMessageAction(\"ButtonPrimaryActionId\", \"InteractiveButtonPayloadPrimary\")                             button(\"Primary\", primaryAction, MessageButtonStyle.PRIMARY)                              val secondaryAction = PostMessageAction(\"ButtonSecondaryActionId\", \"InteractiveButtonPayloadSecondary\")                             button(\"Secondary\", secondaryAction, MessageButtonStyle.SECONDARY)                              val regularAction = PostMessageAction(\"ButtonRegularActionId\", \"InteractiveButtonPayloadRegular\")                             button(\"Regular\", regularAction, MessageButtonStyle.REGULAR)                              val dangerAction = PostMessageAction(\"ButtonDangerActionId\", \"InteractiveButtonPayloadDanger\")                             button(\"Danger\", dangerAction, MessageButtonStyle.DANGER)                         }                     }                 }             }         })     } <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0440\u0430\u0437\u043d\u044b\u0445 ApplicationPayload&#8217;s. \u0414\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u044b \u0438\u0449\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0435\u0451.  <\/p>\n<pre><code class=\"kotlin\">private suspend fun PipelineContext&lt;*, ApplicationCall&gt;.processChatbotMessagePayload(payload: MessagePayload) {     Commands.list.find { it.name == payload.command() }?.action?.invoke(payload)         ?: return call.respond(HttpStatusCode.NotFound)     call.respond(HttpStatusCode.OK) }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u043a\u0430\u0437\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u043a\u043e\u043c\u0430\u043d\u0434 \u043c\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u0430\u043d\u0434. \u0417\u0434\u0435\u0441\u044c \u0436\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u043d\u0435\u0435 Jackson. <\/p>\n<pre><code class=\"kotlin\">private suspend fun PipelineContext&lt;*, ApplicationCall&gt;.processChatbotListCommandsPayload(payload: ListCommandsPayload) {     call.respondText(ObjectMapper().writeValueAsString(Commands.commands), ContentType.Application.Json) }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u043d\u0442\u0438\u0442\u044c actionId \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b.<\/p>\n<pre><code class=\"kotlin\">private suspend fun PipelineContext&lt;*, ApplicationCall&gt;.processChatbotMessageActionPayload(payload: MessageActionPayload) {     printToChat(userContext(payload), message { section { text(payload.actionId) } })     call.respond(HttpStatusCode.OK) }<\/code><\/pre>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0447\u0430\u0442\u0431\u043e\u0442\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u043d\u0430 <a href=\"https:\/\/github.com\/Makentoshe\/Sipichan-chatbot\" rel=\"noopener noreferrer nofollow\"><u>github<\/u><\/a>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e56\/cd3\/9b4\/e56cd39b4d6a60259b1d9f02dabd55f9.png\" width=\"1458\" height=\"839\"><figcaption><\/figcaption><\/figure>\n<h2>\u0418\u0442\u043e\u0433\u043e<\/h2>\n<p>\u041f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f Space \u0447\u0435\u0440\u0435\u0437 \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, \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438 \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0439 Api(\u0435\u0441\u043b\u0438 \u043d\u0430 \u0442\u043e \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f).&nbsp;<\/p>\n<p>\u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0443 Space \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430. \u041c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043b\u0438\u0448\u044c \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c. \u0411\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u043c\u0435\u044f \u0432\u043e\u043e\u0431\u0449\u0435 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u043d\u0430\u0432\u044b\u043a\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.&nbsp;<\/p>\n<p>\u0412\u043e\u0442 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b:&nbsp;<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/www.jetbrains.com\/ru-ru\/space\/extensibility\/external\/#webhooks\" rel=\"noopener noreferrer nofollow\"><u>Webhooks<\/u><\/a> &#8212; \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445 \u0432 Space.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.jetbrains.com\/ru-ru\/space\/extensibility\/external\/#space-as-an-authorization-server\" rel=\"noopener noreferrer nofollow\"><u>Authorizations<\/u><\/a> &#8212; \u0434\u043e\u0441\u0442\u0443\u043f \u043a Space \u0447\u0435\u0440\u0435\u0437 OAuth 2.0.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.jetbrains.com\/ru-ru\/space\/extensibility\/in-product\/#custom-fields\" rel=\"noopener noreferrer nofollow\"><u>Custom fields<\/u><\/a> &#8212; \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u043a \u0441\u0443\u0449\u043d\u043e\u0441\u0442\u044f\u043c Space.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/github.com\/JetBrains\/space-issues-import\" rel=\"noopener noreferrer nofollow\"><u>\u0421\u043a\u0440\u0438\u043f\u0442\u044b<\/u><\/a> \u0434\u043b\u044f \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/www.jetbrains.com\/ru-ru\/space\/extensibility\/in-product\/#no-code-workflows-with-external-tools\" rel=\"noopener noreferrer nofollow\"><u>\u0421\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438<\/u><\/a>.<\/p>\n<\/li>\n<\/ul>\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\/post\/545908\/\"> https:\/\/habr.com\/ru\/post\/545908\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440.<\/p>\n<p>\u041d\u0435\u0434\u0430\u0432\u043d\u043e JetBrains \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043b\u0438 \u0441\u0432\u043e\u0439 \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0434\u0443\u043a\u0442 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c<a href=\"https:\/\/jetbrains.com\/space\" rel=\"noopener noreferrer nofollow\"> <u>Space<\/u><\/a>, \u043e \u0447\u0435\u043c \u0431\u044b\u043b \u0441\u0432\u043e\u0435\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439<a href=\"https:\/\/habr.com\/en\/company\/jetbrains\/blog\/478866\/\" rel=\"noopener noreferrer nofollow\"> <u>\u043f\u043e\u0441\u0442 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435<\/u><\/a>. \u041f\u0440\u043e\u0448\u043b\u043e \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438 \u0443\u0436\u0435 \u043f\u043e\u0440\u0430 \u0431\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0435\u0433\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u043a \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0435\u0447\u044c \u043f\u043e\u0439\u0434\u0435\u0442 \u043e<a href=\"https:\/\/www.jetbrains.com\/help\/space\/applications.html\" rel=\"noopener noreferrer nofollow\"> <u>Space Applications<\/u><\/a>.<\/p>\n<p>Space Applications &#8212; \u044d\u0442\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0435\u0439. Applications \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0435\u0451 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 Space. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 &#8212; Application \u043d\u0435\u043b\u044c\u0437\u044f \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f Space. \u0414\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043c\u0435\u0436\u0434\u0443 Space \u0438 Application \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u0430\u043a \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0439 Endpoint, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043c\u044b \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c Endpoint URI &#8212; \u0430\u0434\u0440\u0435\u0441 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u043b\u0430\u0433\u0438\u043d\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 Space \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043a\u043e\u043c\u043c\u0443\u043d\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Space HTTP API.<\/p>\n<p>\u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0438\u0434\u043e\u0432 Applications:<\/p>\n<h4>Chatbot<\/h4>\n<figure class=\"float full-width\"><figcaption><\/figcaption><\/figure>\n<p>C\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0447\u0430\u0442\u0431\u043e\u0442, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u043c \u0441 \u043d\u0438\u043c \u0447\u0430\u0442\u0435. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0438\u043b\u044c\u043d\u043e \u0443\u0441\u0442\u0443\u043f\u0430\u0435\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Telegram. \u041d\u0435\u043b\u044c\u0437\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u043e\u0442\u0430 \u0432 \u043a\u0430\u043d\u0430\u043b (\u0433\u0440\u0443\u043f\u043f\u043e\u0432\u043e\u0439 \u0447\u0430\u0442), \u0430 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u043e\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043d\u043e\u043f\u043a\u0438.  <\/p>\n<\/p>\n<h4>Slash commands<\/h4>\n<figure class=\"float full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u0430\u043d\u0430\u043b\u0430 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0434\u0430\u043d\u044b \u0440\u0430\u0437\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0438 \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 &#171;\/&#187;, \u0435\u043c\u0443 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434. \u041d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0447\u0430\u0442\u0431\u043e\u0442\u043e\u0432.    <\/p>\n<h4>Client applications<\/h4>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b Space, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0442 \u043d\u0435\u0433\u043e \u0440\u0430\u0437\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438\u043b\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043c\u043e\u0434\u0443\u043b\u044f\u043c\u0438 \u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0442\u044c\/\u0437\u0430\u043a\u0440\u044b\u0432\u0430\u0442\u044c issues, \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u043e\u0441\u0442\u044b \u0432 \u043a\u0430\u043d\u0430\u043b \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435.<\/p>\n<\/p>\n<h4>Custom menus<\/h4>\n<figure class=\"float full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u0435\u043d\u044e \u043d\u043e\u0432\u044b\u043c\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 api \u0434\u043b\u044f \u043d\u0438\u0445 \u0435\u0449\u0435 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d.<\/p>\n<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u043a\u043e\u043c\u0431\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0438\u043f\u043e\u0432 Applications. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0431\u043e\u0442\u0430, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u043a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0431\u0438\u043b\u0434\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 CI\/CD \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0435\u0440\u043d\u0435\u0442\u0441\u044f \u0432 \u043e\u0431\u0449\u0438\u0439 \u043a\u0430\u043d\u0430\u043b.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 Application \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c. \u0414\u0435\u043b\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 Administration menu. \u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u043c\u0438 \u043f\u0440\u0430\u0432\u0430\u043c\u0438 \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043b\u0430\u0434\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u043c\u0435\u043b\u043e \u0434\u043e\u0441\u0442\u0443\u043f \u0442\u043e\u043b\u044c\u043a\u043e \u043a \u0442\u0435\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043c\u0438 \u044f\u0432\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u044b.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432 \u0442\u0430\u0431\u0435 Authentication \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 Authentication flows, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0438\u043f\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041a\u0440\u0430\u0442\u043a\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0430\u043a:<\/p>\n<ul>\n<li>\n<p>Client Credentials Flow &#8212; \u0441\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431. \u0420\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 client id \u0438 client secret. \u041d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043e\u0442 \u0441\u0432\u043e\u0435\u0433\u043e \u043b\u0438\u0446\u0430 \u0438 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>Authorization Code Flow &#8212; \u043b\u043e\u0433\u0438\u043d\u0438\u043c\u0441\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0447\u0435\u0440\u0435\u0437 Space, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u043e\u0434 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0447\u0442\u043e\u0431\u044b \u0438\u0437 \u043d\u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u043e\u043a\u0435\u043d \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043e\u0442 \u043b\u0438\u0446\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.  <\/p>\n<\/li>\n<li>\n<p>Implicit Flow &#8212; \u0438\u0434\u0435\u044f \u0442\u0430\u0436\u0435, \u0447\u0442\u043e \u0438 Authorization Code Flow, \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u0438\u0435\u043d\u0442 \u043b\u043e\u0433\u0438\u043d\u0438\u0442\u0441\u044f \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430.<\/p>\n<\/li>\n<\/ul>\n<h2>Client application<\/h2>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b Space, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0440\u0430\u0437\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e: \u043a\u0430\u043d\u0430\u043b\u044b, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438, \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u0438 \u0442.\u0434.&nbsp;<\/p>\n<details class=\"spoiler\">\n<summary>build.gradle.kts<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"kotlin\">repositories {     mavenCentral()     maven(\"https:\/\/kotlin.bintray.com\/kotlinx\")     maven(\"https:\/\/maven.pkg.jetbrains.space\/public\/p\/space\/maven\") }  dependencies {     implementation(kotlin(\"stdlib\"))      \/\/ Space api sdk     \/\/ https:\/\/www.jetbrains.com\/help\/space\/space-sdk.html     val space_version = \"61400-beta\"     implementation(\"org.jetbrains:space-sdk-jvm:$space_version\")      \/\/ Ktor (http client)     \/\/ https:\/\/github.com\/ktorio\/ktor     val ktor_version = \"1.4.3\"     implementation(\"io.ktor:ktor-client-core:$ktor_version\")     implementation(\"io.ktor:ktor-client-core-jvm:$ktor_version\")     implementation(\"io.ktor:ktor-client-cio:$ktor_version\") } <\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Client Credentials Flow:<\/p>\n<pre><code class=\"kotlin\">private const val spaceInstanceUrl = \"https:\/\/makentoshe.jetbrains.space\"  val spaceClient = SpaceHttpClient(HttpClient(CIO)).withServiceAccountTokenSource(     ClientCredentialsFlow.clientId, ClientCredentialsFlow.clientSecret, spaceInstanceUrl )  object ClientCredentialsFlow {      const val clientId: String = TODO(\u201cPut your client_id here\u201d)      const val clientSecret: String = TODO(\u201cPut your client_secret here\u201d)  } <\/code><\/pre>\n<p>\u041d\u0438\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0439 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432.<\/p>\n<pre><code class=\"kotlin\">\/\/ There are some examples of retrieving several data from the Space instance. \/\/ We can process this info as we want - create analytics, office dashboards, and so on. fun main() = runBlocking {     val channels = spaceClient.chats.channels.listAllChannels(\"\").data     println(\"Channels: ${channels.map { \"${it.name}(${it.channelId})\" }}\")      \/\/ View application rights allows to see all applications     \/\/ If rights were not accepted - the application can see only itself.     val applications = spaceClient.applications.getAllApplications(\"\")     println(\"Applications: ${applications.map { \"${it.name}(${it.id})\" }}\")      \/\/ Works only with View member profile rights     val profiles = spaceClient.teamDirectory.profiles.getAllProfiles().data     println(\"Profiles: ${profiles.map { \"${it.username}(${it.id})\" }}\")      \/\/ Works only with View project parameters rights     \/\/ These rights can be managed for selected projects or for whole projects at one time.     val projects = spaceClient.projects.getAllProjects().data     println(\"Projects: ${projects.map { \"${it.name}(${it.id})\" }}\")                  \/\/ Works only with Project Issues: View issues rights     val issues = projects.firstOrNull()?.let { getProjectIssues(it) }     println(\"Issues: ${issues?.map { \"${it.title}(${it.id})\" }} \") }  private suspend fun getProjectIssues(project: PR_Project): List&lt;Issue&gt; {     return spaceClient.projects.planning.issues.getAllIssues(         project = ProjectIdentifier.Id(project.id),         assigneeId = emptyList(),         statuses = emptyList(),         sorting = IssuesSorting.CREATED,         descending = true     ).data } <\/code><\/pre>\n<details class=\"spoiler\">\n<summary>Output<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>Channels: [Booruchan(4UHs4I3yyno1), general(10xDLp0yqy4w), Habrachan(4HyHLw3SnO9Y), Sipichan(15A2hA1RpAsp)] Applications: [client(2czEkY3AIaV0), chatbot(d3Q8Z0UeVCF)] Profiles: [Makentoshe(2iqI4p3gzufl)] Projects: [Booruchan(qN0K31awqo6), Habrachan(1tJHqn2A76Yf), Sipichan(35BreB35gvdA)] Issues: [Add custom Run Configuration and support ngrok startup(3S09oT4JHvpC), Add Client template for Space plugin with Gradle (atQRe1SIklB), Add Blank template for Space application plugin support for Gradle(4REln04HAo5k)]<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u0430\u0432 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c\u0441\u044f. \u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 .data. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442 Batch, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u0438 \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043d\u0430\u0431\u043e\u0440 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043b\u044e\u0447 \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u043d\u0430\u0431\u043e\u0440\u0443, \u0438 \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u041f\u0440\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430\u0445 \u0441\u0442\u043e\u0438\u0442 \u044d\u0442\u043e \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c, \u043e\u0434\u043d\u0430\u043a\u043e \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0430\u0433\u0438\u043d\u0430\u0446\u0438\u044f \u043e\u043f\u0443\u0449\u0435\u043d\u0430.<\/p>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043d\u0430 <a href=\"https:\/\/github.com\/Makentoshe\/sipichan-client\" rel=\"noopener noreferrer nofollow\">github <\/a>\u0438 \u0441\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0435\u043c \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f.<\/p>\n<h2>Chatbot + slash command application<\/h2>\n<p>\u0421\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 Applications, \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u043c\u0438, \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438. \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0445\u043e\u0441\u0442\u0438\u0442\u044c\u0441\u044f \u043d\u0430\u0448 \u0431\u043e\u0442. \u041c\u044b \u0443\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 HTTP \u043a\u043b\u0438\u0435\u043d\u0442 Ktor, \u0442\u0430\u043a \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0430 \u043d\u0435\u043c \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c. \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0434\u043b\u044f Ktor \u0437\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u043e\u043f\u0443\u0449\u0435\u043d\u043e, \u043d\u043e \u0435\u0441\u0442\u044c<a href=\"https:\/\/ktor.io\/docs\/a-ktor-application.html\" rel=\"noopener noreferrer nofollow\"> <u>\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f<\/u><\/a>, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0435\u0440\u0435\u0442\u044c\u0441\u044f.<\/p>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u043e\u0434\u043d\u0438\u043c\u0435\u043c \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0435\u0440, \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0435\u0433\u043e URL, \u0447\u0442\u043e\u0431\u044b Space \u043c\u043e\u0433 \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u041f\u043e\u043a\u0443\u043f\u0430\u0442\u044c \u0445\u043e\u0441\u0442, \u0438\u043b\u0438 \u0438\u0441\u043a\u0430\u0442\u044c \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 \u043d\u0435 \u043a\u043e\u043c\u0438\u043b\u044c\u0444\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043f\u043e\u0439\u0434\u0435\u043c \u043e\u0431\u0445\u043e\u0434\u043d\u044b\u043c \u043f\u0443\u0442\u0435\u043c &#8212; \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0443\u043d\u043d\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441. \u0412 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f ngrok, \u043e\u0434\u043d\u0430\u043a\u043e \u043b\u0438\u0447\u043d\u043e \u044f \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0438\u0442\u0430\u044e localtunnel, \u0438\u0437-\u0437\u0430 \u0435\u0433\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441.<\/p>\n<pre><code class=\"bash\">\/\/ localtunnel npx localtunnel --port 8080 --subdomain makentoshe \/\/ ngrok ngrok http 8080<\/code><\/pre>\n<p>\u0412 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c URL &#8212; \u044d\u0442\u043e \u043a\u0430\u043a \u0440\u0430\u0437 \u0442\u043e, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e.<\/p>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 Applications \u0432 \u043d\u0430\u0448\u0435\u043c Space. \u0412 \u0442\u0430\u0431\u0435 Endpoint \u0432 \u043f\u043e\u043b\u0435 Endpoint URI \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0430\u0448 url. \u0414\u043b\u044f \u043c\u0435\u043d\u044f \u044d\u0442\u043e <code>https:\/\/makentoshe.loca.lt\/api\/chatbot<\/code>. \u041f\u0440\u043e \u0442\u043e, \u0437\u0430\u0447\u0435\u043c \u043d\u0443\u0436\u0435\u043d <code>\/api\/chatbot<\/code> \u0431\u0443\u0434\u0435\u0442 \u0434\u0430\u043b\u044c\u0448\u0435.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412 \u0442\u043e\u043c \u0436\u0435 \u0442\u0430\u0431\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0432\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0432\u0435\u0440\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u044b:  <\/p>\n<ul>\n<li>\n<p>Verification token &#8212; \u044d\u0442\u043e\u0442 \u0442\u043e\u043a\u0435\u043d \u043a\u043b\u0430\u0434\u0435\u0442\u0441\u044f \u0432 \u043a\u0430\u0436\u0434\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043e\u0442 Space. \u041d\u0430\u043c \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u044d\u0442\u0438 \u0442\u043e\u043a\u0435\u043d\u044b, \u0438 \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442 &#8212; \u043c\u044b \u043e\u0431\u0449\u0430\u0435\u043c\u0441\u044f \u0441 \u043d\u0430\u0448\u0438\u043c Space. <\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440 \u043e\u0442\u0432\u0435\u0442\u0430 \u0441 Verification token<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"json\">{       \"className\": \"ListCommandsPayload\",       \"accessToken\": \"\",       \"verificationToken\": \"d415ca5965b37f4f0cac59fd33de7b94e396284e897d0fb8a070d0a5e1b7f2d3\",       \"userId\": \"2kawvQ4F6GM6\" }<\/code><\/pre>\n<\/div>\n<\/details>\n<ul>\n<li>\n<p>Signing key &#8212; \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439 \u043c\u0435\u0442\u043e\u0434. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0445\u0435\u0448, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043b\u0430\u0434\u0435\u0442\u0441\u044f \u0432 \u0435\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a. \u041a\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0445\u0435\u0448, \u0438 \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442 &#8212; \u0432\u0441\u0435 \u043e\u043a. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0431 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0435 &#8212; <a href=\"https:\/\/www.jetbrains.com\/help\/space\/verify-space-in-application.html#verifying-requests-using-a-signing-key\" rel=\"noopener noreferrer nofollow\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<\/li>\n<\/ul>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440 \u043e\u0442\u0432\u0435\u0442\u0430 \u0441 Signing key<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>POST \/api\/chatbot HTTP\/1.1 Host: 12345abcdef.ngrok.io User-Agent: Space (61355) Ktor http-client Content-Length: 163 Accept: *\/* Accept-Charset: UTF-8 Content-Type: application\/json X-Forwarded-For: 123.456.123.456 X-Forwarded-Proto: https X-Space-Signature: 2aa8cba6217a28686de0ca8dcfe2a1d0795e343d744a0c5307308e43777593a5 X-Space-Timestamp: 1607623492912 Accept-Encoding: gzip  {\"className\":\"ListCommandsPayload\",\"accessToken\":\"\",\"verificationToken\":\"d415ca5965b37f4f0cac59fd33de7b94e396284e897d0fb8a070d0a5e1b7f2d3\",\"userId\":\"2kawvQ4F6GM6\"}<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u044b \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u043e\u0431\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0438 \u0431\u0443\u0434\u0435\u043c \u0441\u0432\u0435\u0440\u044f\u0442\u044c \u0438 \u0445\u0435\u0448\u0438, \u0438 \u0442\u043e\u043a\u0435\u043d\u044b.<\/p>\n<pre><code class=\"kotlin\">object Endpoint {      const val verificationToken: String = TODO(\"Place your verification_token\")     const val signingKey: String = TODO(\"Place your signing_key\")      fun verify(payload: ApplicationPayload): Boolean {         return payload.verifyWithToken(verificationToken)     }      fun verify(timestamp: String, signature: String, body: String): Boolean {         val hmacSha256 = Mac.getInstance(\"HmacSHA256\")         hmacSha256.init(SecretKeySpec(signingKey.toByteArray(), \"HmacSHA256\"))         val hash = hmacSha256.doFinal(\"$timestamp:$body\".toByteArray()).toHexString()         return hash == signature     }      private fun<\/code><\/pre>\n<\/p>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-320054","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/320054","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=320054"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/320054\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=320054"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=320054"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=320054"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}