{"id":392610,"date":"2024-06-29T10:30:39","date_gmt":"2024-06-29T10:30:39","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=392610"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T10:30:39","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=392610","title":{"rendered":"<span>SPA \u043f\u043e\u0442\u043e\u043a\u0438 \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f: \u0448\u0430\u0431\u043b\u043e\u043d \u041c\u0435\u0439\u043e\u0437<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 SPA (\u043e\u0434\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 javascript) \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u2014 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0442\u0435\u043c\u0430. \u0423 \u0432\u0441\u044f\u043a\u043e\u0433\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e js-\u0444\u0440\u0435\u0439\u043c\u043e\u0440\u043a\u0430 \u0435\u0441\u0442\u044c \u043f\u0430\u0440\u0430, \u0442\u0440\u043e\u0439\u043a\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043d\u0430 \u044d\u0442\u043e\u0442 \u0441\u0447\u0435\u0442. &#171;\u0418\u0445 \u0435\u0441\u0442\u044c&#187; \u0438 \u0431\u0435\u0437 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438 javascript, \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043f\u043e\u0441\u043e\u0431 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c (\u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u0448\u0430\u0431\u043b\u043e\u043d). \u0410\u0432\u0442\u043e\u0440 \u043d\u0430\u0437\u0432\u0430\u043b \u0435\u0433\u043e <a href=\"https:\/\/meiosis.js.org\" rel=\"noopener noreferrer nofollow\"><strong>\u041c\u0435\u0439\u043e\u0437<\/strong><\/a>. \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0442\u0430\u043a \u0441\u0435\u0431\u0435 \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u043d\u043e \u0430\u0432\u0442\u043e\u0440\u0443 \u0432\u0438\u0434\u043d\u0435\u0435.<\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u0430 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u2014 \u043f\u043e\u0442\u043e\u043a (<a href=\"https:\/\/mithril.js.org\/stream.html\" rel=\"noopener noreferrer nofollow\">stream<\/a>), \u043d\u0430 \u0443\u0434\u0438\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u0430\u044f, \u043d\u043e &#171;\u043a\u0440\u0443\u0442\u0430\u044f&#187; \u0438\u0434\u0435\u044f \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0435 \u043e\u0441\u043e\u0431\u043e &#171;\u0437\u0430\u043c\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044f\u0441\u044c&#187;.<\/p>\n<h3>Stream &#8212; \u043f\u043e\u0442\u043e\u043a<\/h3>\n<p>\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u2014 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u043e\u0442\u043e\u043a \u2014 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0438\u043f\u0430 \u044f\u0447\u0435\u0439\u043a\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 Excel. \u0415\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u044f\u0447\u0435\u0439\u043a\u0438 \u04212 \u0440\u0430\u0432\u043d\u043e \u0441\u0443\u043c\u043c\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u044f\u0447\u0435\u0439\u043a\u0430\u0445 A1 \u0438 B1, \u0442\u043e \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u043d\u0438\u0445, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u04212 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u043f\u043e\u0442\u043e\u043a \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445, \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0439. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/%D0%A0%D0%B5%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5%20%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20-%20%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20%D1%81%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC%20%D0%B0%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE%20%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85.%20%D0%9F%D0%BE%D1%82%D0%BE%D0%BA%20-%20%D1%80%D0%B5%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%B0%D1%8F%20%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85,%20%D1%82%D0%B8%D0%BF%D0%B0%20%D1%8F%D1%87%D0%B5%D0%B9%D0%BA%D0%B8%20%D0%B2%20%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B5%20Exel.%20%D0%95%D1%81%D0%BB%D0%B8%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20%D1%8F%D1%87%D0%B5%D0%B9%D0%BA%D0%B8%20%D0%A12%20%D1%80%D0%B0%D0%B2%D0%BD%D0%BE%20%D1%81%D1%83%D0%BC%D0%BC%D0%B5%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9%20%D0%B2%20%D1%8F%D1%87%D0%B5%D0%B9%D0%BA%D0%B0%D1%85%20A1%20%D0%B8%20B1,%20%D1%82%D0%BE%20%D0%BF%D1%80%D0%B8%20%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B8%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9%20%D0%B2%20%D0%BB%D1%8E%D0%B1%D0%BE%D0%B9%20%D0%B8%D0%B7%20%D0%BD%D0%B8%D1%85,%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%A12%20%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B8%D1%82%D1%81%D1%8F.%20%D0%90%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%B8%D1%87%D0%BD%D0%BE%20%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%20%D0%BC%D0%BE%D0%B6%D0%B5%D1%82%20%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D1%82%D1%8C%20%D0%BE%D1%82%20%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D1%85%20%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%B2,%20%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F%20%D0%B2%20%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D1%85,%20%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D1%8F%D1%8E%D1%82%20%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D1%8B%D0%B9.%20%D0%92%20%D1%81%D1%82%D0%B0%D1%82%D1%8C%D0%B5%20%D0%B1%D1%83%D0%B4%D0%B5%D0%BC%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%5BMithril.stream%5D(https:\/\/mithril.js.org\/stream.html\" rel=\"noopener noreferrer nofollow\">Mithril.stream<\/a>.<\/p>\n<pre><code class=\"javascript\">\/\/ \u043f\u043e\u0442\u043e\u043a \u044d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f const username = m.stream() \/\/ \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u0443\u0442\u043e console.log(username()) \/\/ logs undefined  \/\/ \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u2013 \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 username(\"John\") console.log(username()) \/\/ logs \"John\"  \/\/ \u043f\u043e\u0442\u043e\u043a \u0445\u0440\u0430\u043d\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 username(\"John Doe\") console.log(username()) \/\/ logs \"John Doe\"  \/\/ \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 js const state = m.stream({}); \/\/ \u043e\u0431\u044a\u0435\u043a\u0442 const update = m.stream( v => v+1 ); \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f const prop = m.stream(Symbol('prop')); \/\/ \u0441\u0438\u043c\u0432\u043e\u043b <\/code><\/pre>\n<p>\u041f\u0430\u0440\u0430 \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 (\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432) \u043d\u0430 \u043f\u043e\u0442\u043e\u043a\u0430\u0445:<\/p>\n<pre><code class=\"javascript\">\/\/ map - \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 const ints = m.stream(); const mul = v => v * 5; const ints_five_times = ints.map(mul); ints(2); \/\/ \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 ints \/\/ \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 ints_five_times \u0431\u0443\u0434\u0435\u0442 \u0447\u0438\u0441\u043b\u043e \u0443\u043c\u043d\u043e\u0436\u0435\u043d\u043d\u043e\u0435 \u043d\u0430 5 console.log(ints_five_times()); \/\/ logs 10  \/\/ scan - \u0441\u0432\u0435\u0440\u0442\u043a\u0430 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 const fold = (acc, value) => acc + value; const folded_ints = m.stream.scan(fold, 0, ints); \/\/ \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438\u0438 \u043e\u0442\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 ints \/\/ \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 folded_ints \u0431\u0443\u0434\u0435\u0442 \u0441\u0443\u043c\u043c\u0430 \u0432\u0441\u0435\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 ints console.log(folded_ints()); \/\/ logs 2 ints(5); console.log(folded_ints()); \/\/ logs 7 ints(10) console.logs(folded_ints()); \/\/ logs 17<\/code><\/pre>\n<h3>\u041f\u0430\u0442\u0442\u0435\u0440\u043d \u041c\u0435\u0439\u043e\u0437<\/h3>\n<p>\u0421\u0443\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u043b\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435) \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 js. \u041f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u2014 \u044d\u0442\u043e \u0441\u0432\u0435\u0440\u0442\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u2014 \u043f\u043e\u0442\u043e\u043a\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<pre><code class=\"javascript\">\/\/ \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f const app = {   initial: {     boxes: [],     colors: [\"red\", \"purple\", \"blue\"],     description: '',     stat: []   }, };  \/\/ \u043f\u043e\u0442\u043e\u043a \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 const update = m.stream()  \/\/ \u0441\u0432\u0435\u0440\u0442\u043e\u0447\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f const fold = (state, patcher) => patcher(state);  \/\/ \u043f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u2013 \u0441\u0432\u0435\u0440\u0442\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 const states = m.stream.scan(fold, app.initial, update);<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u0442\u043e\u043a\u0430 <em>update<\/em> \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u0442\u043e \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u2014 \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u043f\u043e \u0441\u043c\u044b\u0441\u043b\u0443 \u0441\u0432\u0435\u0440\u0442\u043a\u0438 <em>scan<\/em>). <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043d\u0430\u0431\u043e\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435:<\/p>\n<pre><code class=\"javascript\">const Actions = {   addBox(update, color) {     \/\/ \u0432 \u043f\u043e\u0442\u043e\u043a update \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e     update( state => Object.assign(state,       { boxes: state.boxes.concat( color )}     ))   },   removeBox(update, idx) {     update( state => Object.assign(state,       boxes: state.boxes.filter((x, j) => idx != j)     ))   } } \/\/ \u0412\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \/\/ Actions.addBox(update, \"red\"); \/\/ \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 boxes \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \"red\" \/\/ \u0438 \u0432 \u043f\u043e\u0442\u043e\u043a states \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \/\/ Actions.removeBox(update, 3); \/\/ \u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 boxes \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043b\u044f\u0442\u044c\u0441\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u043c 3 \/\/ \u0435\u0441\u043b\u0438 \u043e\u043d \u0442\u0430\u043c \u0435\u0441\u0442\u044c <\/code><\/pre>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u0443\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f, \u0435\u0441\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u0435\u0441\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439, \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439. \u0412\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0432\u0430\u0448\u0435\u0439 \u0444\u0430\u043d\u0442\u0430\u0437\u0438\u0438, \u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u0430, \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<h3>\u0422\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0418\u0434\u0435\u044e \u0438 \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u0434\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f \u043f\u043e\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0443 <a href=\"https:\/\/james-forbes.com\" rel=\"noopener noreferrer nofollow\">James Forbs<\/a>-\u0430. \u0418\u0434\u0435\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u2014 \u0435\u0441\u0442\u044c \u043d\u0430\u0431\u043e\u0440 \u0438\u0437 \u043a\u0443\u0431\u0438\u043a\u043e\u0432 \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u0446\u0432\u0435\u0442\u0430 \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043c\u0435\u043d\u044e, \u0438 \u0442\u0430\u0431\u043b\u043e \u043f\u043e\u0434 \u043d\u0438\u043c. \u041a\u043b\u0438\u043a\u0430\u0435\u043c \u043f\u043e \u043a\u0443\u0431\u0438\u043a\u0443 \u0432 \u043c\u0435\u043d\u044e \u2014 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u0442\u0430\u0431\u043b\u043e. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u0442\u0430\u0431\u043b\u043e \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438 \u0442\u0438\u043f \u0432\u0441\u0435\u0445 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043a\u0443\u0431\u0438\u043a\u043e\u0432. \u041a\u043b\u0438\u043a \u043f\u043e \u043a\u0443\u0431\u0438\u043a\u0443 \u043d\u0430 \u0442\u0430\u0431\u043b\u043e \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0435\u0433\u043e, \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f. \u041c\u043e\u0436\u043d\u043e \u0434\u0443\u043c\u0430\u0442\u044c \u043e\u0431 \u044d\u0442\u043e\u043c, \u043a\u0430\u043a \u043e \u0432\u044b\u0431\u043e\u0440\u0435 \u0442\u0438\u043f\u0430 \u0431\u043b\u044e\u0434\u0430 (\u043f\u0438\u0446\u0446\u044b) \u0438\u0437 \u043c\u0435\u043d\u044e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440. <\/p>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0439 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u0434\u0435\u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0438 \u043f\u043b\u0430\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u041c\u043d\u0435 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u0430\u044f \u0438\u0434\u0435\u044f \u043f\u043e\u0442\u043e\u043a\u0430 <em>cells<\/em> (\u043a\u043b\u0435\u0442\u043a\u0438):<\/p>\n<pre><code class=\"javascript\">const update = m.stream(); const states = scan(...); const getState = () => states(); const createCell = (state) => ({ state, getState, update }); const cells = states.map(createCell);<\/code><\/pre>\n<p>\u0418 \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u2014 \u0434\u0435\u043b\u043e \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u043e\u0435, <em>cells<\/em> \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u043e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0442\u043e\u043a <em>disp<\/em> (\u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439). \u041f\u043e \u043c\u043e\u0435\u043c\u0443 \u043c\u043d\u0435\u043d\u0438\u044e, \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445. \u041e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 \u0430\u0432\u0442\u043e\u0440\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430.<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c:<\/p>\n<pre><code class=\"javascript\">\/\/ P(atcher) - \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u0430\u0442\u0447\u0430 const P = patch => state => Object.assign(state, patch);  \/\/ lift - \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u043e\u0442\u043e\u043a\u0430 update const lift = update => patch => update(P(patch));  \/\/ \u043f\u043e\u0442\u043e\u043a \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 const disp = m.stream(); <\/code><\/pre>\n<p>\u041f\u043e\u0442\u043e\u043a\u0438 <em>update, states<\/em>, \u0444\u0443\u043d\u043a\u0446\u0438\u044f <em>fold<\/em>, \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (<em>app.initial<\/em>) \u0431\u0443\u0434\u0443\u0442 \u0442\u0430\u043a\u0438\u043c \u0436\u0435, \u043a\u0430\u043a \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435. \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e <em>actions<\/em>, \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0443\u044e \u043e\u0431\u044a\u0435\u043a\u0442. \u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/ramdajs.com\" rel=\"noopener noreferrer nofollow\">Ramda<\/a>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0443\u0447\u0443 \u043b\u0438\u0448\u043d\u0435\u0433\u043e \u043a\u043e\u0434\u0430 (\u043f\u0440\u0435\u0444\u0438\u043a\u0441 R).<\/p>\n<pre><code class=\"javascript\">const I = x => x; \/\/ identity  \/\/ \u0430\u043d\u0430\u043b\u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0438 \u0432\u044b\u0432\u043e\u0434 \u0442\u0435\u043a\u0441\u0442\u0430 \u0441 \u0441\u043e\u044e\u0437\u043e\u043c s const humanList = s => xs => xs.length > 1 ?   `${xs.slice(0, -1).join(\", \")} ${s} ${xs.slice(-1)}` :   xs.join(\"\");  \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f const descString = R.pipe(   R.toPairs,   R.groupBy(R.last),   R.map(R.map(R.head)),   R.map(humanList(\"and\")),   R.toPairs,   R.map(R.join(\" \")),   humanList(\"and\"),   x => x + \".\" )  \/\/ returns actions object const Actions = (state, update) => {   \/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e   const stup = lift(update);   \/\/ \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 lift - \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435, \u0442\u043e \u0432\u044b\u0437\u043e\u0432 stup \u0441 \u043e\u0431\u044a\u043a\u0442\u043e\u043c \u043f\u0430\u0442\u0447\u0430 \u043a\u0430\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c   \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 update, \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u0441\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f    return {     \/\/ \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u0443\u0431\u0438\u043a \u043d\u0430 \u0442\u0430\u0431\u043b\u043e     addBox(color) {       return this.countStat(         state().boxes.concat(color[0])       );     },     \/\/ \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043a\u0443\u0431\u0438\u043a     removeBox(idx) {       return this.countStat(         state().boxes.filter((x, j) => idx[0] != j)       );     },     \/\/ \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u0438 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0442\u0435\u043a\u0441\u0442     countStat(boxes) {       let stat = R.countBy(I, boxes), description = descString(stat);       stup({boxes, stat, description});       return false;     }   }; }; <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043e\u0431\u0449\u0438\u043c, \u043d\u043e \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u0443\u0442\u0438 \u0443\u0431\u0440\u0430\u043d\u043e \u0432\u0441\u0435 \u043b\u0438\u0448\u043d\u0435\u0435.<\/p>\n<pre><code class=\"javascript\">\/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 const initApp = (actions) => {   \/\/ \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439   disp.map(av => {     let [event, ...args] = av;     return actions[event] ? actions[event](args) : m.stream.SKIP;   }); }; \/\/ \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f initApp(Actions(states, update));<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/mithril.js.org\" rel=\"noopener noreferrer nofollow\">mithril<\/a>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u043d\u0435 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u0435\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u043f\u043e\u0441\u043b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 DOM.<\/p>\n<pre><code class=\"javascript\">\/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u0442 const BoxesView = function(state, disp) {    \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c   const add = (evt, color) => {     evt.preventDefault();     return disp(['addBox', color])   }   \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u0443\u0434\u0430\u043b\u0438\u0442\u044c   const remove = (evt, idx) => {     evt.preventDefault();     return disp(['removeBox', idx])   }   return {     view: function() {       return m(\".app\", [         m(\"nav.header\", [           m(\"h1\", \"Boxes\"),           state().colors.map(color =>             m(\"button\", {               style: `background-color: ${color}`,               onclick: evt => add(evt, `${color}`)               }, \"+\"             )           )         ]),         m(\"p\", state().description),         m(\".desc\",           state().boxes.map((x, i) =>             m(\".boxs\", {               style: `background-color: ${x}`,               onclick: evt => remove(evt, i)               }             )           )         )       ])     }   } } <\/code><\/pre>\n<p>\u041c\u043e\u043d\u0442\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 (<em>states \u0438 disp<\/em> \u0443 \u043d\u0430\u0441 \u0432\u0438\u0434\u043d\u044b \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e):<\/p>\n<pre><code class=\"javascript\">m.mount(   document.getElementById('app'),   BoxesView(states, disp) );<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0434\u043b\u044f <em>react<\/em> \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 \u0430\u0432\u0442\u043e\u0440\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430. \u0422\u0430\u043c \u0436\u0435, \u0435\u0441\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0447\u0435\u043d\u044c \u043d\u0435\u043f\u043b\u043e\u0445\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 <a href=\"https:\/\/github.com\/foxdonut\/meiosis-tracer\" rel=\"noopener noreferrer nofollow\">meiosis-tracer<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u0430\u043a \u0447\u0430\u0441\u0442\u044c \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\/\u0438\u043b\u0438 \u043a\u0430\u043a \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Chrome. Tracer \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0437\u0430 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 \u0432 \u0446\u0435\u043b\u0435\u0432\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. <\/p>\n<p>\u041a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 <a href=\"https:\/\/github.com\/SLikhachev\/meiosys.git\" rel=\"noopener noreferrer nofollow\">github<\/a>-\u0435.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \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\/707018\/\"> https:\/\/habr.com\/ru\/articles\/707018\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 SPA (\u043e\u0434\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 javascript) \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u2014 \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0442\u0435\u043c\u0430. \u0423 \u0432\u0441\u044f\u043a\u043e\u0433\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e js-\u0444\u0440\u0435\u0439\u043c\u043e\u0440\u043a\u0430 \u0435\u0441\u0442\u044c \u043f\u0430\u0440\u0430, \u0442\u0440\u043e\u0439\u043a\u0430 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u043d\u0430 \u044d\u0442\u043e\u0442 \u0441\u0447\u0435\u0442. &#171;\u0418\u0445 \u0435\u0441\u0442\u044c&#187; \u0438 \u0431\u0435\u0437 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u0432 \u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438 javascript, \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043f\u043e\u0441\u043e\u0431 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c (\u043f\u0430\u0442\u0442\u0435\u0440\u043d, \u0448\u0430\u0431\u043b\u043e\u043d). \u0410\u0432\u0442\u043e\u0440 \u043d\u0430\u0437\u0432\u0430\u043b \u0435\u0433\u043e <a href=\"https:\/\/meiosis.js.org\" rel=\"noopener noreferrer nofollow\"><strong>\u041c\u0435\u0439\u043e\u0437<\/strong><\/a>. \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0442\u0430\u043a \u0441\u0435\u0431\u0435 \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u043d\u043e \u0430\u0432\u0442\u043e\u0440\u0443 \u0432\u0438\u0434\u043d\u0435\u0435.<\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u0430 \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430 \u2014 \u043f\u043e\u0442\u043e\u043a (<a href=\"https:\/\/mithril.js.org\/stream.html\" rel=\"noopener noreferrer nofollow\">stream<\/a>), \u043d\u0430 \u0443\u0434\u0438\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u0430\u044f, \u043d\u043e &#171;\u043a\u0440\u0443\u0442\u0430\u044f&#187; \u0438\u0434\u0435\u044f \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0435 \u043e\u0441\u043e\u0431\u043e &#171;\u0437\u0430\u043c\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044f\u0441\u044c&#187;.<\/p>\n<h3>Stream &#8212; \u043f\u043e\u0442\u043e\u043a<\/h3>\n<p>\u0420\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u2014 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u043e\u0442\u043e\u043a \u2014 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0438\u043f\u0430 \u044f\u0447\u0435\u0439\u043a\u0438 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 Excel. \u0415\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u044f\u0447\u0435\u0439\u043a\u0438 \u04212 \u0440\u0430\u0432\u043d\u043e \u0441\u0443\u043c\u043c\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u044f\u0447\u0435\u0439\u043a\u0430\u0445 A1 \u0438 B1, \u0442\u043e \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u043d\u0438\u0445, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u04212 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u043f\u043e\u0442\u043e\u043a \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445, \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u044b\u0439. \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/%D0%A0%D0%B5%D0%B0%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5%20%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20-%20%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20%D1%81%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%D0%BC%20%D0%B0%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE%20%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85.%20%D0%9F%D0%BE%D1%82%D0%BE%D0%BA%20-%20%D1%80%D0%B5%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%B0%D1%8F%20%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B0%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85,%20%D1%82%D0%B8%D0%BF%D0%B0%20%D1%8F%D1%87%D0%B5%D0%B9%D0%BA%D0%B8%20%D0%B2%20%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B5%20Exel.%20%D0%95%D1%81%D0%BB%D0%B8%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20%D1%8F%D1%87%D0%B5%D0%B9%D0%BA%D0%B8%20%D0%A12%20%D1%80%D0%B0%D0%B2%D0%BD%D0%BE%20%D1%81%D1%83%D0%BC%D0%BC%D0%B5%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9%20%D0%B2%20%D1%8F%D1%87%D0%B5%D0%B9%D0%BA%D0%B0%D1%85%20A1%20%D0%B8%20B1,%20%D1%82%D0%BE%20%D0%BF%D1%80%D0%B8%20%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B8%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9%20%D0%B2%20%D0%BB%D1%8E%D0%B1%D0%BE%D0%B9%20%D0%B8%D0%B7%20%D0%BD%D0%B8%D1%85,%20%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%A12%20%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B8%D1%82%D1%81%D1%8F.%20%D0%90%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%B8%D1%87%D0%BD%D0%BE%20%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%20%D0%BC%D0%BE%D0%B6%D0%B5%D1%82%20%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D1%82%D1%8C%20%D0%BE%D1%82%20%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D1%85%20%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%B2,%20%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F%20%D0%B2%20%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D1%85,%20%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D1%8F%D1%8E%D1%82%20%D0%B7%D0%B0%D0%B2%D0%B8%D1%81%D0%B8%D0%BC%D1%8B%D0%B9.%20%D0%92%20%D1%81%D1%82%D0%B0%D1%82%D1%8C%D0%B5%20%D0%B1%D1%83%D0%B4%D0%B5%D0%BC%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C%20%5BMithril.stream%5D(https:\/\/mithril.js.org\/stream.html\" rel=\"noopener noreferrer nofollow\">Mithril.stream<\/a>.<\/p>\n<pre><code class=\"javascript\">\/\/ \u043f\u043e\u0442\u043e\u043a \u044d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f const username = m.stream() \/\/ \u0441\u0435\u0439\u0447\u0430\u0441 \u043f\u0443\u0442\u043e console.log(username()) \/\/ logs undefined  \/\/ \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u2013 \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 username(\"John\") console.log(username()) \/\/ logs \"John\"  \/\/ \u043f\u043e\u0442\u043e\u043a \u0445\u0440\u0430\u043d\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 username(\"John Doe\") console.log(username()) \/\/ logs \"John Doe\"  \/\/ \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 js const state = m.stream({}); \/\/ \u043e\u0431\u044a\u0435\u043a\u0442 const update = m.stream( v => v+1 ); \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f const prop = m.stream(Symbol('prop')); \/\/ \u0441\u0438\u043c\u0432\u043e\u043b <\/code><\/pre>\n<p>\u041f\u0430\u0440\u0430 \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 (\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432) \u043d\u0430 \u043f\u043e\u0442\u043e\u043a\u0430\u0445:<\/p>\n<pre><code class=\"javascript\">\/\/ map - \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 const ints = m.stream(); const mul = v => v * 5; const ints_five_times = ints.map(mul); ints(2); \/\/ \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 ints \/\/ \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 ints_five_times \u0431\u0443\u0434\u0435\u0442 \u0447\u0438\u0441\u043b\u043e \u0443\u043c\u043d\u043e\u0436\u0435\u043d\u043d\u043e\u0435 \u043d\u0430 5 console.log(ints_five_times()); \/\/ logs 10  \/\/ scan - \u0441\u0432\u0435\u0440\u0442\u043a\u0430 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 const fold = (acc, value) => acc + value; const folded_ints = m.stream.scan(fold, 0, ints); \/\/ \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438\u0438 \u043e\u0442\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430 ints \/\/ \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 folded_ints \u0431\u0443\u0434\u0435\u0442 \u0441\u0443\u043c\u043c\u0430 \u0432\u0441\u0435\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 ints console.log(folded_ints()); \/\/ logs 2 ints(5); console.log(folded_ints()); \/\/ logs 7 ints(10) console.logs(folded_ints()); \/\/ logs 17<\/code><\/pre>\n<h3>\u041f\u0430\u0442\u0442\u0435\u0440\u043d \u041c\u0435\u0439\u043e\u0437<\/h3>\n<p>\u0421\u0443\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (\u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u043b\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435) \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 js. \u041f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u2014 \u044d\u0442\u043e \u0441\u0432\u0435\u0440\u0442\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435 \u2014 \u043f\u043e\u0442\u043e\u043a\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<pre><code class=\"javascript\">\/\/ \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f const app = {   initial: {     boxes: [],     colors: [\"red\", \"purple\", \"blue\"],     description: '',     stat: []   }, };  \/\/ \u043f\u043e\u0442\u043e\u043a \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 const update = m.stream()  \/\/ \u0441\u0432\u0435\u0440\u0442\u043e\u0447\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f const fold = (state, patcher) => patcher(state);  \/\/ \u043f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u2013 \u0441\u0432\u0435\u0440\u0442\u043a\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 const states = m.stream.scan(fold, app.initial, update);<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u0442\u043e\u043a\u0430 <em>update<\/em> \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u0442\u043e \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u2014 \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (\u043f\u043e \u0441\u043c\u044b\u0441\u043b\u0443 \u0441\u0432\u0435\u0440\u0442\u043a\u0438 <em>scan<\/em>). <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043d\u0430\u0431\u043e\u0440 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435:<\/p>\n<pre><code class=\"javascript\">const Actions = {   addBox(update, color) {     \/\/ \u0432 \u043f\u043e\u0442\u043e\u043a update \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e     update( state => Object.assign(state,       { boxes: state.boxes.concat( color )}     ))   },   removeBox(update, idx) {     update( state => Object.assign(state,       boxes: state.boxes.filter((x, j) => idx != j)     ))   } } \/\/ \u0412\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \/\/ Actions.addBox(update, \"red\"); \/\/ \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 boxes \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \"red\" \/\/ \u0438 \u0432 \u043f\u043e\u0442\u043e\u043a states \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \/\/ Actions.removeBox(update, 3); \/\/ \u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 boxes \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043b\u044f\u0442\u044c\u0441\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0441 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u043c 3 \/\/ \u0435\u0441\u043b\u0438 \u043e\u043d \u0442\u0430\u043c \u0435\u0441\u0442\u044c <\/code><\/pre>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0441\u0443\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f, \u0435\u0441\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439, \u0435\u0441\u0442\u044c \u043f\u043e\u0442\u043e\u043a \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439, \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439. \u0412\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0432\u0430\u0448\u0435\u0439 \u0444\u0430\u043d\u0442\u0430\u0437\u0438\u0438, \u0438 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u0430, \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<h3>\u0422\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0418\u0434\u0435\u044e \u0438 \u0447\u0430\u0441\u0442\u044c \u043a\u043e\u0434\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f \u043f\u043e\u0437\u0430\u0438\u043c\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0443 <a href=\"https:\/\/james-forbes.com\" rel=\"noopener noreferrer nofollow\">James Forbs<\/a>-\u0430. \u0418\u0434\u0435\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u2014 \u0435\u0441\u0442\u044c \u043d\u0430\u0431\u043e\u0440 \u0438\u0437 \u043a\u0443\u0431\u0438\u043a\u043e\u0432 \u0440\u0430\u0437\u043d\u043e\u0433\u043e \u0446\u0432\u0435\u0442\u0430 \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043c\u0435\u043d\u044e, \u0438 \u0442\u0430\u0431\u043b\u043e \u043f\u043e\u0434 \u043d\u0438\u043c. \u041a\u043b\u0438\u043a\u0430\u0435\u043c \u043f\u043e \u043a\u0443\u0431\u0438\u043a\u0443 \u0432 \u043c\u0435\u043d\u044e \u2014 \u0442\u0430\u043a\u043e\u0439 \u0436\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u0442\u0430\u0431\u043b\u043e. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u0442\u0430\u0431\u043b\u043e \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0449\u0430\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438 \u0442\u0438\u043f \u0432\u0441\u0435\u0445 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043a\u0443\u0431\u0438\u043a\u043e\u0432. \u041a\u043b\u0438\u043a \u043f\u043e \u043a\u0443\u0431\u0438\u043a\u0443 \u043d\u0430 \u0442\u0430\u0431\u043b\u043e \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0435\u0433\u043e, \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f. \u041c\u043e\u0436\u043d\u043e \u0434\u0443\u043c\u0430\u0442\u044c \u043e\u0431 \u044d\u0442\u043e\u043c, \u043a\u0430\u043a \u043e \u0432\u044b\u0431\u043e\u0440\u0435 \u0442\u0438\u043f\u0430 \u0431\u043b\u044e\u0434\u0430 (\u043f\u0438\u0446\u0446\u044b) \u0438\u0437 \u043c\u0435\u043d\u044e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440. <\/p>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0439 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0438\u0434\u0435\u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0438 \u043f\u043b\u0430\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u041c\u043d\u0435 \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u0430\u044f \u0438\u0434\u0435\u044f \u043f\u043e\u0442\u043e\u043a\u0430 <em>cells<\/em> (\u043a\u043b\u0435\u0442\u043a\u0438):<\/p>\n<pre><code class=\"javascript\">const update = m.stream(); const states = scan(...); const getState = () => states(); const createCell = (state) => ({ state, getState, update }); const cells = states.map(createCell);<\/code><\/pre>\n<p>\u0418 \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u2014 \u0434\u0435\u043b\u043e \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u043e\u0435, <em>cells<\/em> \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u043e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0442\u043e\u043a <em>disp<\/em> (\u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439). \u041f\u043e \u043c\u043e\u0435\u043c\u0443 \u043c\u043d\u0435\u043d\u0438\u044e, \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445. \u041e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 \u0430\u0432\u0442\u043e\u0440\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430.<\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c:<\/p>\n<pre><code class=\"javascript\">\/\/ P(atcher) - \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u0430\u0442\u0447\u0430 const P = patch => state => Object.assign(state, patch);  \/\/ lift - \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u043e\u0442\u043e\u043a\u0430 update const lift = update => patch => update(P(patch));  \/\/ \u043f\u043e\u0442\u043e\u043a \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0445 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 const disp = m.stream(); <\/code><\/pre>\n<p>\u041f\u043e\u0442\u043e\u043a\u0438 <em>update, states<\/em>, \u0444\u0443\u043d\u043a\u0446\u0438\u044f <em>fold<\/em>, \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (<em>app.initial<\/em>) \u0431\u0443\u0434\u0443\u0442 \u0442\u0430\u043a\u0438\u043c \u0436\u0435, \u043a\u0430\u043a \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435. \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e <em>actions<\/em>, \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0443\u044e \u043e\u0431\u044a\u0435\u043a\u0442. \u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/ramdajs.com\" rel=\"noopener noreferrer nofollow\">Ramda<\/a>, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0443\u0447\u0443 \u043b\u0438\u0448\u043d\u0435\u0433\u043e \u043a\u043e\u0434\u0430 (\u043f\u0440\u0435\u0444\u0438\u043a\u0441 R).<\/p>\n<pre><code class=\"javascript\">const I = x => x; \/\/ identity  \/\/ \u0430\u043d\u0430\u043b\u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0438 \u0432\u044b\u0432\u043e\u0434 \u0442\u0435\u043a\u0441\u0442\u0430 \u0441 \u0441\u043e\u044e\u0437\u043e\u043c s const humanList = s => xs => xs.length > 1 ?   `${xs.slice(0, -1).join(\", \")} ${s} ${xs.slice(-1)}` :   xs.join(\"\");  \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f const descString = R.pipe(   R.toPairs,   R.groupBy(R.last),   R.map(R.map(R.head)),   R.map(humanList(\"and\")),   R.toPairs,   R.map(R.join(\" \")),   humanList(\"and\"),   x => x + \".\" )  \/\/ returns actions object const Actions = (state, update) => {   \/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e   const stup = lift(update);   \/\/ \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 lift - \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435, \u0442\u043e \u0432\u044b\u0437\u043e\u0432 stup \u0441 \u043e\u0431\u044a\u043a\u0442\u043e\u043c \u043f\u0430\u0442\u0447\u0430 \u043a\u0430\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c   \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 update, \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0432\u0435\u043d\u043d\u043e \u0432\u0441\u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f    return {     \/\/ \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u0443\u0431\u0438\u043a \u043d\u0430 \u0442\u0430\u0431\u043b\u043e     addBox(color) {       return this.countStat(         state().boxes.concat(color[0])       );     },     \/\/ \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043a\u0443\u0431\u0438\u043a     removeBox(idx) {       return this.countStat(         state().boxes.filter((x, j) => idx[0] != j)       );     },     \/\/ \u043f\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u0438 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0442\u0435\u043a\u0441\u0442     countStat(boxes) {       let stat = R.countBy(I, boxes), description = descString(stat);       stup({boxes, stat, description});       return false;     }   }; }; <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043e\u0431\u0449\u0438\u043c, \u043d\u043e \u0434\u043b\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u0443\u0442\u0438 \u0443\u0431\u0440\u0430\u043d\u043e \u0432\u0441\u0435 \u043b\u0438\u0448\u043d\u0435\u0435.<\/p>\n<pre><code class=\"javascript\">\/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 const initApp = (actions) => {   \/\/ \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0438\u0441\u043f\u0435\u0442\u0447\u0435\u0440\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439   disp.map(av => {     let [event, ...args] = av;     return actions[event] ? actions[event](args) : m.stream.SKIP;   }); }; \/\/ \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f initApp(Actions(states, update));<\/code><\/pre>\n<p>\u0414\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u044f \u0431\u0443\u0434\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/mithril.js.org\" rel=\"noopener noreferrer nofollow\">mithril<\/a>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u043d\u0435 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u0435\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u043f\u043e\u0441\u043b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 DOM.<\/p>\n<pre><code class=\"javascript\">\/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u0442 const BoxesView = function(state, disp) {    \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c   const add = (evt, color) => {     evt.preventDefault();     return disp(['addBox', color])   }   \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u0443\u0434\u0430\u043b\u0438\u0442\u044c   const remove = (evt, idx) => {     evt.preventDefault();     return disp(['removeBox', idx])   }   return {     view: function() {       return m(\".app\", [         m(\"nav.header\", [           m(\"h1\", \"Boxes\"),           state().colors.map(color =>             m(\"button\", {               style: `background-color: ${color}`,               onclick: evt => add(evt, `${color}`)               }, \"+\"             )           )         ]),         m(\"p\", state().description),         m(\".desc\",           state().boxes.map((x, i) =>             m(\".boxs\", {               style: `background-color: ${x}`,               onclick: evt => remove(evt, i)               }             )           )         )       ])     }   } } <\/code><\/pre>\n<p>\u041c\u043e\u043d\u0442\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0443 (<em>states \u0438 disp<\/em> \u0443 \u043d\u0430\u0441 \u0432\u0438\u0434\u043d\u044b \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e):<\/p>\n<pre><code class=\"javascript\">m.mount(   document.getElementById('app'),   BoxesView(states, disp) );<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0434\u043b\u044f <em>react<\/em> \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 \u0430\u0432\u0442\u043e\u0440\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430. \u0422\u0430\u043c \u0436\u0435, \u0435\u0441\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0447\u0435\u043d\u044c \u043d\u0435\u043f\u043b\u043e\u0445\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 <a href=\"https:\/\/github.com\/foxdonut\/meiosis-tracer\" rel=\"noopener noreferrer nofollow\">meiosis-tracer<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043a\u0430\u043a \u0447\u0430\u0441\u0442\u044c \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\/\u0438\u043b\u0438 \u043a\u0430\u043a \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Chrome. Tracer \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0437\u0430 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438 \u0432 \u0446\u0435\u043b\u0435\u0432\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. <\/p>\n<p>\u041a\u043e\u0434 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 <a href=\"https:\/\/github.com\/SLikhachev\/meiosys.git\" rel=\"noopener noreferrer nofollow\">github<\/a>-\u0435.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \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\/707018\/\"> https:\/\/habr.com\/ru\/articles\/707018\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-392610","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/392610","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=392610"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/392610\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=392610"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=392610"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=392610"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}