{"id":308781,"date":"2020-08-20T15:00:50","date_gmt":"2020-08-20T15:00:50","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=308781"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=308781","title":{"rendered":"\u041f\u0438\u0448\u0435\u043c \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0432\u0430\u0448\u0438\u0445 CLI \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/515946\/\">\n<h3 id=\"privetstvie\">\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435<\/h3>\n<p>  <\/p>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0425\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u0440\u043e\u0441\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 C++ \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0432 CLI \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0443\u0441\u0430\u0436\u0438\u0432\u0430\u0439\u0442\u0435\u0441\u044c \u043f\u043e\u0443\u0434\u043e\u0431\u043d\u0435\u0435.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/rh\/gd\/ku\/rhgdkultldauofi3ky2p9_xakxe.gif\" width=\"400\"\/><br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h3 id=\"formulirovka-zadaniya\">\u0424\u043e\u0440\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u043d\u0438\u044f<\/h3>\n<p>  <\/p>\n<ul>\n<li>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 Linux, macOS, Windows<\/li>\n<li>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f<\/li>\n<li>\u041f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043e\u043f\u0435\u0447\u0430\u0442\u043e\u043a<\/li>\n<li>\u041f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0441\u043c\u0435\u043d\u0443 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a \u0441\u0442\u0440\u0435\u043b\u043a\u0430\u043c\u0438 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b<\/li>\n<\/ul>\n<p>  <\/p>\n<h3 id=\"prigotovleniya\">\u041f\u0440\u0438\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u0438\u044f<\/h3>\n<p>  <\/p>\n<p>\u0421\u0440\u0430\u0437\u0443 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0443, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0443\u0434\u0435\u043c <code>C++17<\/code><\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0434\u0435\u043b\u0443. \u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e, \u0442\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u043a\u0440\u043e\u0441\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u044b\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u043c\u0430\u043a\u0440\u043e\u0441 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">#if defined(_WIN32) || defined(_WIN64)     #define OS_WINDOWS #elif defined(__APPLE__) || defined(__unix__) || defined(__unix)     #define OS_POSIX #else     #error unsupported platform #endif<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">#if defined(OS_WINDOWS)     #define ENTER 13     #define BACKSPACE 8     #define CTRL_C 3     #define LEFT 75     #define RIGHT 77     #define DEL 83     #define UP 72     #define DOWN 80     #define SPACE 32 #elif defined(OS_POSIX)     #define ENTER 10     #define BACKSPACE 127     #define SPACE 32     #define LEFT 68     #define RIGHT 67     #define UP 65     #define DOWN 66     #define DEL 51 #endif     #define TAB 9<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u043d\u0430\u0446\u0435\u043b\u0435\u043d\u044b \u043d\u0430 CLI \u043f\u0440\u043e\u0435\u043a\u0442\u044b, \u0438 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u044b Linux \u0438 macOS \u0438\u043c\u0435\u044e\u0442 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0439 API, \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u043c \u0438\u0445 \u0432 \u043e\u0434\u0438\u043d define OS_POSIX. Windows, \u043a\u0430\u043a \u0432\u0441\u0435\u0433\u0434\u0430, \u0441\u0442\u043e\u0438\u0442 \u0432 \u0441\u0442\u043e\u0440\u043e\u043d\u0435, \u0432\u044b\u043d\u0435\u0441\u0435\u043c \u0434\u043b\u044f \u043d\u0435\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 define OS_WINDOWS.<\/p>\n<p>  <\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u0421 \u0441\u0430\u043c\u043e\u0433\u043e \u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0431\u044b\u043b \u0432\u0434\u043e\u0445\u043d\u043e\u0432\u043b\u0435\u043d Redis CLI, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u043f\u043e\u0441\u043a\u0430\u0437\u043a\u0438 \u0434\u0440\u0443\u0433\u0438\u043c \u043d\u0435\u0439\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u043c \u0446\u0432\u0435\u0442\u043e\u043c. \u041d\u043e \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u043c\u0435\u0448\u0430\u0435\u0442 \u043d\u0430\u043c \u0432 \u0438\u0442\u043e\u0433\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u0446\u0432\u0435\u0442\u0430.<\/p>\n<p>  <\/p>\n<p>\u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043d\u0443\u0436\u043d\u043e\u0433\u043e \u0446\u0432\u0435\u0442\u0430 \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/**  * Sets the console color.  *  * @param color System code of target color.  * @return Input parameter os.  *\/ #if defined(OS_WINDOWS) std::string set_console_color(uint16_t color) {     SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);     return &quot;&quot;; #elif defined(OS_POSIX) std::string set_console_color(std::string color) {     return &quot;\\033[&quot; + color + &quot;m&quot;; #endif }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041e\u043f\u044f\u0442\u044c \u0442\u0430\u043a\u0438 \u0438\u0437-\u0437\u0430 \u0440\u0430\u0437\u043d\u0438\u0446\u044b API \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0438\u0441\u043a\u0430\u0442\u044c \u043a\u043e\u043c\u043f\u0440\u043e\u043c\u0438\u0441\u0441, \u0431\u0443\u0434\u0435\u043c \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u0441\u043b\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0432\u044b\u0432\u043e\u0434\u0430 <code>&lt;&lt;<\/code> \u0434\u043b\u044f \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u0434\u0430.<\/em><\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0442\u0435\u0445, \u043a\u043e\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 API \u0434\u043b\u044f \u0446\u0432\u0435\u0442\u0430 \u0432 Posix \u0438 Windows, \u0438 \u043a\u0430\u043a\u0438\u0435 \u0446\u0432\u0435\u0442\u043e\u0432\u044b\u0435 \u043f\u0440\u043e\u0444\u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0431\u044b\u0432\u0430\u044e\u0442, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043e\u0442\u0432\u0435\u0442\u044b \u0434\u043e\u0431\u0440\u044b\u0445 \u043b\u044e\u0434\u0435\u0439 \u043d\u0430 stackoverflow:<\/p>\n<p>  <\/p>\n<ul>\n<li>Windows: <a href=\"https:\/\/stackoverflow.com\/questions\/4053837\/colorizing-text-in-the-console-with-c#answer-4053879\">https:\/\/stackoverflow.com\/questions\/4053837\/colorizing-text-in-the-console-with-c#answer-4053879<\/a><\/li>\n<li>Posix: <a href=\"https:\/\/stackoverflow.com\/questions\/2616906\/how-do-i-output-coloured-text-to-a-linux-terminal#answer-45300654\">https:\/\/stackoverflow.com\/questions\/2616906\/how-do-i-output-coloured-text-to-a-linux-terminal#answer-45300654<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043d\u0430\u043c \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0438\u0437-\u0437\u0430 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f &quot;\u0441\u0442\u0438\u0440\u0430\u043d\u0438\u044f&quot; \u0441\u0442\u0440\u043e\u043a\u0438.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/**  * Get count of terminal cols.  *  * @return Width of terminal.  *\/ #if defined(OS_WINDOWS) size_t console_width() {     CONSOLE_SCREEN_BUFFER_INFO info;     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &amp;info);      short width = --info.dwSize.X;     return size_t((width &lt; 0) ? 0 : width); } #endif  \/**  * Clear terminal line.  *  * @param os Output stream.  * @return input parameter os.  *\/ std::ostream&amp; clear_line(std::ostream&amp; os) { #if defined(OS_WINDOWS)     size_t width = console_width();     os &lt;&lt; '\\r' &lt;&lt; std::string(width, ' '); #elif defined(OS_POSIX)     std::cout &lt;&lt; &quot;\\033[2K&quot;; #endif     return os; }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u041d\u0430 Posix \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445 \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c <code>\\033[2K<\/code>, \u043d\u043e \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 Windows \u043d\u0435\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u043e\u0432, \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u044f \u043d\u0435 \u0441\u043c\u043e\u0433 \u043d\u0430\u0439\u0442\u0438, \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e. <\/em><\/p>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u043d\u044f\u0442\u044c, \u043a\u0430\u043a \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0432\u0432\u043e\u0434 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. \u041e\u0431\u044b\u0447\u043d\u044b\u0439 <code>cin<\/code> \u044f\u0432\u043d\u043e \u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442, \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p>\u0422\u0443\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u043d\u0430 \u0443\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f _getch(), \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u0432 Windows, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u043a\u043e\u0434 \u0441\u0438\u043c\u0432\u043e\u043b\u0430 \u043d\u0430\u0436\u0430\u0442\u043e\u0439 \u043a\u043b\u0430\u0432\u0438\u0448\u0438 \u043d\u0430 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u0435 \u2014 \u044d\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u043e, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0430\u0434\u043e. \u041d\u043e \u0432 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0441 Posix \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u043c\u0438 \u0432\u0441\u0435 \u043f\u043b\u043e\u0445\u043e, \u0443\u0432\u044b, \u043d\u043e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">#if defined(OS_POSIX) \/**  * Read key without press ENTER.  *  * @return Code of key on keyboard.  *\/ int _getch() {     int ch;     struct termios old_termios, new_termios;     tcgetattr( STDIN_FILENO, &amp;old_termios );     new_termios = old_termios;     new_termios.c_lflag &amp;= ~(ICANON | ECHO );     tcsetattr( STDIN_FILENO, TCSANOW, &amp;new_termios );     ch = getchar();     tcsetattr( STDIN_FILENO, TCSANOW, &amp;old_termios );     return ch; } #endif<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"pravila-avtodopolneniya\">\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f<\/h3>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/bw\/oh\/lo\/bwohlodcr6eka9bnvlj4zumvb7m.jpeg\" width=\"400\"\/><\/p>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0435\u043c, \u043a\u0430\u043a \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u0445 \u0438\u0437 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">git     config         --global             user.name                 &quot;[name]&quot;             user.email                 &quot;[email]&quot;         user.name             &quot;[name]&quot;         user.email             &quot;[email]&quot;     init         [repository name]     clone         [url]<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0418\u0434\u0435\u044f \u0442\u0430\u043a\u0430\u044f. \u0417\u0430 \u043a\u0430\u0436\u0434\u044b\u043c \u0441\u043b\u043e\u0432\u043e\u043c \u043c\u043e\u0433\u0443\u0442 \u0438\u0434\u0442\u0438 \u0441\u043b\u043e\u0432\u0430 \u043d\u0430 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0438 1 \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0438 \u043e\u0442 \u043d\u0435\u0433\u043e. \u0422.\u0435. \u043f\u043e\u0441\u043b\u0435 \u0441\u043b\u043e\u0432\u0430 <code>git<\/code> \u043c\u043e\u0433\u0443\u0442 \u0438\u0434\u0442\u0438 \u0441\u043b\u043e\u0432\u0430 <code>config<\/code>, <code>init<\/code> \u0438 <code>global<\/code>. \u041f\u043e\u0441\u043b\u0435 \u0441\u043b\u043e\u0432\u0430 <code>config<\/code> \u043c\u043e\u0433\u0443\u0442 \u0438\u0434\u0442\u0438 \u0441\u043b\u043e\u0432\u0430 <code>--global<\/code>, <code>user.name<\/code> \u0438 <code>user.email<\/code> \u0438 \u0442.\u0434. \u0422\u0430\u043a\u0436\u0435 \u0432\u0432\u0435\u0434\u0435\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u043b\u043e\u0432\u0430, \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0441\u043b\u043e\u0432\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 [] (\u0432\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u0438\u0445 \u0441\u043b\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u0434\u0430\u043d\u043d\u044b\u0435).<\/em><\/p>\n<p>  <\/p>\n<p>\u0425\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0431\u0443\u0434\u0435\u043c \u0432 \u0430\u0441\u0441\u043e\u0446\u0438\u0430\u0442\u0438\u0432\u043d\u043e\u043c \u043c\u0430\u0441\u0441\u0438\u0432\u0435, \u0433\u0434\u0435 \u043a\u043b\u044e\u0447 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u043e\u0439, \u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u2014 \u0432\u0435\u043a\u0442\u043e\u0440 \u0441\u043b\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0438\u0434\u0442\u0438 \u043f\u043e\u0441\u043b\u0435 \u043a\u043b\u044e\u0447\u0430-\u0441\u0442\u0440\u043e\u043a\u0438.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">typedef std::map&lt;std::string, std::vector&lt;std::string&gt;&gt; Dictionary;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0444\u0430\u0439\u043b\u0430 \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/**  * Parse config file to dictionary.  *  * @param file_path The path to the configuration file.  * @return Tuple of dictionary with autocomplete rules, status of parsing and message.  *\/ std::tuple&lt;Dictionary, bool, std::string&gt;  parse_config_file(const std::string&amp; file_path) {     Dictionary dict;            \/\/ \u0421\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438 \u0430\u0432\u0442\u043e\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f      std::map&lt;int, std::string&gt;  \/\/ \u041c\u0430\u0441\u0441\u0438\u0432 \u0434\u043b\u044f \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u044f \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0441\u043b\u043e\u0432\u0430     root_words_by_tabsize;      \/\/  \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0434\u043b\u0438\u043d\u044b \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0438      std::string line;           \/\/ \u0421\u0442\u0440\u043e\u043a\u0430 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f     std::string token;          \/\/ \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438     std::string root_word;      \/\/ \u041a\u043e\u0440\u043d\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u043a\u0430\u043a \u043a\u043b\u044e\u0447      long tab_size = 0;          \/\/ \u0411\u0430\u0437\u043e\u0432\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0438 (\u043f\u0440\u043e\u0431\u0435\u043b\u043e\u0432)     long tab_count = 0;         \/\/ \u041a\u043e\u043b\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0439 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435      \/\/ \u041e\u0442\u043a\u0440\u044b\u0442\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439     std::ifstream config_file(file_path);      \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435, \u0435\u0441\u043b\u0438 \u0444\u0430\u0439\u043b \u043d\u0435 \u0431\u044b\u043b \u043e\u0442\u043a\u0440\u044b\u0442     if (!config_file.is_open()) {         return std::make_tuple(             dict,             false,             &quot;Error! Can't open &quot; + file_path + &quot; file.&quot;         );     }      \/\/ \u0421\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u0442\u0440\u043e\u043a\u0438     while (std::getline(config_file, line)) {         \/\/ \u041f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0443 \u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u043f\u0443\u0441\u0442\u0430\u044f         if (line.empty()) {             continue;         }          \/\/ \u0415\u0441\u043b\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d \u0441\u0438\u043c\u0432\u043e\u043b \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0438, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e \u043e\u0448\u0438\u0431\u043a\u0435         if (std::count(line.begin(), line.end(), '\\t') != 0) {             return std::make_tuple(                 dict,                 false,                 &quot;Error! Use a sequence of spaces instead of a tab character.&quot;             );         }          \/\/ \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u0440\u043e\u0431\u0435\u043b\u043e\u0432 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438         auto spaces = std::count(             line.begin(),             line.begin() + line.find_first_not_of(&quot; &quot;),             ' '         );          \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0438, \u0435\u0441\u043b\u0438         \/\/ \u0431\u044b\u043b\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u0441 \u043f\u0440\u043e\u0431\u0435\u043b\u0430\u043c\u0438 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435         if (spaces != 0 &amp;&amp; tab_size == 0) {             tab_size = spaces;         }          \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u043e\u0432\u043e \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438         token = trim(line);          \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0434\u043b\u0438\u043d\u044b \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0438         if (tab_size != 0 &amp;&amp; spaces % tab_size != 0) {             return std::make_tuple(                 dict,                 false,                 &quot;Error! Tab length error was made.\\nPossibly in line: &quot; + line             );         }          \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0439         tab_count = (tab_size == 0) ? 0 : (spaces \/ tab_size);          \/\/ \u0417\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u043c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0439         root_words_by_tabsize[tab_count] = token;          \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u0434\u043b\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430         root_word = (tab_count == 0) ? &quot;&quot; : root_words_by_tabsize[tab_count - 1];          \/\/ \u0412\u0441\u0442\u0430\u0432\u043a\u0430 \u0442\u043e\u043a\u0435\u043d\u0430 \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0435\u0441\u043b\u0438 \u0435\u0433\u043e \u0442\u0430\u043c \u043d\u0435\u0442         if (std::count(dict[root_word].begin(), dict[root_word].end(), token) == 0) {             dict[root_word].push_back(token);         }     }      \/\/ \u0417\u0430\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0444\u0430\u0439\u043b     config_file.close();      \/\/ \u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u041e\u041a \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c     return std::make_tuple(         dict,         true,         &quot;Success. The rule dictionary has been created.&quot;     ); }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0420\u0430\u0437\u0431\u0435\u0440\u0435\u043c\u0441\u044f \u0441 \u043d\u0430\u043a\u043e\u043f\u0438\u0432\u0448\u0438\u043c\u0438\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u0430\u043c\u0438.<\/em><\/p>\n<p>  <\/p>\n<ol>\n<li>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a\u043e\u0440\u0442\u0435\u0436, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u043e \u043c\u043e\u0435\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u0430\u0447\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442.<\/li>\n<li>\u041f\u043e\u0447\u0435\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u0430 <code>\\t<\/code> \u0432 \u0444\u0430\u0439\u043b\u0435 \u0437\u0430\u043f\u0440\u0435\u0449\u0435\u043d\u043e? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u0432\u044b\u043a\u0430\u0442\u044c \u043a \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0431\u0435\u043b\u043e\u0432 \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0438.<\/li>\n<li>\u041e\u0442\u043a\u0443\u0434\u0430 \u0432\u0437\u044f\u043b\u0430\u0441\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f trim, \u0438 \u0447\u0442\u043e \u043e\u043d\u0430 \u0434\u0435\u043b\u0430\u0435\u0442? \u0421\u0435\u0439\u0447\u0430\u0441 \u043f\u043e\u043a\u0430\u0436\u0443 \u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u0443\u044e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e.<\/li>\n<\/ol>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/**  * Remove extra spaces to the left and right of the string.  *  * @param str Source string.  * @return Line without spaces on the left and right.  *\/ std::string trim(std::string_view str) {     std::string result(str);     result.erase(0, result.find_first_not_of(&quot; \\n\\r\\t&quot;));     result.erase(result.find_last_not_of(&quot; \\n\\r\\t&quot;) + 1);     return result; }<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442\u0440\u0435\u0437\u0430\u0435\u0442 \u043b\u0438\u0448\u043d\u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0441\u043b\u0435\u0432\u0430 \u0438 \u0441\u043f\u0440\u0430\u0432\u0430 \u0443 \u0441\u0442\u0440\u043e\u043a\u0438<\/em><\/p>\n<p>  <\/p>\n<h3 id=\"avtodopolnenie\">\u0410\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435<\/h3>\n<p>  <\/p>\n<p>\u0425\u043e\u0440\u043e\u0448\u043e. \u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043b\u043e\u0432\u0430\u0440\u044c \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438, \u0430 \u0447\u0442\u043e \u0434\u0430\u043b\u044c\u0448\u0435? \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0430\u043c\u043e \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435.<br \/>  \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0432\u043e\u0434\u0438\u0442 \u0447\u0442\u043e-\u0442\u043e \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b. \u0427\u0442\u043e \u043c\u044b \u0438\u043c\u0435\u0435\u043c? \u041e\u0434\u043d\u043e \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0445 \u0441\u043b\u043e\u0432.<\/p>\n<p>  <\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0443\u0447\u0438\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043b\u043e\u0432\u043e \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/**  * Get the position of the beginning of the last word.  *  * @param str String with words.  * @return Position of the beginning of the last word.  *\/ size_t get_last_word_pos(std::string_view str) {     \/\/ \u0412\u0435\u0440\u043d\u0443\u0442\u044c 0 \u0435\u0441\u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043f\u0440\u043e\u0431\u0435\u043b\u043e\u0432     if (std::count(str.begin(), str.end(), ' ') == str.length()) {         return 0;     }      \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043f\u0440\u043e\u0431\u0435\u043b\u0430     auto last_word_pos = str.rfind(' ');      \/\/ \u0412\u0435\u0440\u043d\u0443\u0442\u044c 0, \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0431\u0435\u043b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d, \u0438\u043d\u0430\u0447\u0435 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u043e\u0437\u0438\u0446\u0438\u044e + 1     return (last_word_pos == std::string::npos) ? 0 : last_word_pos + 1; }  \/**  * Get the last word in string.  *  * @param str String with words.  * @return Pair Position of the beginning of the  *         last word and the last word in string.  *\/ std::pair&lt;size_t, std::string&gt; get_last_word(std::string_view str) {     \/\/ \u041f\u043e\u0443\u043b\u0447\u0430\u0435\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u044e     size_t last_word_pos = get_last_word_pos(str);      \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043b\u043e\u0432\u043e \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438     auto last_word = str.substr(last_word_pos);      \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u0430\u0440\u0443 \u0438\u0437 \u0441\u043b\u043e\u0432\u0430 \u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0441\u043b\u043e\u0432\u0430 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 (\u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430)     return std::make_pair(last_word_pos, last_word.data()); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u043e \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u0443\u0433\u0430\u0434\u0430\u0442\u044c, \u0447\u0442\u043e \u0445\u043e\u0447\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c, \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0437\u043d\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043b\u043e\u0432\u043e, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0443\u0433\u0430\u0434\u0430\u0442\u044c, \u043d\u043e \u0438 \u0442\u043e, \u0447\u0442\u043e \u0448\u043b\u043e \u0434\u043e \u043d\u0435\u0433\u043e.<\/p>\n<p>  <\/p>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u0443\u0447\u0438\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043b\u043e\u0432\u043e \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/\/ \u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b std::min \u0438\u0437-\u0437\u0430 \u0441\u0442\u0440\u0430\u043d\u043d\u043e\u0433\u043e  \/\/ \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f MSVC \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 \/**  * Get the minimum of two numbers.  *  * @param a First value.  * @param b Second value.  * @return Minimum of two numbers.  *\/ size_t min_of(size_t a, size_t b) {     return (a &lt; b) ? a : b; }  \/**  * Get the penultimate words.  *  * @param str String with words.  * @return Pair Position of the beginning of the penultimate  *         word and the penultimate word in string.  *\/ std::pair&lt;size_t, std::string&gt; get_penult_word(std::string_view str) {     \/\/ \u041d\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u0440\u0430\u0432\u0443\u044e \u0433\u0440\u0430\u043d\u0438\u0446\u0443 \u043f\u043e\u0438\u0441\u043a\u0430     size_t end_pos = min_of(str.find_last_not_of(' ') + 2, str.length());      \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0441\u043b\u043e\u0432\u0430     size_t last_word = get_last_word_pos(str.substr(0, end_pos));      size_t penult_word_pos = 0;     std::string penult_word = &quot;&quot;;      \/\/ \u041d\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u0440\u0435\u0434\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043b\u043e\u0432\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u044f      \/\/ \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0431\u044b\u043b\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u0430     if (last_word != 0) {         \/\/ \u041d\u0430\u0445\u043e\u0434\u0438\u043c \u043d\u0430\u0447\u0430\u043b\u043e \u043f\u0440\u0435\u0434\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0441\u043b\u043e\u0432\u0430         penult_word_pos = str.find_last_of(' ', last_word - 2);          \/\/ \u041d\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u0440\u0435\u0434\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043b\u043e\u0432\u043e \u0435\u0441\u043b\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u0430         if (penult_word_pos != std::string::npos) {             penult_word = str.substr(penult_word_pos, last_word - penult_word_pos - 1);         }         \/\/ \u0418\u043d\u0430\u0447\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043b\u043e\u0432\u043e - \u0432\u0441\u0435, \u0447\u0442\u043e \u0434\u043e\u0448\u043b\u043e \u0434\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0441\u043b\u043e\u0432\u0430         else {             penult_word = str.substr(0, last_word - 1);         }     }      \/\/ \u041e\u0431\u0440\u0435\u0437\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0443     penult_word = trim(penult_word);      \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u0430\u0440\u0443 \u0438\u0437 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0438 \u0441\u043b\u043e\u0432\u0430 (\u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430)     return std::make_pair(penult_word_pos, penult_word); }<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"nahozhdenie-slov-dlya-avtodopolneniya\">\u041d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u0441\u043b\u043e\u0432 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f<\/h3>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/nv\/ad\/el\/nvadeldmm0f2_g5zwdg56ad8yhu.jpeg\" width=\"400\"\/><\/p>\n<p>\u0427\u0442\u043e \u0436\u0435 \u043c\u044b \u0437\u0430\u0431\u044b\u043b\u0438? \u0424\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0441\u043b\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435, \u043a\u0430\u043a \u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0441\u043b\u043e\u0432\u043e \u0432 \u0441\u0442\u0440\u043e\u043a\u0435.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/**  * Find strings in vector starts with substring.  *  * @param substr String with which the word should begin.  * @param penult_word Penultimate word in user-entered line.  * @param dict Vector of words.  * @param optional_brackets String with symbols for optional values.  * @return Vector with words starts with substring.  *\/ std::vector&lt;std::string&gt; words_starts_with(std::string_view substr, std::string_view penult_word,                   Dictionary&amp; dict, std::string_view optional_brackets) {     std::vector&lt;std::string&gt; result;      \/\/ \u0412\u044b\u0445\u043e\u0434 \u0435\u0441\u043b\u0438 \u043d\u0435\u0442 \u043a\u043b\u044e\u0447\u0430 \u0440\u0430\u0432\u043d\u043e\u0433\u043e penult_word \u0438\u043b\u0438     \/\/ substr \u0438\u043c\u0435\u0435\u0442 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0434\u043b\u044f \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u043b\u043e\u0432      if (!dict.count(penult_word.data()) ||         substr.find_first_of(optional_brackets) != std::string::npos)      {         return result;     }      \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043b\u043e\u0432\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c      \/\/ \u043f\u043e\u0441\u043b\u0435 last_word, \u0435\u0441\u043b\u0438 substr \u043f\u0443\u0441\u0442\u0430     if (substr.empty()) {         return dict[penult_word.data()];     }      \/\/ \u041d\u0430\u0445\u043e\u0434\u0438\u043c \u0441\u0442\u0440\u043e\u043a\u0438, \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0441 substr     std::vector&lt;std::string&gt; candidates_list = dict[penult_word.data()];     for (size_t i = 0 ; i &lt; candidates_list.size(); i++) {         if (candidates_list[i].find(substr) == 0) {             result.push_back(dict[penult_word.data()][i]);         }     }      return result; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0410 \u0447\u0442\u043e \u043f\u043e \u043f\u043e\u0432\u043e\u0434\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438? \u041c\u044b \u0436\u0435 \u0445\u043e\u0442\u0435\u043b\u0438 \u0435\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c? \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u044d\u0442\u043e.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/**  * Find strings in vector similar to a substring (max 1 error).  *  * @param substr String with which the word should begin.  * @param penult_word Penultimate word in user-entered line.  * @param dict Vector of words.  * @param optional_brackets String with symbols for optional values.  * @return Vector with words similar to a substring.  *\/ std::vector&lt;std::string&gt; words_similar_to(std::string_view substr, std::string_view penult_word,                   Dictionary&amp; dict, std::string_view optional_brackets) {     std::vector&lt;std::string&gt; result;      \/\/ \u0412\u044b\u0445\u043e\u0434, \u0435\u0441\u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0430 \u043f\u0443\u0441\u0442\u0430\u044f     if (substr.empty()) {         return result;     }      std::vector&lt;std::string&gt; candidates_list = dict[penult_word.data()];     for (size_t i = 0 ; i &lt; candidates_list.size(); i++) {         int errors = 0;          \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u0430         std::string candidate = candidates_list[i];          \/\/ \u041f\u043e\u0441\u0438\u043c\u0432\u043e\u043b\u044c\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u0430         for (size_t j = 0; j &lt; substr.length(); j++) {              \/\/ \u041f\u0440\u043e\u043f\u0443\u0441\u043a, \u0435\u0441\u043b\u0438 \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0434\u043b\u044f \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u043b\u043e\u0432             if (optional_brackets.find_first_of(candidate[j]) != std::string::npos) {                 errors = 2;                 break;             }              if (substr[j] != candidate[j]) {                 errors += 1;             }              if (errors &gt; 1) {                 break;             }         }          \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u0430\u043d\u0434\u0438\u0434\u0430\u0442\u0430, \u0435\u0441\u043b\u0438 \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u043e\u0434\u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0430         if (errors &lt;= 1) {             result.push_back(candidate);         }     }      return result; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u0441\u0435, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043b\u043e\u0432\u043e \u043f\u043e \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0435.<br \/>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0440\u0435\u0448\u0438\u043c \u044d\u0442\u0443 \u0437\u0430\u0434\u0430\u0447\u0443.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/**  * Get the word-prediction by the index.  *  * @param buffer String with user input.  * @param dict Dictionary with rules.  * @param number Index of word-prediction.  * @param optional_brackets String with symbols for optional values.  * @return Tuple of word-prediction, phrase for output, substring of buffer  *         preceding before phrase, start position of last word.  *\/ std::tuple&lt;std::string, std::string, std::string, size_t&gt; get_prediction(std::string_view buffer, Dictionary&amp; dict, size_t number,                std::string_view optional_brackets) {     \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u0441\u043b\u043e\u0432\u0435     auto [last_word_pos, last_word] = get_last_word(buffer);      \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043f\u0440\u0435\u0434\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u0441\u043b\u043e\u0432\u0435     auto [_, penult_word] = get_penult_word(buffer);      std::string prediction; \/\/ \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0435     std::string phrase;     \/\/ \u0444\u0440\u0430\u0437\u0430 \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430     std::string prefix;     \/\/ \u043f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0430 \u0431\u0443\u0444\u0435\u0440\u0430, \u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0444\u0440\u0430\u0437\u0435      \/\/ \u0418\u0449\u0435\u043c \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f     std::vector&lt;std::string&gt; starts_with = words_starts_with(         last_word, penult_word, dict, optional_brackets     );      \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0435\u0441\u043b\u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0431\u044b\u043b\u0438 \u043d\u0430\u0439\u0434\u0435\u043d\u044b     if (!starts_with.empty()) {         prediction = starts_with[number % starts_with.size()];         phrase = prediction;         prefix = buffer.substr(0, last_word_pos);     }     \/\/ \u0415\u0441\u043b\u0438 \u0441\u043b\u043e\u0432\u0430 \u043d\u0435 \u0431\u044b\u043b\u0438 \u043d\u0430\u0439\u0434\u0435\u043d\u044b     else {         \/\/ \u0418\u0449\u0435\u043c \u0441\u043b\u043e\u0432\u0430 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438         std::vector&lt;std::string&gt; similar = words_similar_to(             last_word, penult_word, dict, optional_brackets         );          \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0435\u0441\u043b\u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0431\u044b\u043b\u0438 \u043d\u0430\u0439\u0434\u0435\u043d\u044b         if (!similar.empty()) {             prediction = similar[number % similar.size()];             phrase = &quot; maybe you mean &quot; + prediction + &quot;?&quot;;             prefix = buffer;         }     }      \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435     return std::make_tuple(prediction, phrase, prefix, last_word_pos); }<\/code><\/pre>\n<p>  <\/p>\n<h3 id=\"vvod-polzovatelya-s-klaviatury\">\u0412\u0432\u043e\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b<\/h3>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/b5\/ud\/ba\/b5udba7w9mtihnxxwmqqmei5o6s.gif\" width=\"400\"\/><\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043e\u0434\u043d\u043e \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u043d\u0438\u0439. \u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0430\u043c\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u0432\u043e\u0434\u0430 \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">\/**  * Gets current terminal cursor position.  *  * @return Y position of terminal cursor.  *\/ short cursor_y_pos() { #if defined(OS_WINDOWS)     CONSOLE_SCREEN_BUFFER_INFO info;     GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &amp;info);     return info.dwCursorPosition.Y; #elif defined(OS_POSIX)     struct termios term, restore;     char ch, buf[30] = {0};     short i = 0, pow = 1, y = 0;      tcgetattr(0, &amp;term);     tcgetattr(0, &amp;restore);     term.c_lflag &amp;= ~(ICANON|ECHO);     tcsetattr(0, TCSANOW, &amp;term);      write(1, &quot;\\033[6n&quot;, 4);      for (ch = 0; ch != 'R'; i++) {         read(0, &amp;ch, 1);         buf[i] = ch;     }      i -= 2;     while (buf[i] != ';') {         i -= 1;     }      i -= 1;     while (buf[i] != '[') {         y = y + ( buf[i] - '0' ) * pow;         pow *= 10;         i -= 1;     }      tcsetattr(0, TCSANOW, &amp;restore);     return y; #endif }  \/**  * Move terminal cursor at position x and y.  *  * @param x X position to move.  * @param x Y position to move.  * @return Void.  *\/ void goto_xy(short x, short y) { #if defined(OS_WINDOWS)     COORD xy {--x, y};     SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), xy); #elif defined(OS_POSIX)     printf(&quot;\\033[%d;%dH&quot;, y, x); #endif }  \/**  * Printing user input with prompts.  *  * @param buffer String - User input.  * @param dict Vector of words.  * @param line_title Line title of CLI when entering command.  * @param number Hint number.  * @param optional_brackets String with symbols for optional values.  * @param title_color System code of title color     (line title color).  * @param predict_color System code of predict color (prediction color).  * @param default_color System code of default color (user input color).  * @return Void.  *\/ #if defined(OS_WINDOWS) void print_with_prompts(std::string_view buffer, Dictionary&amp; dict,                         std::string_view line_title, size_t number,                         std::string_view optional_brackets,                         uint16_t title_color, uint16_t predict_color,                         uint16_t default_color) { #else void print_with_prompts(std::string_view buffer, Dictionary&amp; dict,                         std::string_view line_title, size_t number,                         std::string_view optional_brackets,                         std::string title_color, std::string predict_color,                         std::string default_color) { #endif     \/\/ \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u0443\u0435\u043c\u0443\u044e \u0444\u0440\u0430\u0437\u0443 \u0438 \u0447\u0430\u0441\u0442\u044c \u0431\u0443\u0444\u0435\u0440\u0430, \u043f\u0440\u0435\u0434\u0448\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0444\u0440\u0430\u0437\u0435     auto [_, phrase, prefix, __] =          get_prediction(buffer, dict, number, optional_brackets);      std::string delimiter = line_title.empty() ? &quot;&quot; : &quot; &quot;;      std::cout &lt;&lt; clear_line;      std::cout &lt;&lt; '\\r' &lt;&lt; set_console_color(title_color) &lt;&lt; line_title               &lt;&lt; set_console_color(default_color) &lt;&lt; delimiter &lt;&lt; prefix               &lt;&lt; set_console_color(predict_color) &lt;&lt; phrase;      std::cout &lt;&lt; '\\r' &lt;&lt; set_console_color(title_color) &lt;&lt; line_title               &lt;&lt; set_console_color(default_color) &lt;&lt; delimiter &lt;&lt; buffer; }  \/**  * Reading user input with autocomplete.  *  * @param dict Vector of words.  * @param optional_brackets String with symbols for optional values.  * @param title_color System code of title color     (line title color).  * @param predict_color System code of predict color (prediction color).  * @param default_color System code of default color (user input color).  * @return User input.  *\/ #if defined(OS_WINDOWS) std::string input(Dictionary&amp; dict, std::string_view line_title,                   std::string_view optional_brackets, uint16_t title_color,                   uint16_t predict_color, uint16_t default_color) { #else std::string input(Dictionary&amp; dict, std::string_view line_title,                   std::string_view optional_brackets, std::string title_color,                   std::string predict_color, std::string default_color) { #endif     std::string buffer;       \/\/ \u0411\u0443\u0444\u0435\u0440     size_t offset = 0;        \/\/ \u0421\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u043e\u0442 \u043a\u043e\u043d\u0446\u0430 \u0431\u0443\u0444\u0435\u0440\u0430     size_t number = 0;        \/\/ \u041d\u043e\u043c\u0435\u0440 (\u0438\u043d\u0434\u0435\u043a\u0441) \u043f\u043e\u0441\u0434\u043a\u0430\u0437\u043a\u0438, \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f     short y = cursor_y_pos(); \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u043f\u043e \u043e\u0441\u0438 Y \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435      \/\/ \u0418\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b     #if defined(OS_WINDOWS)     std::vector&lt;int&gt; ignore_keys({1, 2, 19, 24, 26});     #elif defined(OS_POSIX)     std::vector&lt;int&gt; ignore_keys({1, 2, 4, 24});     #endif      while (true) {         \/\/ \u0412\u044b\u0432\u043e\u0434\u0438\u043c \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0435\u043c         print_with_prompts(buffer, dict, line_title, number, optional_brackets,                            title_color, predict_color, default_color);          \/\/ \u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u043c \u043a\u0443\u0440\u0441\u043e\u0440 \u0432 \u043d\u0443\u0436\u043d\u0443\u044e \u043f\u043e\u0437\u0438\u0446\u0438\u044e         short x = short(             buffer.length() + line_title.length() + !line_title.empty() + 1 - offset         );         goto_xy(x, y);          \/\/ \u0421\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0441\u0438\u043c\u0432\u043e\u043b         int ch = _getch();          \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0431\u0443\u0444\u0435\u0440, \u0435\u0441\u043b\u0438 \u043d\u0430\u0436\u0430\u0442 Enter         if (ch == ENTER) {             return buffer;         }          \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u044b\u0445\u043e\u0434\u0430 \u0438\u0437 CLI \u0432 Windows         #if defined(OS_WINDOWS)         else if (ch == CTRL_C) {             exit(0);         }         #endif          \/\/ \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0431\u0443\u0444\u0435\u0440\u0430 \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 BACKSPACE         else if (ch == BACKSPACE) {             if (!buffer.empty() &amp;&amp; buffer.length() - offset &gt;= 1) {                 buffer.erase(buffer.length() - offset - 1, 1);             }         }          \/\/ \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 TAB         else if (ch == TAB) {             \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e             auto [prediction, _, __, last_word_pos] =                  get_prediction(buffer, dict, number, optional_brackets);              \/\/ \u0414\u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0430\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f             if (!prediction.empty() &amp;&amp;                  prediction.find_first_of(optional_brackets) == std::string::npos) {                 buffer = buffer.substr(0, last_word_pos) + prediction + &quot; &quot;;             }              \/\/ \u041e\u0447\u0438\u0449\u0430\u0435\u043c \u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 \u0438 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435             offset = 0;             number = 0;         }          \/\/ \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u0442\u0440\u0435\u043b\u043e\u043a         #if defined(OS_WINDOWS)         else if (ch == 0 || ch == 224)         #elif defined(OS_POSIX)         else if (ch == 27 &amp;&amp; _getch() == 91)         #endif                 switch (_getch()) {                     case LEFT:                         \/\/ \u0423\u0432\u0435\u043b\u0438\u0447\u044c\u0442\u0435 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u043d\u0430\u0436\u0430\u0442\u0430 \u043b\u0435\u0432\u0430\u044f \u043a\u043b\u0430\u0432\u0438\u0448\u0430                         offset = (offset &lt; buffer.length())                                      ? offset + 1                                     : buffer.length();                         break;                     case RIGHT:                         \/\/ \u0423\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u043d\u0430\u0436\u0430\u0442\u0430 \u043f\u0440\u0430\u0432\u0430\u044f \u043a\u043b\u0430\u0432\u0438\u0448\u0430                         offset = (offset &gt; 0) ? offset - 1 : 0;                         break;                     case UP:                         \/\/ \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438                         number = number + 1;                         std::cout &lt;&lt; clear_line;                         break;                     case DOWN:                         \/\/ \u0423\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0438\u043d\u0434\u0435\u043a\u0441 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438                         number = number - 1;                         std::cout &lt;&lt; clear_line;                         break;                     case DEL:                     \/\/ \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0431\u0443\u0444\u0435\u0440\u0430, \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 DELETE                     #if defined(OS_POSIX)                     if (_getch() == 126)                     #endif                     {                         if (!buffer.empty() &amp;&amp; offset != 0) {                             buffer.erase(buffer.length() - offset, 1);                             offset -= 1;                         }                     }                     default:                         break;                 }          \/\/ \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0438\u043c\u0432\u043e\u043b \u0432 \u0431\u0443\u0444\u0435\u0440 \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f         \/\/ \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u043b\u0430\u0432\u0438\u0448\u0438         else if (!std::count(ignore_keys.begin(), ignore_keys.end(), ch)) {             buffer.insert(buffer.end() - offset, (char)ch);              if (ch == SPACE) {                 number = 0;             }         }     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435, \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043d\u0430\u0448 \u043a\u043e\u0434 \u0432 \u0434\u0435\u043b\u0435.<\/p>\n<p>  <\/p>\n<h3 id=\"primer-ispolzovaniya\">\u041f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/h3>\n<p>  <\/p>\n<pre><code class=\"cpp\">#include &lt;iostream&gt; #include &lt;string&gt;  #include &quot;..\/include\/autocomplete.h&quot;  int main() {     \/\/ \u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438     std::string config_file_path = &quot;..\/config.txt&quot;;      \/\/ \u0421\u0438\u043c\u0432\u043e\u043b\u044b, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0435      \/\/ \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440)     std::string optional_brackets = &quot;[&quot;;      \/\/ \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0434\u0430\u0442\u044c \u0446\u0432\u0435\u0442     #if defined(OS_WINDOWS)         uint16_t title_color = 160; \/\/ by default 10         uint16_t predict_color = 8; \/\/ by default 8         uint16_t default_color = 7; \/\/ by default 7     #elif defined(OS_POSIX)         \/\/ Set the value that goes between \\033 and m ( \\033{your_value}m )         std::string title_color = &quot;0;30;102&quot;;  \/\/ by default 92         std::string predict_color = &quot;90&quot;;      \/\/ by default 90         std::string default_color = &quot;0&quot;;       \/\/ by default 90     #endif      \/\/ \u041f\u0435\u0440\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u043b\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0441\u0442\u0440\u043e\u043a\u0438     size_t command_counter = 0;      \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u043e\u0432\u0430\u0440\u044c     auto [dict, status, message] = parse_config_file(config_file_path);      \/\/ \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0441\u043b\u043e\u0432\u0430\u0440\u044f \u0443\u0441\u043f\u0435\u0448\u043d\u043e     if (status) {         std::cerr &lt;&lt; &quot;Attention! Please run the executable file only&quot; &lt;&lt; std::endl                   &lt;&lt; &quot;through the command line!\\n\\n&quot;;          std::cerr &lt;&lt; &quot;- To switch the prompts press UP or DOWN arrow.&quot; &lt;&lt; std::endl;         std::cerr &lt;&lt; &quot;- To move cursor press LEFT or RIGHT arrow.&quot; &lt;&lt; std::endl;         std::cerr &lt;&lt; &quot;- To edit input press DELETE or BACKSPACE key.&quot; &lt;&lt; std::endl;         std::cerr &lt;&lt; &quot;- To apply current prompt press TAB key.\\n\\n&quot;;          \/\/ \u041d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u0441\u043b\u0443\u0448\u0430\u0442\u044c         while (true) {             \/\/ \u0417\u0430\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u0442\u0440\u043e\u043a\u0438             std::string line_title = &quot;git [&quot; + std::to_string(command_counter) + &quot;]:&quot;;              \/\/ \u041e\u0436\u0438\u0434\u0430\u0435\u043c \u0432\u0432\u043e\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043e\u043a             std::string command = input(dict, line_title, optional_brackets,                                         title_color, predict_color, default_color);              \/\/ \u0414\u0435\u043b\u0430\u0435\u043c \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439             std::cout &lt;&lt; std::endl &lt;&lt; command &lt;&lt; std::endl &lt;&lt; std::endl;              command_counter++;         }     }     \/\/ \u0412\u044b\u0432\u043e\u0434 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u0435\u0441\u043b\u0438 \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043d\u0435 \u0431\u044b\u043b \u0441\u0447\u0438\u0442\u0430\u043d     else {         std::cerr &lt;&lt; message &lt;&lt; std::endl;     }      return 0; }<\/code><\/pre>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/rh\/gd\/ku\/rhgdkultldauofi3ky2p9_xakxe.gif\" width=\"400\"\/><\/p>\n<p>\u041a\u043e\u0434 \u0431\u044b\u043b \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d \u043d\u0430 macOS, Linux, Windows. \u0412\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043e\u0442\u043b\u0438\u0447\u043d\u043e.<\/p>\n<p>  <\/p>\n<h3 id=\"zaklyuchenie\">\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/h3>\n<p>  <\/p>\n<p>\u041a\u0430\u043a \u0432\u044b \u0432\u0438\u0434\u0438\u0442\u0435, \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0440\u043e\u0441\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043f\u0438\u0441\u0430\u0442\u044c, \u0442\u043e \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u043d\u0430 Windows \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438 \u0434\u043b\u044f Linux \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0438 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442), \u043e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u0438 \u0441\u0430\u043c \u0444\u0430\u043a\u0442, \u0447\u0442\u043e \u044d\u0442\u043e \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 \u0432\u0441\u0435\u0445 \u0442\u0440\u0435\u0445 \u041e\u0421, \u043a\u0440\u0430\u0439\u043d\u0435 \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u044f \u0431\u044b\u043b \u043a\u043e\u043c\u0443-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u043e\u043b\u0435\u0437\u0435\u043d. \u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u0435\u0441\u0442\u044c \u0447\u0442\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u044c, \u0431\u0443\u0434\u0443 \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043b\u0443\u0448\u0430\u0442\u044c \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445.<\/p>\n<p>  <\/p>\n<p><em><a href=\"https:\/\/github.com\/DieTime\/CLI-AutoComplete\">\u0418\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0442\u0443\u0442<\/a>.<br \/>  \u041f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u043d\u0430 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435.<\/em><\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/515946\/\"> https:\/\/habr.com\/ru\/post\/515946\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/515946\/\">\n<h3 id=\"privetstvie\">\u041f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435<\/h3>\n<p>  <\/p>\n<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442! \u0425\u043e\u0447\u0443 \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u0440\u043e\u0441\u0441\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043d\u0430 C++ \u0434\u043b\u044f \u0438\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0430\u0432\u0442\u043e\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0432 CLI \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0443\u0441\u0430\u0436\u0438\u0432\u0430\u0439\u0442\u0435\u0441\u044c \u043f\u043e\u0443\u0434\u043e\u0431\u043d\u0435\u0435.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/rh\/gd\/ku\/rhgdkultldauofi3ky2p9_xakxe.gif\" width=\"400\"\/>  <\/p>\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-308781","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308781","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=308781"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/308781\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=308781"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=308781"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=308781"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}