{"id":492942,"date":"2026-08-31T12:28:45","date_gmt":"2026-08-31T12:28:45","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=492942"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2026-08-31T12:28:45","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=492942","title":{"rendered":"\u0410\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0432\u00a0\u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435\u00a0\u2014 \u044d\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u043e (\u0438\u043d\u043e\u0433\u0434\u0430)"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!<\/p>\n<p>\u041d\u0435\u00a0\u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e \u044f \u043d\u0430\u00a0\u0440\u043e\u0432\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0437\u0430\u043d\u044f\u043b\u0441\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0430\u00a0Go \u0434\u043b\u044f, \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c\u00a0\u0431\u044b, \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438\u00a0\u2014 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u043d\u0435\u00a0\u0431\u0443\u0434\u0435\u0442 \u043b\u043e\u043c\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438\u00a0\u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u044f\u0445 \u0432\u00a0stderr \u0438 stdout.<\/p>\n<p>\u0412\u0441\u0435 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441\u00a0\u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u00a0\u044f \u043f\u0438\u0441\u0430\u043b \u0432\u043e\u043e\u0431\u0449\u0435 \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u043e\u0434\u00a0\u2014 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u0443\u044e \u0443\u0442\u0438\u043b\u0438\u0442\u0443 \u0434\u043b\u044f\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432. \u0418 \u0437\u0430\u0445\u043e\u0442\u0435\u043b \u043f\u0440\u0438\u043a\u0440\u0443\u0442\u0438\u0442\u044c \u0442\u0443\u0434\u0430 \u0441\u043f\u0438\u043d\u043d\u0435\u0440. \u041d\u043e\u00a0\u043d\u0435\u00a0\u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043f\u0438\u043d\u043d\u0435\u0440, \u0430\u00a0\u0442\u0430\u043a\u043e\u0439, \u0447\u0442\u043e\u00a0\u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u00a0\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0432\u044b\u0432\u043e\u0434\u0430\u00a0\u2014 stderr \u0438 stdout, \u0431\u0435\u0437\u00a0\u0440\u0438\u0441\u043a\u0430 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u043d\u0430\u00a0\u044d\u043a\u0440\u0430\u043d\u0435. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u0432\u043e\u00a0\u0432\u0440\u0435\u043c\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u00a0\u044d\u043a\u0440\u0430\u043d\u0435 \u043e\u0442\u0447\u0435\u0442\u044b \u043f\u043e\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0432\u0448\u0438\u043c\u0441\u044f \u0442\u0435\u0441\u0442\u0430\u043c, \u043d\u0435\u00a0\u043e\u0442\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044f \u044d\u0442\u043e \u0432\u0441\u0435 \u0434\u043e\u00a0\u043a\u043e\u043d\u0446\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\/\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430. \u0418 \u0442\u0430\u043a \u0443\u0436 \u043f\u043e\u0447\u0435\u043c\u0443\u2011\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c (\u0441\u043f\u043e\u0439\u043b\u0435\u0440: \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u043d\u0435\u00a0\u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u043e, \u0438\u043d\u043e\u0433\u0434\u0430 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u043c\u0430\u043b\u043e \u043a\u043e\u043c\u0443 \u043d\u0443\u0436\u043d\u043e), \u0447\u0442\u043e\u00a0\u044f \u043d\u0435\u00a0\u0441\u043c\u043e\u0433 \u043d\u0430\u0439\u0442\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f\u00a0\u0431\u044b \u043c\u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u0430.<\/p>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 \u043c\u043d\u0435 \u043d\u0435\u00a0\u043f\u043e\u0434\u0445\u043e\u0434\u0438\u043b\u043e \u043d\u0438 \u043e\u0434\u043d\u043e \u0438\u0437\u00a0\u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439:<\/p>\n<ul>\n<li>\n<p>\u0421\u0430\u043c\u044b\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043d\u0435\u00a0\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0438 \u0437\u0430\u043f\u0438\u0441\u044c (<a href=\"https:\/\/github.com\/briandowns\/spinner\" rel=\"noopener nofollow\">github.com\/briandowns\/spinner<\/a>, <a href=\"https:\/\/github.com\/yarlson\/pin\" rel=\"noopener nofollow\">github.com\/yarlson\/pin<\/a>).<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u00a0\u043f\u043e\u0442\u043e\u043a \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 \u043d\u0435\u00a0\u043b\u043e\u043c\u0430\u044f \u0435\u0433\u043e, \u0443\u0436\u0435 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0442\u044f\u0436\u0435\u043b\u043e\u0432\u0435\u0441\u043d\u0435\u0435 \u0438 \u043d\u0435\u00a0\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 stdout\/stderr (<a href=\"https:\/\/github.com\/theckman\/yacspin\" rel=\"noopener nofollow\">github.com\/theckman\/yacspin<\/a>).<\/p>\n<\/li>\n<li>\n<p>\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0435 \u0432\u0441\u0435 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435,\u00a0\u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u043d\u043e\u0432\u0435\u0441\u043d\u044b\u0435 TUI \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438 \u0441\u00a0\u0440\u0435\u043d\u0434\u0435\u0440\u2011\u0431\u0443\u0444\u0435\u0440\u043e\u043c \u0438 raw\u2011\u0440\u0435\u0436\u0438\u043c\u043e\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0435\u0441\u044c \u0444\u0430\u0439\u043b \u043c\u043e\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u0435\u0441\u0438\u0442 \u043c\u0435\u043d\u044c\u0448\u0435 9\u00a0\u041c\u0411. \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u044f\u0436\u0435\u043b\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u00a0\u043b\u0438\u0448\u044c \u0440\u0430\u0434\u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 (\u0438 \u043a\u0430\u043a\u00a0\u043f\u043e\u0437\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c\u00a0\u2014 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u2011\u0431\u0430\u0440\u0430)\u00a0\u2014 \u043d\u0435\u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0441\u0442\u043e\u0447\u0438\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e.<\/p>\n<h3>\u041c\u043e\u043b\u043e\u0434\u043e\u0441\u0442\u044c \u0438 \u0440\u0430\u0434\u043e\u0441\u0442\u044c (\u043d\u0430\u0438\u0432\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435)<\/h3>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0441\u043f\u0438\u043d\u043d\u0435\u0440 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e. \u041d\u0430\u00a0\u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u044d\u0442\u043e \u043d\u0435\u00a0\u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430\u00a0\u2014 \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u0432\u0441\u0435\u0433\u043e \u043f\u0430\u0440\u0443 \u0432\u0435\u0449\u0435\u0439:<\/p>\n<ul>\n<li>\n<p>ANSI\u2011\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c <code>\"\\033[K\"<\/code> \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u0432\u0441\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u0440\u0430\u0432\u0435\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0440\u0430 (\u0435\u0441\u0442\u044c \u0435\u0449\u0435 <code>\"\\033[1K\"<\/code>\u00a0\u2014 \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u0432\u0441\u0435 \u043b\u0435\u0432\u0435\u0435, \u0438 <code>\"\\033[2K\"<\/code>\u00a0\u2014 \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u0432\u0441\u044e \u0441\u0442\u0440\u043e\u043a\u0443, \u043d\u043e\u00a0\u043e\u0431\u00a0\u044d\u0442\u043e\u043c \u043f\u043e\u0437\u0436\u0435) <strong>\u0432\u00a0\u043f\u043e\u0442\u043e\u043a\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 ANSI\u2011\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438<\/strong>.<\/p>\n<\/li>\n<li>\n<p>\u0411\u0430\u0439\u0442 <code>'\\r'<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u0442 \u043a\u0443\u0440\u0441\u043e\u0440 \u0432\u00a0\u043d\u0430\u0447\u0430\u043b\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f <code>\"\\r\\033[K\"<\/code>, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0438 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u043a\u0443\u0440\u0441\u043e\u0440 \u0432\u00a0\u0441\u0430\u043c\u043e\u0435 \u043d\u0430\u0447\u0430\u043b\u043e. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 <code>\"\\033[1K\\r\"<\/code>, \u0438 <code>\"\\r\\033[2K\"<\/code>, \u043d\u043e\u00a0\u0437\u0430\u0447\u0435\u043c \u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435, \u043a\u043e\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435?<\/p>\n<p>\u041d\u0443 \u0430\u00a0\u0434\u0430\u043b\u044c\u0448\u0435 \u0432\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u043e\u00a0\u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e. \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e <code>io.Writer<\/code> \u0438 \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e:<\/p>\n<pre><code class=\"go\">var clearBytes []byte = []byte(\"\\r\\033[K\")var spinnerBytes []byte = []byte(\"\u0422\u0443\u0442 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u043e\")type Spinner struct {  io.Writer}func (s Spinner) Write(data []byte) (int, error) {  s.Writer.Write(clearBytes)  res, err := s.Writer.Write(data)  s.Writer.Write(spinnerBytes)  return res, err}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u00a0\u0436\u0435, \u0432\u0441\u0435 \u043d\u0435\u00a0\u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430\u00a0\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u00a0\u043d\u0430\u0441 \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0442\u0441\u044f:<\/p>\n<ol>\n<li>\n<p>\u0422\u043e, \u0447\u0442\u043e\u00a0\u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438\u00a0\u2014 \u044d\u0442\u043e \u043d\u0435\u00a0\u0441\u043f\u0438\u043d\u043d\u0435\u0440. \u042d\u0442\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u00a0\u2014 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0442\u0435\u043a\u0441\u0442, \u0437\u0430\u043a\u0440\u0435\u043f\u043b\u0435\u043d\u043d\u044b\u0439 \u043d\u0430\u00a0\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041c\u044b \u0432\u0441\u0435 \u0435\u0449\u0435 \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c\u00a0\u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u043f\u043e\u0442\u043e\u043a\u00a0\u2014 \u043b\u044e\u0431\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0stdout \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a\u00a0\u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044e \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0430\u043c\u0430\u044f \u043c\u0435\u043b\u043e\u0447\u044c\u00a0\u2014 \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u0442\u0438\u0445\u0443\u044e \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u00a0\u044d\u043a\u0440\u0430\u043d\u0430. \u0412\u0435\u0434\u044c \u0435\u0441\u043b\u0438 <code>data<\/code> \u043d\u0435\u00a0\u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439, \u043d\u0430\u0448\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0432\u00a0\u043f\u043e\u0442\u043e\u043a \u043f\u0440\u0438\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0437\u0430\u043f\u0438\u0441\u0438, \u0441\u043e\u0442\u0440\u0435\u0442 \u0432\u0441\u044e \u0441\u0442\u0440\u043e\u043a\u0443\u00a0\u2014 \u0438 \u043d\u0430\u0448 \u0441\u043f\u0438\u043d\u043d\u0435\u0440, \u0438 \u0432\u0441\u0435, \u0447\u0442\u043e\u00a0\u0431\u044b\u043b\u043e \u0434\u043e\u00a0\u043d\u0435\u0433\u043e.<\/p>\n<\/li>\n<\/ol>\n<p>\u0425\u043e\u0440\u043e\u0448\u043e, \u043d\u0430\u0447\u043d\u0435\u043c \u0441\u00a0\u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e. \u0411\u0443\u0434\u0435\u043c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0442\u043e, \u0447\u0442\u043e\u00a0\u043d\u0430\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0438, \u0438 \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u043d\u043d\u0435\u0440 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0431\u0430\u0439\u0442\u00a0\u2014 \u044d\u0442\u043e \u043d\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430.<\/p>\n<pre><code class=\"go\">type Spinner struct {  io.Writer  frame []byte  isDrawn bool}func (s *Spinner) Write(data []byte) (int, error) {  if s.isDrawn {      s.Writer.Write(clearBytes)      s.isDrawn = false  }  res, err := s.Writer.Write(data)  \/\/ \u0412\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u0441\u043a\u0430\u0436\u0435\u0442 \"res-1 &lt; len(data) \u0431\u0435\u0441\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\",  \/\/ \u043d\u043e \u044f \u043e\u0442\u0432\u0435\u0447\u0443 - io.Writer \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u044e\u0437\u0435\u0440, \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u043d\u0430  \/\/ \u0434\u0436\u0435\u043d\u0442\u043b\u044c\u043c\u0435\u043d\u0441\u043a\u0438\u0435 \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u0438 - \u044d\u0442\u043e \u0438\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u043d\u043e\u0432\u0438\u0447\u043a\u0430 \u0438\u043b\u0438 \u0448\u0430\u0433  \/\/ \u0443\u043b\u044c\u0442\u0440\u0430\u0441\u0435\u043d\u044c\u043e\u0440\u0430. \u042f \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043d\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u044e \u043d\u0438 \u0432 \u043e\u0434\u043d\u0443 \u0438\u0437 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439  if err == nil &amp;&amp; res &gt; 0 &amp;&amp; res-1 &lt; len(data) &amp;&amp; data[res-1] == '\\n' {      s.Writer.Write(s.frame)      s.isDrawn = true  }  return res, err}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u043e\u0434\u043d\u043e \u044f \u043f\u0435\u0440\u0435\u043d\u0435\u0441 \u043d\u0430\u0448\u0438 \u0431\u0430\u0439\u0442\u044b \u0444\u0440\u0435\u0439\u043c\u0430 \u0432\u00a0\u0441\u0430\u043c \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u00a0\u2014 \u044d\u0442\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0432\u00a0\u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c. \u041d\u043e\u00a0\u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043e\u0434\u043d\u0443 \u0438\u0437\u00a0\u0442\u0440\u0435\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c. \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0435\u0449\u0435 \u0434\u0432\u0435? \u041d\u0430\u00a0\u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u0440\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>bool<\/code> \u0434\u043b\u044f\u00a0\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430, \u043d\u043e\u00a0\u0443\u00a0\u043d\u0430\u0441 \u043d\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0439, \u0447\u0442\u043e\u00a0\u043a\u0430\u043a\u043e\u0439\u2011\u043d\u0438\u0431\u0443\u0434\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 <code>Write<\/code> \u043d\u0435\u00a0\u0432\u043c\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u0432\u00a0\u043d\u0430\u0448\u0443 \u043b\u043e\u0433\u0438\u043a\u0443. \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043d\u0435\u00a0\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e\u00a0\u2014 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u044c\u044e\u0442\u0435\u043a\u0441 \u043d\u0430\u00a0\u0432\u0435\u0441\u044c \u0431\u043b\u043e\u043a <code>Write<\/code>:<\/p>\n<pre><code class=\"go\">type Spinner struct {  ...  mut *sync.Mutex}func (s *Spinner) Write(data []byte) (int, error) {  s.mut.Lock()  defer s.mut.Unlock()  ...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u043e\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043a\u043e\u043d\u0435\u0446\u2011\u0442\u043e \u0443\u00a0\u043d\u0430\u0441 \u0432\u0441\u0435\u0433\u043e \u0434\u0432\u0435 \u043a\u0440\u0443\u043f\u043d\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u041e\u0434\u043d\u0430 \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u00a0\u2014 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u044b \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u00a0\u0444\u043e\u043d\u043e\u0432\u043e\u0439 \u0433\u043e\u0440\u0443\u0442\u0438\u043d\u0435 \u0440\u0430\u0437 \u0432\u00a0\u043a\u0430\u043a\u043e\u0435\u2011\u0442\u043e \u0432\u0440\u0435\u043c\u044f:<\/p>\n<pre><code class=\"go\">func (s *Spinner) Start() context.CancelFunc {  t := time.NewTicker(100 * time.Millisecond)  ctx, cancel := context.WithCancel(context.Background())  ch := make(chan struct{}, 1)  s.mut.Lock()  s.frame = []byte(\"- Running\")  if s.isDrawn {    \/\/ \u0417\u0434\u0435\u0441\u044c \u0438 \u0434\u0430\u043b\u0435\u0435 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c append(packageVar, other...) -    \/\/ \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043b\u044f \u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0442\u0438. \u041d\u0435 \u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u0442\u0430\u043a \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u0434\u0435.    s.Writer.Write(append(clearBytes, s.frame...))  }  s.mut.Unlock()  go func() {    states := []byte{'\\\\', '|', '\/', '-'}    idx := 0  Loop:    for {      select {        case &lt;-t.C:          s.mut.Lock()          s.frame[0] = states[idx]          if s.isDrawn {            s.Writer.Write(append(clearBytes, s.frame...))          }          s.mut.Unlock()          idx = (idx + 1) % len(states)        case &lt;-ctx.Done():          break Loop      }    }    s.mut.Lock()    s.frame = []byte{}    if s.isDrawn {      s.Writer.Write(clearBytes)    }    s.mut.Unlock()    close(ch)  }()  return func() {    t.Stop()    cancel()    &lt;-ch  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0441\u043f\u0438\u043d\u043d\u0435\u0440. \u041d\u0435\u00a0\u0431\u0435\u0437\u00a0\u0438\u0437\u044a\u044f\u043d\u043e\u0432, \u043d\u043e\u00a0\u0440\u0430\u0431\u043e\u0447\u0438\u0439. \u041a\u0430\u043a\u00a0\u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u0430\u043d\u0433\u043b\u043e\u044f\u0437\u044b\u0447\u043d\u044b\u0435\u00a0\u2014 \u00ab\u0442\u0430\u043a \u0434\u0430\u043b\u0435\u043a\u043e \u0442\u0430\u043a \u0445\u043e\u0440\u043e\u0448\u043e\u00bb. \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0435\u0448\u0438\u0442\u044c \u043e\u0434\u043d\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443\u00a0\u2014 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u044e \u0434\u0432\u0443\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432. \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u043e\u0447\u0435\u043d\u044c \u0447\u0430\u0441\u0442\u043e \u0437\u0430\u043f\u0438\u0441\u0438 \u0432\u00a0stderr \u0438 stdout \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432\u00a0\u043e\u0434\u043d\u043e\u043c \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435. \u041d\u0443 \u0438 \u043f\u043e\u0434\u00a0\u0448\u0443\u043c\u043e\u043a \u0440\u0435\u0448\u0438\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u00a0\u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438\u00a0\u0437\u0430\u043f\u0438\u0441\u0438\/\u043e\u0447\u0438\u0441\u0442\u043a\u0435 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 \u043d\u0430\u00a0\u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0442\u0438\u0445\u0443\u044e \u043f\u0440\u043e\u0433\u043b\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f. \u0423\u00a0\u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043c\u044c\u044e\u0442\u0435\u043a\u0441, \u0430\u00a0\u0437\u043d\u0430\u0447\u0438\u0442, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0438\u0441\u0438. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u00a0\u2014 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 \u0438 \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0438, \u043d\u043e\u00a0\u043f\u0440\u0438\u00a0\u044d\u0442\u043e\u043c \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0435 \u0441\u043e \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u043e\u043c (\u0442\u0430\u043a \u043a\u0430\u043a\u00a0\u0443\u00a0\u043d\u0438\u0445 \u043e\u0431\u0449\u0438\u0435 <code>isDrawn<\/code>, <code>mut<\/code>, <code>frame<\/code>):<\/p>\n<pre><code class=\"go\">type spinnerState struct {  io.Writer  sync.Mutex  errCh   chan error  frame   []byte  isDrawn bool}type Spinner struct {  io.Writer  state *spinnerState}func (s *Spinner) Write(data []byte) (int, error) {  s.state.Lock()  defer s.state.Unlock()  if s.state.isDrawn {    _, err := s.state.Write(clearBytes)    s.state.isDrawn = false    if err != nil {      select {      case s.state.errCh &lt;- err:      default:      }    }  }  res, err := s.Writer.Write(data)  if err == nil &amp;&amp; res &gt; 0 &amp;&amp; res-1 &lt; len(data) &amp;&amp; data[res-1] == '\\n' {    _, localErr := s.state.Write(s.state.frame)    if localErr != nil {      select {      case s.state.errCh &lt;- localErr:      default:      }    } else {      s.state.isDrawn = true    }  }  return res, err}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>Start<\/code> \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0432\u0441\u0435 \u0442\u0435\u00a0\u0436\u0435 \u0437\u0430\u043c\u0435\u043d\u044b <code>s.Writer.Write<\/code> \u2192 <code>s.state.Write<\/code>, <code>s.mut.Lock<\/code> \u2192 <code>s.state.Lock<\/code> \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435, \u0438 \u0432\u0441\u0435 \u0442\u0430\u043a\u00a0\u0436\u0435 \u043f\u0438\u0448\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432\u00a0\u043a\u0430\u043d\u0430\u043b \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0439 <code>select<\/code>. \u041f\u043e\u0447\u0435\u043c\u0443 \u043c\u044b \u0434\u043e\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u00a0\u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0443 <code>Start<\/code> \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e \u043d\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 (\u043d\u0443 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u0430\u043d\u0430\u043b \u0441\u00a0\u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438 \u0435\u0449\u0435, \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u043c\u0430\u043b\u043e \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f), \u0430\u00a0\u0432\u043e <code>Write<\/code>\u00a0\u0431\u044b\u043b\u043e\u00a0\u0431\u044b \u0441\u0442\u0440\u0430\u043d\u043d\u043e, \u043a\u00a0\u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u043d\u0430\u00a0\u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0stdout \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432\u00a0stderr.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/18e\/11b\/be3\/18e11bbe31a8c1c8a50c73947227d058.gif\" alt=\"\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 - \u0431\u0435\u0437 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0441 \u043d\u0435\u0439\" width=\"1100\" height=\"860\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/18e\/11b\/be3\/18e11bbe31a8c1c8a50c73947227d058.gif 780w,&#10;       https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/18e\/11b\/be3\/18e11bbe31a8c1c8a50c73947227d058.gif 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435\u00a0\u2014 \u0431\u0435\u0437\u00a0\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0441\u00a0\u043d\u0435\u0439<\/figcaption><\/div>\n<\/figure>\n<p>\u0412\u00a0\u0446\u0435\u043b\u043e\u043c, \u044d\u0442\u043e \u043f\u043b\u044e\u0441\u2011\u043c\u0438\u043d\u0443\u0441 \u0432\u0441\u0435. \u0414\u043b\u044f\u00a0\u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u00a0\u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043f\u043e\u0434\u00a0\u0437\u0430\u0434\u0430\u0447\u0443 \u0432\u00a0\u0442\u043e\u043c, \u0447\u0442\u043e\u00a0\u043a\u043e\u0433\u0434\u0430\u2011\u043d\u0438\u0431\u0443\u0434\u044c \u0442\u0430\u043a\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0440\u0435\u0448\u0430\u0442\u044c \u0435\u0449\u0435 \u0440\u0430\u0437\u2026 \u0418 \u0437\u0430\u00a0\u043d\u0435\u0438\u043c\u0435\u043d\u0438\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u044f \u0440\u0435\u0448\u0438\u043b\u00a0\u2014 \u0430\u00a0\u0431\u0430\u0445\u043d\u0443\u2011\u043a\u0430 \u044f \u0441\u0432\u043e\u044e. \u041a\u0430\u043a\u00a0\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u00a0\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0432\u0435\u0440\u0441\u0442\u043a\u043e\u0439 \u0438 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u2011\u0431\u0430\u0440\u0430\u043c\u0438.<\/p>\n<h3>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430? \u041b\u0443\u0447\u0448\u0435\u00a0\u2014 \u0441\u0435\u043a\u0446\u0438\u044f \u043e\u00a0\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435<\/h3>\n<p>\u0418\u0442\u0430\u043a, \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a\u00a0\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u0447\u043d\u043e\u043c\u0443 \u043a\u043e\u0434\u0443. \u0427\u0442\u043e\u00a0\u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f?<\/p>\n<ol>\n<li>\n<p>\u041d\u0430\u00a0\u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 <code>Start<\/code> \u043d\u0435\u00a0\u0438\u0434\u0435\u043c\u043f\u043e\u0442\u0435\u043d\u0442\u0435\u043d, \u0430\u00a0\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u0435\u00a0\u0434\u043e\u043b\u0436\u0435\u043d \u043b\u043e\u043c\u0430\u0442\u044c\u0441\u044f \u043e\u0442\u00a0\u0442\u0430\u043a\u0438\u0445 \u043c\u0435\u043b\u043e\u0447\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0425\u043e\u0442\u0435\u043b\u043e\u0441\u044c\u00a0\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u044b\u0435 \u0444\u0440\u0435\u0439\u043c\u044b \u0432\u00a0\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435.<\/p>\n<\/li>\n<\/ol>\n<p>\u041a\u0430\u043a\u0438\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0435\u0441\u0442\u044c \u0443\u00a0\u043d\u0430\u0441 \u0434\u043b\u044f\u00a0\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c? \u041d\u0430\u043c, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <code>spinnerState<\/code>: \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0443\u0434\u0430 \u0444\u043b\u0430\u0433 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0447\u0442\u043e\u2011\u0442\u043e, \u0447\u0442\u043e\u00a0\u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0444\u0440\u0435\u0439\u043c\u044b. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u043e:<\/p>\n<pre><code class=\"go\">type FrameFunc func() ([]byte, error)type spinnerState struct {  ...  getFrame FrameFunc  isRunning bool}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u043e\u00a0\u0437\u0434\u0435\u0441\u044c \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u043d\u043e\u0432\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b:<\/p>\n<ol>\n<li>\n<p>\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0434\u043e\u043b\u0436\u0435\u043d\u00a0\u0431\u044b\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0434\u043b\u044f\u00a0\u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u044f \u0434\u0430\u0442\u0430\u0440\u0435\u0439\u0441\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u00a0\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043d\u043e\u0432\u043e\u0439 <code>getFrame<\/code> \u043d\u043e\u0432\u044b\u0439 \u0444\u0440\u0435\u0439\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c\u0441\u044f \u0441\u0440\u0430\u0437\u0443\u00a0\u0436\u0435 \u0438 \u043d\u0435\u00a0\u0437\u0430\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u0440\u0430\u043d\u043d\u0438\u043c.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a <code>FrameFunc<\/code> \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438\u00a0\u2014 \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043f\u0430\u043d\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0438\u043b\u0438\u00a0\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0447\u0435\u043d\u044c \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e. \u0410\u00a0\u0435\u0449\u0435 \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u043d\u0435\u00a0\u0431\u044b\u0442\u044c \u043f\u043e\u0442\u043e\u043a\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c\u0438.<\/p>\n<\/li>\n<\/ol>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u00a0\u043f\u043e\u043c\u043e\u0449\u0438 \u0442\u043e\u0433\u043e\u00a0\u0436\u0435 \u0441\u0430\u043c\u043e\u0433\u043e \u043c\u044c\u044e\u0442\u0435\u043a\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0443\u0436\u0435 \u0432\u0432\u0435\u043b\u0438 \u0434\u043b\u044f <code>Write<\/code>. \u041d\u043e\u00a0\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (<code>isRunning<\/code>, <code>getFrame<\/code>) \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <code>Write<\/code>\u00a0\u2014 \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u0435 \u0432\u0435\u0449\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u00a0\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u0440\u0443\u0433 \u0441\u00a0\u0434\u0440\u0443\u0433\u043e\u043c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u043c\u044c\u044e\u0442\u0435\u043a\u0441 \u0434\u043b\u044f\u00a0\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u042d\u0442\u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u00a0\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438\u00a0\u2014 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u043a\u0446\u0438\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u0430\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u0431\u0430 \u043c\u044c\u044e\u0442\u0435\u043a\u0441\u0430, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d\u00a0\u2014 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u043d\u0443\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430\u00a0\u043f\u043e\u0440\u044f\u0434\u043a\u043e\u043c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a, \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435. \u041f\u043e\u0432\u0435\u0440\u0445 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 <code>FrameFunc<\/code>, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u0430\u00a0\u0435\u0449\u0435 \u043b\u0443\u0447\u0448\u0435\u00a0\u2014 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0432\u044b\u0437\u043e\u0432\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f\u00a0\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u0443\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043e\u0434\u043d\u043e \u0434\u0430\u043b \u043c\u043d\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0432\u00a0\u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435. \u042f \u043f\u0440\u0438\u0448\u0435\u043b \u043a\u00a0\u0430\u043a\u0442\u043e\u0440\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438:<\/p>\n<pre><code class=\"go\">type spinnerState struct {  ...  ctx       context.Context  task      chan any  revision  uint64  wg        sync.WaitGroup  inFlight  bool}type start struct {  notify chan error}type stop struct {  notify chan error}type setGetFrame struct {  getFrame FrameFunc  notify   chan error}type drawFrame struct {  revision uint64  frame    []byte  err      error}func (st *spinnerState) set(newFrame []byte) error {  st.Lock()  defer st.Unlock()  st.frame = newFrame  if st.isDrawn {    _, err := st.Write(append(clearBytes, st.frame...))    return err  }  return nil}func (st *spinnerState) startBackground(t *time.Ticker) {  go func() {    for {      select {      case task := &lt;-st.task:        switch typed := task.(type) {        case start:          if st.isRunning {            continue          }          \/\/ \u0414\u043e\u0436\u0438\u0434\u0430\u0435\u043c\u0441\u044f \u0432\u044b\u0437\u043e\u0432\u043e\u0432 getFrame, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0435\u0449\u0435 \u0431\u044b\u0442\u044c          \/\/ \u0430\u043a\u0442\u0438\u0432\u043d\u044b          st.wg.Wait()          \/\/ \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u0444\u0440\u0435\u0439\u043c, \u043f\u0438\u0448\u0435\u043c \u0435\u0433\u043e \u0447\u0435\u0440\u0435\u0437 set        case stop:          if !st.isRunning {            continue          }          \/\/ \u041e\u0447\u0438\u0449\u0430\u0435\u043c \u0444\u0440\u0435\u0439\u043c, \u043f\u0440\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c st.isRunning = false        case drawFrame:          st.inFlight = false          if typed.revision != st.revision || !st.isRunning {            continue          }          if typed.err != nil {            continue          }          err := st.set(typed.frame)          if err != nil {            select {            case st.errCh &lt;- err:            default:            }          }        case setGetFrame:          if typed.getFrame == nil {            typed.notify &lt;- errors.New(\"unable to set nil FrameFunc\")            close(typed.notify)            continue          }          st.getFrame = typed.getFrame          st.revision += 1          st.wg.Wait()          if st.isRunning {            frame, err := st.getFrame()            \/\/ err != nil \u043d\u0435 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c            \/\/ \u0441\u043c\u044b\u0441\u043b\u0435 - \u044f \u0440\u0435\u0448\u0438\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u043e\u0442            \/\/ FrameFunc \u043a\u0430\u043a \u0441\u0438\u0433\u043d\u0430\u043b, \u0447\u0442\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u043d\u0438\u0447\u0435\u0433\u043e            \/\/ \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043d\u0430 \u043d\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442            \/\/ \u0432 \u043a\u0430\u043d\u0430\u043b            if err == nil {              err = st.set(frame)              if err != nil {                st.isRunning = false              }              typed.notify &lt;- err            }          }          close(typed.notify)        default:          continue        }      case &lt;-t.C:        if st.inFlight || !st.isRunning {          continue        }        st.wg.Add(1)        st.inFlight = true        go func(getFrame FrameFunc, revision uint64) {          frame, err := getFrame()          st.wg.Done()          select {          case st.task &lt;- drawFrame{            revision: revision,            frame:    frame,            err:      err,          }:          case &lt;-st.ctx.Done():          }        }(st.getFrame, st.revision)      case &lt;-st.ctx.Done():        return      }    }  }()}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u043e\u043d\u0435\u0447\u043d\u043e, \u043c\u044b \u0443\u0436\u0435 \u043e\u0442\u043e\u0448\u043b\u0438 \u043e\u0442\u00a0\u0440\u0435\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430\u00a0\u2014 \u0438\u043d\u0430\u0447\u0435 \u0441\u0442\u0430\u0442\u044c\u044f\u00a0\u0431\u044b\u043b\u0430\u00a0\u0431\u044b \u0440\u0430\u0437\u0430 \u0432\u00a0\u0434\u0432\u0430 \u0434\u043b\u0438\u043d\u043d\u0435\u0435\u00a0\u2014 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043e\u043f\u0443\u0441\u043a\u0430\u044e \u043c\u043d\u043e\u0433\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u0441\u00a0\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u043e\u0439 \u043e\u0448\u0438\u0431\u043e\u043a, \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442\u00a0\u0433\u043b\u0443\u043f\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435. \u042d\u0442\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a\u00a0\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0439\u0442\u0438 \u0434\u043e\u00a0\u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u044f. \u041d\u043e\u00a0\u0434\u0430\u0436\u0435 \u0442\u0430\u043a \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d \u043a\u043e\u0434, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0441\u00a0\u043e\u043f\u044b\u0442\u043e\u043c \u0434\u043e\u043b\u0433\u0438\u0445 \u0441\u0435\u0441\u0441\u0438\u0439 \u0434\u0435\u0431\u0430\u0433\u0433\u0438\u043d\u0433\u0430, \u043e\u0442\u043b\u043e\u0432\u0430 \u0433\u043e\u043d\u043e\u043a \u0438 \u0432\u00a0\u0446\u0435\u043b\u043e\u043c \u043d\u0435\u043c\u0430\u043b\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0439.<\/p>\n<p>\u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u044d\u0442\u043e \u0432\u0441\u0435 \u043d\u0435\u00a0\u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u0442\u0430\u043a \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u00a0\u2014 \u044f \u0434\u0430\u0436\u0435 \u0443\u043c\u0443\u0434\u0440\u0438\u043b\u0441\u044f \u0437\u0430\u0442\u0430\u0449\u0438\u0442\u044c <a href=\"https:\/\/pkg.go.dev\/golang.org\/x\/sync\/singleflight\" rel=\"noopener nofollow\">golang.org\/x\/sync\/singleflight<\/a>\u00a0\u2014 \u0432\u0435\u0434\u044c \u043b\u043e\u0433\u0438\u0447\u043d\u043e, \u0447\u0442\u043e\u00a0\u0440\u0430\u0437 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0442\u044c \u0432\u044b\u0437\u043e\u0432\u044b <code>FrameFunc<\/code>, \u043b\u0443\u0447\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0438 \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f. \u041a\u00a0\u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043d\u0430\u0434\u0435\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043d\u0435\u00a0\u0441\u043f\u0430\u0441\u0430\u0435\u0442 \u043e\u0442\u00a0\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b \u0441\u00a0\u043f\u0440\u043e\u043a\u043b\u0430\u0434\u043a\u043e\u0439 \u043c\u0435\u0436\u0434\u0443 \u0441\u0442\u0443\u043b\u043e\u043c \u0438 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u043e\u0439. \u0412\u00a0\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043b\u044e\u0447\u0430 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0440\u0435\u0432\u0438\u0437\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430\u00a0\u0442\u043e\u0442 \u043c\u043e\u043c\u0435\u043d\u0442 \u0438\u043c\u0435\u043b\u0430 \u0441\u043e\u0432\u0441\u0435\u043c \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u043c\u044b\u0441\u043b\u00a0\u2014 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0435 \u0444\u0440\u0435\u0439\u043c\u0430, \u0430\u00a0\u043d\u0435 <code>FrameFunc<\/code>. \u0418 \u0437\u0434\u0435\u0441\u044c, \u043d\u0430\u043c\u0435\u0448\u0430\u0432 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432\u00a0\u043e\u0434\u043d\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e (\u044d\u0442\u043e \u0438 \u043a\u043b\u044e\u0447 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f, \u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442\u00a0\u043f\u0440\u043e\u0442\u0443\u0445\u0448\u0438\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439), \u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b \u043d\u0435\u00a0\u0444\u0438\u0447\u0443, \u0430\u00a0\u0431\u0430\u0433. \u0411\u0430\u0433, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u0448\u0438\u043b\u0441\u044f \u043e\u0442\u043a\u0430\u0437\u043e\u043c \u043e\u0442\u00a0singleflight \u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 <code>revision<\/code>. \u041f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0435 <code>FrameFunc<\/code> \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0443 <code>revision<\/code>, \u0430\u00a0\u0432\u043e\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0432\u00a0\u043a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0435\u043a\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u0435\u0445\u0430\u043b\u043e \u0432 <code>inFlight bool<\/code>.<\/p>\n<p>\u041d\u043e\u00a0\u0438 \u043f\u043e\u043c\u0438\u043c\u043e \u044d\u0442\u043e\u0433\u043e \u0437\u0434\u0435\u0441\u044c \u0443\u0436\u0435 \u0441\u043e\u0431\u0440\u0430\u043d\u044b \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0435\u00a0\u0441\u0430\u043c\u044b\u0445 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u00a0\u2014 \u043a\u00a0\u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f <code>start<\/code> \u0438 <code>setGetFrame<\/code> \u0441 <code>st.wg<\/code> \u0434\u043b\u044f\u00a0\u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u044f \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 \u0434\u0430\u0436\u0435 \u0440\u0430\u0437\u043d\u044b\u0445 <code>FrameFunc<\/code>. \u0414\u0430\u043b\u044c\u0448\u0435 \u043e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0434\u0432\u044f\u0437\u0430\u0442\u044c \u044d\u0442\u043e \u0432\u0441\u0435 \u043a\u00a0\u043c\u0435\u0442\u043e\u0434\u0430\u043c \u043d\u0430\u0448\u0435\u0433\u043e <code>Spinner<\/code>, \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0434\u043b\u044f\u00a0\u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0434\u0432\u0443\u0445 <code>io.Writer<\/code> \u0437\u0430\u00a0\u043e\u0434\u043d\u0438\u043c \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u043e\u043c \u0438 \u0432\u00a0\u0446\u0435\u043b\u043e\u043c \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e. \u0418\u0442\u0430\u043a, \u043c\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u0441\u00a0\u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438, \u043d\u043e\u00a0\u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u0432\u044b\u0437\u043e\u0432\u0430\u043c\u0438 <code>FrameFunc<\/code>, \u0441\u00a0\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0438 \u0434\u0430\u0436\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u043e\u0439 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c \u0441\u0430\u043c\u043e\u0433\u043e \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430. \u041f\u043e\u0440\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043a\u00a0\u0441\u0430\u043c\u043e\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u043c\u0443.<\/p>\n<h3>\u0416\u0430\u0434\u043d\u043e\u0441\u0442\u044c \u0444\u0440\u0430\u0435\u0440\u0430 \u0441\u0433\u0443\u0431\u0438\u043b\u0430<\/h3>\n<p>\u0412\u00a0\u0446\u0435\u043b\u043e\u043c \u043d\u0430\u00a0\u044d\u0442\u043e\u043c \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e\u00a0\u0431\u044b\u043b\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f. \u0423\u00a0\u043c\u0435\u043d\u044f \u043d\u0430\u00a0\u0440\u0443\u043a\u0430\u0445\u00a0\u0431\u044b\u043b\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430, \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u0430\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u043a\u00a0\u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u044b, \u0442\u0430\u043a \u0438 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u2011\u0431\u0430\u0440\u044b. \u041f\u0440\u0430\u0432\u0434\u0430, \u0431\u0435\u0437\u00a0\u043f\u043e\u0434\u0433\u043e\u043d\u043a\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u043f\u043e\u0434\u00a0\u0448\u0438\u0440\u0438\u043d\u0443 \u044d\u043a\u0440\u0430\u043d\u0430. \u0418 \u0435\u0441\u043b\u0438 \u044d\u0442\u043e\u00a0\u0431\u044b\u043b\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043f\u043e\u00a0\u0440\u0430\u0437\u043c\u0435\u0440\u0443 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f\u043c, \u0442\u043e \u0434\u043b\u044f\u00a0\u0431\u0430\u0440\u043e\u0432 \u044d\u0442\u043e \u0443\u0436\u0435 \u0441\u0440\u043e\u0434\u043d\u0438 \u043f\u0440\u0435\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044e. \u00ab\u0412 \u0447\u0435\u043c \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c?\u00bb\u00a0\u2014 \u0441\u043f\u0440\u043e\u0441\u0438\u0442\u0435 \u0432\u044b. \u0412\u00a0\u0442\u043e\u043c, \u0447\u0442\u043e\u00a0\u044d\u0442\u043e \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e. \u041d\u0435\u0442, \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e. \u0427\u0442\u043e\u00a0\u043c\u044b \u0438\u043c\u0435\u0435\u043c:<\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0440\u0435\u0439\u043c\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u0448\u0438\u0440\u0438\u043d\u044b \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430\u00a0\u2014 \u0444\u0440\u0435\u0439\u043c \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u0442\u0441\u044f \u043d\u0430\u00a0\u043d\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443. \u0410\u00a0\u0432\u044b \u0432\u0435\u0434\u044c \u043f\u043e\u043c\u043d\u0438\u0442\u0435 \u043d\u0430\u0448\u0443 ANSI\u2011\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c? \u041f\u0435\u0440\u0435\u043d\u043e\u0441 \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u0432\u00a0\u043d\u0430\u0447\u0430\u043b\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e, \u0447\u0442\u043e\u00a0\u043f\u0440\u0430\u0432\u0435\u0435 \u043a\u0443\u0440\u0441\u043e\u0440\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0440\u0435\u0434\u0438 \u0432\u0441\u0435\u0433\u043e \u0437\u043e\u043e\u043f\u0430\u0440\u043a\u0430 \u041e\u0421 \u0438 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u043e\u0432 \u043e\u0447\u0435\u043d\u044c \u0442\u044f\u0436\u0435\u043b\u043e \u0441\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0448\u0438\u0440\u0438\u043d\u0443 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430.<\/p>\n<\/li>\n<li>\n<p>\u042e\u0437\u0435\u0440\u044b \u043d\u0435\u00a0\u0443\u0432\u0430\u0436\u0430\u044e\u0442 \u043c\u044c\u044e\u0442\u0435\u043a\u0441\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0443 \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u00ab\u043f\u0430\u0434\u0430\u0436\u0436\u0438, \u043d\u0435\u00a0\u043c\u0435\u043d\u044f\u0439 \u0440\u0430\u0437\u043c\u0435\u0440\u00bb.<\/p>\n<\/li>\n<li>\n<p>\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0431\u00a0\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0448\u0438\u0440\u0438\u043d\u044b \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0443 \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043e\u00a0Windows\u00a0\u2014 \u0442\u0430\u043c \u043d\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b \u043e\u00a0\u0441\u043c\u0435\u043d\u0435 \u0448\u0438\u0440\u0438\u043d\u044b \u0432\u043e\u043e\u0431\u0449\u0435. \u041c\u043e\u0436\u043d\u043e\u00a0\u043b\u0438\u0431\u043e \u0432\u043b\u0435\u0437\u0430\u0442\u044c \u0432\u00a0API, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430\u00a0\u0440\u0430\u0431\u043e\u0442\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u043d\u0443 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0442\u044f\u043d\u0435\u0442 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0432\u00a0raw\u2011\u0440\u0435\u0436\u0438\u043c),\u00a0\u043b\u0438\u0431\u043e \u0441\u0442\u0430\u0440\u044b\u0439 \u0434\u043e\u0431\u0440\u044b\u0439 \u043f\u043e\u043b\u043b\u0438\u043d\u0433.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u0441\u0435 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e\u00a0\u043a\u0430\u043a\u00a0\u0431\u044b \u043c\u044b \u043d\u0438 \u0441\u0442\u0430\u0440\u0430\u043b\u0438\u0441\u044c, \u043d\u0438\u0447\u0442\u043e \u043d\u0435\u00a0\u0437\u0430\u0449\u0438\u0442\u0438\u0442 \u043d\u0430\u0441 \u043e\u0442\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0448\u0438\u0440\u0438\u043d\u0443\/\u0441\u043b\u0443\u0448\u0430\u0435\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0448\u0438\u0440\u0438\u043d\u044b, \u0432\u0438\u0434\u0438\u043c \u0448\u0438\u0440\u0438\u043d\u0443 60.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0444\u0440\u0435\u0439\u043c \u0448\u0438\u0440\u0438\u043d\u043e\u0439 40\u00a0\u2014 \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u044e \u0448\u0438\u0440\u0438\u043d\u0443 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u043d\u0430\u043c \u043d\u0435\u00a0\u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u043b\u0438\u0433\u0438\u044f. \u041d\u0443 \u0438\u043b\u0438\u00a0\u043f\u0440\u043e\u0441\u0442\u043e \u0431\u0435\u0437\u00a0\u043f\u0440\u0438\u0447\u0438\u043d\u044b. \u041d\u0435\u0432\u0430\u0436\u043d\u043e \u0441\u043a\u043e\u043b\u044c\u043a\u043e\u00a0\u2014 \u0432\u0430\u0436\u043d\u043e, \u0447\u0442\u043e\u00a0\u0431\u043e\u043b\u044c\u0448\u0435 20.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u00a0\u043d\u043e\u0432\u044b\u0439 \u0444\u0440\u0435\u0439\u043c \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u043c \u043f.1\u00a0\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0441\u0435 \u0442\u0435\u00a0\u0436\u0435 60.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0438\u0448\u0435\u043c \u043d\u0430\u0448\u0443 \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u043b\u044f\u00a0\u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0441\u0442\u0440\u043e\u043a\u0438. \u041d\u043e\u00a0\u0445\u0438\u0442\u0440\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0436\u0434\u0430\u043b \u0442\u0430\u043a\u043e\u0439 \u043d\u0435\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u00a0\u043c\u043e\u043c\u0435\u043d\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 \u043e\u043d \u0442\u044f\u043d\u0435\u0442 \u0437\u0430\u00a0\u043a\u0440\u0430\u0439 \u043e\u043a\u043d\u0430 \u0438 \u0441\u0436\u0438\u043c\u0430\u0435\u0442 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0434\u043e 20. \u041d\u0430\u0448 \u0444\u0440\u0435\u0439\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0441\u0442\u0435\u0440\u0435\u0442\u044c, \u0442\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0434\u0432\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437\u2011\u0437\u0430 \u043f\u0435\u0440\u0435\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0441\u043b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430. \u041f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u0442\u0438\u0440\u0430\u0435\u0442 \u043e\u0434\u043d\u0443 \u0441\u0442\u0440\u043e\u043a\u0443. <\/p>\n<\/li>\n<li>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043d\u0430\u00a0\u043f. 1.<\/p>\n<\/li>\n<\/ol>\n<p>\u0417\u0434\u0435\u0441\u044c, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043d\u0443\u0436\u0435\u043d \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0434\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440\u00a0\u2014 \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u00a0\u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430\u0445 \u0441\u00a0\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c \u043f\u0435\u0440\u0435\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c. \u041a\u00a0\u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0438\u043b\u0438\u00a0\u043a\u00a0\u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u043e\u0432 \u043a\u0430\u043a\u00a0\u0440\u0430\u0437 \u0442\u0430\u043a\u0438\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043e\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439, \u0432\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0435\u0440\u0435\u043d\u043e\u0441 \u043d\u0435\u00a0\u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442. \u0412\u00a0\u0438\u0442\u043e\u0433\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443:<\/p>\n<pre><code>[===================  &lt;- \u0410\u0440\u0442\u0435\u0444\u0430\u043a\u0442! \u041d\u0438\u0436\u043d\u044f\u044f \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u0431\u044b\u043b\u0430 \u0441\u0442\u0435\u0440\u0442\u0430, \u0430 \u044d\u0442\u0430 \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c[========&gt;   ] 22\/33  &lt;- \u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0443\u0436\u0435 \u0441\u043f\u043e\u0445\u0432\u0430\u0442\u0438\u043b\u0438\u0441\u044c \u0438 \u0441\u0436\u0430\u043b\u0438 \u0444\u0440\u0435\u0439\u043c<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0425\u043e\u0440\u043e\u0448\u043e, \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c 100% \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432\u043e\u043e\u0431\u0449\u0435 \u0431\u0435\u0437\u00a0\u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u043e\u0432 \u043c\u044b \u043d\u0435\u00a0\u043c\u043e\u0436\u0435\u043c. \u0410\u00a0\u0447\u0442\u043e\u00a0\u043c\u043e\u0436\u0435\u043c? \u041a\u0430\u043a\u00a0\u043c\u0438\u043d\u0438\u043c\u0443\u043c\u00a0\u2014 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u044b \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0438 best\u2011effort \u043f\u043e\u0434\u0433\u043e\u043d\u043a\u0443 \u043f\u043e\u0434\u00a0\u0440\u0430\u0437\u043c\u0435\u0440 \u043f\u0440\u0438\u00a0\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0448\u0438\u0440\u0438\u043d\u044b. \u0414\u043b\u044f\u00a0\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u043c, \u043a\u0430\u043a\u00a0\u0431\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u0443\u0434\u043e\u0431\u043d\u043e\u0435 \u043d\u0430\u043c API \u0434\u043b\u044f\u00a0\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0448\u0438\u0440\u0438\u043d\u044b.\u00a0\u041b\u0438\u0447\u043d\u043e \u043c\u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043d\u0440\u0430\u0432\u044f\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438:<\/p>\n<pre><code class=\"go\">type WidthFunc func() inttype spinnerState struct {  ...  width int  getWidth WidthFunc}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e\u0433\u0434\u0430 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c best\u2011effort \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u043e\u0432:<\/p>\n<pre><code class=\"go\">\/\/ \u041d\u0435 \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u043b \u0432 \u0442\u0435\u043a\u0441\u0442\u0435 - \u043d\u043e \u043c\u044b \u043e\u043f\u044f\u0442\u044c \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u0438\u0431\u0435\u0433\u0430\u0442\u044c \u043a\/\/ ANSI-\u0442\u0440\u044e\u043a\u0430\u043c. \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u044d\u0442\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u0433\u0430\u0435\u0442\/\/ \u043a\u0443\u0440\u0441\u043e\u0440 \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0443 \u0432\u044b\u0448\u0435var jumpLineUp = []byte(\"\\033[A\")\/\/ \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e\/\/ \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u044c\u044e\u0442\u0435\u043a\u0441\u043e\u043c \u0431\u043b\u043e\u043a\u0430func (st *spinnerState) clear() error {  if !st.isDrawn {    return nil  }  st.isDrawn = false  oldWidth := st.width  st.width = st.getWidth()  if st.width != 0 &amp;&amp; st.width &lt; oldWidth {    \/\/ \u0421\u043f\u0430\u0441\u0430\u0435\u043c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e, \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0438 - len(st.frame)\/st.width    lines := max((len(st.frame)+st.width-1)\/st.width, 1)    \/\/ \u041a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043e\u0434\u043d\u0443 \u0441\u0442\u0440\u043e\u043a\u0443 \u043d\u0430\u043c \u0442\u043e\u0447\u043d\u043e \u043d\u0430\u0434\u043e \u0441\u0442\u0438\u0440\u0430\u0442\u044c    _, err := st.Write(clearBytes)    \/\/ \u041d\u0443 \u0430 \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u0432\u0448\u0435\u0435\u0441\u044f    clearLineUp := append(jumpLineUp, clearBytes...)    for range lines-1 {      _, wErr := st.Write(clearLineUp)      err = errors.Join(err, wErr)    }    return err  } else {    _, err := st.Write(clearBytes)    return err  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u00a0\u0446\u0435\u043b\u043e\u043c \u044d\u0442\u043e\u0433\u043e \u0443\u0436\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043b\u044f\u00a0\u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u043e\u0432. \u0414\u043b\u044f\u00a0\u043f\u0443\u0449\u0435\u0439 \u043d\u0430\u0440\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u0438 \u0447\u0443\u0432\u0441\u0442\u0432\u0430 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u043e\u0438\u043d\u0441\u0442\u0432\u0430 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u0434\u0433\u043e\u043d\u043a\u0443 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0432\u0438\u0434\u0438\u043c\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0430 \u043f\u043e\u0434\u00a0\u043d\u043e\u0432\u0443\u044e \u0448\u0438\u0440\u0438\u043d\u0443, \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0435\u00a0\u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u00a0\u043e\u0447\u0438\u0441\u0442\u043a\u0435, \u043d\u043e\u00a0\u0438 \u043d\u0430\u00a0\u0437\u0430\u043f\u0438\u0441\u0438, \u043d\u0443 \u0438 \u043d\u0430\u043a\u043e\u043d\u0435\u0446\u2011\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u043e\u043c\u0430\u0442\u044c\u0441\u044f \u043d\u0430\u00a0\u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u2011\u0431\u0430\u0440\u0435 \u0432\u0438\u0434\u0430 \ud83c\udf57\ud83c\udf57\ud83d\udc14\ud83d\udc14\ud83d\udc14\ud83d\udc14\ud83d\udc14\ud83d\udc14\ud83d\udc14\ud83d\udc14 20\/100. \u041d\u0443 \u0434\u0430, \u0430\u00a0\u0447\u0435\u0433\u043e \u0432\u044b \u0445\u043e\u0442\u0435\u043b\u0438? \u0412\u043f\u0440\u043e\u0447\u0435\u043c, \u044d\u0442\u043e \u043c\u0435\u043b\u043e\u0447\u0438\u00a0\u2014 \u0442\u0443\u0442 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u0439\u0442\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u043c\u0435\u0435\u0442 \u0432\u00a0\u043f\u043e\u0434\u0441\u0447\u0435\u0442 \u0432\u0438\u0434\u0438\u043c\u043e\u0439 \u0448\u0438\u0440\u0438\u043d\u044b \u0441\u0442\u0440\u043e\u043a. \u042f \u0432\u044b\u0431\u0440\u0430\u043b <a href=\"https:\/\/github.com\/clipperhouse\/displaywidth\" rel=\"noopener nofollow\">github.com\/clipperhouse\/displaywidth<\/a>. \u0418 \u0432\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u043d\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e:<\/p>\n<pre><code class=\"go\">var graphemeOpts = displaywidth.Options{  ControlSequences: true,}func (st *spinnerState) clear() error {    ...    \/\/ st.visible \u0437\u0434\u0435\u0441\u044c \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u0431\u044b\u043b\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e \u0432 Writer \u043d\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0435    lines := max((graphemeOpts.Bytes(st.visible)+st.width-1)\/st.width, 1)    ...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u043b\u0438 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435? <code>ControlSequences: true<\/code>\u00a0\u2014 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e\u00a0\u0431\u044b\u0442\u044c \u0432\u00a0\u043a\u0443\u0440\u0441\u0435 ANSI\u2011\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0435\u0439. \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0432 <code>visible<\/code> \u043a\u0440\u043e\u0435\u0442\u0441\u044f \u0435\u0449\u0435 \u043e\u0434\u043d\u0430 \u043c\u0438\u043d\u0430. \u0426\u0432\u0435\u0442\u0430. \u0426\u0432\u0435\u0442\u0430 \u0432\u00a0\u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u0438\u00a0\u043f\u043e\u043c\u043e\u0449\u0438 \u0442\u0435\u0445\u00a0\u0436\u0435 \u0441\u0430\u043c\u044b\u0445 ANSI\u2011\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0435\u0439. \u041d\u043e\u00a0\u044d\u0442\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u043d\u0435\u00a0\u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0441\u0430\u043c\u0438 \u043f\u043e\u00a0\u0441\u0435\u0431\u0435\u00a0\u2014 \u0438\u043c\u0435\u044e\u0442 \u043d\u0443\u043b\u0435\u0432\u0443\u044e \u0448\u0438\u0440\u0438\u043d\u0443. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u043f\u0440\u0438\u00a0\u043f\u043e\u0434\u0433\u043e\u043d\u043a\u0435 \u0444\u0440\u0435\u0439\u043c\u0430 \u043f\u043e\u0434\u00a0\u0432\u0438\u0434\u0438\u043c\u0443\u044e \u0448\u0438\u0440\u0438\u043d\u0443 \u0445\u043e\u0440\u043e\u0448\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 <strong>\u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0432\u0441\u0435 ANSI\u2011\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432\u00a0\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435<\/strong>, \u0438\u043d\u0430\u0447\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u043e\u043a\u0440\u0430\u0441\u0438\u0442\u044c \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u043b\u0438\u00a0\u0441\u043b\u043e\u043c\u0430\u0442\u044c \u0435\u0433\u043e \u043a\u0443\u0440\u0441\u043e\u0440. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u0448 \u0441\u043f\u0438\u043d\u043d\u0435\u0440 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0441\u0442\u0430\u0442\u044c \u0445\u0435\u043b\u043f\u0435\u0440\u0430\u043c\u0438.<\/p>\n<pre><code class=\"go\">func (st *spinnerState) adjust() {  \/\/ \u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u043f\u0443\u0442\u044c - \u0442\u0430\u043a \u043a\u0430\u043a \u043a\u0430\u0436\u0434\u044b\u0439 \u0431\u0430\u0439\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u0442\u044c  \/\/ \u0431\u043e\u043b\u044c\u0448\u0435 1 \u0441\u0442\u043e\u043b\u0431\u0446\u0430 \u0432\u0438\u0434\u0438\u043c\u043e\u0439 \u0448\u0438\u0440\u0438\u043d\u044b  if st.width &gt;= len(st.frame) {    st.visible = st.frame    return  }  iter := graphemeOpts.BytesGraphemes(st.frame)  total := 0  canTakeMore := true  result := bytes.Buffer{}  for iter.Next() {    size := iter.Width()    cur := iter.Value()    \/\/ \u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435, \u0447\u0442\u043e \u043d\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f    if size == 0 {      result.Write(cur)      continue    }    if canTakeMore &amp;&amp; total+size &lt;= st.width {      total += size      result.Write(cur)      continue    }    canTakeMore = false  }  st.visible = result.Bytes()}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u0441\u00a0\u044d\u0442\u0438\u043c \u043c\u044b \u0434\u0430\u0436\u0435 \u043f\u043e\u0447\u0442\u0438 \u0447\u0442\u043e\u00a0\u0440\u0430\u0437\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c. \u041e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0430\u044f \u043d\u0435\u0441\u043e\u0441\u0442\u044b\u043a\u043e\u0432\u043e\u0447\u043a\u0430. \u041a\u0430\u043a\u00a0\u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0441\u043e\u043e\u0431\u0449\u0430\u0442\u044c \u043d\u0430\u043c \u043e\u00a0\u0441\u0432\u043e\u0435\u0439 \u0448\u0438\u0440\u0438\u043d\u0435 \u0432\u00a0\u0442\u043e\u043c \u0432\u0438\u0434\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0434\u043e\u0431\u0435\u043d \u043d\u0430\u043c?\u00a0\u041b\u0438\u0447\u043d\u043e \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u043f\u0443\u0442\u044c \u043d\u0430\u0438\u043c\u0435\u043d\u044c\u0448\u0435\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f:<\/p>\n<pre><code class=\"go\">func CachedGetWidth(sigwinch &lt;-chan struct{}, getWidth WidthFunc) WidthFunc {  getWidth = zeroOnPanic(getWidth)  current := atomic.Int64{}  current.Store(int64(getWidth()))  go func() {    for range sigwinch {    Drain:      for {        select {        case _, ok := &lt;-sigwinch:          if !ok {            break Drain          }        default:          break Drain        }      }      current.Store(int64(getWidth()))    }  }()  return func() int {    return int(current.Load())  }}func WidthFromFile(file *os.File) (WidthFunc, error) {  if file == nil {    return func() int { return -1 }, errors.New(\"unable to determine width for nil file\")  }  \/\/ \u0422\u0443\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043b\u044f\u043c\u0431\u0434\u0443, \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044e\u0449\u0443\u044e  \/\/ \u0432\u044b\u0437\u043e\u0432 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0438 \u0432 \u044d\u0442\u043e\u043c \u0442\u0435\u043a\u0441\u0442\u0435 \u0443\u0436\u0435 \u0438  \/\/ \u0442\u0430\u043a \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u043e\u0442 \u0432\u0430\u043c \u043a\u043e\u0442: \ud83d\ude3a}func DefaultGetWidth(ctx context.Context) (WidthFunc, error) {  if ctx == nil {    ctx = context.Background()  }  getWidth, err := WidthFromFile(os.Stderr)  if err != nil {    return nil, err  }  return CachedGetWidth(DefaultSigwinch(ctx), getWidth), nil}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u043b\u0435\u043d\u044c \u0447\u0438\u0442\u0430\u0442\u044c \u043a\u043e\u0434\u00a0\u2014 \u0442\u043e \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0438\u0433\u043d\u0430\u043b\u0430 SIGWINCH (\u043d\u0430 Unix\u2011\u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445), \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u043e\u0431\u00a0\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043e\u043a\u043d\u0430. \u041d\u0430\u00a0\u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u0438\u0433\u043d\u0430\u043b \u044f \u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0441\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 <a href=\"https:\/\/pkg.go.dev\/golang.org\/x\/term\" rel=\"noopener nofollow\">golang.org\/x\/term<\/a>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u0448\u0438\u0440\u0438\u043d\u0443 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e \u0435\u0435 \u0432\u00a0\u0430\u0442\u043e\u043c\u0438\u043a\u0435. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u0435\u0448\u0435\u0432\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0434\u0430\u0436\u0435 \u043d\u0430\u00a0\u0441\u0430\u043c\u043e\u043c \u0433\u043e\u0440\u044f\u0447\u0435\u043c \u043f\u0443\u0442\u0438\u00a0\u2014 \u043e\u0432\u0435\u0440\u0445\u0435\u0434 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0435\u043d\u00a0\u2014 \u0443\u0436 \u0442\u043e\u0447\u043d\u043e \u043d\u0435\u00a0\u0441\u0440\u0430\u0432\u043d\u0438\u043c\u044b\u0439 \u0441\u00a0\u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u0432\u044b\u0437\u043e\u0432\u043e\u043c.<\/p>\n<h3>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0412\u00a0\u0446\u0435\u043b\u043e\u043c, \u043f\u043e\u00a0\u043c\u043e\u0438\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c \u0432\u0441\u0435, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0435 \u0432\u044b\u0448\u0435\u00a0\u2014 \u044d\u0442\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c, \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0431\u0435\u0437\u00a0\u0431\u0443\u0444\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u0432\u00a0raw\u2011\u0440\u0435\u0436\u0438\u043c, \u0430\u00a0\u0438\u043c\u0435\u043d\u043d\u043e:<\/p>\n<ul>\n<li>\n<p>\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0stderr \u0438 stdout \u0441\u00a0\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u0414\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u044b \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 (\u043e\u0442 FPS \u0434\u043e\u00a0\u0441\u0430\u043c\u043e\u0439 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0444\u0440\u0435\u0439\u043c\u043e\u0432)<\/p>\n<\/li>\n<li>\n<p>\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043d\u0430\u0434 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0430\u00a0\u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0437\u0434\u0435\u0441\u044c \u0434\u0430\u0436\u0435 \u043d\u0435\u00a0\u0431\u044b\u043b\u0430 \u0437\u0430\u0442\u0440\u043e\u043d\u0443\u0442\u0430 \u043a\u0443\u0434\u0430 \u0431\u043e\u043b\u0435\u0435 \u0441\u043a\u0443\u0447\u043d\u0430\u044f, \u043d\u043e\u00a0\u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438\u00a0\u2014 \u0434\u0438\u0437\u0430\u0439\u043d \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f API. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0441\u043b\u0438 \u0432\u0430\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430\u00a0\u0432\u0441\u0435, \u0447\u0442\u043e\u00a0\u044f \u0437\u0434\u0435\u0441\u044c \u043e\u043f\u0438\u0441\u0430\u043b, \u0432\u00a0\u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0439 \u0443\u043f\u0430\u043a\u043e\u0432\u043a\u0435 (\u0438 \u0447\u0443\u0442\u044c \u043c\u0435\u043d\u0435\u0435 \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u043c \u043a\u043e\u0434\u0435\u00a0\u2014 \u0437\u0430\u0434\u043d\u0438\u043c \u0443\u043c\u043e\u043c \u043a\u043e\u0434 \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0449\u0435)\u00a0\u2014 \u043c\u0438\u043b\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0448\u0443 \u0432 <a href=\"https:\/\/github.com\/Veitangie\/spinq\" rel=\"noopener nofollow\">\u043c\u043e\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a>. \u0422\u0430\u043c \u0432\u044b \u043d\u0430\u0439\u0434\u0435\u0442\u0435 \u044d\u0442\u043e \u0438 \u0434\u0430\u0436\u0435 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u044c\u0448\u0435 (\u041a\u0430\u043a \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u2011\u0431\u0430\u0440? \u041a\u0430\u043a\u00a0\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u044d\u0442\u043e \u0432\u0441\u0435 \u0441\u00a0\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0443\u0441\u0438\u043b\u0438\u044f\u043c\u0438?). \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>spinq<\/code>, \u0447\u0442\u043e\u00a0\u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u00ab<strong>S<\/strong>imple s<strong>PIN<\/strong>ner tool<strong>Q<\/strong>it\u00bb \u0438 \u043d\u0430\u00a0\u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0435\u0449\u0435 \u043d\u0435\u00a0\u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0435\u043b\u0438\u0437\u0430, \u043d\u043e\u00a0\u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0432\u0435\u0440\u0438\u0442\u044c, \u0447\u0442\u043e\u00a0\u043e\u043d \u043d\u0435\u00a0\u0437\u0430\u00a0\u0433\u043e\u0440\u0430\u043c\u0438.<\/p>\n<p>\u0410\u00a0\u043d\u0430 \u044d\u0442\u043e\u043c \u0443\u00a0\u043c\u0435\u043d\u044f \u0432\u0441\u0435. \u0414\u043e\u00a0\u0441\u043a\u043e\u0440\u044b\u0445, \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0432\u0441\u0442\u0440\u0435\u0447!<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1076736\/\">https:\/\/habr.com\/ru\/articles\/1076736\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440!\u041d\u0435\u00a0\u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e \u044f \u043d\u0430\u00a0\u0440\u043e\u0432\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0437\u0430\u043d\u044f\u043b\u0441\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0430\u00a0Go \u0434\u043b\u044f, \u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c\u00a0\u0431\u044b, \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438\u00a0\u2014 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u043d\u0435\u00a0\u0431\u0443\u0434\u0435\u0442 \u043b\u043e\u043c\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0438\u00a0\u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u044f\u0445 \u0432\u00a0stderr \u0438 stdout.\u0412\u0441\u0435 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c \u0441\u00a0\u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u00a0\u044f \u043f\u0438\u0441\u0430\u043b \u0432\u043e\u043e\u0431\u0449\u0435 \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u043e\u0434\u00a0\u2014 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u0443\u044e \u0443\u0442\u0438\u043b\u0438\u0442\u0443 \u0434\u043b\u044f\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0442\u0435\u0441\u0442\u043e\u0432. \u0418 \u0437\u0430\u0445\u043e\u0442\u0435\u043b \u043f\u0440\u0438\u043a\u0440\u0443\u0442\u0438\u0442\u044c \u0442\u0443\u0434\u0430 \u0441\u043f\u0438\u043d\u043d\u0435\u0440. \u041d\u043e\u00a0\u043d\u0435\u00a0\u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043f\u0438\u043d\u043d\u0435\u0440, \u0430\u00a0\u0442\u0430\u043a\u043e\u0439, \u0447\u0442\u043e\u00a0\u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u00a0\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0430 \u043f\u043e\u0442\u043e\u043a\u0430 \u0432\u044b\u0432\u043e\u0434\u0430\u00a0\u2014 stderr \u0438 stdout, \u0431\u0435\u0437\u00a0\u0440\u0438\u0441\u043a\u0430 \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u043d\u0430\u00a0\u044d\u043a\u0440\u0430\u043d\u0435. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u0432\u043e\u00a0\u0432\u0440\u0435\u043c\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043c\u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u00a0\u044d\u043a\u0440\u0430\u043d\u0435 \u043e\u0442\u0447\u0435\u0442\u044b \u043f\u043e\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0432\u0448\u0438\u043c\u0441\u044f \u0442\u0435\u0441\u0442\u0430\u043c, \u043d\u0435\u00a0\u043e\u0442\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044f \u044d\u0442\u043e \u0432\u0441\u0435 \u0434\u043e\u00a0\u043a\u043e\u043d\u0446\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\/\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430. \u0418 \u0442\u0430\u043a \u0443\u0436 \u043f\u043e\u0447\u0435\u043c\u0443\u2011\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c (\u0441\u043f\u043e\u0439\u043b\u0435\u0440: \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u043d\u0435\u00a0\u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u043e, \u0438\u043d\u043e\u0433\u0434\u0430 \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438 \u043c\u0430\u043b\u043e \u043a\u043e\u043c\u0443 \u043d\u0443\u0436\u043d\u043e), \u0447\u0442\u043e\u00a0\u044f \u043d\u0435\u00a0\u0441\u043c\u043e\u0433 \u043d\u0430\u0439\u0442\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f\u00a0\u0431\u044b \u043c\u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u0430.\u041f\u043e\u0447\u0435\u043c\u0443 \u043c\u043d\u0435 \u043d\u0435\u00a0\u043f\u043e\u0434\u0445\u043e\u0434\u0438\u043b\u043e \u043d\u0438 \u043e\u0434\u043d\u043e \u0438\u0437\u00a0\u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439:\u0421\u0430\u043c\u044b\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043d\u0435\u00a0\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e \u0438 \u0437\u0430\u043f\u0438\u0441\u044c (github.com\/briandowns\/spinner, github.com\/yarlson\/pin).\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0432\u00a0\u043f\u043e\u0442\u043e\u043a \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 \u043d\u0435\u00a0\u043b\u043e\u043c\u0430\u044f \u0435\u0433\u043e, \u0443\u0436\u0435 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0442\u044f\u0436\u0435\u043b\u043e\u0432\u0435\u0441\u043d\u0435\u0435 \u0438 \u043d\u0435\u00a0\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 stdout\/stderr (github.com\/theckman\/yacspin).\u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0435 \u0432\u0441\u0435 \u0432\u044b\u0448\u0435\u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435,\u00a0\u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u043d\u043e\u0432\u0435\u0441\u043d\u044b\u0435 TUI \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0438 \u0441\u00a0\u0440\u0435\u043d\u0434\u0435\u0440\u2011\u0431\u0443\u0444\u0435\u0440\u043e\u043c \u0438 raw\u2011\u0440\u0435\u0436\u0438\u043c\u043e\u043c.\u0412\u0435\u0441\u044c \u0444\u0430\u0439\u043b \u043c\u043e\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u0435\u0441\u0438\u0442 \u043c\u0435\u043d\u044c\u0448\u0435 9\u00a0\u041c\u0411. \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u044f\u0436\u0435\u043b\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u00a0\u043b\u0438\u0448\u044c \u0440\u0430\u0434\u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 (\u0438 \u043a\u0430\u043a\u00a0\u043f\u043e\u0437\u0436\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c\u00a0\u2014 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u2011\u0431\u0430\u0440\u0430)\u00a0\u2014 \u043d\u0435\u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0441\u0442\u043e\u0447\u0438\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e.\u041c\u043e\u043b\u043e\u0434\u043e\u0441\u0442\u044c \u0438 \u0440\u0430\u0434\u043e\u0441\u0442\u044c (\u043d\u0430\u0438\u0432\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435)\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0441\u043f\u0438\u043d\u043d\u0435\u0440 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e. \u041d\u0430\u00a0\u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u044d\u0442\u043e \u043d\u0435\u00a0\u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043b\u043e\u0436\u043d\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430\u00a0\u2014 \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u0432\u0441\u0435\u0433\u043e \u043f\u0430\u0440\u0443 \u0432\u0435\u0449\u0435\u0439:ANSI\u2011\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c &#171;\\033[K&#187; \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u043e \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u0432\u0441\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u0440\u0430\u0432\u0435\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0440\u0430 (\u0435\u0441\u0442\u044c \u0435\u0449\u0435 &#171;\\033[1K&#187;\u00a0\u2014 \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u0432\u0441\u0435 \u043b\u0435\u0432\u0435\u0435, \u0438 &#171;\\033[2K&#187;\u00a0\u2014 \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u0432\u0441\u044e \u0441\u0442\u0440\u043e\u043a\u0443, \u043d\u043e\u00a0\u043e\u0431\u00a0\u044d\u0442\u043e\u043c \u043f\u043e\u0437\u0436\u0435) \u0432\u00a0\u043f\u043e\u0442\u043e\u043a\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 ANSI\u2011\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438.\u0411\u0430\u0439\u0442 &#8216;\\r&#8217; \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u0442 \u043a\u0443\u0440\u0441\u043e\u0440 \u0432\u00a0\u043d\u0430\u0447\u0430\u043b\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0438.\u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f &#171;\\r\\033[K&#187;, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0438 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u043a\u0443\u0440\u0441\u043e\u0440 \u0432\u00a0\u0441\u0430\u043c\u043e\u0435 \u043d\u0430\u0447\u0430\u043b\u043e. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 &#171;\\033[1K\\r&#187;, \u0438 &#171;\\r\\033[2K&#187;, \u043d\u043e\u00a0\u0437\u0430\u0447\u0435\u043c \u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435, \u043a\u043e\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c \u043c\u0435\u043d\u044c\u0448\u0435?\u041d\u0443 \u0430\u00a0\u0434\u0430\u043b\u044c\u0448\u0435 \u0432\u0441\u0435 \u0434\u043e\u043b\u0436\u043d\u043e\u00a0\u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e. \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e io.Writer \u0438 \u0432\u0441\u0435 \u0433\u043e\u0442\u043e\u0432\u043e:var clearBytes []byte = []byte(&#171;\\r\\033[K&#187;)var spinnerBytes []byte = []byte(&#171;\u0422\u0443\u0442 \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u0441\u043b\u043e\u0436\u043d\u043e&#187;)type Spinner struct {  io.Writer}func (s Spinner) Write(data []byte) (int, error) {  s.Writer.Write(clearBytes)  res, err := s.Writer.Write(data)  s.Writer.Write(spinnerBytes)  return res, err}\u041d\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u00a0\u0436\u0435, \u0432\u0441\u0435 \u043d\u0435\u00a0\u0442\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430\u00a0\u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u00a0\u043d\u0430\u0441 \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0442\u0441\u044f:\u0422\u043e, \u0447\u0442\u043e\u00a0\u043c\u044b \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438\u00a0\u2014 \u044d\u0442\u043e \u043d\u0435\u00a0\u0441\u043f\u0438\u043d\u043d\u0435\u0440. \u042d\u0442\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u00a0\u2014 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0442\u0435\u043a\u0441\u0442, \u0437\u0430\u043a\u0440\u0435\u043f\u043b\u0435\u043d\u043d\u044b\u0439 \u043d\u0430\u00a0\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430.\u041c\u044b \u0432\u0441\u0435 \u0435\u0449\u0435 \u0437\u0430\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c\u00a0\u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u043f\u043e\u0442\u043e\u043a\u00a0\u2014 \u043b\u044e\u0431\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0stdout \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043a\u00a0\u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044e \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u043e\u0432.\u0421\u0430\u043c\u0430\u044f \u043c\u0435\u043b\u043e\u0447\u044c\u00a0\u2014 \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0432\u0442\u0438\u0445\u0443\u044e \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u00a0\u044d\u043a\u0440\u0430\u043d\u0430. \u0412\u0435\u0434\u044c \u0435\u0441\u043b\u0438 data \u043d\u0435\u00a0\u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439, \u043d\u0430\u0448\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0432\u00a0\u043f\u043e\u0442\u043e\u043a \u043f\u0440\u0438\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0437\u0430\u043f\u0438\u0441\u0438, \u0441\u043e\u0442\u0440\u0435\u0442 \u0432\u0441\u044e \u0441\u0442\u0440\u043e\u043a\u0443\u00a0\u2014 \u0438 \u043d\u0430\u0448 \u0441\u043f\u0438\u043d\u043d\u0435\u0440, \u0438 \u0432\u0441\u0435, \u0447\u0442\u043e\u00a0\u0431\u044b\u043b\u043e \u0434\u043e\u00a0\u043d\u0435\u0433\u043e.\u0425\u043e\u0440\u043e\u0448\u043e, \u043d\u0430\u0447\u043d\u0435\u043c \u0441\u00a0\u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e. \u0411\u0443\u0434\u0435\u043c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0442\u043e, \u0447\u0442\u043e\u00a0\u043d\u0430\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043b\u0438, \u0438 \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u043d\u043d\u0435\u0440 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0431\u0430\u0439\u0442\u00a0\u2014 \u044d\u0442\u043e \u043d\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430.type Spinner struct {  io.Writer  frame []byte  isDrawn bool}func (s *Spinner) Write(data []byte) (int, error) {  if s.isDrawn {      s.Writer.Write(clearBytes)      s.isDrawn = false  }  res, err := s.Writer.Write(data)  \/\/ \u0412\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u0441\u043a\u0430\u0436\u0435\u0442 &#171;res-1 &lt; len(data) \u0431\u0435\u0441\u0441\u043c\u044b\u0441\u043b\u0435\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430&#187;,  \/\/ \u043d\u043e \u044f \u043e\u0442\u0432\u0435\u0447\u0443 &#8212; io.Writer \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u044e\u0437\u0435\u0440, \u0442\u0430\u043a \u0447\u0442\u043e \u043f\u043e\u043b\u0430\u0433\u0430\u0442\u044c\u0441\u044f \u043d\u0430  \/\/ \u0434\u0436\u0435\u043d\u0442\u043b\u044c\u043c\u0435\u043d\u0441\u043a\u0438\u0435 \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u0438 &#8212; \u044d\u0442\u043e \u0438\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u043d\u043e\u0432\u0438\u0447\u043a\u0430 \u0438\u043b\u0438 \u0448\u0430\u0433  \/\/ \u0443\u043b\u044c\u0442\u0440\u0430\u0441\u0435\u043d\u044c\u043e\u0440\u0430. \u042f \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043d\u0435 \u043f\u043e\u043f\u0430\u0434\u0430\u044e \u043d\u0438 \u0432 \u043e\u0434\u043d\u0443 \u0438\u0437 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439  if err == nil &amp;&amp; res &gt; 0 &amp;&amp; res-1 &lt; len(data) &amp;&amp; data[res-1] == &#8216;\\n&#8217; {      s.Writer.Write(s.frame)      s.isDrawn = true  }  return res, err}\u0417\u0430\u043e\u0434\u043d\u043e \u044f \u043f\u0435\u0440\u0435\u043d\u0435\u0441 \u043d\u0430\u0448\u0438 \u0431\u0430\u0439\u0442\u044b \u0444\u0440\u0435\u0439\u043c\u0430 \u0432\u00a0\u0441\u0430\u043c \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u00a0\u2014 \u044d\u0442\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0432\u00a0\u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c. \u041d\u043e\u00a0\u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043e\u0434\u043d\u0443 \u0438\u0437\u00a0\u0442\u0440\u0435\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c. \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0435\u0449\u0435 \u0434\u0432\u0435? \u041d\u0430\u00a0\u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u0440\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c bool \u0434\u043b\u044f\u00a0\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430, \u043d\u043e\u00a0\u0443\u00a0\u043d\u0430\u0441 \u043d\u0435\u0442 \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0439, \u0447\u0442\u043e\u00a0\u043a\u0430\u043a\u043e\u0439\u2011\u043d\u0438\u0431\u0443\u0434\u044c \u0434\u0440\u0443\u0433\u043e\u0439 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 Write \u043d\u0435\u00a0\u0432\u043c\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u0432\u00a0\u043d\u0430\u0448\u0443 \u043b\u043e\u0433\u0438\u043a\u0443. \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043d\u0435\u00a0\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u0442\u043e\u043a\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e\u00a0\u2014 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u044c\u044e\u0442\u0435\u043a\u0441 \u043d\u0430\u00a0\u0432\u0435\u0441\u044c \u0431\u043b\u043e\u043a Write:type Spinner struct {  &#8230;  mut *sync.Mutex}func (s *Spinner) Write(data []byte) (int, error) {  s.mut.Lock()  defer s.mut.Unlock()  &#8230;}\u0412\u043e\u0442 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043a\u043e\u043d\u0435\u0446\u2011\u0442\u043e \u0443\u00a0\u043d\u0430\u0441 \u0432\u0441\u0435\u0433\u043e \u0434\u0432\u0435 \u043a\u0440\u0443\u043f\u043d\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u041e\u0434\u043d\u0430 \u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u00a0\u2014 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0444\u0440\u0435\u0439\u043c\u044b \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u00a0\u0444\u043e\u043d\u043e\u0432\u043e\u0439 \u0433\u043e\u0440\u0443\u0442\u0438\u043d\u0435 \u0440\u0430\u0437 \u0432\u00a0\u043a\u0430\u043a\u043e\u0435\u2011\u0442\u043e \u0432\u0440\u0435\u043c\u044f:func (s *Spinner) Start() context.CancelFunc {  t := time.NewTicker(100 * time.Millisecond)  ctx, cancel := context.WithCancel(context.Background())  ch := make(chan struct{}, 1)  s.mut.Lock()  s.frame = []byte(&#171;- Running&#187;)  if s.isDrawn {    \/\/ \u0417\u0434\u0435\u0441\u044c \u0438 \u0434\u0430\u043b\u0435\u0435 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c append(packageVar, other&#8230;) &#8212;    \/\/ \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043b\u044f \u043a\u0440\u0430\u0442\u043a\u043e\u0441\u0442\u0438. \u041d\u0435 \u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u0442\u0430\u043a \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u0434\u0435.    s.Writer.Write(append(clearBytes, s.frame&#8230;))  }  s.mut.Unlock()  go func() {    states := []byte{&#8216;\\\\&#8217;, &#8216;|&#8217;, &#8216;\/&#8217;, &#8216;-&#8216;}    idx := 0  Loop:    for {      select {        case &lt;-t.C:          s.mut.Lock()          s.frame[0] = states[idx]          if s.isDrawn {            s.Writer.Write(append(clearBytes, s.frame&#8230;))          }          s.mut.Unlock()          idx = (idx + 1) % len(states)        case &lt;-ctx.Done():          break Loop      }    }    s.mut.Lock()    s.frame = []byte{}    if s.isDrawn {      s.Writer.Write(clearBytes)    }    s.mut.Unlock()    close(ch)  }()  return func() {    t.Stop()    cancel()    &lt;-ch  }}\u042d\u0442\u043e \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0441\u043f\u0438\u043d\u043d\u0435\u0440. \u041d\u0435\u00a0\u0431\u0435\u0437\u00a0\u0438\u0437\u044a\u044f\u043d\u043e\u0432, \u043d\u043e\u00a0\u0440\u0430\u0431\u043e\u0447\u0438\u0439. \u041a\u0430\u043a\u00a0\u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u0430\u043d\u0433\u043b\u043e\u044f\u0437\u044b\u0447\u043d\u044b\u0435\u00a0\u2014 \u00ab\u0442\u0430\u043a \u0434\u0430\u043b\u0435\u043a\u043e \u0442\u0430\u043a \u0445\u043e\u0440\u043e\u0448\u043e\u00bb. \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0435\u0448\u0438\u0442\u044c \u043e\u0434\u043d\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443\u00a0\u2014 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u044e \u0434\u0432\u0443\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432. \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u043e\u0447\u0435\u043d\u044c \u0447\u0430\u0441\u0442\u043e \u0437\u0430\u043f\u0438\u0441\u0438 \u0432\u00a0stderr \u0438 stdout \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432\u00a0\u043e\u0434\u043d\u043e\u043c \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435. \u041d\u0443 \u0438 \u043f\u043e\u0434\u00a0\u0448\u0443\u043c\u043e\u043a \u0440\u0435\u0448\u0438\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u00a0\u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438\u00a0\u0437\u0430\u043f\u0438\u0441\u0438\/\u043e\u0447\u0438\u0441\u0442\u043a\u0435 \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 \u043d\u0430\u00a0\u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0442\u0438\u0445\u0443\u044e \u043f\u0440\u043e\u0433\u043b\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f. \u0423\u00a0\u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043c\u044c\u044e\u0442\u0435\u043a\u0441, \u0430\u00a0\u0437\u043d\u0430\u0447\u0438\u0442, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0438\u0441\u0438. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430\u00a0\u2014 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430 \u0438 \u043f\u043e\u0442\u043e\u043a \u0437\u0430\u043f\u0438\u0441\u0438, \u043d\u043e\u00a0\u043f\u0440\u0438\u00a0\u044d\u0442\u043e\u043c \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u043e\u0435 \u0441\u043e \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u043e\u043c (\u0442\u0430\u043a \u043a\u0430\u043a\u00a0\u0443\u00a0\u043d\u0438\u0445 \u043e\u0431\u0449\u0438\u0435 isDrawn, mut, frame):type spinnerState struct {  io.Writer  sync.Mutex  errCh   chan error  frame   []byte  isDrawn bool}type Spinner struct {  io.Writer  state *spinnerState}func (s *Spinner) Write(data []byte) (int, error) {  s.state.Lock()  defer s.state.Unlock()  if s.state.isDrawn {    _, err := s.state.Write(clearBytes)    s.state.isDrawn = false    if err != nil {      select {      case s.state.errCh &lt;- err:      default:      }    }  }  res, err := s.Writer.Write(data)  if err == nil &amp;&amp; res &gt; 0 &amp;&amp; res-1 &lt; len(data) &amp;&amp; data[res-1] == &#8216;\\n&#8217; {    _, localErr := s.state.Write(s.state.frame)    if localErr != nil {      select {      case s.state.errCh &lt;- localErr:      default:      }    } else {      s.state.isDrawn = true    }  }  return res, err}\u041c\u0435\u0442\u043e\u0434 Start \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0432\u0441\u0435 \u0442\u0435\u00a0\u0436\u0435 \u0437\u0430\u043c\u0435\u043d\u044b s.Writer.Write \u2192 s.state.Write, s.mut.Lock \u2192 s.state.Lock \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435, \u0438 \u0432\u0441\u0435 \u0442\u0430\u043a\u00a0\u0436\u0435 \u043f\u0438\u0448\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432\u00a0\u043a\u0430\u043d\u0430\u043b \u0447\u0435\u0440\u0435\u0437 \u043d\u0435\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0439 select. \u041f\u043e\u0447\u0435\u043c\u0443 \u043c\u044b \u0434\u043e\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u043c \u043e\u0431\u00a0\u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0443 Start \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e \u043d\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 (\u043d\u0443 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u043a\u0430\u043d\u0430\u043b \u0441\u00a0\u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438 \u0435\u0449\u0435, \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u043e \u043c\u0430\u043b\u043e \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f), \u0430\u00a0\u0432\u043e Write\u00a0\u0431\u044b\u043b\u043e\u00a0\u0431\u044b \u0441\u0442\u0440\u0430\u043d\u043d\u043e, \u043a\u00a0\u043f\u0440\u0438\u043c\u0435\u0440\u0443, \u043d\u0430\u00a0\u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0stdout \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0443 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432\u00a0stderr.\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435\u00a0\u2014 \u0431\u0435\u0437\u00a0\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0438 \u0441\u00a0\u043d\u0435\u0439\u0412\u00a0\u0446\u0435\u043b\u043e\u043c, \u044d\u0442\u043e \u043f\u043b\u044e\u0441\u2011\u043c\u0438\u043d\u0443\u0441 \u0432\u0441\u0435. \u0414\u043b\u044f\u00a0\u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u0441\u043f\u0438\u043d\u043d\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u00a0\u043e\u0434\u043d\u0443 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u043e\u0434\u043d\u043e\u0440\u0430\u0437\u043e\u0432\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043f\u043e\u0434\u00a0\u0437\u0430\u0434\u0430\u0447\u0443 \u0432\u00a0\u0442\u043e\u043c, \u0447\u0442\u043e\u00a0\u043a\u043e\u0433\u0434\u0430\u2011\u043d\u0438\u0431\u0443\u0434\u044c \u0442\u0430\u043a\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0440\u0435\u0448\u0430\u0442\u044c \u0435\u0449\u0435 \u0440\u0430\u0437\u2026 \u0418 \u0437\u0430\u00a0\u043d\u0435\u0438\u043c\u0435\u043d\u0438\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u044f \u0440\u0435\u0448\u0438\u043b\u00a0\u2014 \u0430\u00a0\u0431\u0430\u0445\u043d\u0443\u2011\u043a\u0430 \u044f \u0441\u0432\u043e\u044e. \u041a\u0430\u043a\u00a0\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0441\u00a0\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0432\u0435\u0440\u0441\u0442\u043a\u043e\u0439 \u0438 \u043f\u0440\u043e\u0433\u0440\u0435\u0441\u0441\u2011\u0431\u0430\u0440\u0430\u043c\u0438.\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430? \u041b\u0443\u0447\u0448\u0435\u00a0\u2014 \u0441\u0435\u043a\u0446\u0438\u044f \u043e\u00a0\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435\u0418\u0442\u0430\u043a, \u043f\u0435\u0440\u0435\u0445\u043e\u0434 \u043a\u00a0\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u0447\u043d\u043e\u043c\u0443 \u043a\u043e\u0434\u0443. \u0427\u0442\u043e\u00a0\u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f?\u041d\u0430\u00a0\u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 Start \u043d\u0435\u00a0\u0438\u0434\u0435\u043c\u043f\u043e\u0442\u0435\u043d\u0442\u0435\u043d, \u0430\u00a0\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u043d\u0435\u00a0\u0434\u043e\u043b\u0436\u0435\u043d \u043b\u043e\u043c\u0430\u0442\u044c\u0441\u044f \u043e\u0442\u00a0\u0442\u0430\u043a\u0438\u0445 \u043c\u0435\u043b\u043e\u0447\u0435\u0439.\u0425\u043e\u0442\u0435\u043b\u043e\u0441\u044c\u00a0\u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u044b\u0435 \u0444\u0440\u0435\u0439\u043c\u044b \u0432\u00a0\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435.\u041a\u0430\u043a\u0438\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0435\u0441\u0442\u044c \u0443\u00a0\u043d\u0430\u0441 \u0434\u043b\u044f\u00a0\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043f\u0440\u043e\u0431\u043b\u0435\u043c? \u041d\u0430\u043c, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 spinnerState: \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0443\u0434\u0430 \u0444\u043b\u0430\u0433 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0447\u0442\u043e\u2011\u0442\u043e, \u0447\u0442\u043e\u00a0\u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0444\u0440\u0435\u0439\u043c\u044b. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u044d\u0442\u043e:type FrameFunc func() ([]byte, error)type spinnerState struct {  &#8230;  getFrame FrameFunc  isRunning bool}\u041d\u043e\u00a0\u0437\u0434\u0435\u0441\u044c \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u043d\u043e\u0432\u044b\u0435 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b:\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0434\u043e\u043b\u0436\u0435\u043d\u00a0\u0431\u044b\u0442\u044c \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u0434\u043b\u044f\u00a0\u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u044f \u0434\u0430\u0442\u0430\u0440\u0435\u0439\u0441\u043e\u0432.\u041f\u0440\u0438\u00a0\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0435 \u043d\u043e\u0432\u043e\u0439 getFrame \u043d\u043e\u0432\u044b\u0439 \u0444\u0440\u0435\u0439\u043c \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c\u0441\u044f \u0441\u0440\u0430\u0437\u0443\u00a0\u0436\u0435 \u0438 \u043d\u0435\u00a0\u0437\u0430\u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u0440\u0430\u043d\u043d\u0438\u043c.\u0422\u0430\u043a \u043a\u0430\u043a FrameFunc \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438\u00a0\u2014 \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043f\u0430\u043d\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0438\u043b\u0438\u00a0\u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u0447\u0435\u043d\u044c \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e. \u0410\u00a0\u0435\u0449\u0435 \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u043d\u0435\u00a0\u0431\u044b\u0442\u044c \u043f\u043e\u0442\u043e\u043a\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u043c\u0438.\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043f\u0440\u0438\u00a0\u043f\u043e\u043c\u043e\u0449\u0438 \u0442\u043e\u0433\u043e\u00a0\u0436\u0435 \u0441\u0430\u043c\u043e\u0433\u043e \u043c\u044c\u044e\u0442\u0435\u043a\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0443\u0436\u0435 \u0432\u0432\u0435\u043b\u0438 \u0434\u043b\u044f Write. \u041d\u043e\u00a0\u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (isRunning, getFrame) \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 Write\u00a0\u2014 \u044d\u0442\u043e \u0440\u0430\u0437\u043d\u044b\u0435 \u0432\u0435\u0449\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u00a0\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u0440\u0443\u0433 \u0441\u00a0\u0434\u0440\u0443\u0433\u043e\u043c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0435 \u043e\u0434\u0438\u043d \u043c\u044c\u044e\u0442\u0435\u043a\u0441 \u0434\u043b\u044f\u00a0\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u042d\u0442\u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0449\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0432\u00a0\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438\u00a0\u2014 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0435\u043a\u0446\u0438\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u0430\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u0431\u0430 \u043c\u044c\u044e\u0442\u0435\u043a\u0441\u0430, \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d\u00a0\u2014 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u0431\u0443\u0434\u0435\u0442 \u043d\u0443\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430\u00a0\u043f\u043e\u0440\u044f\u0434\u043a\u043e\u043c \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043e\u043a, \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0435\u043d\u0438\u0435\u043c \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435. \u041f\u043e\u0432\u0435\u0440\u0445 \u0432\u0441\u0435\u0433\u043e \u044d\u0442\u043e\u0433\u043e \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 FrameFunc, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0438\u0445 \u043e\u0448\u0438\u0431\u043e\u043a \u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f, \u0430\u00a0\u0435\u0449\u0435 \u043b\u0443\u0447\u0448\u0435\u00a0\u2014 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0432\u044b\u0437\u043e\u0432\u043e\u0432. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043b\u044f\u00a0\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u044f \u0432\u044b\u0431\u0440\u0430\u043b \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u0443\u0442\u044c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043e\u0434\u043d\u043e \u0434\u0430\u043b \u043c\u043d\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0432\u00a0\u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435. \u042f \u043f\u0440\u0438\u0448\u0435\u043b \u043a\u00a0\u0430\u043a\u0442\u043e\u0440\u043d\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438:type spinnerState struct {  &#8230;  ctx       context.Context  task      chan any  revision  uint64  wg        sync.WaitGroup  inFlight  bool}type start struct {  notify chan error}type stop struct {  notify chan error}type setGetFrame struct {  getFrame&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-492942","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/492942","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=492942"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/492942\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=492942"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=492942"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=492942"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}