{"id":324334,"date":"2021-06-04T09:00:42","date_gmt":"2021-06-04T09:00:42","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=324334"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=324334","title":{"rendered":"\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Google Sheets, Netlify Functions \u0438 React. \u0427\u0430\u0441\u0442\u044c 1"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u0412 \u044d\u0442\u043e\u043c \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0435 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c <code>~~Real World App~~<\/code> \u2014 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0433\u0443\u0433\u043b \u0442\u0430\u0431\u043b\u0438\u0446, \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438 \u0440\u0435\u0430\u043a\u0442\u0430.<\/p>\n<p>  <\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f<\/li>\n<li>\u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 &quot;\u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f&quot;, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u0444\u043e\u0440\u043c\u043e\u0439, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0439 \u0434\u0432\u0430 \u043f\u043e\u043b\u044f: \u0438\u043c\u044f \u0438 \u0430\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b<\/li>\n<li>\u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u0431\u043e\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0433\u0443\u0433\u043b \u0440\u0435\u043a\u0430\u043f\u0447\u0430 2 \u0432\u0435\u0440\u0441\u0438\u0438<\/li>\n<li>\u043f\u0440\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043f\u043e\u043b\u0435\u0439 \u0438 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0430 &quot;\u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f&quot;<\/li>\n<li>\u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u044d\u0442\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439<\/li>\n<li>\u0432 \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0435\u043c\u044b\u0445 \u043f\u0438\u0441\u044c\u043c\u0430\u0445 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0442\u043f\u0438\u0441\u043a\u0443 \u043e\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439<\/li>\n<li>\u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u043f\u043e \u044d\u0442\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0435 \u0430\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u2014 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u2014 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e, \u0437\u0430\u0442\u0435\u043c \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 <code>Netlify<\/code> (\u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u044b \u044d\u0442\u0438\u043c \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u043e\u043c, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u0442 \u043d\u0435\u0433\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f) \u0438 \u0431\u0443\u0434\u0435\u0442 \u0435\u0433\u043e \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c.<\/p>\n<p>  <\/p>\n<p>\u0414\u0435\u043c\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/mail-list.netlify.app\/\">\u0437\u0434\u0435\u0441\u044c<\/a> (\u043e\u043d\u043e \u0432\u043f\u043e\u043b\u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0435, \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u0438\u0442\u0435, \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f).<\/p>\n<p>  <\/p>\n<p>\u041a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f <a href=\"https:\/\/github.com\/harryheman\/Mail-List\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/netlify\/cli\"><code>netlify-cli<\/code><\/a> \u2014 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439) \u0438 &quot;\u0434\u0435\u043f\u043b\u043e\u044f&quot; \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 <code>Netlify<\/code>; \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0430\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430: <code>yarn global add netlify-cli<\/code> \u0438\u043b\u0438 <code>npm i -g netlify-cli<\/code>; \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e<\/li>\n<li><a href=\"https:\/\/theoephraim.github.io\/node-google-spreadsheet\/#\/\"><code>google-spreadsheet<\/code><\/a> \u2014 JavaScript-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0433\u0443\u0433\u043b \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u043c\u0438; \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e<\/li>\n<li><a href=\"https:\/\/ru.reactjs.org\/\"><code>react<\/code><\/a> \u2014 \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u044d\u0442\u043e \u043b\u0443\u0447\u0448\u0438\u0439 JavaScript-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0430, \u043d\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u0443\u044e \u0434\u0440\u0443\u0433\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443; \u043d\u0430\u0448\u0438 \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430<\/li>\n<li><a href=\"https:\/\/reactrouter.com\/web\/guides\/quick-start\"><code>react-router-dom<\/code><\/a> \u2014 React-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438<\/li>\n<li><a href=\"https:\/\/react.semantic-ui.com\/\"><code>semantic-ui-react<\/code><\/a> \u2014 React-CSS-\u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a (\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0441 \u0433\u043e\u0442\u043e\u0432\u044b\u043c\u0438 \u0441\u0442\u0438\u043b\u044f\u043c\u0438, \u043d\u0443, \u043f\u043e\u0447\u0442\u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u043c\u0438, \u043c\u044b \u0438\u0445 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043c)<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/react-google-recaptcha\"><code>react-google-recaptcha<\/code><\/a> \u2014 React-\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0439 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c<\/li>\n<li><a href=\"https:\/\/nodemailer.com\/\"><code>nodemailer<\/code><\/a> \u2014 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u0430\u044f Node.js-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u043e\u0439 (\u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438 \u043f\u0438\u0441\u0435\u043c)<\/li>\n<li><a href=\"https:\/\/www.npmjs.com\/package\/dotenv\"><code>dotenv<\/code><\/a> \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u0441\u0440\u0435\u0434\u044b \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u043d\u0430 \u0432\u0430\u0448\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d <a href=\"https:\/\/nodejs.org\/en\/\"><code>Node.js<\/code><\/a> \u0438, \u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e, <a href=\"https:\/\/yarnpkg.com\/\"><code>yarn<\/code><\/a> (\u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0432\u044b \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u0441 \u044d\u0442\u0438\u043c \u043f\u0430\u043a\u0435\u0442\u043d\u044b\u043c \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u043e\u043c, \u0432\u044b \u0435\u0434\u0432\u0430 \u043b\u0438 \u0432\u0435\u0440\u043d\u0435\u0442\u0435\u0441\u044c \u043a <code>npm<\/code>).<\/p>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u044c\u0442\u0435 \u0433\u043e\u0442\u043e\u0432\u044b \u043a \u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043f\u0440\u0438\u0434\u0435\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u043e\u0432 \u0438, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043a\u043e\u0435-\u0447\u0442\u043e \u043f\u043e\u0433\u0443\u0433\u043b\u0438\u0442\u044c \u0432 \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u044f \u0437\u0430\u0431\u0443\u0434\u0443 \u043e\u0431 \u044d\u0442\u043e\u043c \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044c \u0432 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0435 (\u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u0442\u044c).<\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u043c\u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0432\u0430\u0441 \u0437\u0430\u0438\u043d\u0442\u0440\u0438\u0433\u043e\u0432\u0430\u0442\u044c, \u0438 \u0432\u044b \u0441 \u043d\u0435\u0442\u0435\u0440\u043f\u0435\u043d\u0438\u0435\u043c \u0436\u0434\u0435\u0442\u0435, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434. \u0421\u043a\u043e\u0440\u043e, \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0432\u044f\u0436\u0435\u043c \u0435\u0435 \u0441 <a href=\"https:\/\/console.cloud.google.com\/home\/dashboard\"><code>Google Cloud Platform<\/code><\/a>.<\/p>\n<p>  <\/p>\n<h2 id=\"podgotovka-tablicy\">\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/h2>\n<p>  <\/p>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 <code>Google Cloud Platform<\/code> (\u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435, \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u043e\u0439 \u0432\u044b\u0448\u0435) \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>mail-list<\/code><\/li>\n<li>\u043e\u0436\u0438\u0434\u0430\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0435\u0433\u043e<\/li>\n<li>\u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u043e\u0431\u0437\u043e\u0440\u0443 API (<code>Go to APIs overview<\/code>)<\/li>\n<li>\u0432\u043a\u043b\u044e\u0447\u0430\u0435\u043c <code>Google Sheets API<\/code> (<code>Enable APIs and services<\/code>)<\/li>\n<li>\u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0438\u0441-\u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a API (<code>Create credentials<\/code>)<\/li>\n<li>\u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441-\u0430\u043a\u043a\u0430\u0443\u043d\u0442<\/li>\n<li>\u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0432\u043a\u043b\u0430\u0434\u043a\u0443 <code>Keys<\/code> \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043b\u044e\u0447 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON (<code>Add key -&gt; Create new key<\/code>)<\/li>\n<li>\u0432 \u0441\u043a\u0430\u0447\u0430\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <code>mail-list-315211-ca347b50f56a.json<\/code>) \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0442 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>private_key<\/code> \u0438 <code>client_email<\/code>; \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u0435 \u0438\u0445 \u0433\u0434\u0435-\u043d\u0438\u0431\u0443\u0434\u044c, \u043f\u043e\u0437\u0436\u0435 \u043c\u044b \u0437\u0430\u043f\u0438\u0448\u0435\u043c \u0438\u0445 \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u044b \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f<\/li>\n<\/ul>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/gc\/lx\/tw\/gclxtwxxduuhgewn37rldtvnhyo.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/9l\/wz\/bx\/9lwzbxqqo50yapilutpkytbh1sk.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/826\/ff8\/d7e\/826ff8d7e69c68b192e807918d743596.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/e48\/e14\/422\/e48e14422352d1a60344bee2aff2a7b5.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/ddd\/751\/b8f\/ddd751b8ffacc115447f436b2df723c1.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/526\/439\/e09\/526439e09823d0d4bf6f7b18eb5af4a2.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/wx\/kq\/16\/wxkq16czaxyfgyn05riw9rywhzu.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/nt\/z_\/4t\/ntz_4th5dnwfjpik65ftk5jwefc.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/lz\/gd\/_a\/lzgd_akq0dfol-egonbp1pyhfna.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/p4\/k9\/9h\/p4k99hct2ztojciv_ersnlgpila.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/4m\/kc\/yq\/4mkcyqjmxulzes_jrxvunaydzli.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/xf\/59\/rs\/xf59rsvmmb1rv5c_slaokkqwfgy.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/a4\/3z\/gq\/a43zgqfldwm8pimyfffh2noo_4g.png\">. <\/p>\n<p>  <\/p>\n<p>\u0417\u0430\u0445\u043e\u0434\u0438\u043c \u0432 <a href=\"https:\/\/docs.google.com\/spreadsheets\"><code>Google Speadsheets<\/code><\/a> \u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u0443 (<code>\u041f\u0443\u0441\u0442\u043e\u0439 \u0444\u0430\u0439\u043b<\/code>) \u0441 \u0434\u0432\u0443\u043c\u044f \u0433\u0440\u0430\u0444\u0430\u043c\u0438: <code>username<\/code> \u0438 <code>email<\/code>.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/0e\/7b\/9z\/0e7b9zdhlcndxrggkdztn99qojo.png\">. <\/p>\n<p>  <\/p>\n<p>\u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430, \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u043d\u0430\u043c\u0438 \u0441\u0435\u0440\u0432\u0438\u0441-\u0430\u043a\u043a\u0430\u0443\u043d\u0442 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0435\u0433\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 <code>\u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430<\/code>.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/jc\/aq\/rj\/jcaqrjyfpt9ut5wpnl-3jjm1pzu.png\">. <\/p>\n<p>  <\/p>\n<p>\u0412 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u043c\u0435\u0436\u0434\u0443 <code>d\/<\/code> \u0438 <code>\/edit<\/code> \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0442\u0430\u043a\u0436\u0435 \u0433\u0434\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u0435\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u0435.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043d\u0430\u0448\u0435\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430.<\/p>\n<p>  <\/p>\n<h2 id=\"besservernye-funkcii\">\u0411\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/h2>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u043c\u0441\u044f, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439: \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u0435\u043d \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440, \u043c\u044b \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u0445\u043e\u0442\u0438\u043c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u043e\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u0444\u043e\u0440\u043c\u044b \u0432 \u0433\u0443\u0433\u043b \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0447\u0438\u0442\u0430\u0442\u044c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u043c. <code>Netlify Functions<\/code> \u2014 \u044d\u0442\u043e \u043b\u0438\u0448\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f <code>AWS Lambda Functions<\/code> \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0430\u0434\u0430\u0447.<\/p>\n<p>  <\/p>\n<p>\u041e \u0442\u043e\u043c, \u0447\u0442\u043e \u0442\u0430\u043a\u043e\u0435 <code>Netlify Functions<\/code>, \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c <a href=\"https:\/\/docs.netlify.com\/functions\/overview\/\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u044e\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>functions<\/code> \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043d\u043e\u0432\u044b\u0439 React-\u043f\u0440\u043e\u0435\u043a\u0442 (<code>mail-list<\/code> \u2014 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430):<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">yarn create react-app mail-list # \u0438\u043b\u0438 npx create ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u044c\u0435\u043c \u0447\u0430\u0439 \u0432 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">cd mail-list  yarn add google-spreadsheet dotenv # \u0438\u043b\u0438 npm i ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <code>.env<\/code> (<code>touch .env<\/code>) \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0432 \u043d\u0435\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">GOOGLE_SERVICE_ACCOUNT_EMAIL=&quot;YOUR_CLIENT_EMAIL&quot; GOOGLE_PRIVATE_KEY=&quot;-----BEGIN PRIVATE KEY----- YOUR_PRIVATE_KEY -----END PRIVATE KEY-----\\n&quot; GOOGLE_SPREADSHEET_ID=&quot;YOUR_SPREADSHEET_ID&quot;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>functions<\/code>, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u043d\u0435\u0435, \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <code>subscribe.js<\/code> \u0438 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u043a\u043e\u0434\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">mkdir functions cd !$ touch subscribe.js code subscribe.js<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0435\u0440\u0432\u0438\u0441-\u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0443, \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 (\u0438\u043c\u044f \u0438 \u0430\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f) \u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443. \u041f\u0435\u0440\u0435\u0434 \u0437\u0430\u043f\u0438\u0441\u044c\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c email \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043d\u0435 \u0442\u0430\u043a, \u0442\u043e \u043c\u044b \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e, \u0447\u0442\u043e \u043e\u043d \u0443\u0436\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">\/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0441\u0440\u0435\u0434\u044b \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0444\u0430\u0439\u043b\u0430 &quot;.env&quot; require('dotenv').config()  const { GoogleSpreadsheet } = require('google-spreadsheet')  \/\/ \u0411\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f (\u043e \u0435\u0435 \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0435 \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u043e\u0437\u0436\u0435) \/\/ \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u043d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0432\u044b\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442, \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 - `event` \/\/ `event` - \u044d\u0442\u043e \u0442\u043e\u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e `req` \u0432 `express`, \u0442.\u0435. \u043e\u0431\u044a\u0435\u043a\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 exports.handler = async (event) =&gt; {   \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0433\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u0433\u0443\u0433\u043b \u0442\u0430\u0431\u043b\u0438\u0446   \/\/ \u041a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0442\u0430\u0431\u043b\u0438\u0446\u044b   const doc = new GoogleSpreadsheet(process.env.GOOGLE_SPREADSHEET_ID)    try {     \/\/ \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0435\u0440\u0432\u0438\u0441-\u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430     await doc.useServiceAccountAuth({       client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,       private_key: process.env.GOOGLE_PRIVATE_KEY.replace(\/\\\\n\/g, '\\n')     })      \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430     await doc.loadInfo()      \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u043d\u0430\u043c\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0443     const sheet = doc.sheetsByIndex[0]      \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON \u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0438\u0445 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442     const data = JSON.parse(event.body)      \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b     const rows = await sheet.getRows()      \/\/ \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438 \u0441\u0442\u0440\u043e\u043a     \/\/ \u0415\u0441\u043b\u0438 \u043a\u0430\u043a\u0430\u044f-\u043b\u0438\u0431\u043e \u0438\u0437 \u0441\u0442\u0440\u043e\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 email, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c,     \/\/ \u0437\u043d\u0430\u0447\u0438\u0442, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0436\u0435 \u043e\u0444\u043e\u0440\u043c\u0438\u043b \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f     if (rows.some((row) =&gt; row.email === data.email)) {       \/\/ \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043e\u0442\u0432\u0435\u0442       const response = {         statusCode: 400,         body: JSON.stringify({           error: '\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0441 \u0442\u0430\u043a\u0438\u043c email \u0443\u0436\u0435 \u043e\u0444\u043e\u0440\u043c\u0438\u043b \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443'         }),         \/\/ \u041f\u0440\u043e \u044d\u0442\u043e \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u043f\u043e\u0437\u0436\u0435         headers: {           'Access-Control-Allow-Origin': '*',           'Access-Control-Allow-Credentials': 'true'         }       }       \/\/ \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0435\u0433\u043e       return response     }      \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0432 \u0432\u0438\u0434\u0435 \u043d\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438     await sheet.addRow(data)      \/\/ \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043e\u0442\u0432\u0435\u0442     const response = {       statusCode: 200,       body: JSON.stringify({ message: '\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443!' }),       headers: {         'Access-Control-Allow-Origin': '*',         'Access-Control-Allow-Credentials': 'true'       }     }     \/\/ \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0435\u0433\u043e     return response   } catch (err) {     \/\/ \u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0443, \u0432\u043e\u0437\u043d\u0438\u043a\u0448\u0443\u044e \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u0430     console.error(err)     const response = {       statusCode: 500,       body: JSON.stringify({ error: '\u0427\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043f\u043e\u0437\u0436\u0435' }),       headers: {         'Access-Control-Allow-Origin': '*',         'Access-Control-Allow-Credentials': 'true'       }     }     return response   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0411\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u043c\u0435\u044e\u0442 \u0442\u0430\u043a\u0443\u044e \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">exports.handler = (event, context, callback) =&gt; {...}<\/code><\/pre>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u043e\u0447\u0435\u043d\u044c \u043a\u043e\u0440\u043e\u0442\u043a\u043e, \u0442\u043e <code>event<\/code>, \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043e \u0440\u0430\u043d\u0435\u0435, \u044d\u0442\u043e \u043e\u0431\u044a\u0435\u043a\u0442 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 (\u0434\u0430\u043d\u043d\u044b\u0435, \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u0435 \u043e\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0430), <code>context<\/code> \u2014 \u043b\u044e\u0431\u0430\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u0430\u044f \u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441\u0442\u0430\u0442\u0443\u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, <code>callback<\/code> \u043d\u0443\u0436\u0435\u043d \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 (\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0435\u0439) \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 (\u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u043d\u0435 \u043d\u0443\u0436\u0435\u043d, \u0432\u043f\u0440\u043e\u0447\u0435\u043c, \u043a\u0430\u043a \u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 <code>context<\/code>).<\/p>\n<p>  <\/p>\n<p>\u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u044d\u0442\u0438\u0445 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u043e\u0442\u0432\u0435\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">headers: {   'Access-Control-Allow-Origin': '*',   'Access-Control-Allow-Credentials': 'true' }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u043e \u043e\u043d\u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0441 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 <code>Netlify<\/code> (\u0441 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u043c\u0438 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u0440\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0438 \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438\u0437 \u043a\u043b\u0438\u0435\u043d\u0442\u0430). \u041f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442\u0441\u044f <code>CORS<\/code> (Cross-Origin Resource Sharing \u2014 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0440\u0435\u0441\u0443\u0440\u0441\u0443 \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430), \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435, \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c \u043e\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u042d\u0442\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u043d\u043e \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0445\u043e\u0441\u0442\u0438\u043d\u0433\u0435 \u0431\u0435\u0437 \u043d\u0438\u0445 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f. \u0412 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043f\u0440\u043e \u044d\u0442\u043e \u043d\u0438 \u0441\u043b\u043e\u0432\u0430. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043a \u0442\u043e\u043c\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u0443, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u0447\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0430\u0442\u044c\u044e, \u044d\u0442\u043e\u0442 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a \u0431\u0443\u0434\u0435\u0442 \u0443\u0441\u0442\u0440\u0430\u043d\u0435\u043d.<\/p>\n<p>  <\/p>\n<p>\u0421\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u044d\u0442\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0432 \u0444\u0430\u0439\u043b\u0435 <a href=\"https:\/\/docs.netlify.com\/configure-builds\/file-based-configuration\/\"><code>netlify.toml<\/code><\/a>.<\/p>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f. \u0412\u0442\u043e\u0440\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043f\u043e\u0437\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b\u044f\u0441\u043d\u0438\u043c, \u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u044b, \u043a\u0430\u043a \u043d\u0430\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u043a\u043b\u0438\u0435\u043d\u0442\u0435 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0438\u0445 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e.<\/p>\n<p>  <\/p>\n<h2 id=\"klient\">\u041a\u043b\u0438\u0435\u043d\u0442<\/h2>\n<p>  <\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0430:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">yarn add react-router-dom semantic-ui-css semantic-ui-react react-google-recaptcha # \u0438\u043b\u0438 npm i ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u043e\u0434 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>src<\/code>. \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0438\u0437 \u043d\u0435\u0435 \u043b\u0438\u0448\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u044b (\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e <code>index.js<\/code> \u0438 <code>index.css<\/code>), \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>pages<\/code> \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0438 <code>hooks<\/code> \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0445\u0443\u043a\u043e\u0432. \u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>pages<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>Home.js<\/code> \u2014 \u0434\u043e\u043c\u0430\u0448\u043d\u044f\u044f\/\u0433\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430<\/li>\n<li><code>Subscribe.js<\/code> \u2014 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u0444\u043e\u0440\u043c\u043e\u0439<\/li>\n<li><code>Success.js<\/code> \u2014 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c \u043e\u0431 \u0443\u0441\u043f\u0435\u0445\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/li>\n<li><code>NotFound.js<\/code> \u2014 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 (\u043e\u0448\u0438\u0431\u043a\u0430 404)<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>hooks<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0442\u0440\u0438 \u0444\u0430\u0439\u043b\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>useDeferredRoute.js<\/code> \u2014 \u0445\u0443\u043a \u0434\u043b\u044f \u043e\u0442\u043b\u043e\u0436\u0435\u043d\u043d\u043e\u0439 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438 (\u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e)<\/li>\n<li><code>useTimeout.js<\/code> \u2014 \u0445\u0443\u043a-\u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u0434\u043b\u044f <code>setTimeout<\/code><\/li>\n<li><code>index.js<\/code> \u2014 \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0438 \u0440\u0435-\u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0445\u0443\u043a\u043e\u0432<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>src<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">src   hooks     index.js     useDeferredRoute.js     useTimeout.js   pages     Home.js     NotFound.js     Subscribe.js     Success.js   index.css   index.js<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 <code>index.css<\/code> \u043c\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0439 \u0448\u0440\u0438\u0444\u0442 \u0438 \u0432\u043d\u043e\u0441\u0438\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u043f\u0440\u0430\u0432\u043a\u0438 \u0432 \u0441\u0442\u0438\u043b\u0438 <code>semantic-ui<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"css\">@import url('https:\/\/fonts.googleapis.com\/css2?family=Montserrat&amp;display=swap');  * {   font-family: 'Montserrat', sans-serif !important; }  body {   min-height: 100vh;   display: grid;   align-content: center;   background: #8360c3;   background: linear-gradient(135deg, #2ebf91, #8360c3); }  h2 {   margin-bottom: 3rem; }  .ui.container {   max-width: 480px !important;   margin: 0 auto !important;   text-align: center; }  .ui.form {   max-width: 300px;   margin: 0 auto; }  .ui.form .field &gt; label {   text-align: left;   font-size: 1.2rem;   margin-bottom: 0.8rem; }  .ui.button {   margin-top: 1.5rem;   font-size: 1rem;   letter-spacing: 1px;   box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3) !important; }  .email-error {   color: #f93154;   text-align: left; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 <code>index.js<\/code> \u043c\u044b \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u0434\u0430 \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>lazy<\/code> \u0438 <code>Suspense<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">import React, { lazy, Suspense } from 'react' import ReactDOM from 'react-dom' \/\/ \u0421\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0434\u043b\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0438\u0437\u0430\u0446\u0438\u0438 import { BrowserRouter as Router, Switch, Route } from 'react-router-dom' \/\/ \u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 import { Spinner } from '.\/hooks'  \/\/ \u0421\u0442\u0438\u043b\u0438 `semantic-ui` import 'semantic-ui-css\/semantic.min.css' \/\/ \u041a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 \u0441\u0442\u0438\u043b\u0438 import '.\/index.css'  \/\/ &quot;\u041b\u0435\u043d\u0438\u0432\u044b\u0435&quot; \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b - \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0438\u043c\u043f\u043e\u0440\u0442 const Home = lazy(() =&gt; import('.\/pages\/Home')) const Subscribe = lazy(() =&gt; import('.\/pages\/Subscribe')) const Success = lazy(() =&gt; import('.\/pages\/Success')) const NotFound = lazy(() =&gt; import('.\/pages\/NotFound'))  ReactDOM.render(   &lt;Suspense fallback={&lt;Spinner \/&gt;}&gt;     &lt;Router&gt;       &lt;Switch&gt;         &lt;Route path='\/' exact component={Home} \/&gt;         &lt;Route path='\/subscribe' component={Subscribe} \/&gt;         &lt;Route path='\/success' component={Success} \/&gt;         &lt;Route component={NotFound} \/&gt;       &lt;\/Switch&gt;     &lt;\/Router&gt;   &lt;\/Suspense&gt;,   document.getElementById('root') )<\/code><\/pre>\n<p>  <\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u0438\u0437 \u0441\u0435\u0431\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0445\u0443\u043a\u0438.<\/p>\n<p>  <\/p>\n<p>\u0425\u0443\u043a <code>useDeferredRoute<\/code> \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0443 \u043f\u0440\u0438 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043a \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435. \u042d\u0442\u043e \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043a\u0442\u043e-\u0442\u043e \u0434\u0430\u0436\u0435 \u0441\u043a\u0430\u0436\u0435\u0442, \u0447\u0442\u043e \u044d\u0442\u043e \u043f\u043b\u043e\u0445\u0430\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430, \u043d\u043e \u043c\u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u0442\u0430\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 &quot;\u0436\u0438\u0432\u044b\u043c&quot;. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043d\u0435 \u0442\u0430\u043a \u0434\u0430\u0432\u043d\u043e \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u043d\u0430\u0434 \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u044f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0441\u043a\u0440\u044b\u0442\u0438\u044f \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0444\u043e\u043d\u0430 \u043e\u0442\u0440\u0435\u043d\u0434\u0435\u0440\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 \u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0443 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 (\u0432\u043e\u0442 \u0433\u0434\u0435 \u0431\u044b \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u043b\u0441\u044f \u0445\u0443\u043a <a href=\"https:\/\/ru.reactjs.org\/docs\/concurrent-mode-reference.html#usetransition\"><code>useTransition<\/code><\/a>, \u043d\u043e \u043e\u043d \u043f\u043e\u043a\u0430 \u0435\u0449\u0435 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u0439).<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">import { useState, useEffect } from 'react'  const sleep = (ms) =&gt; new Promise((r) =&gt; setTimeout(r, ms))  export const useDeferredRoute = (ms) =&gt; {   const [loading, setLoading] = useState(true)    useEffect(() =&gt; {     const wait = async () =&gt; {       await sleep(ms)       setLoading(false)     }     wait()   }, [ms])    return { loading } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0425\u0443\u043a <code>useTimeout<\/code>, \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043e, \u044d\u0442\u043e \u0432\u0441\u0435\u0433\u043e \u043b\u0438\u0448\u044c \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u043c <code>setTimeout<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">import { useEffect, useRef } from 'react'  export const useTimeout = (cb, ms) =&gt; {   const cbRef = useRef()    useEffect(() =&gt; {     cbRef.current = cb   }, [cb])    useEffect(() =&gt; {     function tick() {       cbRef.current()     }     if (ms &gt; 1) {       const id = setTimeout(tick, ms)       return () =&gt; {         clearTimeout(id)       }     }   }, [ms]) }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0410 \u0432\u043e\u0442 \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 <code>hooks\/index.js<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">\/\/ \u041c\u043d\u0435 \u043d\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e `components` \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 import { Loader } from 'semantic-ui-react'  export const Spinner = () =&gt; &lt;Loader active inverted size='large' \/&gt;  export { useDeferredRoute } from '.\/useDeferredRoute' export { useTimeout } from '.\/useTimeout'<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u043c\u0438.<\/p>\n<p>  <\/p>\n<p>\u0412 <code>Home.js<\/code> \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0433\u043e. \u041f\u043e\u0441\u043b\u0435 \u0441\u043a\u0440\u044b\u0442\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u043c\u044b \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u0435\u043c\u0443 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 (\u043a\u043d\u043e\u043f\u043a\u0430 &quot;\u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f&quot; \u2014 \u044d\u0442\u043e \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 <code>Subscribe<\/code>):<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">import { Link } from 'react-router-dom' import { Container, Button } from 'semantic-ui-react'  import { Spinner, useDeferredRoute } from '..\/hooks'  function Home() {   const { loading } = useDeferredRoute(1500)    if (loading) return &lt;Spinner \/&gt;    return (     &lt;Container&gt;       &lt;h2&gt;\u0414\u043e\u0431\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a!&lt;\/h2&gt;       &lt;h3&gt;         \u041f\u043e\u0434\u043f\u0438\u0448\u0438\u0442\u0435\u0441\u044c \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f, &lt;br \/&gt; \u0447\u0442\u043e\u0431\u044b \u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u0443\u0440\u0441\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0439!       &lt;\/h3&gt;       &lt;Button color='teal' as={Link} to='\/subscribe'&gt;         \u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f       &lt;\/Button&gt;     &lt;\/Container&gt;   ) }  export default Home<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 <code>Success.js<\/code> \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0433\u043e. \u041f\u043e\u0441\u043b\u0435 \u0441\u043a\u0440\u044b\u0442\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u043c\u044b \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0437\u0430 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0447\u0435\u0440\u0435\u0437 3 \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0430\u0448\u0435\u0433\u043e \u0445\u0443\u043a\u0430 <code>useTimeout<\/code>. \u041d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439, \u0435\u0441\u043b\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e, \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0430-\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 <code>Home<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">import { Link, useHistory } from 'react-router-dom' import { Container, Button } from 'semantic-ui-react'  import { Spinner, useDeferredRoute, useTimeout } from '..\/hooks'  function Success() {   const { loading } = useDeferredRoute(500)   const history = useHistory()    const redirectToHomePage = () =&gt; {     history.push('\/')   }    useTimeout(redirectToHomePage, 3000)    if (loading) return &lt;Spinner \/&gt;    return (     &lt;Container&gt;       &lt;h2&gt;\u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443!&lt;\/h2&gt;       &lt;h3&gt;\u0421\u0435\u0439\u0447\u0430\u0441 \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443&lt;\/h3&gt;       &lt;Button color='teal' as={Link} to='\/'&gt;         \u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e       &lt;\/Button&gt;     &lt;\/Container&gt;   ) }  export default Success<\/code><\/pre>\n<p>  <\/p>\n<p>\u0415\u0449\u0435 \u043e\u0434\u043d\u0430 \u043f\u0440\u043e\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u2014 <code>NotFound<\/code> \u2014 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u044d\u0442\u0443 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0441 \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">import { Link, useHistory } from 'react-router-dom' import { Container, Button } from 'semantic-ui-react'  import { Spinner, useDeferredRoute, useTimeout } from '..\/hooks'  function NotFound() {   const { loading } = useDeferredRoute(500)   const history = useHistory()    const redirectToHomePage = () =&gt; {     history.push('\/')   }    useTimeout(redirectToHomePage, 2000)    if (loading) return &lt;Spinner \/&gt;    return (     &lt;Container&gt;       &lt;h2&gt;\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442&lt;\/h2&gt;       &lt;h3&gt;\u0421\u0435\u0439\u0447\u0430\u0441 \u0432\u044b \u0431\u0443\u0434\u0435\u0442\u0435 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443&lt;\/h3&gt;       &lt;Button color='teal' as={Link} to='\/'&gt;         \u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e       &lt;\/Button&gt;     &lt;\/Container&gt;   ) }  export default NotFound<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 <code>Subscribe<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>react-google-recaptcha<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u043e\u043f\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u043a\u043b\u044e\u0447 \u0441\u0430\u0439\u0442\u0430 (<code>sitekey<\/code>). \u0414\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 <a href=\"https:\/\/www.google.com\/recaptcha\/admin\"><code>Google ReCAPTCHA<\/code><\/a>, \u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430\u0434\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u043d\u0430 <code>Netlify<\/code>. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u044e\u0447 (<a href=\"https:\/\/developers.google.com\/recaptcha\/docs\/faq\">\u044d\u0442\u043e \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u044e\u0447 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/a>): <code>6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI<\/code>. \u041f\u043e\u0437\u0436\u0435 \u043c\u044b \u0432\u0435\u0440\u043d\u0435\u043c\u0441\u044f \u043a \u044d\u0442\u043e\u043c\u0443 \u0432\u043e\u043f\u0440\u043e\u0441\u0443.<\/p>\n<p>  <\/p>\n<p>\u0415\u0449\u0435 \u043e\u0434\u0438\u043d \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u2014 \u044d\u0442\u043e \u043a\u043e\u043d\u0435\u0447\u043d\u0430\u044f \u0442\u043e\u0447\u043a\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u041e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0441 <code>\/.netlify\/<\/code>, \u0437\u0430\u0442\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0443\u0442\u044c \u043a \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438: <code>functions\/subscribe<\/code> \u2014 <code>\/.netlify\/functions\/subscribe<\/code> (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u2014 \u0447\u0430\u0441\u0442\u044c \u043f\u0443\u0442\u0438). \u0421\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0447\u0430\u0441\u0442\u044c \u043f\u0443\u0442\u0438 <code>\/.netlify\/functions<\/code> \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0432 <code>netlify.toml<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0412 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u043c, \u0432\u0441\u0435 \u043f\u0440\u043e\u0441\u0442\u043e: \u043f\u043e\u0441\u043b\u0435 \u0441\u043a\u0440\u044b\u0442\u0438\u044f \u0438\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u043c\u044b \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0432\u0432\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u0435 \u0438\u043c\u044f \u0438 \u0430\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c, \u0447\u0442\u043e \u043e\u043d &quot;\u043d\u0435 \u0440\u043e\u0431\u043e\u0442&quot;. \u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u0435\u0439 \u0438 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441 \u043a\u043d\u043e\u043f\u043a\u0438 &quot;\u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f&quot; \u0441\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430. \u041f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u044d\u0442\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0438\u0445 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443.<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">import { useState } from 'react' import { useHistory } from 'react-router-dom' import { Container, Form, Button } from 'semantic-ui-react' import ReCAPTCHA from 'react-google-recaptcha'  import { Spinner, useDeferredRoute } from '..\/hooks'  \/\/ \u0423\u0442\u0438\u043b\u0438\u0442\u0430 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u044b const isEmpty = (fields) =&gt; fields.some((f) =&gt; f.trim() === '') \/\/ \u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0443\u0442\u0438\u043b\u0438\u0442\u044b \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0430\u0434\u0440\u0435\u0441\u0430 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b const isEmail = (v) =&gt; \/\\w+@\\w+\\.\\w+\/i.test(v)  function Subscribe() {   const [formData, setFormData] = useState({     username: '',     email: ''   })   const [error, setError] = useState(null)   const [recaptcha, setRecaptcha] = useState(false)    const { loading } = useDeferredRoute(1000)   const history = useHistory()    const onChange = ({ target: { name, value } }) =&gt; {     setError(null)     setFormData({       ...formData,       [name]: value     })   }    const onSubmit = async (e) =&gt; {     e.preventDefault()      const email = isEmail(formData.email)      if (!email) {       return setError('\u0412\u0432\u0435\u0434\u0435\u043d \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 email')     }      try {       const response = await fetch('\/.netlify\/functions\/subscribe', {         method: 'POST',         body: JSON.stringify(formData),         headers: {           'Content-Type': 'application\/json'         }       })       if (!response.ok) {         const json = await response.json()         return setError(json.error)       }       history.push('\/success')     } catch (err) {       console.error(err)     }   }    \/\/ \u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f, \u0447\u0442\u043e \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u043a\u043b\u044e\u0447, \u043a\u0430\u043f\u0447\u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0438\u0441\u0442\u0438\u043d\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435   const disabled = isEmpty(Object.values(formData)) || !recaptcha    const { username, email } = formData    if (loading) return &lt;Spinner \/&gt;    return (     &lt;Container&gt;       &lt;h2&gt;\u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f&lt;\/h2&gt;       &lt;Form onSubmit={onSubmit}&gt;         &lt;Form.Field&gt;           &lt;label&gt;\u0412\u0430\u0448\u0435 \u0438\u043c\u044f&lt;\/label&gt;           &lt;input             placeholder='\u0418\u043c\u044f'             type='text'             name='username'             value={username}             onChange={onChange}             required           \/&gt;         &lt;\/Form.Field&gt;         &lt;Form.Field&gt;           &lt;label&gt;\u0412\u0430\u0448 email&lt;\/label&gt;           &lt;input             placeholder='Email'             type='email'             name='email'             value={email}             onChange={onChange}             required           \/&gt;         &lt;\/Form.Field&gt;         &lt;p className='email-error'&gt;{error}&lt;\/p&gt;         &lt;ReCAPTCHA           sitekey='6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'           onChange={() =&gt; setRecaptcha(true)}         \/&gt;         &lt;Button color='teal' type='submit' disabled={disabled}&gt;           \u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f         &lt;\/Button&gt;       &lt;\/Form&gt;     &lt;\/Container&gt;   ) }  export default Subscribe<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u0443 \u043d\u0430\u0441 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443. \u041f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0435\u0449\u0435 \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438 <code>netlify-cli<\/code>, \u0441\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">yarn global add netlify-cli # \u0438\u043b\u0438 npm i -g ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u0441\u0435, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u044d\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">netlify dev<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043a\u043b\u0438\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0449\u0435\u043d \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443 <code>localhost:3000<\/code>, \u0430 \u0441\u0435\u0440\u0432\u0435\u0440 \u2014 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0445\u043e\u0441\u0442\u0435, \u043d\u043e \u0441 \u043f\u043e\u0440\u0442\u043e\u043c <code>8888<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041f\u0440\u0435\u043b\u0435\u0441\u0442\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e <code>netlify-cli<\/code> \u0443\u043c\u0435\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043b\u044f \u0435\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 &quot;\u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f&quot;, \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043f\u043e\u043b\u044f \u0444\u043e\u0440\u043c\u044b, \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0438 \u0441\u043d\u043e\u0432\u0430 \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u043c \u043d\u0430 &quot;\u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f&quot;. \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c \u043e\u0431 \u0443\u0441\u043f\u0435\u0445\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u0437\u0430\u0442\u0435\u043c \u0435\u0449\u0435 \u043e\u0434\u043d\u043e \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443. \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0432\u0438\u0434\u0438\u043c \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u043d\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0435.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ky\/hc\/sl\/kyhcsl6arhq6t0zsaeipq-fwntc.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/01\/rg\/_c\/01rg_c_isjivm9etzmfa54lm4mm.png\">. <\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/0e\/7b\/9z\/0e7b9zdhlcndxrggkdztn99qojo.png\">. <\/p>\n<p>  <\/p>\n<p>\u041e\u0442\u043b\u0438\u0447\u043d\u043e, \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043a\u0430\u043a \u043e\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044f.<\/p>\n<p>  <\/p>\n<p>\u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u043c\u044b \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 <code>Netlify<\/code>, \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043a\u0430\u043f\u0447\u0438, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0443 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u0438 \u043e\u0442\u043f\u0438\u0441\u043a\u0443 \u043e\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439.<\/p>\n<p>  <\/p>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0438 \u0445\u043e\u0440\u043e\u0448\u0435\u0433\u043e \u0434\u043d\u044f!<\/p>\n<p>  <\/p>\n<hr>\n<p>  <\/p>\n<p>\u041e\u0431\u043b\u0430\u0447\u043d\u044b\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u044b \u043e\u0442 <a href=\"https:\/\/macloud.ru\/?partner=4189mjxpzx\">\u041c\u0430\u043a\u043b\u0430\u0443\u0434<\/a> \u0431\u044b\u0441\u0442\u0440\u044b\u0435 \u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0435.<\/p>\n<p>  <\/p>\n<p>\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0439\u0442\u0435\u0441\u044c \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432\u044b\u0448\u0435 \u0438\u043b\u0438 \u043a\u043b\u0438\u043a\u043d\u0443\u0432 \u043d\u0430 \u0431\u0430\u043d\u043d\u0435\u0440 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 10% \u0441\u043a\u0438\u0434\u043a\u0443 \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u043c\u0435\u0441\u044f\u0446 \u0430\u0440\u0435\u043d\u0434\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043b\u044e\u0431\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438!<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/macloud.ru\/?partner=4189mjxpzx&amp;utm_source=habr&amp;utm_medium=origianl&amp;utm_campaign=igor\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/et\/1a\/yp\/et1aypandyuamqprsz3m2ntm4ky.png\"><\/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\/company\/macloud\/blog\/560932\/\"> https:\/\/habr.com\/ru\/company\/macloud\/blog\/560932\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u0412 \u044d\u0442\u043e\u043c \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0435 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c <code>~~Real World App~~<\/code> \u2014 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443 \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0433\u0443\u0433\u043b \u0442\u0430\u0431\u043b\u0438\u0446, \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438 \u0440\u0435\u0430\u043a\u0442\u0430.<\/p>\n<p>  <\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0438 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f<\/li>\n<li>\u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 &quot;\u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f&quot;, \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u0442 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u0444\u043e\u0440\u043c\u043e\u0439, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0439 \u0434\u0432\u0430 \u043f\u043e\u043b\u044f: \u0438\u043c\u044f \u0438 \u0430\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b<\/li>\n<li>\u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u0431\u043e\u0442\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0433\u0443\u0433\u043b \u0440\u0435\u043a\u0430\u043f\u0447\u0430 2 \u0432\u0435\u0440\u0441\u0438\u0438<\/li>\n<li>\u043f\u0440\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043f\u043e\u043b\u0435\u0439 \u0438 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0440\u0430\u0437\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0430 &quot;\u041f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f&quot;<\/li>\n<li>\u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u044d\u0442\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0430 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439<\/li>\n<li>\u0432 \u0440\u0430\u0441\u0441\u044b\u043b\u0430\u0435\u043c\u044b\u0445 \u043f\u0438\u0441\u044c\u043c\u0430\u0445 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0442\u043f\u0438\u0441\u043a\u0443 \u043e\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439<\/li>\n<li>\u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0435 \u043f\u043e \u044d\u0442\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0435 \u0430\u0434\u0440\u0435\u0441 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0441\u0441\u0435\u0440\u0432\u0435\u0440\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u2014 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u2014 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439.<\/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-324334","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/324334","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=324334"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/324334\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=324334"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=324334"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=324334"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}