{"id":485224,"date":"2026-06-26T19:18:20","date_gmt":"2026-06-26T19:18:20","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=485224"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=485224","title":{"rendered":"\u0417\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 Cruzo. \u0427\u0430\u0441\u0442\u044c 2. \u041e\u0431\u0437\u043e\u0440 \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0430\u044f \u043c\u0430\u0448\u0438\u043d\u0430"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/1020698\/\" rel=\"noopener noreferrer nofollow\">Cruzo \u2014 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 UI-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0435\u0439 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438<\/a>\u00a0<\/p>\n<p><a href=\"https:\/\/habr.com\/ru\/articles\/1050020\/\" rel=\"noopener noreferrer nofollow\">\u0417\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 Cruzo. \u0427\u0430\u0441\u0442\u044c 1. RxBucket \u2013 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435<\/a><\/p>\n<p>\u042f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u044e \u0441\u0435\u0440\u0438\u044e \u043e\u0431\u0437\u043e\u0440\u043d\u044b\u0445 \u0441\u0442\u0430\u0442\u0435\u0439 \u043e js-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 Cruzo. \u042f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u043d\u0430\u0434 \u044d\u0442\u0438\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 6 \u043b\u0435\u0442, \u043c\u043d\u043e\u0433\u043e \u0438\u0434\u0435\u0439 \u043e\u0442\u043f\u0430\u043b\u043e, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0432 \u0440\u0430\u0431\u043e\u0442\u0435. <br \/>\u0417\u0434\u0435\u0441\u044c \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0432\u0430\u043c \u043e \u0441\u0435\u0440\u0434\u0446\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u2013 \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440\u0435. \u0414\u043b\u044f \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u044b\u043b\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0441\u0442\u0435\u043a\u043e\u0432\u0430\u044f \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0430\u044f \u043c\u0430\u0448\u0438\u043d\u0430. <br \/>\u041a\u0430\u043a\u0430\u044f \u0435\u0449\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0430\u044f \u043c\u0430\u0448\u0438\u043d\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 js \u0441\u043f\u0440\u043e\u0441\u0438\u0442\u0435 \u0432\u044b? \u042d\u0442\u043e VM \u2014 \u043d\u043e \u043d\u0435 \u00ab\u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u00bb \u0432\u0440\u043e\u0434\u0435 JVM \u0438\u043b\u0438 WebAssembly, \u0430 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0442\u043e\u0440 \u0431\u0430\u0439\u0442\u043a\u043e\u0434\u0430, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 JavaScript.<\/p>\n<h3>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043e \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0432 Cruzo<\/h3>\n<p>\u0420\u0430\u0437\u043c\u0435\u0442\u043a\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 Cruzo \u044d\u0442\u043e \u2013 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0439 HTML, \u0430 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e JavaScript, \u043d\u043e \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043e\u0433\u043e\u0432\u043e\u0440\u043a\u0430\u043c\u0438 (<code>::rx<\/code>, <code>once::<\/code>).<\/p>\n<pre><code class=\"xml\">&lt;span&gt;{{ once::root.label }}&lt;\/span&gt;&lt;button onclick=\"{{root.count$.update(root.count$::rx + 1)}}\"&gt;  ping: {{root.count$::rx}}&lt;\/button&gt;<\/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>\u0412\u0434\u043e\u0431\u0430\u0432\u043e\u043a \u043a \u044d\u0442\u043e\u043c\u0443, \u0435\u0441\u043b\u0438 \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u0440\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Cruzo (AbstractComponent), \u0442\u0430\u043c \u0448\u0430\u0431\u043b\u043e\u043d \u2013 \u044d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b.<\/p>\n<pre><code class=\"typescript\">export class MyComponent extends AbstractComponent {  ...  getHTML() {    return `&lt;div&gt;        &lt;button onclick=\"{{ root.count.update(root.count::rx + 1) }}\"&gt;        Clicks: &lt;b&gt;{{ root.count::rx }}&lt;\/b&gt;        &lt;\/button&gt;      &lt;\/div&gt;`;  }  ...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0428\u0430\u0431\u043b\u043e\u043d \u0432 \u0432\u0438\u0434\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u0435\u043d, \u0435\u0441\u043b\u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u0435\u043d\u044f\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0443 \u043d\u0430 \u0445\u043e\u0434\u0443 \u2014 \u0431\u0435\u0437 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0430\u043c\u043e\u0433\u043e HTML:<\/p>\n<pre><code class=\"typescript\">export class MyComponent extends AbstractComponent {  ...  getHTML() {    let extHTML = ``;      if (this.config.myParam) {      extHTML = &lt;div class=\"ext-block\"&gt;&lt;\/div&gt;;    }      return `${extHTML}        &lt;button onclick=\"{{root.count$.update(root.count$::rx + 1)}}\"&gt;          ping: {{root.count$::rx}}        &lt;\/button&gt;    `;  }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u041a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0448\u0430\u0431\u043b\u043e\u043d \u0432 Cruzo<\/h3>\n<p>\u041f\u0443\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0432 Cruzo \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0441 \u201c\u0440\u0443\u0447\u043d\u043e\u0433\u043e\u201d \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430, \u043f\u0430\u0440\u0441\u0438\u043d\u0433 HTML-\u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0441\u0430\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440<\/p>\n<pre><code class=\"typescript\">export abstract class AbstractComponent&lt;Config = any, ValueType = any, StateType = any&gt;{  ...    protected initTemplate() {    const html = this.getHTML();      if (html) {      this.node.innerHTML = html;            this.template = new Template({        node: this.node,        self: () =&gt; this,        selector: this.selector,        tplFile: this.tplFile,        domStructureChanged: () =&gt; {          this.domStructureChanged();        },      });          this.template.detectChanges();      this.updateDependencies();    }  }  ...}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u043a\u043b\u0430\u0441\u0441 Template \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0434\u0430 \u0441 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u043c<\/p>\n<pre><code class=\"typescript\">export class Template {  ...  constructor(params: TemplateParams) {    Object.assign(this, params);      if (typeof this.self !== \"function\") {      throw new Error(\"Invalid self param\");    }      if (!this.root) {      this.root = this;      this.debug = {        selector: params.selector,        tplFile: params.tplFile,      };            this.onRxUpdate = this.getRxUpdate();    }      this.handleDomAttributes();    this.handleAttributes();    if (!this.innerHtmlTemplateBC) this.handleChildrens(this.node);    this.setEvents();  }  ...}<\/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\u043d\u0443\u0442\u0440\u0438 \u0441\u0430\u043c\u043e\u0433\u043e <code>Template<\/code> \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0445\u043e\u0434 DOM-\u0434\u0435\u0440\u0435\u0432\u0430. \u0418\u0449\u0443\u0442\u0441\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441 <code>{{...}}<\/code>, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a <code>attached<\/code>, <code>inner-html<\/code>, <code>repeat<\/code>, <code>let-...<\/code><\/p>\n<h2>Lifecycle \u0448\u0430\u0431\u043b\u043e\u043d\u0430<\/h2>\n<p><code>AbstractComponent.initTemplate()<\/code> \u2192 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <code>Template<\/code>, \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0445\u043e\u0434 DOM, \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f <code>{{expr}}<\/code> \u2192 <code>tokenizeExpr(expr)<\/code> \u2192 <code>new VMProgramCompiler(tokens).getBytecode(expr)<\/code><\/p>\n<p>\u0427\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435, \u043a\u0430\u043a \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434. <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430. <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>AbstractComponent.template.detectChanges()<\/code> \u043c\u044b \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u0434\u0435\u043b\u0430\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432 DOM, \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u0441\u043d\u0438\u043c\u0443\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0443\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0435. \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 <code>AbstractComponent.initTemplate()<\/code>, \u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <code>Rx.update(newVal)<\/code>. \u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0430<code>AbstractComponent.template.detectChanges()<\/code> \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e<\/p>\n<p>\u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437. \u041f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 <code>Rx<\/code> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434, \u0441\u0442\u0440\u043e\u043a\u0430 \u0437\u0430\u043d\u043e\u0432\u043e \u043d\u0435 \u043f\u0430\u0440\u0441\u0438\u0442\u0441\u044f.<\/p>\n<h3>\u0421\u043f\u0435\u0446\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0448\u0430\u0431\u043b\u043e\u043d\u0430<\/h3>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e\u00a0<code>{{ }}<\/code>, \u0432 Cruzo \u0435\u0441\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u0441\u043e\u0431\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<ul>\n<li>\n<p><code>repeat<\/code>\u00a0\u2014 \u0446\u0438\u043a\u043b, \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 DOM-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><code>let-*<\/code>\u00a0\u2014 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u0430<\/p>\n<\/li>\n<li>\n<p><code>inner-html<\/code>\u00a0\u2014 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430 HTML<\/p>\n<\/li>\n<li>\n<p><code>attached<\/code>\u00a0\u2014 \u0443\u0441\u043b\u043e\u0432\u043d\u043e\u0435 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0432 DOM<\/p>\n<\/li>\n<li>\n<p><code>onclick<\/code>,\u00a0<code>oninput<\/code>\u00a0\u0438 \u0434\u0440\u0443\u0433\u0438\u0435\u00a0<code>on*<\/code>\u00a0\u2014 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 VM<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u00a0<code>let-*<\/code>\u00a0\u0438\u00a0<code>inner-html<\/code>:<\/p>\n<pre><code class=\"xml\">&lt;div let-name=\"{{root.user$::rx.name}}\" let-tags=\"{{root.user$::rx.tags}}\"&gt;  Name: &lt;b&gt;{{name ?? \"Anonymous\"}}&lt;\/b&gt;  &lt;span inner-html=\"{{root.html$::rx}}\"&gt;&lt;\/span&gt;&lt;\/div&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434<\/h3>\n<p>\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0448\u0430\u0431\u043b\u043e\u043d:<\/p>\n<pre><code class=\"xml\">&lt;button onclick=\"{{root.count$.update(root.count$::rx + 1)}}\"&gt;  ping: {{root.count$::rx}}&lt;\/button&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u0430 \u043d\u0430 \u0442\u043e\u043a\u0435\u043d\u044b. \u0423 \u0442\u043e\u043a\u0435\u043d\u043e\u0432 \u0435\u0441\u0442\u044c \u0442\u0438\u043f\u044b<\/p>\n<pre><code class=\"typescript\">export type Tok =| { t: \"num\"; v: number }| { t: \"str\"; v: string }| { t: \"id\"; v: string }| { t: \"op\"; v: string }| { t: \"punc\"; v: string }| { t: \"eof\" };<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u0422\u0438\u043f<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0427\u0442\u043e \u044d\u0442\u043e<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041f\u0440\u0438\u043c\u0435\u0440\u044b v<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">id<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440<\/p>\n<\/td>\n<td>\n<p align=\"left\">&#171;root&#187;, &#171;count$&#187;, &#171;rx&#187;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">op<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440<\/p>\n<\/td>\n<td>\n<p align=\"left\">&#171;.&#187;, &#171;+&#187;, &#171;::&#187;, &#171;&amp;&amp;&#187;, &#171;===&#187;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">punc<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u0443\u043d\u043a\u0442\u0443\u0430\u0446\u0438\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">&#171;(&#171;, &#171;)&#187;, &#171;[&#171;, &#171;,&#187;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">num<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0447\u0438\u0441\u043b\u043e (\u0443\u0436\u0435 number)<\/p>\n<\/td>\n<td>\n<p align=\"left\">1, 3.14<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">str<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0439 \u043b\u0438\u0442\u0435\u0440\u0430\u043b<\/p>\n<\/td>\n<td>\n<p align=\"left\">&#171;hello&#187;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">eof<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043a\u043e\u043d\u0435\u0446 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0448\u0435, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0430\u043a\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u044b \u0447\u0435\u0440\u0435\u0437 <code>tokenizeExpr()<\/code><\/p>\n<pre><code class=\"json\"> 0  { t: \"id\",    v: \"root\" } 1  { t: \"op\",    v: \".\" } 2  { t: \"id\",    v: \"count$\" } 3  { t: \"op\",    v: \".\" } 4  { t: \"id\",    v: \"update\" } 5  { t: \"punc\",  v: \"(\" } 6  { t: \"id\",    v: \"root\" } 7  { t: \"op\",    v: \".\" } 8  { t: \"id\",    v: \"count$\" } 9  { t: \"op\",    v: \"::\" }10  { t: \"id\",    v: \"rx\" }11  { t: \"op\",    v: \"+\" }12  { t: \"num\",   v: 1 }13  { t: \"punc\",  v: \")\" }14  { t: \"eof\" }<\/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>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u0430\u043f \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u00a0<code>VMProgramCompiler<\/code>.<\/p>\n<p><code>VMProgramCompiler<\/code> \u043e\u0431\u0445\u043e\u0434\u0438\u0442 \u0442\u043e\u043a\u0435\u043d\u044b \u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u0430\u043a\u043e\u0439 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434<\/p>\n<pre><code class=\"assembly\"> 0  LOAD_ID            root 1  GET_PROP           \"count$\" 2  GET_PROP_KEEP      \"update\" 3  LOAD_ID            root 4  GET_PROP           \"count$\" 5  RX_UI 6  PUSH_CONST         1 7  BIN_ADD 8  CALL_METHOD        argc=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>\u042d\u0442\u043e\u0442 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 Template.<\/p>\n<p>\u041a\u0430\u043a \u044f \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b \u0440\u0430\u043d\u0435\u0435, \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043a\u0435\u0448\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u2014 \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u043d\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442\u0441\u044f.<\/p>\n<h3>\u0427\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435<\/h3>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u0442 \u043a\u043d\u043e\u043f\u043a\u0443, VM \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u00a0<code>onclick<\/code>. \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0437\u0434\u0435\u0441\u044c \u2014 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 (<code>event<\/code>), \u0430 \u043d\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u0430\u044f \u043d\u043e\u0434\u0430.<\/p>\n<p>\u041f\u043e \u0441\u0443\u0442\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<ol>\n<li>\n<p><code>root<\/code>\u00a0\u2014 \u044d\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442<\/p>\n<\/li>\n<li>\n<p><code>count$::rx<\/code>\u00a0\u2014 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0447\u0451\u0442\u0447\u0438\u043a\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, 3)<\/p>\n<\/li>\n<li>\n<p><code>3 + 1 = 4<\/code><\/p>\n<\/li>\n<li>\n<p>\u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f\u00a0<code>count$.update(4)<\/code><\/p>\n<\/li>\n<li>\n<p>\u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0438 \u2014 \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0442\u0435\u043a\u0441\u0442\u00a0<code>ping: {{root.count$::rx}}<\/code>\u00a0\u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0435<\/p>\n<\/li>\n<li>\n<p>UI \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f<\/p>\n<\/li>\n<\/ol>\n<p>\u0422\u0435\u043a\u0441\u0442 \u043a\u043d\u043e\u043f\u043a\u0438 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u2014 \u0434\u0432\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u041e\u043d\u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0438 \u0436\u0438\u0432\u0443\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e.<\/p>\n<h3>::rx \u0432 \u0442\u0435\u043a\u0441\u0442\u0435 \u0438 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435<\/h3>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"left\"><code>{{ root.count$::rx }}<\/code>\u00a0\u0432 \u0442\u0435\u043a\u0441\u0442\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0447\u0438\u0442\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>onclick=\"{{ ... count$::rx ... }}\"<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0438\u0442\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0412 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0435 \u043d\u0443\u0436\u043d\u0430 \u2014 \u0442\u0430\u043c \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043a\u043b\u0438\u043a\u0430. \u0412 \u0442\u0435\u043a\u0441\u0442\u0435 \u2014 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, DOM \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u0430\u043c, \u043a\u043e\u0433\u0434\u0430 Rx \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f.<\/p>\n<h3>\u0417\u0430\u0447\u0435\u043c VM, \u0430 \u043d\u0435 eval<\/h3>\n<ul>\n<li>\n<p>\u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435<\/p>\n<\/li>\n<li>\n<p><code>::rx<\/code>\u00a0\u0438\u00a0<code>once::<\/code>\u00a0\u0432\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u043f\u0440\u044f\u043c\u043e \u0432 VM<\/p>\n<\/li>\n<li>\n<p>\u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u043a\u0435\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f<\/p>\n<\/li>\n<li>\n<p>\u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0441 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u2014 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 CSP-\u0442\u0435\u0433\u0430\u043c\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u043b\u044f \u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u2014 \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430:<\/p>\n<pre><code class=\"typescript\">formatDate(lastLogin: number) {  return lastLogin ? new Date(lastLogin).toLocaleString() : \"-\";}<\/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<pre><code class=\"xml\">&lt;b&gt;{{root.formatDate(root.user$::rx.meta?.lastLogin)}}&lt;\/b&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h3><\/h3>\n<p>\u0428\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440 Cruzo \u2014 \u044d\u0442\u043e \u043d\u0435 \u043f\u0430\u0440\u0441\u0435\u0440 HTML \u0438 \u043d\u0435\u00a0<code>eval<\/code>\u00a0\u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435. \u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u043f\u0430\u0440\u0441\u0438\u0442 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0443, Cruzo \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0442\u043e\u043a\u0435\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442, \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442 \u0438\u0445 \u0432 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u0441\u0432\u043e\u044e VM, \u0430 \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <code>::rx<\/code>\u00a0\u2014 \u043f\u043e\u0441\u043b\u0435 \u0438\u0445 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u0438 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u0442\u043e\u0447\u0435\u0447\u043d\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u044b <code>Rx<\/code> \u0438 <code>RxFunc<\/code><\/p>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c Cruzo:\u00a0<a href=\"https:\/\/github.com\/MaratBektemirov\/cruzo\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/MaratBektemirov\/cruzo<\/a>,\u00a0<a href=\"https:\/\/cruzo.org\" rel=\"noopener noreferrer nofollow\">https:\/\/cruzo.org<\/a><\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1052512\/\">https:\/\/habr.com\/ru\/articles\/1052512\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cruzo \u2014 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 UI-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0435\u0439 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438\u00a0\u0417\u043d\u0430\u043a\u043e\u043c\u0438\u043c\u0441\u044f \u0441 Cruzo. \u0427\u0430\u0441\u0442\u044c 1. RxBucket \u2013 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435\u042f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u044e \u0441\u0435\u0440\u0438\u044e \u043e\u0431\u0437\u043e\u0440\u043d\u044b\u0445 \u0441\u0442\u0430\u0442\u0435\u0439 \u043e js-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0435 Cruzo. \u042f \u0440\u0430\u0431\u043e\u0442\u0430\u044e \u043d\u0430\u0434 \u044d\u0442\u0438\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 6 \u043b\u0435\u0442, \u043c\u043d\u043e\u0433\u043e \u0438\u0434\u0435\u0439 \u043e\u0442\u043f\u0430\u043b\u043e, \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0432 \u0440\u0430\u0431\u043e\u0442\u0435. \u0417\u0434\u0435\u0441\u044c \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u0432\u0430\u043c \u043e \u0441\u0435\u0440\u0434\u0446\u0435 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 \u2013 \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440\u0435. \u0414\u043b\u044f \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u044b\u043b\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0430 \u0441\u0442\u0435\u043a\u043e\u0432\u0430\u044f \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0430\u044f \u043c\u0430\u0448\u0438\u043d\u0430. \u041a\u0430\u043a\u0430\u044f \u0435\u0449\u0435 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0430\u044f \u043c\u0430\u0448\u0438\u043d\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 js \u0441\u043f\u0440\u043e\u0441\u0438\u0442\u0435 \u0432\u044b? \u042d\u0442\u043e VM \u2014 \u043d\u043e \u043d\u0435 \u00ab\u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u00bb \u0432\u0440\u043e\u0434\u0435 JVM \u0438\u043b\u0438 WebAssembly, \u0430 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0442\u043e\u0440 \u0431\u0430\u0439\u0442\u043a\u043e\u0434\u0430, \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u043d\u0430 JavaScript.\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043e \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0432 Cruzo\u0420\u0430\u0437\u043c\u0435\u0442\u043a\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 Cruzo \u044d\u0442\u043e \u2013 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0439 HTML, \u0430 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043f\u043e\u0434\u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e JavaScript, \u043d\u043e \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043e\u0433\u043e\u0432\u043e\u0440\u043a\u0430\u043c\u0438 (::rx, once::).&lt;span&gt;{{ once::root.label }}&lt;\/span&gt;&lt;button onclick=&#187;{{root.count$.update(root.count$::rx + 1)}}&#187;&gt;  ping: {{root.count$::rx}}&lt;\/button&gt;\u0412\u0434\u043e\u0431\u0430\u0432\u043e\u043a \u043a \u044d\u0442\u043e\u043c\u0443, \u0435\u0441\u043b\u0438 \u043c\u044b \u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u0440\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 Cruzo (AbstractComponent), \u0442\u0430\u043c \u0448\u0430\u0431\u043b\u043e\u043d \u2013 \u044d\u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u0442\u0430\u0442\u0438\u0447\u043d\u044b\u0439 \u0444\u0430\u0439\u043b.export class MyComponent extends AbstractComponent {  &#8230;  getHTML() {    return `&lt;div&gt;        &lt;button onclick=&#187;{{ root.count.update(root.count::rx + 1) }}&#187;&gt;        Clicks: &lt;b&gt;{{ root.count::rx }}&lt;\/b&gt;        &lt;\/button&gt;      &lt;\/div&gt;`;  }  &#8230;}\u0428\u0430\u0431\u043b\u043e\u043d \u0432 \u0432\u0438\u0434\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u0435\u043d, \u0435\u0441\u043b\u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u043c\u0435\u043d\u044f\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430.\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0443 \u043d\u0430 \u0445\u043e\u0434\u0443 \u2014 \u0431\u0435\u0437 \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0430\u043c\u043e\u0433\u043e HTML:export class MyComponent extends AbstractComponent {  &#8230;  getHTML() {    let extHTML = &#171;;      if (this.config.myParam) {      extHTML = &lt;div class=&#187;ext-block&#187;&gt;&lt;\/div&gt;;    }      return `${extHTML}        &lt;button onclick=&#187;{{root.count$.update(root.count$::rx + 1)}}&#187;&gt;          ping: {{root.count$::rx}}        &lt;\/button&gt;    `;  }}\u041a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0448\u0430\u0431\u043b\u043e\u043d \u0432 Cruzo\u041f\u0443\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0432 Cruzo \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u043d\u0435 \u0441 \u201c\u0440\u0443\u0447\u043d\u043e\u0433\u043e\u201d \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430, \u043f\u0430\u0440\u0441\u0438\u043d\u0433 HTML-\u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0441\u0430\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440export abstract class AbstractComponent&lt;Config = any, ValueType = any, StateType = any&gt;{  &#8230;    protected initTemplate() {    const html = this.getHTML();      if (html) {      this.node.innerHTML = html;            this.template = new Template({        node: this.node,        self: () =&gt; this,        selector: this.selector,        tplFile: this.tplFile,        domStructureChanged: () =&gt; {          this.domStructureChanged();        },      });          this.template.detectChanges();      this.updateDependencies();    }  }  &#8230;}\u0412 \u043a\u043b\u0430\u0441\u0441 Template \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0434\u0430 \u0441 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u043cexport class Template {  &#8230;  constructor(params: TemplateParams) {    Object.assign(this, params);      if (typeof this.self !== &#171;function&#187;) {      throw new Error(&#171;Invalid self param&#187;);    }      if (!this.root) {      this.root = this;      this.debug = {        selector: params.selector,        tplFile: params.tplFile,      };            this.onRxUpdate = this.getRxUpdate();    }      this.handleDomAttributes();    this.handleAttributes();    if (!this.innerHtmlTemplateBC) this.handleChildrens(this.node);    this.setEvents();  }  &#8230;}\u0412\u043d\u0443\u0442\u0440\u0438 \u0441\u0430\u043c\u043e\u0433\u043e Template \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0445\u043e\u0434 DOM-\u0434\u0435\u0440\u0435\u0432\u0430. \u0418\u0449\u0443\u0442\u0441\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441 {{&#8230;}}, \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a attached, inner-html, repeat, let-&#8230;Lifecycle \u0448\u0430\u0431\u043b\u043e\u043d\u0430AbstractComponent.initTemplate() \u2192 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 Template, \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0445\u043e\u0434 DOM, \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f {{expr}} \u2192 tokenizeExpr(expr) \u2192 new VMProgramCompiler(tokens).getBytecode(expr)\u0427\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435, \u043a\u0430\u043a \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434. \u0422\u0430\u043a\u0436\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430. \u0415\u0441\u043b\u0438 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c AbstractComponent.template.detectChanges() \u043c\u044b \u043f\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0438 \u0434\u0435\u043b\u0430\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432 DOM, \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u0441\u043d\u0438\u043c\u0443\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0443\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0435. \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 AbstractComponent.initTemplate(), \u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f Rx.update(newVal). \u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0430AbstractComponent.template.detectChanges() \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043d\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e\u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u0438\u043d \u0440\u0430\u0437. \u041f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 Rx \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0443\u0436\u0435 \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434, \u0441\u0442\u0440\u043e\u043a\u0430 \u0437\u0430\u043d\u043e\u0432\u043e \u043d\u0435 \u043f\u0430\u0440\u0441\u0438\u0442\u0441\u044f.\u0421\u043f\u0435\u0446\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u041f\u043e\u043c\u0438\u043c\u043e\u00a0{{ }}, \u0432 Cruzo \u0435\u0441\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0448\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u0441\u043e\u0431\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:repeat\u00a0\u2014 \u0446\u0438\u043a\u043b, \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 DOM-\u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432let-*\u00a0\u2014 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0432\u043d\u0443\u0442\u0440\u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u0430inner-html\u00a0\u2014 \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430 HTMLattached\u00a0\u2014 \u0443\u0441\u043b\u043e\u0432\u043d\u043e\u0435 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0432 DOMonclick,\u00a0oninput\u00a0\u0438 \u0434\u0440\u0443\u0433\u0438\u0435\u00a0on*\u00a0\u2014 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 VM\u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u00a0let-*\u00a0\u0438\u00a0inner-html:&lt;div let-name=&#187;{{root.user$::rx.name}}&#187; let-tags=&#187;{{root.user$::rx.tags}}&#187;&gt;  Name: &lt;b&gt;{{name ?? &#171;Anonymous&#187;}}&lt;\/b&gt;  &lt;span inner-html=&#187;{{root.html$::rx}}&#187;&gt;&lt;\/span&gt;&lt;\/div&gt;\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u0430\u043a \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434\u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u0448\u0430\u0431\u043b\u043e\u043d:&lt;button onclick=&#187;{{root.count$.update(root.count$::rx + 1)}}&#187;&gt;  ping: {{root.count$::rx}}&lt;\/button&gt;\u0414\u0430\u043b\u044c\u0448\u0435 \u0438\u0434\u0435\u0442 \u0440\u0430\u0437\u0431\u0438\u0432\u043a\u0430 \u043d\u0430 \u0442\u043e\u043a\u0435\u043d\u044b. \u0423 \u0442\u043e\u043a\u0435\u043d\u043e\u0432 \u0435\u0441\u0442\u044c \u0442\u0438\u043f\u044bexport type Tok =| { t: &#171;num&#187;; v: number }| { t: &#171;str&#187;; v: string }| { t: &#171;id&#187;; v: string }| { t: &#171;op&#187;; v: string }| { t: &#171;punc&#187;; v: string }| { t: &#171;eof&#187; };\u0422\u0438\u043f\u0427\u0442\u043e \u044d\u0442\u043e\u041f\u0440\u0438\u043c\u0435\u0440\u044b vid\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440&#187;root&#187;, &#171;count$&#187;, &#171;rx&#187;op\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440&#187;.&#187;, &#171;+&#187;, &#171;::&#187;, &#171;&amp;&amp;&#187;, &#171;===&#187;punc\u043f\u0443\u043d\u043a\u0442\u0443\u0430\u0446\u0438\u044f&#187;(&#171;, &#171;)&#187;, &#171;[&#171;, &#171;,&#187;num\u0447\u0438\u0441\u043b\u043e (\u0443\u0436\u0435 number)1, 3.14str\u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0439 \u043b\u0438\u0442\u0435\u0440\u0430\u043b&#187;hello&#187;eof\u043a\u043e\u043d\u0435\u0446 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u0415\u0441\u043b\u0438 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u0432\u044b\u0448\u0435, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0430\u043a\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u044b \u0447\u0435\u0440\u0435\u0437 tokenizeExpr() 0  { t: &#171;id&#187;,    v: &#171;root&#187; } 1  { t: &#171;op&#187;,    v: &#171;.&#187; } 2  { t: &#171;id&#187;,    v: &#171;count$&#187; } 3  { t: &#171;op&#187;,    v: &#171;.&#187; } 4  { t: &#171;id&#187;,    v: &#171;update&#187; } 5  { t: &#171;punc&#187;,  v: &#171;(&#187; } 6  { t: &#171;id&#187;,    v: &#171;root&#187; } 7  { t: &#171;op&#187;,    v: &#171;.&#187; } 8  { t: &#171;id&#187;,    v: &#171;count$&#187; } 9  { t: &#171;op&#187;,    v: &#171;::&#187; }10  { t: &#171;id&#187;,    v: &#171;rx&#187; }11  { t: &#171;op&#187;,    v: &#171;+&#187; }12  { t: &#171;num&#187;,   v: 1 }13  { t: &#171;punc&#187;,  v: &#171;)&#187; }14  { t: &#171;eof&#187; }\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u0430\u043f \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u00a0VMProgramCompiler.VMProgramCompiler \u043e\u0431\u0445\u043e\u0434\u0438\u0442 \u0442\u043e\u043a\u0435\u043d\u044b \u0438 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0442\u0430\u043a\u043e\u0439 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434 0  LOAD_ID            root 1  GET_PROP           &#171;count$&#187; 2  GET_PROP_KEEP      &#171;update&#187; 3  LOAD_ID            root 4  GET_PROP           &#171;count$&#187; 5  RX_UI 6  PUSH_CONST         1 7  BIN_ADD 8  CALL_METHOD        argc=1\u042d\u0442\u043e\u0442 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0432 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 Template.\u041a\u0430\u043a \u044f \u0443\u043f\u043e\u043c\u0438\u043d\u0430\u043b \u0440\u0430\u043d\u0435\u0435, \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043a\u0435\u0448\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u2014 \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u043d\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442\u0441\u044f.\u0427\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u0442 \u043a\u043d\u043e\u043f\u043a\u0443, VM \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u00a0onclick. \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0437\u0434\u0435\u0441\u044c \u2014 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 (event), \u0430 \u043d\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u0430\u044f \u043d\u043e\u0434\u0430.\u041f\u043e \u0441\u0443\u0442\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:root\u00a0\u2014 \u044d\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442count$::rx\u00a0\u2014 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0447\u0451\u0442\u0447\u0438\u043a\u0430 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, 3)3 + 1 = 4\u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f\u00a0count$.update(4)\u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0438 \u2014 \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0442\u0435\u043a\u0441\u0442\u00a0ping: {{root.count$::rx}}\u00a0\u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0435UI \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f\u0422\u0435\u043a\u0441\u0442 \u043a\u043d\u043e\u043f\u043a\u0438 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u2014 \u0434\u0432\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f. \u041e\u043d\u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0438 \u0436\u0438\u0432\u0443\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e.::rx \u0432 \u0442\u0435\u043a\u0441\u0442\u0435 \u0438 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435{{ root.count$::rx }}\u00a0\u0432 \u0442\u0435\u043a\u0441\u0442\u0435\u0447\u0438\u0442\u0430\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044fonclick=&#187;{{ &#8230; count$::rx &#8230; }}&#187;\u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0438\u0442\u0430\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0412 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430 \u043d\u0435 \u043d\u0443\u0436\u043d\u0430 \u2014 \u0442\u0430\u043c \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043a\u043b\u0438\u043a\u0430. \u0412 \u0442\u0435\u043a\u0441\u0442\u0435 \u2014 \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, DOM \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0441\u0430\u043c, \u043a\u043e\u0433\u0434\u0430 Rx \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f.\u0417\u0430\u0447\u0435\u043c VM, \u0430 \u043d\u0435 eval\u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434 \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435::rx\u00a0\u0438\u00a0once::\u00a0\u0432\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u043f\u0440\u044f\u043c\u043e \u0432 VM\u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u043a\u0435\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f\u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0441 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u2014 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u0441\u0435\u043b\u0435\u043a\u0442\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 CSP-\u0442\u0435\u0433\u0430\u043c\u0438\u0414\u043b\u044f \u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434\u044b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u2014 \u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430:formatDate(lastLogin: number) {  return lastLogin ? new Date(lastLogin).toLocaleString() : &#171;-&#171;;}&lt;b&gt;{{root.formatDate(root.user$::rx.meta?.lastLogin)}}&lt;\/b&gt;\u0428\u0430\u0431\u043b\u043e\u043d\u0438\u0437\u0430\u0442\u043e\u0440 Cruzo \u2014 \u044d\u0442\u043e \u043d\u0435 \u043f\u0430\u0440\u0441\u0435\u0440 HTML \u0438 \u043d\u0435\u00a0eval\u00a0\u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435. \u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u043f\u0430\u0440\u0441\u0438\u0442 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u0443, Cruzo \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0442\u043e\u043a\u0435\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442, \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442 \u0438\u0445 \u0432 \u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 \u0441\u0432\u043e\u044e VM, \u0430 \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f ::rx\u00a0\u2014 \u043f\u043e\u0441\u043b\u0435 \u0438\u0445 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0431\u0430\u0439\u0442-\u043a\u043e\u0434 \u0438 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u0442\u043e\u0447\u0435\u0447\u043d\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0440\u0435\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u044b Rx \u0438 RxFunc\u041f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c Cruzo:\u00a0https:\/\/github.com\/MaratBektemirov\/cruzo,\u00a0https:\/\/cruzo.org\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 https:\/\/habr.com\/ru\/articles\/1052512\/<\/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-485224","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/485224","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=485224"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/485224\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=485224"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=485224"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=485224"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}