<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>guakamole🩸🪓</title><generator>teletype.in</generator><description><![CDATA[пишу код на javascript
увлекаюсь web3 и cryptoвалюти]]></description><image><url>https://img1.teletype.in/files/8d/a8/8da8ede6-3e8d-45ab-9dfe-5a2dd586763b.png</url><title>guakamole🩸🪓</title><link>https://teletype.in/@rubyuroboros</link></image><link>https://teletype.in/@rubyuroboros?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/rubyuroboros?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/rubyuroboros?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Wed, 29 Apr 2026 01:40:50 GMT</pubDate><lastBuildDate>Wed, 29 Apr 2026 01:40:50 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@rubyuroboros/-2OTQOB_Kno</guid><link>https://teletype.in/@rubyuroboros/-2OTQOB_Kno?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><comments>https://teletype.in/@rubyuroboros/-2OTQOB_Kno?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros#comments</comments><dc:creator>rubyuroboros</dc:creator><title>Резюме, которое работает или как искать работу</title><pubDate>Fri, 15 Sep 2023 13:59:14 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/94/ae/94ae3985-88b7-4609-b902-7ecbccde3520.png"></media:content><description><![CDATA[<img src="https://img4.teletype.in/files/b7/7f/b77f54e7-3325-4a84-bb59-8ca26c184135.png"></img>Резюме должно работать на тебя, а не против.]]></description><content:encoded><![CDATA[
  <p id="ZnPj">Резюме должно работать на тебя, а не против.</p>
  <hr />
  <p id="9icS"><strong>Дисклеймер:</strong> в статье описывается субъективное мнение автора. Советы, техники и наставления не работают на 100% и никому не гарантируют оффер в Google после прочтения.</p>
  <p id="oMhW">Тебе могут не понравиться мои выводы, может показаться, что я что-то или кого-то осуждаю, но нет, я пишу только со своей колокольни, как я видел: что работает, а что нет.</p>
  <p id="WJyV">Я собрал здесь максимум информации, которую знаю на протяжении своего профессионального опыта, и которая помогает мне находить работу достаточно быстро.</p>
  <p id="30MO">Начнём!</p>
  <hr />
  <h2 id="aLMh">Предисловие</h2>
  <p id="6IPk">Я решил написать эту статью-гайд, так как продолжаю видеть очень большое количество резюме, которые я бы отложил в далекий ящик, потратив на них 5-10 секунд времени. Хороших программистов могли динамить из-за плохого резюме.</p>
  <p id="HZ3K">Я видел также множество прекрасных примеров резюме. Лично у меня в этом плане всё далеко не идеально, но тем не менее я неоднократно получал хорошие сообщения от HR и других людей, потому что моё CV крутое/прикольное/милое/нестандартное, хотя у меня и по сей день сейчас это просто страничка в Notion. Есть в общем куда расти. Всем.</p>
  <hr />
  <h2 id="r5RE">Что я видел в работающих резюме</h2>
  <p id="I13A">Напишу список, который разберу в подробностях:</p>
  <ol id="QYG7">
    <li id="pOpV">Портфолио</li>
    <li id="gMh2">Опен-сорс</li>
    <li id="5Kyq">Педантичность</li>
    <li id="pSNK">Продаваемость</li>
    <li id="QJxi">Манера</li>
    <li id="XXdw">Краткость</li>
  </ol>
  <p id="2YyT">Я расположил пункты в порядке приоритета. Конечно, возглавляют строчки списка всё, что связано непосредственно с самой профессией — разработкой.</p>
  <h2 id="bWGb">Портфолио</h2>
  <p id="8QWa">Портфолио... очень важная вещь. Везде. В нашем случае в качестве портфолио может выступить</p>
  <ol id="PAvM">
    <li id="qBTP">Твой сайт</li>
    <li id="AhB4">Твой GitHub</li>
    <li id="6nWE">Сайты, которые ты делал для кого-то (естественно, с исходниками)</li>
    <li id="7MfO">zip архивы с проектами, или грубо говоря &quot;куски кода&quot; (ну, так тоже можно в принципе)</li>
  </ol>
  <p id="QMtv">Начну разбор с последнего пункта.</p>
  <h3 id="6I1j">Куски кода</h3>
  <p id="vBsD">Я давно активно не смотрел на рынок, но год назад либо общаясь с HR, либо в самой вакансии можно было встретить строчку &quot;предоставьте кусок кода&quot;. Возможно я предвзято отношусь к этому, но что может сказать о программисте кусок кода, особенно в расцвет LLM? Я могу написать ChatGPT — сгенерируй мне хорошо структурированный кусок кода, и вуаля: я крутой программист? Я в 99% случаев обходил такие вакансии стороной.</p>
  <p id="UDOz">Пет-проект может многое сказать о компетенции программиста, но никак не кусок кода. Я бывало сидел думал: <em>&quot;а из какого файла вы хотите кусок кода-то?&quot;</em></p>
  <h3 id="nuJ1">Сайты на заказ</h3>
  <p id="Aaj3">Важная штука. Можно существовать без портфолио в виде сайта, без GitHub, но если у тебя есть опыт в крутых проектах — это козырь. В начале особенно лучше не брезговать тематикой проектов, а браться за всё (ну, кроме того, к чему совсем душа не лежит).</p>
  <h3 id="9TuS">GitHub</h3>
  <p id="BeK2">О, это место, куда любой человек может зайти и посмотреть на твой код. Супер крутой инструмент, чтобы показать насколько ты хорош. Человеку даже не надо писать тебе в личку, чтобы ты ему скинул проекты, которые ты делал. Тыкнул — и любуешься, как человек код пишет и что у него в голове бывает.</p>
  <h3 id="JAx8">Портфолио</h3>
  <p id="MjTt">Жемчужина списка. GitHub на максималках, и вот почему — если в GitHub полезет обычно только программист, то по ссылке на твое портфолио может перейти любой ребенок, не говоря уже об HR. Ты показываешь всё, что у тебя в голове в виде портфолио. Можно проявить креатив, воображение и что угодно. По моему мнению, это самая интересная и работающая техника. Ты можешь понравиться людям просто по тому, как ты себя представил.</p>
  <p id="B28I">Да и еще, какой веб-разработчик без портфолио в виде веб-сайта? Может выглядеть, как юрист, никогда не бывавший в суде. Именно &quot;может&quot;, потому что отсутствие портфолио не ставит под сомнение профессионализм разработчика.</p>
  <p id="Re0i"><strong>Мораль:</strong> портфолио — это очень важный пункт в резюме, который поможет найти работу быстрее, чем другие кандидаты без портфолио.</p>
  <h2 id="VnqZ">Опен-сорс</h2>
  <p id="jiqT">Я поставил этот пункт за портфолио, потому что активное участие в опен-сорс разработке может быть большим плюсом, так как показывает, что человек не просто работает от зарплаты до зарплаты, но и живет кодингом. <strong>Живет идеей.</strong> Я думаю, CEO в восторге, когда его коллега живет идеей и кайфует от разработки. И опять же, как в случае с портфолио, полное отсутствие зеленых квадратиков в GitHub не означает, что разработчик плох. Пока разбирал опен-сорс, вспомнил <a href="https://www.youtube.com/watch?v=r6tH55syq0o" target="_blank">это</a> видео.</p>
  <p id="yiHU"><strong>Мораль:</strong> опен-сорс это круто, и круто, когда на него есть время.</p>
  <h2 id="UUJ3">Педантичность</h2>
  <p id="eqX7">Под педантичностью я не имею ввиду перфекционизм. Мне очень мешал перфекционизм. Это стремление &quot;сделать все идеально&quot; в итоге не доводило ни одну мою идею до MVP, не говоря уже о том, чтобы идея увидела свет. Ещё говоря про педантичность в этом контексте, я не имею ввиду, что мне всегда нужно было излишнее внимание к мельчайшим деталям. Внимание должно быть, но не излишнее.</p>
  <p id="YdAP">Например, я часто встречал резюме/портфолио с грамматическими ошибками, явным отсутствием симметрии в вёрстке, не очень внятным UX (но это совершенно легко можно списать на грейд разработчика), а что ещё хуже — вовсе не работающими кнопками или ссылками.</p>
  <p id="Wap5">Причём я встречал это не только у Junior разработчиков, но и у Middle+.</p>
  <p id="Gi79"><strong>Мораль:</strong> просто будь внимателен без фанатизма. Упускать что-то нормально, все мы люди.</p>
  <h2 id="6WMK">Продаваемость</h2>
  <p id="6FrJ">О, дошли до денег. Наверное сейчас самое интересное.</p>
  <p id="U7L6">Давай сравним два резюме:</p>
  <ol id="6DDQ">
    <li id="xxbG">Привет! Я разработчик с [...] навыками и опытом X месяцев. Ожидания по зарплате: $3 в час/рад поработать за идею. Вообще я горю разработкой, я её очень люблю! Писать сюда -&gt; @ruburi</li>
    <li id="UQ2w">Привет! Я разработчик с [...] навыками и опытом X месяцев. Ожидания по зарплате: $10 в час. По выходным не работаю. Писать сюда -&gt; @ruburi</li>
  </ol>
  <p id="s6uX">Я посмотрел бы на эти два резюме, будучи CEO продукта, и мне конечно стало бы интересно, на что способен второй разработчик, который задвигает аж в 3 раза больше, чем первый.</p>
  <p id="Ccc2">Во втором случае человек явно выставляет границы и дает понять, что он ценит свое время и не готов его разбазаривать куда угодно, несмотря на то, что он недавно начал профессиональный путь в разработке. Я бы не сказал, что это говорит об ответственности за своё время, но кто-то может так посчитать.</p>
  <p id="yA5g">Если рассмотреть строчку &quot;Вообще я горю разработкой, я её очень люблю!&quot; — ну, я думаю тут палка о двух концах. HR это может обрадовать, мол вот смотри — тут разработчик любит кодить и вообще он так горит этим! С другой стороны, это может походить на конфетно-букетный период у молодых влюблённых, когда человек только начал и его прёт, а потом бах — и первое выгорание! Осознание того, что жизнь — тлен, а программирование — не моё. И вот ушёл с проекта. А потом еще окажется, что лид не смотрел за джуном. Ой.</p>
  <p id="K7qH">Что я хочу этим сказать? Нет, не то, что если человек пишет, что он любит разработку, значит он плохой. Просто скорее всего, если человек пишет об этом, скорее всего он это докажет, если это действительно так (например, тем же опен-сорс). Не путать с тем, что человек пишет, например — создаю крутые интерфейсы, которые нравятся людям. Тут скорее можно увидеть подход к разработке.</p>
  <p id="SfIU"><strong>Мораль:</strong> цените своё время и нервы, пытайтесь продавать себя дороже, чем вы себя оцениваете — только так покоряются новые вершины, на уверенном.</p>
  <h2 id="v2Zv">Манера</h2>
  <p id="nHjM">Манера — коротенький пункт. Под манерой я имею ввиду манеру &quot;коммуникации&quot; с внешним миром через резюме. Никому не будет приятно читать хабалистую или наглую писанину. Я предпочитаю общаться с людьми через резюме. Так и в статьях. Я пишу так, как будто я сижу и общаюсь с человеком в реальной жизни. Кому-то это может не нравиться, может вызвать споры между тыканьем и выканьем, формальностями и бюрократией, но мне так просто комфортно.</p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="uRYS">💗                                                                                                                                  💗</p>
    <p id="jZBg" data-align="center">Если тебе нравится статья, можешь поддержать автора лайком под постом в Telegram канале — <a href="https://t.me/ruburi" target="_blank"><strong>@ruburi</strong></a></p>
    <p id="Im8e">💗                                                                                                                                  💗</p>
  </section>
  <h2 id="OZ52">Краткость</h2>
  <p id="AhKU">Краткость — сестра таланта. Когда-то давно я услышал слова: &quot;HR неинтересно, занимаешься ты плаванием или прочитал 100 книг, если ты не принесешь пользы или денег.&quot;</p>
  <p id="odub">Цитата, конечно, грубоватая, но в целом это так. Пункт не про то, что никому неинтересны твои достижения, нет. Просто я стараюсь не заполнять резюме/CV информацией, не связанной с профессией. О том, сколько я книг прочитал можно рассказать коллеге в курилке, если ему станет интересно.</p>
  <p id="HYbd"><strong>Мораль:</strong> не переполнять резюме лишним шумом.</p>
  <hr />
  <h2 id="dygK">Заметки и мини-разбор других резюме</h2>
  <p id="gWAQ">Сейчас я открою несколько сервисов для поиска работы и возьму оттуда парочку резюме. Разберём на примерах, чтобы было яснее, и возможно, я вспомню что-нибудь ещё интересного.</p>
  <h3 id="tigW">1 заметка</h3>
  <p id="Fzw1">Важно оценивать себя адекватно. В продаваемости я написал, что надо ценить своё время, но важно также уметь оценить свои навыки адекватно. Чтобы не было такого, что человек просит $5000 и прикрепляет в примеры работ To-Do лист. Ну вы поняли.</p>
  <h3 id="gSvK">2 заметка</h3>
  <p id="zwKf">Префаернул по 2 заметке. Человек опубликовал своё резюме в Google Disk -&gt; переходим -&gt; нет доступа.</p>
  <p id="PhyQ">Старайся публиковать резюме там, где его легко достать и удобно читать. И не забудь открыть его в паблик.</p>
  <h3 id="klxh">3 заметка</h3>
  <p id="kkJQ">Есть тут один красный флаг, если можно так выразиться. Избегай оценки своих навыков в процентах. Что-то в духе знаю JavaScript на 50%, а HTML на 100% — моветон. Честно признаться, я сам таким маялся когда только учился.</p>
  <h3 id="r7ou">4 заметка</h3>
  <p id="kh13">Стиль резюме тоже решает. Главное, чтобы при просмотре резюме у человека не случился приступ от переизбытка смайликов, ярких цветов и прочего, отвлекающего фокус.</p>
  <h3 id="295P">5 заметка</h3>
  <p id="ADvP">Английский — решает. Всё новое, что я изучаю эти 3 года как минимум — ресурсы и материалы на английском.</p>
  <h3 id="phXF">6 заметка</h3>
  <p id="rzJm">Когда будешь писать о своём опыте в проектах, пиши конкретно, что ты делал, какие были у тебя обязанности и что тебя радовало в процессе работы. Я не использую слово &quot;гордишься&quot;, ну потому что иногда это прямо звучит очень резко. Можно работать в компании, где не происходило ничего выдающегося, зато ты просто стабильно выполнял свою работу качественно.</p>
  <h3 id="uhWf">7 заметка</h3>
  <p id="DziL">LinkedIn — мастхев, если ищешь работу за рубежом.</p>
  <h3 id="8JSy">8 заметка</h3>
  <p id="v4PJ">Иногда я замечаю, как люди перечисляют софт-скиллы и пишут: я добрый, трудолюбивый, хороший. Ну в общем такие софт-скиллы, как будто бы для кого как. Как будто сочинение школьное пишешь о том, какой ты у мамы получился. Тут есть тонкая грань между тем, что перечислять, а что нет. Поэтому не пойми неправильно. На вкус и цвет.</p>
  <h3 id="0yHg">9 заметка</h3>
  <p id="EfiO">Помнишь я говорил про продаваемость?</p>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="tg4K">Цитирую строчки из резюме:</p>
    <p id="a9MD"><em>&quot;Я готов предложить свою полную приверженность, и быть полезным дополнением к Вашей команде. Вместе мы выведем Ваш бизнес на новый уровень!&quot;</em></p>
  </section>
  <p id="YidR">Приверженность? Выведем Ваш бизнес на новый уровень? Одним разработчиком клиентской части?</p>
  <p id="j9Ja">Это примерно то, о чём я говорил. Человек может быть хороший, искренний, но в строчках есть такая толика напыщенности, как будто я сейчас напишу принимать на работу, а потом закую в наручники у батареи и код заставлю писать, пока бизнес не выведется на новый уровень.</p>
  <h3 id="1sNp">10 заметка</h3>
  <p id="xuec">Отзывы и рекомендации решают. Тут шатаут <a href="https://t.me/workwor" target="_blank">@workwor</a> за наставление. Круто, когда за тебя могут замолвить слово другие разработчики.</p>
  <hr />
  <h2 id="75IT">Заключение</h2>
  <p id="B46j">Ну вот и подошла к концу статейка. Что могу сказать? Учись, разрабатывай, пили проекты себе в кайф и не забывай отдыхать. Надеюсь, я помог тебе, анон.</p>
  <h3 id="3byj">Отзыв</h3>
  <p id="YUnN">Если заметил где-то ошибку, или что-то не складывается в голове — ты всегда можешь обратиться за вопросом ко мне в Telegram <strong><a href="https://t.me/rubyuroboros" target="_blank">@rubyuroboros</a></strong></p>
  <hr />
  <p id="Rm05">Мой канал — <a href="https://t.me/ruburi" target="_blank">https://t.me/ruburi</a></p>
  <figure id="CKJH" class="m_retina" data-caption-align="center">
    <img src="https://img4.teletype.in/files/b7/7f/b77f54e7-3325-4a84-bb59-8ca26c184135.png" width="540" />
    <figcaption>лайк?</figcaption>
  </figure>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rubyuroboros/z5hFBkOks83</guid><link>https://teletype.in/@rubyuroboros/z5hFBkOks83?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><comments>https://teletype.in/@rubyuroboros/z5hFBkOks83?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros#comments</comments><dc:creator>rubyuroboros</dc:creator><title>TELEGRAM BOT QUICK START</title><pubDate>Fri, 03 Mar 2023 22:07:01 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/38/74/3874e07b-0858-4588-9469-6f2bb75f40b7.png"></media:content><description><![CDATA[<img src="https://img1.teletype.in/files/08/c1/08c1bbd8-205a-4ea8-8d3b-034f6a3e6f11.png"></img>с первым днем весны! (у рубури это так на момент написания этой строки)]]></description><content:encoded><![CDATA[
  <figure id="OvrE" class="m_retina" data-caption-align="center">
    <img src="https://img1.teletype.in/files/08/c1/08c1bbd8-205a-4ea8-8d3b-034f6a3e6f11.png" width="512" />
    <figcaption>миниатюра рубури и подпищек</figcaption>
  </figure>
  <p id="vYaE">с первым днем весны! (у рубури это так на момент написания этой строки)</p>
  <p id="w6tQ">предоставляю тебе альманах как написать бота в телеге простыми словами без заморочек</p>
  <p id="MtLK">если ты давно хотел написать своего бота в телеге — щас самое время для того чтобы научиться это делать!</p>
  <hr />
  <p id="s7oK">давай накатаю тебе план действий то есть что мы будем делать:</p>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="LVN3">1. <a href="#rAej"><strong>как читать эту статью?</strong></a></p>
    <p id="nLTq">2. <a href="#A5n6"><strong>изучим основы</strong></a></p>
    <p id="ijUV">2.1.<strong> <a href="#HcJp">создаем бота в BotFather</a></strong></p>
    <p id="bJN0">    2.2. <a href="#GBVE"><strong>разворачиваем среду обитания бота</strong></a></p>
    <p id="iAc5">    2.3. <a href="#zYdD"><strong>пишем первого простецкого бота</strong></a></p>
    <p id="BlRa">3. <a href="#Z4en"><strong>пишем славу бота</strong></a></p>
    <p id="AsJW">    3.1. <a href="#xR2w"><strong>создаем бота в BotFather</strong></a></p>
    <p id="350e">    3.2. <a href="#YnCB"><strong>создаем приветственное сообщение</strong></a></p>
    <p id="zHJn">    3.3. <a href="#IoTG"><strong>пишем логику обработки ввода от юзера</strong></a></p>
    <p id="b84F">    3.4. <a href="#6MGy"><strong>пишем логику получения данных о монете</strong></a></p>
    <p id="66B6">    3.5. <a href="#QqJv"><strong>отвечаем юзеру котировками пон</strong></a></p>
    <p id="PqMW">    3.6. <a href="#Aixf"><strong>поздравляю! ты написал почти клона славы!</strong></a></p>
    <p id="j8uP">4. <a href="#XMgv"><strong>пишем бот агрегатор каналов</strong></a></p>
    <p id="Ym1h">    4.1. <a href="#1qWh"><strong>получаем API ID и хэш</strong></a></p>
    <p id="ZqjK">    4.2. <a href="#oTLy"><strong>готовим окружение</strong></a></p>
    <p id="T40A">    4.3. <a href="#rYva"><strong>коннектим бота к аккаунту</strong></a></p>
    <p id="fPmi">    4.4. <a href="#FxyR"><strong>получаем инфу о постах в канале</strong></a></p>
    <p id="XVlB">    4.5. <a href="#d5cq"><strong>пересылаем пост из канала в канал</strong></a></p>
    <p id="saRX">    4.6. <a href="#BLAW"><strong>настраиваем автоматическую пересылку из одного канала</strong></a></p>
    <p id="Jmm4">    4.7. <a href="#3E6B"><strong>пересылаем посты из нескольких каналов</strong></a></p>
    <p id="Prpd">    4.8. <a href="#gPiu"><strong>поздравляю! ты написал бот агрегатор каналов!</strong></a></p>
    <p id="fRLp">5. <a href="#oQqU"><strong>как сделать так, чтобы бот работал всегда?</strong></a></p>
    <p id="IAdP">6. <a href="#ciES"><strong>заключение</strong></a></p>
    <p id="w5Pr">7. <a href="#76kW"><strong>благодарности</strong></a></p>
    <p id="t4vB">8. <a href="#3byj"><strong>отзыв</strong></a></p>
  </section>
  <p id="R4PW">ниже я оставлю ссылочки для навигации по определенным частям статьи. надеюсь ты подхватишь какие нибудь интересные техники или любую другую интересующую тебя инфу из этой статьи! погнали!</p>
  <hr />
  <h2 id="rAej">как читать эту статью?</h2>
  <p id="Uw0X">в целом все просто</p>
  <p id="B09y">ты можешь читать все разом, либо просто перейти к интересующему тебя разделу (например, слава бот или бот агрегатор)</p>
  <p id="eosw">в обоих разделах ты найдешь для себя что то новое, я постарался расписать какие то интересные техники и новые концепты</p>
  <hr />
  <h2 id="A5n6">основы</h2>
  <h3 id="HcJp">создаем бота в BotFather</h3>
  <p id="hwwh">весь код будет на js. начнем с того что мы создадим самого бота через <a href="https://t.me/botfather" target="_blank"><strong>BotFather</strong></a></p>
  <p id="5Hmq">нас интересует команда <code>/newbot</code></p>
  <figure id="XTdA" class="m_column" data-caption-align="center">
    <img src="https://img3.teletype.in/files/e7/16/e716e425-32c2-41a1-af76-99807f1f0a6c.png" width="346" />
    <figcaption>вот таке команда</figcaption>
  </figure>
  <p id="Al4A">после чего вводим имя бота, в нашем случае — &quot;Абузим гем&quot;</p>
  <p id="xbc7">и наконец юзернейм, необходимо чтобы юзернейм заканчивался словом <strong>bot</strong></p>
  <figure id="DVYM" class="m_column">
    <img src="https://img1.teletype.in/files/04/e6/04e619fd-5c1d-481d-8576-8b7a612d208d.png" width="2066" />
    <figcaption>абузим гем?</figcaption>
  </figure>
  <p id="96At">после чего в сообщении мы получаем токен бота, который будет использован для того чтобы мы могли взаимодействовать с ботом по API</p>
  <h3 id="GBVE">разворачиваем среду обитания бота</h3>
  <p id="OX6i">если ты не знаешь что такое nodejs или у тебя не установлен Node.js либо yarn: проходи <a href="https://teletype.in/@rubyuroboros/CWzk3G8-7Ld" target="_blank"><strong>сюда</strong></a> в раздел <strong>&quot;Подготавливаем среду обитания нашего скрипта&quot;</strong></p>
  <p id="bu0C">создаем папку, создаем файл <code>index.js</code>, заходим в нее в редакторе, открываем консоль и пишем:</p>
  <pre id="lDSX" data-lang="bash">yarn init -y
yarn add node-telegram-bot-api
yarn add --dev nodemon</pre>
  <p id="APHC">для разработки бота мы будем использовать библиотеку <a href="https://github.com/yagop/node-telegram-bot-api/" target="_blank"><strong>node-telegram-bot-api</strong></a></p>
  <p id="6UqZ">также мы будем использовать тулзу <a href="https://www.npmjs.com/package/nodemon" target="_blank"><strong>nodemon</strong></a> чтобы бот перезапускался за нас всякий раз когда мы обновляем код</p>
  <p id="gzzZ">заходим в <code>package.json</code> и вставляем туда следующее содержимое:</p>
  <pre id="rV31" data-lang="javascript">{
  &quot;type&quot;: &quot;module&quot;,
  &quot;name&quot;: &quot;telegram-bot&quot;,
  &quot;private&quot;: true,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;license&quot;: &quot;MIT&quot;,
  &quot;dependencies&quot;: {
    &quot;node-telegram-bot-api&quot;: &quot;^0.61.0&quot;
  },
  &quot;scripts&quot;: {
    &quot;dev&quot;: &quot;nodemon ./index.js&quot; // &lt;&lt;&lt;&lt;&lt;
  }
}</pre>
  <p id="CKq2">в помеченной строке мы создаем скрипт dev который будет за нас вызывать команду <code>nodemon ./index.js</code>, мы будем включать бота так — <code>yarn dev</code></p>
  <p id="ZC8U">в скрипте мы говорим <code>nodemon</code> чтобы он следил за обновлениями файла <code>index.js</code></p>
  <h3 id="zYdD">пишем первого простецкого бота</h3>
  <p id="WrwD">твой первый бот просто будет повторять за тобой сообщения, ниже я опубликую код для этого бота и мы с тобой разберем его по пунктам</p>
  <pre id="eMSB" data-lang="javascript">import TelegramBot from &#x27;node-telegram-bot-api&#x27;;

const TELEGRAM_BOT_TOKEN = &quot;...&quot;;
const bot = new TelegramBot(TELEGRAM_BOT_TOKEN, { polling: true });

bot.on(&#x27;message&#x27;, async (msg) =&gt; {
  const {
    chat: { id },
    text
  } = msg;
  
  await bot.sendMessage(id, text);
});</pre>
  <p id="qmIF">давай по порядку:</p>
  <pre id="CTdC" data-lang="javascript">import TelegramBot from &#x27;node-telegram-bot-api&#x27;;</pre>
  <p id="a3kU"><code>import</code> — директива которая запрашивает доступ к какой-либо библиотеке. здесь мы запрашиваем библиотеку <code>node-telegram-bot-api</code> через <code>import</code></p>
  <p id="dKZX">имей ввиду что <code>import</code> и <code>export</code> не работают если не указать в <code>package.json</code> <code>&quot;type&quot;: &quot;module&quot;</code></p>
  <pre id="TvIZ" data-lang="javascript">const TELEGRAM_BOT_TOKEN = &quot;...&quot;;</pre>
  <p id="2IH8">сюда тебе надо вставить токен который ты получил у <strong>BotFather</strong>. имена констант почти всегда пишутся капсом и используя <a href="https://medium.com/@alivander/camel-pascal-snake-case-%D0%B8-%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D0%B5-%D1%81%D1%82%D0%B8%D0%BB%D0%B8-%D0%BD%D0%B0%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D1%8F-288ec62ca0d0" target="_blank"><strong>snake_case</strong></a></p>
  <pre id="paMU" data-lang="javascript">const bot = new TelegramBot(token, { polling: true });</pre>
  <p id="pe6T">инициализируем бота, включаем поллинг апдейтов, это нужно для того чтобы бот постоянно можно сказать был на связи и получал все сообщения которые к нему поступают</p>
  <p id="B0iH">сам &quot;конструктор&quot; бота включает в себя 2 аргумента:</p>
  <ol id="yL13">
    <li id="uFuE">токен бота</li>
    <li id="Us4N">различные опции. полный список опций можно посмотреть <a href="https://github.com/yagop/node-telegram-bot-api/blob/master/doc/api.md#new_TelegramBot_new" target="_blank"><strong>тут</strong></a></li>
  </ol>
  <pre id="Bzf0" data-lang="javascript">bot.on(&#x27;message&#x27;, async (msg) =&gt; {});</pre>
  <p id="AMzY">с помощью метода <code>on</code> у бота ты можешь реагировать на различные обновления, будь-то обновления аватарки в канале, новый мембер в канале, новая гифка в личку бота и так далее. обновление в последующем я буду называть <strong>ивент</strong>. щас мы с тобой будем обрабатывать каждое сообщение которое приходит боту в лс с помощью ивента <code>message</code>. ивент <code>message</code> будет срабатывать каждый раз когда пишут боту в лс либо пишут в канал где есть бот</p>
  <p id="ww0R">метдо <code>on</code> принимает два аргумента:</p>
  <ol id="C9JZ">
    <li id="uSH1">ивент на который мы хотим реагировать</li>
    <li id="HVU6">колбек функция (она будет вызвана как только мы получим какой то апдейт по нашему ивенту, например, юзер написал сообщение - выполняется колбек функция). в моем случае она асинхронная (<code>async</code>), об этом позже</li>
  </ol>
  <p id="zqQL">колбек функция хранит в себе один аргумент — это само сообщение юзера <code>msg</code> с дополнительной информацией</p>
  <pre id="LQoq" data-lang="javascript">const {
  chat: { id },
  text
} = msg;</pre>
  <p id="gILI"><a href="https://learn.javascript.ru/destructuring" target="_blank"><strong>деструктуризируем</strong></a> объект <code>msg</code> и получаем оттуда chat id и текст сообщения</p>
  <pre id="o7kW" data-lang="javascript">await bot.sendMessage(id, text);</pre>
  <p id="hScv">и наконец отправляем сообщение, повторяющее текст юзера используя метод <code>sendMessage</code></p>
  <p id="a1N0">метод <code>sendMessage</code> принимает три аргумента:</p>
  <ol id="U7On">
    <li id="kCW4">chat id — идентификатор чата которому бот отправит сообщение. когда юзер пишет боту, и на бота навесили обработчик сообщений, в объекте <code>msg</code> из функции обработчика всегда есть chat id, то есть идентификатор юзера который написал это сообщение</li>
    <li id="Y8RY">текст сообщения</li>
    <li id="v2h1">опции отправки сообщений от бота, но об этом позже</li>
  </ol>
  <p id="hflK">запускаем бота с помощью команды <code>yarn dev</code> и идем писать боту</p>
  <figure id="IngP" class="m_column">
    <img src="https://img4.teletype.in/files/35/52/35524e99-798a-4524-bfd3-e87c0fb58b40.png" width="2070" />
    <figcaption>оп</figcaption>
  </figure>
  <p id="5G6w">вуаля! бот должен повторять все сообщения которые ты ему пишешь</p>
  <hr />
  <h2 id="Z4en">пишем славу бот</h2>
  <p id="Q5rr">итак, давай набросаем логику для бота:</p>
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <ol id="xqnM">
      <li id="A6AU">юзер будет запускать бота и бот будет выдавать приветственное сообщение с информацией о том как им пользоваться</li>
      <li id="k5Qc">юзер будет писать условно <code>1 eth</code> и бот будет выдавать ему курс в долларах на введенную монету</li>
      <li id="Glkb">предотвратим потенциальные ошибочные сценарии</li>
    </ol>
  </section>
  <p id="nSh0">погнали!</p>
  <hr />
  <h3 id="xR2w">создаем бота в BotFather</h3>
  <p id="Mral">здесь все дефолтно и уже знакомо. просто создаем бота и получаем токен</p>
  <h3 id="YnCB">создаем приветственное сообщение</h3>
  <p id="wuB2">как только юзер вводит команду <code>/start</code> мы будем показывать ему приветственное сообщение о том как пользоваться ботом</p>
  <pre id="EEP7" data-lang="javascript">import TelegramBot from &#x27;node-telegram-bot-api&#x27;;

const TELEGRAM_BOT_TOKEN = &#x27;...&#x27;; // токен
const bot = new TelegramBot(TELEGRAM_BOT_TOKEN, { polling: true });

const welcomeMessage = &#x60;привет\! я бот для чека курсов криптовалют \- клон славы
как это работает?
\&gt; ты пишешь &lt;code&gt;1 eth&lt;/code&gt;
\&gt; бот отвечает
Ethereum &lt;code&gt;(ETH)&lt;/code&gt;:
&lt;code&gt;$ 1,641&lt;/code&gt;
&lt;code&gt;₽ 124,716&lt;/code&gt;&#x60;;

bot.onText(/\/start/, (msg) =&gt; {
  const {
    chat: { id }
  } = msg;
  
  bot.sendMessage(id, welcomeMessage, {
    parse_mode: &#x27;HTML&#x27;
  });
});</pre>
  <p id="NRh9">не забудь вставить свой токен в переменную <code>token</code></p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="4rUd"><code>welcomeMessage</code></p>
    <p id="VawZ">в эту переменную я кладу приветственное сообщение. давай разберем его</p>
    <p id="3WcK">я использую кривые кавычки <code>&#x60;&#x60;</code> — это нужно для того чтобы я не трахал мозги с тем как <a href="https://code-basics.com/ru/languages/javascript/lessons/string-concatenation" target="_blank"><strong>конкатенировать</strong></a> строки и не было необходимости писать каждый раз <code>\n</code> для пропуска строки на следующую так как кривые кавычки сохраняют все отступы и <a href="https://ru.wikipedia.org/wiki/%D0%9F%D0%B5%D1%80%D0%B5%D0%B2%D0%BE%D0%B4_%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8" target="_blank"><strong>line breaks</strong></a></p>
    <p id="Uhhm">все специальные знаки которые пишет бот в телеграм должны быть написаны с обратным слэшем (<code>\</code>) перед ними. это нужно грубо говоря для того чтобы парсер библиотеки не путался в символах и понимал какой символ где и что мы действительно имели ввиду, так как символы во первых могут повторяться, например как в js кавычки в кавычках (&quot;qwe &quot;lolol&quot;&quot; &lt;- ты не можешь так написать, парсер запутается где нужные кавычки и почему строка в строке). поэтому ты &quot;предохраняешь&quot; нужный символ слэшем, давая понять парсеру что это ты специально кавычки поставил, а не случайно, то есть -&gt; <code>&quot;qwe \&quot;lolol\&quot;&quot;</code>, так будет работать</p>
    <p id="xPaP">также если ты знаешь хтмл ты мог заметить использование тега <code>code</code>. дело в том, что в сообщениях можно применять два метода форматирования, а именно <strong>Markdown</strong> и <strong>HTML</strong>. то есть ты можешь делать текст жирным, курсивным и так далее с помощью <strong>Markdown</strong> или <strong>HTML</strong></p>
    <p id="Nmhz">-&gt; <a href="https://lifehacker.ru/chto-takoe-markdown/" target="_blank"><strong>что такое Markdown?</strong></a></p>
    <p id="ztmP">с помощью тега <code>code</code> я меняю шрифт в некоторых местах (с тикером и с цифрами) на <strong><a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%BD%D0%BE%D1%88%D0%B8%D1%80%D0%B8%D0%BD%D0%BD%D1%8B%D0%B9_%D1%88%D1%80%D0%B8%D1%84%D1%82" target="_blank">monospace</a></strong>. так нагляднее видно цифры и остальные &quot;технические&quot; детали</p>
  </section>
  <p id="C9Tb">двигаем дальше</p>
  <pre id="EfNn" data-lang="javascript">bot.onText(/\/start/, (msg) =&gt; {
  //...
});</pre>
  <p id="1192">тут я говорю боту — поставь обработчик если юзер написал текст <code>/start</code></p>
  <p id="t7un">как видишь здесь я тоже ставлю обратный слэш, это еще один из примеров использования <strong>escape character</strong></p>
  <pre id="4r4R" data-lang="javascript">bot.sendMessage(id, welcomeMessage, {
  parse_mode: &#x27;HTML&#x27;
});</pre>
  <p id="AHM4">затем я просто отправляю сообщение с единственной помаркой. я указал в опциях <code>parse_mode: &#x27;HTML&#x27;</code></p>
  <p id="xowd">это нужно для того чтобы бот отформатировал сообщение используя HTML, так как мы используем HTML форматирование в нашем сообщении. если не указать эту опцию получится вот это:</p>
  <figure id="trsp" class="m_column">
    <img src="https://img2.teletype.in/files/5c/a2/5ca2d913-d862-4e73-a067-fe89d1561d3e.png" width="2088" />
    <figcaption>вообще ничего не отформатировано</figcaption>
  </figure>
  <p id="ZRYG">теперь если указать обратно:</p>
  <figure id="sTIO" class="m_column">
    <img src="https://img3.teletype.in/files/ee/28/ee282f1f-8cb6-45b1-8ef8-1d9d41669390.png" width="2078" />
    <figcaption>красота</figcaption>
  </figure>
  <h3 id="IoTG">пишем логику обработки ввода от юзера</h3>
  <p id="kwFd">нам нужно сделать так чтоб бот умел преобразовывать пользовательский ввод в вид данных с помощью которого мы сможем получать информацию из биржи, а точнее:</p>
  <p id="XtOA">если юзер написал <code>1 eth</code>, мы должны дать понять боту где количество монет, а где символ монеты</p>
  <pre id="aSZL" data-lang="javascript">bot.on(&#x27;message&#x27;, (msg) =&gt; {
  const {
    text
  } = msg;
  
  const [strAmount, symbol] = text.split(&#x27; &#x27;);
  const isAmountValid = !/\D/g.test(strAmount);
  if (isAmountValid) {
    const amount = parseFloat(amount);
    // amount - количество монет, symbol - тикер монеты
  }
});</pre>
  <p id="dHOX">процедура обработчика ничем не поменялась, все знакомо. давай дальше</p>
  <pre id="lB3f" data-lang="javascript">const [strAmount, symbol] = text.split(&#x27; &#x27;);</pre>
  <p id="ZlzP">здесь мы используем метод <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/split" target="_blank"><strong>split</strong></a> у строки. работает это следующим образом:</p>
  <section style="background-color:hsl(hsl(170, 33%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="kX52">Array.split</h3>
    <p id="CfDJ">юзер вводит <code>420 eth</code></p>
    <p id="nQUh">количество монет (<code>420</code>) и символ (<code>eth</code>) разделяет пробел. метод split работает так, что он <strong>&quot;нарезает&quot;</strong> строку по <strong>разделителю</strong> на массив строк. пример:</p>
    <p id="L5jm"><code>&#x27;a b o b a&#x27;.split(&#x27; &#x27;)</code> </p>
    <p id="VrPM">даст нам следующий результат</p>
    <p id="JIvz"><code>[&#x27;a&#x27;, &#x27;b&#x27;, &#x27;o&#x27;, &#x27;b&#x27;, &#x27;a&#x27;]</code></p>
    <p id="G7of">и также:</p>
    <p id="OvYy"><code>&#x27;a-b-o-b-a&#x27;.split(&#x27;-&#x27;)</code> -&gt; <code>[&#x27;a&#x27;, &#x27;b&#x27;, &#x27;o&#x27;, &#x27;b&#x27;, &#x27;a&#x27;]</code></p>
    <hr />
    <p id="jyur">в нашем случае:</p>
    <p id="0Sbt"><code>&#x27;420 eth&#x27;.split(&#x27; &#x27;)</code> -&gt; <code>[&#x27;420&#x27;, &#x27;eth&#x27;]</code></p>
  </section>
  <pre id="3hHI" data-lang="javascript">const isAmountValid = !/\D/.test(strAmount);</pre>
  <p id="OGnn">разве мы можем доверять юзеру? конечно нет. он может ввести туда случайно не цифру, а что то другое. и чтобы наш бот не ломался, нам нужно определить точно ли юзер ввел цифру в начале. здесь получилась на первый взгляд страшная конструкция, но ща я разберу тебе ее и все прояснится</p>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="GeQO">давай начнем с конструкции</p>
    <pre id="zBTE" data-lang="javascript">/\D/g.test(strAmount)</pre>
    <p id="lMfM">здесь я использую <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Regular_Expressions" target="_blank"><strong>регулярное выражение</strong></a></p>
    <p id="8kFJ">говоря кратко, регулярки нужны для того чтобы искать комплексные и необязательно комплексные конструкции в строках и что то с ними делать, как то их преобразовывать и тд</p>
    <p id="y0BV">в нашем случае я применил регулярное выражение &quot;есть ли в строке не цифра&quot;</p>
    <p id="pNee">чтобы написать регулярное выражение тебе нужно два слэша <code>/aboba/</code> &lt;- в данном случае регулярное выражение способно искать сочетание символов aboba в строках</p>
    <p id="1NJC">конструкция <code>\D</code> отвечает за то чтобы искать все символы кроме цифр (то есть не цифра). со всеми конструкциями и в целом регулярками можно ознакомиться по ссылке выше. регулярки — мастхев!</p>
    <p id="nwI7">далее за регуляркой следует метод <code>test</code> который ищет все совпадения регулярки в строке. в нашем случае это звучит так — есть ли не цифры в строке? метод <code>test</code> возвращает булево значение, то есть <code>true</code> или <code>false</code></p>
    <hr />
    <p id="Hu9q">и наконец, символ <code>!</code> обозначает &quot;не&quot;. то есть если наша регулярка нашла не цифру, значит то что ввел юзер не является корректным числом так как там есть не цифра. нам же нужно что то делать только если регулярка не нашла не цифру (<code>false</code>), мы преобразуем <code>false</code> в <code>true</code> используя <code>!</code></p>
    <p id="NvvF"><code>!false</code> = <code>true</code></p>
    <p id="M12q"><code>!true</code> = <code>false</code></p>
  </section>
  <pre id="9TPu" data-lang="javascript">if (isAmountValid) {
  const amount = parseFloat(amount);
  // amount - количество монет, symbol - тикер монеты
}</pre>
  <p id="bdlN">если цифра корректная, мы преобразуем строку в число с которым можно проводить математические операции используя parseFloat</p>
  <p id="unjG">почему <code>parseFloat</code>, а не <code>parseInt</code>? <code>parseFloat</code> учитывает знаки после запятой (например, <code>3.5 sol</code>), тогда как <code>parseInt</code> округляет число до целого</p>
  <p id="Vdxz">оп, вот мы и получили нужные данные от юзера!</p>
  <h3 id="6MGy">пишем логику получения данных о монете</h3>
  <p id="MwqE">мы с тобой будем использовать CoinMarketCap API для получения инфы о цене. как это вообще работает? ну, твоему боту нужно получать данные из внешнего мира, хранящиеся на чьих-то серверах, да не просто на чьих-то, а на серверах тех, кто еще и предоставляет API для доступа к данным. API — это то благодаря чему ты можешь взаимодействовать с серверами, также API описывает как эти данные получать и в каком виде ты их будешь получать. часто для API бывает нужен API ключ, который ты получаешь допустим на нужном сайте, который принадлежит владельцу API. с помощью API ключа сервер дает тебе возможность делать запросы, без него это было бы невозможно</p>
  <p id="DhDe">гуглим CoinMarketCap API, переходим по <a href="https://coinmarketcap.com/api/" target="_blank"><strong>этой</strong></a> ссылке, жмем <strong>GET YOUR API KEY NOW</strong></p>
  <figure id="0tV5" class="m_column">
    <img src="https://img3.teletype.in/files/6c/72/6c724b4d-c28d-47f5-89b9-acfc37c8f253.png" width="1230" />
    <figcaption>The world&#x27;s cryptocurrency data authority has a professional API made for you. Ок...</figcaption>
  </figure>
  <p id="ctN4">получаем ключ (он должен быть в твоем дашборде после регистрации бемс демс) и едем дальше</p>
  <p id="tfL8">нам нужно разобраться как пользоваться этим API и как получить цену на нужную нам крипту используя <a href="https://coinmarketcap.com/api/documentation/v1/#section/Introduction" target="_blank"><strong>документацию</strong></a></p>
  <p id="1oMG">открыв ссылку и пролистав до Quick Start Guide мы видим примеры запросов на разных языках программирования</p>
  <figure id="GD43" class="m_column">
    <img src="https://img3.teletype.in/files/2f/f1/2ff10c96-13df-41a5-87b4-b688e61a5c3b.png" width="1272" />
    <figcaption>пример запроса на js</figcaption>
  </figure>
  <p id="N3fM">здесь в примере используется библиотека <code>axios</code>, поверхностно у нее мало отличий от <code>got</code>, который мы будем использовать. эти библиотеки нужны для того чтобы связываться с сервером, проще говоря HTTP клиент (типа <a href="https://learn.javascript.ru/fetch" target="_blank"><strong>fetch</strong></a> в js, только круче)</p>
  <section style="background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="qYbq">структура запроса следующая:</p>
    <pre id="0nNJ" data-lang="javascript">await axios.get(&#x27;https://sandbox-api.coinmarketcap.com/v1/cryptocurrency/listings/latest&#x27;, {
  headers: {
    &#x27;X-CMC_PRO_API_KEY&#x27;: &#x27;b54bcf4d-1bca-4e8e-9a24-22ff2c3d462c&#x27;,
  }
});</pre>
    <p id="Cntr">первым аргументом указывается URL по которому мы будем стучать к серверу, а точнее эндпоинт</p>
    <h3 id="mARD">что такое эндпоинт?</h3>
    <p id="hASI">API может иметь несколько эндпоинтов. благодаря эндпоинтам происходит разделение данных по &quot;коробкам&quot;, типа по &quot;местам&quot;. например, получить категории можно по одной ссылке, а вот цена на монету уже по другой ссылке. это сделано для того чтобы разработчик не получал в одном эндпоинте большую кипу ненужной ему информации, а подтягивал лишь то что нужно</p>
    <p id="Q60G">в примере выше эндпоинтом является <code>cryptocurrency/listings/latest</code></p>
    <p id="eLgG">этот эндпоинт позволяет нам получить данные о последних листингах монет</p>
    <hr />
    <p id="tdnV">вторым аргументом указываются опции, среди которых единственная опция <strong>headers</strong></p>
    <h3 id="98Qq">что такое headers?</h3>
    <p id="QthY"><strong>headers</strong> — заголовки, которые клиент отправляет серверу. клиент — это наш бот в этом случае. заголовки нужны для того чтобы передавать серверу периферийную информацию не относяющуюся к эндпоинту (к эндпоинту непосредственно относится такая информация как символ монеты, цену на которую мы хотим получить)</p>
    <p id="4ACd">в данном случае в заголовках указан один <code>X-CMC_PRO_API_KEY</code> — сюда мы вставим наш апи ключ, иначе сервер нас не пустит</p>
    <p id="VdNT">в большинстве своем апи ключи вставляются в <strong>headers</strong></p>
  </section>
  <p id="CcL1">окей с тем как делать запрос разобрались, давай теперь найдем нужный нам эндпоинт!</p>
  <p id="ppJi">полистав немного вниз в документации API, мы можем найти вкладку <strong>Cryptocurrencies</strong>, а внутри эндпоинт <strong>Quotes Latest v2</strong> — то что нам нужно!</p>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="j81F"><strong>небольшое примечание</strong></p>
    <p id="yr3C">на самом деле можно и правильнее будет использовать эндпоинт <strong><a href="https://coinmarketcap.com/api/documentation/v1/#operation/getV2CryptocurrencyOhlcvLatest" target="_blank">OHLCV Latest v2</a></strong>, так как нам нужны лишь цены, но дело в том что он <strong>заблокирован</strong> для использования простыми смертными</p>
    <figure id="qB5J" class="m_retina" data-caption-align="center">
      <img src="https://img4.teletype.in/files/3a/13/3a1343f1-ad0b-47f2-a61d-58f522675811.png" width="381" />
      <figcaption>булщит</figcaption>
    </figure>
  </section>
  <p id="OPu7">внутри мы видим URL по которому мы можем обратиться к эндпоинту, а также пролистав ниже мы видим параметры которые мы можем передать ему</p>
  <figure id="7pDN" class="m_column">
    <img src="https://img4.teletype.in/files/fe/e1/fee1fb70-5471-4f8a-9d72-00afe2e5c418.png" width="1290" />
    <figcaption>параметры эндпоинта</figcaption>
  </figure>
  <p id="E42j">среди них мы видим параметр symbol — это то что нам нужно для того чтобы получать цену на определенную крипту</p>
  <p id="MweT">создавай файл <code>api.js</code> где ты будешь хранить всю логику связанную с API</p>
  <p id="lklz">затем открывай консоль и давай подтянем нашу библиотеку <code>got</code></p>
  <pre id="agvg" data-lang="bash">yarn add got</pre>
  <p id="BbSj">с помощью этого зверька мы сможем делать запросы к любому API</p>
  <p id="nQy1">пишем код:</p>
  <pre id="SyEP" data-lang="javascript">import got from &#x27;got&#x27;;

const COINMARKETCAP_API_TOKEN = &#x27;...&#x27;; // твой токен

const client = got.extend({
  prefixUrl: &#x27;https://pro-api.coinmarketcap.com/v2&#x27;,
  headers: {
    &#x27;X-CMC_PRO_API_KEY&#x27;: COINMARKETCAP_API_TOKEN
  }
});

export const getCoinQuotes = async (symbol) =&gt; {
  const { data } = await client
    .get(&#x27;cryptocurrency/quotes/latest&#x27;, {
      searchParams: new URLSearchParams({
        symbol
      })
    })
    .json();

  const quote = data[symbol.toUpperCase()][0].quote;
  return quote;
}</pre>
  <p id="jARx">здесь мы инициализируем нашу библиотеку для запросов к серверу используя метод <code>extend</code></p>
  <pre id="jARx" data-lang="javascript">const client = got.extend({
  prefixUrl: &#x27;https://pro-api.coinmarketcap.com/v2&#x27;,
  headers: {
    &#x27;X-CMC_PRO_API_KEY&#x27;: COINMARKETCAP_API_TOKEN
  }
});</pre>
  <p id="7Zrp">-&gt; <a href="https://github.com/sindresorhus/got" target="_blank"><strong>документация got на github</strong></a></p>
  <p id="krJp">extend принимает объект с опциями, из которых мы используем:</p>
  <p id="CZOr"><code>prefixUrl</code> — здесь мы прописываем ссылку на API CoinMarketCap, чтобы не вставлять ее постоянно каждый раз когда мы хотим сделать запрос (библиотека будет вставлять его за нас). к примеру если эндпоинт выглядит так:</p>
  <pre id="xWIO">https://pro-api.coinmarketcap.com/v2/cryptocurrency/listings/latest</pre>
  <p id="E6zN">то <code>prefixUrl</code> будет являться <code>https://pro-api.coinmarketcap.com/v2</code></p>
  <p id="bB1x"><code>headers</code> — наши заголовки</p>
  <pre id="WA3R" data-lang="javascript">export const getCoinQuotes = async (symbol) =&gt; {
  const { data: usd } = await client
    .get(&#x27;cryptocurrency/quotes/latest&#x27;, {
      searchParams: new URLSearchParams({
        symbol
      })
    })
    .json();
  const coin = usd[symbol.toUpperCase()][0];
  const usdQuote = coin.quote.USD;

  const { data: rub } = await client
    .get(&#x27;cryptocurrency/quotes/latest&#x27;, {
      searchParams: new URLSearchParams({
        symbol,
        convert: &#x27;RUB&#x27;
      })
    })
    .json();
  const rubQuote = rub[symbol.toUpperCase()][0].quote.RUB;

  const name = coin.name;
  return {
    name: 
    usd: usdQuote,
    rub: rubQuote
  };
}</pre>
  <p id="c2EX">здесь мы объявляем функцию с помощью которой мы будем получать цены на введенный пользователем символ монеты</p>
  <section style="background-color:hsl(hsl(24,  24%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="JiaK">немного слов про async/await</h3>
    <p id="2Fj4">асинхронная функция — функция которая может выполняться не блокируя основной поток скрипта (то есть какие либо другие конструкции)</p>
    <p id="3kvy">в данном случае я объявил функцию асинхронной чтобы воспользоваться возможностью ждать до тех пор пока я не получу ответ с сервера</p>
    <p id="2cci">для того чтобы объявить функцию асинхронной достаточно добавить ключевое слово <code>async</code> перед аргументами</p>
    <p id="ubmB">-&gt; <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank"><strong>про Promise API в JavaScript</strong></a></p>
    <p id="jmxT">метод <code>get</code> возвращает <code>Promise</code> объект. объект <code>Promise</code> можно либо дождаться либо оставить его выполняться в потоке не блокируя другой код</p>
    <p id="sXBU">например, конструкция:</p>
    <pre id="dKAY" data-lang="javascript">const data = client.get(&#x27;...&#x27;);
console.log(&#x27;aboba&#x27;);</pre>
    <p id="3Euz">не будет ждать ответа сервера и сразу выведет aboba в консоль, а в переменной <code>data</code> будет храниться <code>Promise</code></p>
    <p id="e1ju">в свою очередь, конструкция:</p>
    <pre id="PwIi" data-lang="javascript">const data = await client.get(&#x27;...&#x27;);
console.log(&#x27;aboba&#x27;);</pre>
    <p id="fwvy">дождется ответа сервера и лишь потом выведет лог aboba, а в переменной <code>data</code> будет ответ сервера, а не <code>Promise</code></p>
    <p id="k27f"><strong>учти</strong> что ты не можешь использовать <code>await</code> просто так. <code>await</code> можно использовать лишь в асинхронной функции</p>
  </section>
  <pre id="H5sm" data-lang="javascript">const { data } = await client
  .get(&#x27;cryptocurrency/quotes/latest&#x27;, {
    searchParams: new URLSearchParams({
      symbol
    })
  })
  .json();</pre>
  <p id="EN7H">конструкция совсем не отличается от той что была в примере. единственное отличие — опция <code>searchParams</code> и вызов функции <code>json</code> после метода <code>get</code></p>
  <p id="aMdY">мы используем <code>searchParams</code> для того чтобы указать те самые параметры которые ты видел в доке (<code>id</code>, <code>symbol</code> и тд)</p>
  <p id="3jx9">создать эти параметры в удобном виде нам поможет <code>URLSearchParams</code></p>
  <p id="Efu3">работает это просто, в качестве аргумента мы кладем объект с параметрами</p>
  <p id="5xvF">затем мы по цепочке вызываем метод <code>json</code> для того чтобы преобразить ответ сервера в объект, который мы можем использовать для манипуляции с данными</p>
  <figure id="wvOW" class="m_retina" data-caption-align="center">
    <img src="https://img2.teletype.in/files/9d/2b/9d2bef24-3157-4b7f-9b23-f4a297cd7dd3.png" width="323" />
    <figcaption>так выглядит ответ сервера для эфира</figcaption>
  </figure>
  <p id="BepN">из ответа сервера нам нужен объект <code>data</code> поэтому мы его сразу деструктуризируем</p>
  <p id="dIFk">сохраним данные по монете в переменную <code>coin</code>, затем сохраняем подробности о цене, объеме и тд в долларах в переменную <code>usdQuote</code></p>
  <pre id="BepN" data-lang="javascript">const coin = usd[symbol.toUpperCase()][0];
const usdQuote = coin.quote.USD;</pre>
  <p id="NcTp">здесь мы получаем информацию о монете в долларах, также ниже мы делаем еще один запрос, только в этот раз добавляем опцию в <code>URLSearchParams</code>:</p>
  <pre id="Z7qM" data-lang="javascript">convert: &#x27;RUB&#x27;</pre>
  <p id="Rtve">для конвертации цены в рубли</p>
  <p id="PiJW">у них странно работает API в этом плане, потому что я должен делать два запроса для того чтобы получить инфу в долларах и в рублях, но да ладно, не страшно</p>
  <p id="ZHE3">и наконец, сохраняем полное имя монеты в переменную <code>name</code>:</p>
  <pre id="EWVg" data-lang="javascript">const name = coin.name;</pre>
  <p id="khX4">надеюсь ты не запутался, потому что мы сделали два вызова, один для долларового эквивалента, другой для рублевого. информация по монете (то есть имя) хранится по сути в обоих объектах, я просто решил достать полное имя из первого вызова (<code>coin.name</code>)</p>
  <p id="RPuj">в конечном итоге если мы вызовем нашу функцию с аргументом <code>ETH</code>, то получим следующий объект:</p>
  <figure id="kVpB" class="m_retina" data-caption-align="center">
    <img src="https://img3.teletype.in/files/a5/99/a599e106-a40b-4eb2-a01a-f3f656c6469f.png" width="363" />
    <figcaption>оп оп цены объемы все дела</figcaption>
  </figure>
  <p id="jYpK">ну теперь мы можем ответить юзеру!</p>
  <h3 id="QqJv">отвечаем юзеру котировками пон</h3>
  <p id="P2JY">прежде чем мы допишем код для бота давай подумаем как форматировать цифры которые мы будем отображать юзеру, потому что числа в объекте с ценой и тд очень громоздкие (например,  <code>122526.61682949228</code>)</p>
  <p id="MILV">давай создадим файл <code>utils.js</code> и в нем напишем функцию форматирования наших чисел в более менее удобочитаемый вид:</p>
  <pre id="p7Mm" data-lang="javascript">const SMALL_NUMBER_DECIMALS = 4;

export const formatNumber = (number, decimals) =&gt;
  parseFloat(
    number.toFixed(number &lt; 10 ? SMALL_NUMBER_DECIMALS : decimals)
  ).toLocaleString(&#x27;en-US&#x27;);</pre>
  <p id="FoLy">внутри функции мы сначала приводим в порядок числа после запятой. если число меньше 10, нам нужно 4 (SMALL_NUMBER_DECIMALS) знака после запятой как минимум, если число больше, то приводим как будет указано при вызове функции</p>
  <p id="Nini">после того как мы привели в порядок числа после запятой, мы используем функцию <code>parseFloat</code> чтобы убрать лишние нули в конце, если они есть</p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="sShr">как работает <code>toFixed</code></h3>
    <p id="1Vot">если использовать <code>toFixed</code> с числом <code>1.1</code> желая получить <strong>5</strong> знаков после запятой то получится следующая картина:</p>
    <pre id="31xJ" data-lang="javascript">(1.1).toFixed(5) // = &quot;1.10000&quot; Wtf?</pre>
    <p id="Olzj">нам не нужны пустые нули в конце, поэтому используем <code>parseFloat</code> который их уберет, заодно приведет строку в число</p>
  </section>
  <p id="xNU2">и наконец, мы используем <code>toLocaleString(&#x27;en-US&#x27;)</code> чтобы жиэс добавил за нас запятые после каждого числового разряда</p>
  <p id="ywGp">выглядит это так:</p>
  <pre id="kkOl" data-lang="javascript">(1500).toLocaleString(&#x27;en-US&#x27;) // &quot;1,500&quot; good</pre>
  <p id="zcgV">теперь возвращаемся в <code>index.js</code></p>
  <p id="UWSd">импортируем обе наши функции (иначе мы не сможем получить к ним доступ из другого файла)</p>
  <p id="i42f">в самом верху после импорта <code>node-telegram-bot-api</code> пишем</p>
  <pre id="6HF7" data-lang="javascript">import { getCoinData } from &#x27;./api.js&#x27;
import { formatNumber } from &#x27;./utils.js&#x27;</pre>
  <p id="wkVZ">теперь мы можем продолжить дальше</p>
  <pre id="KsTL" data-lang="javascript">if (isAmountValid) {
  const amount = parseFloat(strAmount);
  
  if (amount &gt; 0) {
    const {
      name,
      usd: { price: usdPrice, percent_change_24h: usdPercentChange24h },
      rub: { price: rubPrice, percent_change_24h: rubPercentChange24h }
    } = await getCoinData(symbol);
    
    await bot.sendMessage(
      id,
      &#x60;${amount} ${name} (&lt;code&gt;${symbol.toUpperCase()}&lt;/code&gt;):
&lt;code&gt;$ ${formatNumber(usdPrice * amount, 1)} | ${usdPercentChange24h.toFixed(2)%&lt;/code&gt;
&lt;code&gt;₽ ${formatNumber(rubPrice * amount, 0)} | ${rubPercentChange24h.toFixed(2)}%&lt;/code&gt;
      &#x60;,
      {
        parse_mode: &#x27;HTML&#x27;
      }
    );
  }
}</pre>
  <p id="bfzR">прежде чем делать какие то конвертации, надо убедиться что юзер не ввел <code>0 eth</code> или <code>-1 eth</code></p>
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="JRcy">основное правило разработки чего либо</h3>
    <p id="Icdv">когда ты разрабатываешь какую то штуку, смотри на код с позиции того как можно его сломать</p>
  </section>
  <p id="lD0B">в связи с этим я добавил правило <code>if (amount &gt; 0)</code> в код для того чтобы проверять что юзер вводит натуральное число</p>
  <pre id="0duz" data-lang="javascript">const {
  name,
  usd: { price: usdPrice, percent_change_24h: usdPercentChange24h },
  rub: { price: rubPrice, percent_change_24h: rubPercentChange24h }
} = await getCoinData(symbol);</pre>
  <p id="sMTv">здесь мы вызываем нашу функцию из <code>api.js</code> и передаем туда символ который ввел юзер, после чего деструктуризируем результат функции и получаем имя и рублевые/долларовые цены на данный момент + изменения цены за сутки</p>
  <p id="tbCE">не забываем <code>await</code> иначе бот не дождется результата вызова API и возникнет ошибка</p>
  <pre id="gqDV" data-lang="javascript">await bot.sendMessage(
  id,
  &#x60;${amount} ${name} (&lt;code&gt;${symbol.toUpperCase()}&lt;/code&gt;):
&lt;code&gt;$ ${formatNumber(usdPrice * amount, 1)} | ${usdPercentChange24h.toFixed(2)%&lt;/code&gt;
&lt;code&gt;₽ ${formatNumber(rubPrice * amount, 0)} | ${rubPercentChange24h.toFixed(2)}%&lt;/code&gt;
  &#x60;,
  {
    parse_mode: &#x27;HTML&#x27;
  }
);</pre>
  <p id="mCB9">и здесь мы наконец пишем ответ юзеру, используем нашу утилиту <code>formatNumber</code>, преобразовываем введеный юзером символ в капс методом <code>toUpperCase()</code> и прибираем порядок числа после запятой у процентных соотношений. все это мы уже с тобой прошли. естественно, не забываем указать <code>parse_mode</code></p>
  <p id="cjpB">тестируем!</p>
  <figure id="zBgH" class="m_column">
    <img src="https://img1.teletype.in/files/8a/6c/8a6c8f5a-20af-44d6-a189-c567ba02da67.png" width="2082" />
    <figcaption>тест тест тест</figcaption>
  </figure>
  <p id="zoYA">все збс работает, но есть одно но. юзер может ввести не только не натуральное число, но еще и несуществующий символ типа запросто</p>
  <p id="BWvn">если щас попробовать с ботом что то в духе <code>1 dolbaeb</code> то хорошим ничем для него это не закончится</p>
  <p id="HFp1">поэтому давай сделаем так что если пользователь вводит несуществующую монету то просто не будем ничего выводить. нам нужно добавить обработчик потенциальной ошибки в то место где мы запрашиваем данные о символе</p>
  <pre id="L9MD" data-lang="javascript">if (amount &gt; 0) {
  try {
    const {
      name,
      usd: { price: usdPrice, percent_change_24h: usdPercentChange24h },
      rub: { price: rubPrice, percent_change_24h: rubPercentChange24h }
    } = await getCoinData(symbol);
    
    await bot.sendMessage(
      id,
      &#x60;${amount} ${name} (&lt;code&gt;${symbol.toUpperCase()}&lt;/code&gt;):
&lt;code&gt;$ ${formatNumber(usdPrice * amount, 1)} | ${usdPercentChange24h.toFixed(2)%&lt;/code&gt;
&lt;code&gt;₽ ${formatNumber(rubPrice * amount, 0)} | ${rubPercentChange24h.toFixed(2)}%&lt;/code&gt;
      &#x60;,
      {
        parse_mode: &#x27;HTML&#x27;
      }
    );
  } catch (e) {
    console.error(e);
  }
}</pre>
  <p id="6M1d">используем <code>try...catch</code> конструкцию (подробнее про это читать <a href="https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/try...catch" target="_blank"><strong>тут</strong></a>) для того чтобы отловить ошибку в момент ее возникновения тем самым предотвратив падение бота. ошибка просто высветится в консоль</p>
  <figure id="AZff" class="m_column">
    <img src="https://img3.teletype.in/files/63/9d/639d9bd0-f9d9-49db-96fb-698684e7b2b9.png" width="2098" />
    <figcaption>так то лучше</figcaption>
  </figure>
  <h3 id="Aixf">поздравляю! ты написал почти клона славы!</h3>
  <p id="nYO5">в целом бота можно даже добавить в свой чат, конечно же его надо будет подправить чтоб он не сьедал и не пытался конвертировать каждое попавшееся сообщение типа &quot;20 бананов&quot; или &quot;я гей&quot; в общем ты понял</p>
  <p id="EuYD">мои большие поздравления если у тебя удалось все написать! 🎉</p>
  <p id="t5Ia">весь код доступен здесь -&gt; <a href="https://file.io/LonWaVbNBHQ5" target="_blank"><strong>https://file.io/LonWaVbNBHQ5</strong></a></p>
  <figure id="iAxx" class="m_column" data-caption-align="center">
    <img src="https://blobcdn.same.energy/d/c6/f7/c6f7d52d1f5317d0d0306c4f71276923a1f4b9f8" width="540" />
    <figcaption>отдохнем, посозерцаем на ахуенный пиксельартик</figcaption>
  </figure>
  <hr />
  <h2 id="XMgv">пишем бот агрегатор каналов</h2>
  <p id="gy2S">так, вот тут задача не менее интересная. начнем с того что телеграм бот не может переслать сообщения из какого либо канала так как у него просто напросто нет возможностей читать посты каналов, также как и сажать обычно бота в какие либо паблики с целью прочесть что то оттуда</p>
  <p id="Fd0O">для таких задач используется более &quot;умная&quot; если можно так выразиться версия бота, проще говоря — просто телеграм клиент в жиэс. то есть мы будем поднимать прям дефолтный телеграм клиент используя жиэс и библиотеку <a href="https://github.com/gram-js/gramjs" target="_blank"><strong>gramjs</strong></a></p>
  <section style="background-color:hsl(hsl(24,  24%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="YpVd">план следующий:</p>
    <ol id="QZfe">
      <li id="C9Hu">получаем API ID и хэш (для того чтобы бот мог дергать аккаунт)</li>
      <li id="N6cB">логинимся в нашем боте в телеграм используя телефон + пароль + код из уведомления при входе</li>
      <li id="jQnq">подписываемся на обновления какого либо канала (мы создадим канал чисто для этого)</li>
      <li id="iTGz">аккаунт будет репостить сообщения в другой канал агрегатор</li>
      <li id="icK2">профит</li>
    </ol>
  </section>
  <p id="0bP6">приступим!</p>
  <h3 id="1qWh">получаем API ID и хэш</h3>
  <p id="BjGD">переходим на <a href="https://my.telegram.org" target="_blank"><strong>https://my.telegram.org</strong></a> и логинимся</p>
  <p id="zTiU">жмем <strong>API Development tools</strong></p>
  <figure id="sRho" class="m_retina" data-caption-align="center">
    <img src="https://img4.teletype.in/files/76/ec/76ece27c-d031-4e6a-b3f9-a2899bb055b6.png" width="444" />
    <figcaption>сидит лыбит</figcaption>
  </figure>
  <p id="L79c">устанавливаем App title (название бота) и Short name (типа никнейм)</p>
  <figure id="8mu1" class="m_retina" data-caption-align="center">
    <img src="https://img2.teletype.in/files/da/44/da445c5d-9f80-442c-8cef-09c79a048931.png" width="591" />
    <figcaption>оп оп</figcaption>
  </figure>
  <p id="Nxn7">выше будут твой id и hash, ты будешь использовать их чтобы бот получил доступ к аккаунту</p>
  <h3 id="oTLy">готовим окружение</h3>
  <p id="GJQh">в целом все то же самое как и с клоном славы, единственное что вместо <code>node-telegram-bot-api</code> мы установим <code>telegram</code> и <code>input</code></p>
  <pre id="DNyE" data-lang="bash">yarn add telegram input</pre>
  <p id="o7M5"><code>telegram</code> — это сама библиотека gramjs</p>
  <p id="R9Km"><code>input</code> — будет использоваться для того чтобы залогиниться в аккаунт, а точнее чтобы мы могли ввести номер, пароль, код для аутентификации</p>
  <h3 id="rYva">коннектим бота к аккаунту</h3>
  <p id="8bIh">в файле <code>index.js</code> прописываем:</p>
  <pre id="JYXm" data-lang="javascript">import { TelegramClient } from &#x27;telegram&#x27;
import { StringSession } from &#x27;telegram/sessions/index.js&#x27;
import input from &#x27;input&#x27;

const apiId = 666666; // сюда пишешь API ID
const apiHash = &#x27;hash&#x27;; // сюда API hash
const stringSession = new StringSession(&#x27;&#x27;); // это объясню ниже

(async () =&gt; {
  const client = new TelegramClient(stringSession, apiId, apiHash, {
    connectionRetries: 5
  });

  await client.start({
    phoneNumber: async () =&gt; await input.text(&#x27;Введи номер телефона телеги: &#x27;),
    password: async () =&gt; await input.text(&#x27;Введи пароль: &#x27;),
    phoneCode: async () =&gt; await input.text(&#x27;Введи полученный код от телеги: &#x27;),
    onError: (err) =&gt; console.log(err)
  });
  console.log(client.session.save());
})();</pre>
  <p id="aBPd">начнем с того как мы инициализируем клиент</p>
  <pre id="6sIJ" data-lang="javascript">const client = new TelegramClient(stringSession, apiId, apiHash, {
  connectionRetries: 5
});</pre>
  <p id="mcU1">мы вызываем конструктор <code>TelegramClient</code> с аргументами сессии, API ID, API hash и объектом опций</p>
  <p id="aqmt">немного выше я прописал переменную <code>stringSession</code>. она нам понадобится как только мы залогинимся для того чтобы вставить туда токен сессии, чтобы не логиниться каждый раз заново. переменная <code>stringSession</code> будет использоваться в инициализации клиента</p>
  <p id="bVoV">теперь разберемся что дальше</p>
  <pre id="mnS1" data-lang="javascript">await client.start({
  phoneNumber: async () =&gt; await input.text(&#x27;Введи номер телефона телеги: &#x27;),
  password: async () =&gt; await input.text(&#x27;Введи пароль: &#x27;),
  phoneCode: async () =&gt; await input.text(&#x27;Введи полученный код от телеги: &#x27;),
  onError: (err) =&gt; console.log(err)
});</pre>
  <p id="tMvd">используя метод <code>start</code> мы можем законнектиться к аккаунту. метод <code>start</code> принимает объект свойств, а именно:</p>
  <ol id="TpuD">
    <li id="slXX"><code>phoneNumber</code> — номер телефона по которому логиниться</li>
    <li id="cqMz"><code>password</code> — пароль от аккаунта</li>
    <li id="FJOo"><code>phoneCode</code> — код который приходит на телефон (обычно в телеграм, можно сделать также код в смс)</li>
    <li id="aoOu"><code>onError</code> — просто колбек чтобы повесить обработчик в случае если произошла ошибка</li>
  </ol>
  <p id="R6uU">чтобы получить номер телефона, пароль и код уведомления мы используем библиотеку <strong><a href="https://www.npmjs.com/package/input" target="_blank">input</a></strong> чтобы мы могли вводить что то в консоль, то есть получать пользовательский ввод извне. также сразу бросается в глаза то, что перед <code>input.text</code> стоит <code>await</code>, что означает что скрипт должен ждать до тех пор пока юзер что то не введет</p>
  <pre id="IeSd" data-lang="javascript">console.log(client.session.save());</pre>
  <p id="DI9t">в этой строке мы отображаем в консоли токен сессии, который мы вставим в переменную <code>stringSession</code> после первого логина, чтобы не заходить в аккаунт по 500 раз</p>
  <p id="J1zG">запускай код, тебе будет предложено ввести номер телефона, вводи все данные, логинься. после успешного входа тебе выйдет сообщение что то типа <code>&quot;Signed in successfully&quot;</code>, в телегу придет уведомление о новом логине и в девайсе можно будет увидеть название твоего бота</p>
  <p id="4zFC">нас интересует строка которая отобразилась в консоли после всего, а именно длиннющая строка обозначающая токен сессии. копируй ее и вставляй в переменную stringSession следующим образом:</p>
  <pre id="4AtA" data-lang="javascript">const stringSession = new StringSession(&#x27;...token&#x27;);</pre>
  <p id="PO5W">после чего мы можем убрать конструкцию с <code>client.start</code> и <code>client.session.save</code> и написать логику подключения проще, тк у нас есть уже токен сессии по которому мы можем входить в аккаунт</p>
  <pre id="QAPJ" data-lang="javascript">import { TelegramClient } from &#x27;telegram&#x27;
import { StringSession } from &#x27;telegram/sessions/index.js&#x27;

const apiId = 666666;
const apiHash = &#x27;hash&#x27;;
const stringSession = new StringSession(&#x27;...token&#x27;);

(async () =&gt; {
  const client = new TelegramClient(stringSession, apiId, apiHash, {
    connectionRetries: 5
  });

  await client.connect();
})();</pre>
  <p id="lcU5">и о чудо! мы изи коннектимся к акку и готовы теперь манипулировать канальчиками и постами</p>
  <p id="LmOp">если у тебя возник вопрос откуда я взял эти функции, методы и тд, то этот пример можно свободно посмотреть в <a href="https://github.com/gram-js/gramjs" target="_blank"><strong>гитхабе</strong></a> библиотеки, в самом начале <strong>README</strong>, раздел <strong>How to get started</strong>, так что если что, читай внимательно и будь внимателен вообще — экономит время</p>
  <h3 id="FxyR">получаем инфу о постах в канале</h3>
  <p id="cYTN">для того чтобы получить какую то инфу нужно покопаться в документации какой либо штуки, помнишь? почти у всех технических штучек есть документации, поэтому не стесняйся гуглить. гуглить — мастхев. старайся уменьшать усилия, мы живем в мире где в интернете есть почти все что ты хочешь написать!</p>
  <p id="COWK">листаем гитхаб <strong>gramjs</strong> ниже и видим раздел с документацией</p>
  <figure id="ZBJy" class="m_column">
    <img src="https://img1.teletype.in/files/83/e9/83e9f36b-d171-4c7c-854f-4ebe58ddbc45.png" width="1678" />
    <figcaption>то что нужно!</figcaption>
  </figure>
  <p id="DY2S">переходим в <a href="https://gram.js.org/" target="_blank"><strong>документацию</strong></a>, бетка нам не нужна, тк там все может быть нестабильно и коряво, а мы тут не делаем единственного уникального в мире бота, поэтому хватит и стабильной</p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="00lL">задачка</h3>
    <p id="ox2W">найди метод, отвечающий за сообщения в каналах. ответ — под картинкой</p>
  </section>
  <figure id="KfCg" class="m_column">
    <img src="https://blobcdn.same.energy/a/81/b9/81b9f0691f9078672a3c00b96592460b0864805c" width="810" />
    <figcaption>красата да и только</figcaption>
  </figure>
  <p id="jEXy">правильный ответ — <code>channels.GetMessages</code></p>
  <p id="yd1M">если получилось — ты крут менчик! а если нет, то не парься, ведь все еще впереди, главное опыта набираться!</p>
  <p id="zApI">давай разберемся как работает метод <code>channels.GetMessages</code></p>
  <figure id="oBgj" class="m_retina" data-caption-align="center">
    <img src="https://img4.teletype.in/files/3c/9e/3c9ee375-a5f2-40ee-8672-48751eb2ab01.png" width="467" />
    <figcaption>параметры для метода</figcaption>
  </figure>
  <p id="hii2">в доке мы видим что метод принимает свойство <code>channel</code> где будет находиться ник канала, а также массив <code>id</code>, в который мы будем класть ID сообщения, контент которого хотим получить</p>
  <p id="zqaM">давай создадим тестовый канал, где будем делать посты, которые бот будет пересылать в другой канал</p>
  <figure id="CaQa" class="m_column">
    <img src="https://img4.teletype.in/files/b3/8a/b38a6edf-6ab0-47e2-81ea-248794e9f34c.png" width="1490" />
  </figure>
  <p id="7lSs">вместо нашего новосозданного канала позже мы будем парсить другие паблики</p>
  <p id="MbG0">возвращаемся к методу <code>channels.GetMessages</code>, а точнее параметру <code>id</code></p>
  <p id="WkIT">прежде чем что то переслать, нам нужно получить айди сообщения. сделать это можно скопировав ссылку на сообщение, в моем примере ссылка будет выглядеть так: <a href="https://t.me/testruburibotchannel/3" target="_blank">https://t.me/testruburibotchannel/3</a>, где <strong>testruburibotchannel</strong> — ник паблика, <strong>3</strong> — айди последнего сообщения</p>
  <p id="dwlH">давай попробуем получить контент поста, используя метод <code>channels.GetMessages</code></p>
  <section style="background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="zgJP">заметка</h3>
    <p id="G7rw">для наглядности я не буду переписывать весь предыдущий код подключения к аккаунту</p>
  </section>
  <pre id="NkUW" data-lang="javascript">import { Api, TelegramClient } from &#x27;telegram&#x27; // импортируем Api
// ...код
const result = await client.invoke(
  new Api.channels.GetMessages({
    channel: &#x27;testruburibotchannel&#x27;,
    id: [3]
  })
);
console.log(result);</pre>
  <p id="KDgk">сначала импортируем модуль <code>Api</code>, там хранятся методы для работы с аккаунтом, затем вызываем метод <code>GetMessages</code> как описано в документации, только с измененными параметрами и выводим результат в консоль</p>
  <figure id="m80e" class="m_retina">
    <img src="https://img4.teletype.in/files/30/9f/309fe885-86e6-491f-9e05-89ba23102a9f.png" width="505" />
    <figcaption>вот такой результат мы должны получить, и это еще не все</figcaption>
  </figure>
  <p id="2f0l">выводится большой объект с сообщениями, юзерами, чатами, топиками (это для супергрупп, где есть треды и тд)</p>
  <p id="S5Fr">нас интересует только массив <code>messages</code> в котором мы видим текст, время и остальная инфа о первом посте</p>
  <figure id="InGN" class="m_original" data-caption-align="center">
    <img src="https://img4.teletype.in/files/3c/02/3c020d3b-b53e-4142-a2c9-2f833334cffc.png" width="404" />
    <figcaption>также есть поле media, в котором хранятся картинки, гифки прикрепленные к посту</figcaption>
  </figure>
  <p id="WB9N">давай вытащим наше сообщение из массива <code>messages</code></p>
  <pre id="Lwhm" data-lang="javascript">// ...код
const result = await client.invoke(
  new Api.channels.GetMessages({
    channel: &#x27;testruburibotchannel&#x27;,
    id: [3]
  })
);
const post = result.messages[0].message;
console.log(post);</pre>
  <figure id="YM0l" class="m_original" data-caption-align="center">
    <img src="https://img4.teletype.in/files/f8/c6/f8c60d1e-fe3f-4494-9eb1-b1ab90252395.png" width="270" />
    <figcaption>получаем текст поста</figcaption>
  </figure>
  <p id="K3lh">супер! мы получили текст нужного нам поста!</p>
  <h3 id="d5cq">пересылаем пост из канала в канал</h3>
  <p id="3KUt">давай создадим канал агрегатор, в моем случае это — <a href="https://t.me/aggregatorruburi" target="_blank"><strong>https://t.me/aggregatorruburi</strong></a></p>
  <p id="II5w">у бота (или аккаунта) обязательно должен быть доступ к постам в канале, иначе переслать сообщение не получится</p>
  <p id="QGGt">ищем в документации gramjs что то связанное с forward message и находим <a href="https://gram.js.org/tl/messages/ForwardMessages#messagesforwardmessages" target="_blank"><strong>следующий</strong></a> метод:</p>
  <figure id="9HJr" class="m_retina" data-caption-align="center">
    <img src="https://img2.teletype.in/files/db/4b/db4bb652-717b-404a-827f-4c3e738cc607.png" width="376" />
    <figcaption>нам подходит</figcaption>
  </figure>
  <p id="3Dqo">читаем пример и параметры. в целом все что нам нужно это параметры <code>fromPeer</code>, <code>id</code>, <code>toPeer</code></p>
  <section style="background-color:hsl(hsl(170, 33%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <ul id="xrUJ">
      <li id="XDr8"><code>fromPeer</code> — ник канала откуда будем пересылать</li>
      <li id="hv7Q"><code>id</code> — массив айди сообщений которые пересылаем (можно указать несколько, в нашем случае один пост)</li>
      <li id="eegA"><code>toPeer</code> — ник канала куда пересылаем</li>
      <li id="g3KG"><code>dropAuthor</code> — указывать ли из какого канала пересылка (мы не будем это использовать, но если не хотите палить откуда пересылаете, указываете <code>dropAuthor</code> на <code>true</code>)</li>
    </ul>
  </section>
  <p id="4xzW">в целом там есть много интересных параметров, советую почитать если интересно</p>
  <p id="UzAY">пишем код для пересылки сообщения:</p>
  <pre id="NiVJ" data-lang="javascript">// ...код
await client.invoke(
  new Api.messages.ForwardMessages({
    fromPeer: &#x27;testruburibotchannel&#x27;,
    id: [3],
    toPeer: &#x27;aggregatorruburi&#x27;
  })
);</pre>
  <p id="3lTs">запускаем бота, и вуаля:</p>
  <figure id="wuRD" class="m_column">
    <img src="https://img1.teletype.in/files/8c/4b/8c4b9f4f-5f8d-4630-bf3d-56d989647d49.png" width="1244" />
    <figcaption>збс</figcaption>
  </figure>
  <p id="M0z5">окей, мы научились пересылать сообщения, но теперь надо сделать так, чтобы всякий раз когда появляется новый пост в канале за которым мы следим, бот автоматически его пересылал</p>
  <h3 id="BLAW">настраиваем автоматическую пересылку из одного канала</h3>
  <p id="N5kH">для того чтобы автоматически пересылать сообщения, боту нужно запоминать какой пост он переслал последним, и с какого вообще айди начинаются посты, которые бот начнет пересылать</p>
  <p id="bQpZ">помнишь, как мы копировали ссылку на сообщение? самый недавний пост был с айди <strong>3</strong>, значит боту надо дать понять, что все посты начиная с <strong>4</strong> мы пересылаем</p>
  <section style="background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="RpXi">почему 4?</h3>
    <p id="L6fm">последний пост был с айди <strong>3</strong>, бот не должен его пересылать так как он уже существует. он начнет следить за всеми постами начиная со <strong>следующего</strong> (то есть <strong>id = 4</strong>)</p>
  </section>
  <p id="sRUz">окей, тут разобрались</p>
  <p id="C0vM">для того чтобы бот постоянно следил за каналом, нам нужно постоянно проверять есть ли новый пост в канале. <strong>но</strong> <strong>как мы можем проверить появился ли новый пост в канале?</strong></p>
  <p id="RSer">мысль следующая: мы можем проверять не пустой ли пост с <strong>id последнего поста + 1</strong></p>
  <p id="QL1v">то есть, если крайний пост был <strong>3</strong>, боту надо проверять появился ли пост с <strong>id 4</strong></p>
  <p id="FNvU">давай попробуем написать код, который проверяет несуществующий пост с <strong>id 4</strong> в нашем примере</p>
  <pre id="S9iO" data-lang="javascript">const result = await client.invoke(
  new Api.channels.GetMessages({
    channel: &#x27;testruburibotchannel&#x27;,
    id: [4]
  })
);
console.log(result);</pre>
  <p id="TNiz">получаем следующий вывод в консоли и смотрим на массив <code>messages</code>, где хранятся полученные сообщения:</p>
  <figure id="Rfnc" class="m_retina" data-caption-align="center">
    <img src="https://img1.teletype.in/files/4e/50/4e508e71-3bc8-4376-9ce7-e761fd87d4f5.png" width="231" />
    <figcaption>MessageEmpty</figcaption>
  </figure>
  <p id="KM21">смотри, в массиве <code>messages</code> действительно есть сообщение, хотя его вроде по факту нет. но если посмотреть внимательнее, можно увидеть свойство <code>className</code> со значением <code>MessageEmpty</code>. так телега помечает пустые сообщения (а если сообщение пусто, значит его нет)</p>
  <p id="SsTS">таким образом мы можем понять появился ли новый пост в канале!</p>
  <p id="TheS">вернемся к тому, что бот должен следить и реагировать каждый раз когда пост все таки появляется. если есть какая то логика, связанная со &quot;следить&quot; в игру вступает <code>setInterval</code></p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="rk8n">setInterval</h3>
    <p id="LtyJ"><code>setInterval</code> используется для того чтобы выполнять какой либо код каждые <code>N</code> миллисекунд</p>
    <pre id="saBV" data-lang="javascript">setInterval(() =&gt; {
  console.log(&#x27;RUBURI&#x27;);
}, 1000);</pre>
    <p id="Tgum">этот код будет выводить в консоль <code>RUBURI</code> каждую секунду (1000 мс = 1 сек)</p>
    <p id="gork">функция <code>setInterval</code> возвращает сам интервал. это нужно для того чтобы ты мог его остановить, когда тебе захочется</p>
    <pre id="IFwK" data-lang="javascript">const interval = setInterval(() =&gt; {
  console.log(&#x27;RUBURI&#x27;);
}, 1000);

setTimeout(() =&gt; {
  clearInterval(interval);
}, 10000);</pre>
    <p id="PqyD">в этом коде мы остановим интервал через 10 секунд, используя функцию <code>clearInterval</code>, которая принимает в качестве аргумента интервал</p>
    <p id="3Pro">видишь как я ниже использовал <code>setTimeout</code>? <code>setTimeout</code> работает также как <code>setInterval</code>, только он выполняет код единожды. его тоже можно остановить до тех пор пока он не выполнился, используя функцию <code>clearTimeout</code></p>
  </section>
  <p id="5lf0">давай условимся, что бот будет проверять новый пост в канале каждые 2 секунды</p>
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="0T1U">логика у нас уже выходит такая:</p>
    <ol id="3y40">
      <li id="MYjy">даем боту понять какой пост в канале был крайним (<code>id</code>)</li>
      <li id="QmHC">запускаем интервал каждые 2 секунды</li>
      <li id="0acB">в интервале проверяем пуст ли пост с <code>id + 1</code></li>
      <li id="gCu0">если не пуст, пост появился! а если пусто, то пока нет</li>
      <li id="tBWG">обновляем <code>id</code> на новый если появился новый пост (а то бот будет думать что пост появляется каждые 2 секунды, так как будет сверяться со старым <code>id</code>)</li>
    </ol>
  </section>
  <p id="bYlU">давай выведем текст в консоль, что появился новый пост, как только он появится</p>
  <pre id="yHav" data-lang="javascript">// ...код
let lastMessageId = 3;
setInterval(async () =&gt; {
  const result = await client.invoke(
    new Api.channels.GetMessages({
      channel: &#x27;testruburibotchannel&#x27;,
      id: [lastMessageId + 1]
    })
  );
  
  const message = result.messages[0];
  if (message.className !== &#x27;MessageEmpty&#x27;) {
    lastMessageId++;
    console.log(&#x27;появился новый пост!&#x27;);
  }
}, 2000);</pre>
  <p id="ncJt">все расписали как и хотели. проверяем не равно ли <code>message.className</code> строке <code>MessageEmpty</code></p>
  <p id="MYdA">запускаем код и постим что то в канал за которым следим:</p>
  <figure id="F5cm" class="m_original" data-caption-align="center">
    <img src="https://img1.teletype.in/files/c3/6a/c36ad27d-030d-4654-8456-33550c596302.png" width="384" />
    <figcaption>абоба? мен?</figcaption>
  </figure>
  <p id="vqhf">а затем смотрим в консоль:</p>
  <figure id="cOIZ" class="m_original" data-caption-align="center">
    <img src="https://img3.teletype.in/files/65/dd/65dd25e5-3563-462d-a92d-30e7ee08da23.png" width="352" />
    <figcaption>опачки а это мне?</figcaption>
  </figure>
  <p id="Qawb">постим еще раз, смотрим еще раз, все работает! то что нужно!</p>
  <p id="HjBx">теперь давай сделаем так чтобы пост пересылался каждый раз как он появлятеся в наш канал агрегатор</p>
  <p id="VwCx">если ты писал новые посты, помни что нужно обновить <code>lastMessageId</code> с <code>id</code> крайнего поста чтобы все работало</p>
  <pre id="Sh6U" data-lang="javascript">// ...код
let lastMessageId = 5;
setInterval(async () =&gt; {
  const result = await client.invoke(
    new Api.channels.GetMessages({
      channel: &#x27;testruburibotchannel&#x27;,
      id: [lastMessageId + 1]
    })
  );
  
  const message = result.messages[0];
  if (message.className !== &#x27;MessageEmpty&#x27;) {
    lastMessageId++;
    await client.invoke(
      new Api.messages.ForwardMessages({
        fromPeer: &#x27;testruburibotchannel&#x27;,
        id: [lastMessageId],
        toPeer: &#x27;aggregatorruburi&#x27;
      })
    );
  }
}, 2000);</pre>
  <p id="PuGp">запускаем, постим, смотрим</p>
  <figure id="Gb7K" class="m_original" data-caption-align="center">
    <img src="https://img3.teletype.in/files/29/6b/296b0d46-192b-45a9-802f-57b2a4221f3f.png" width="346" />
    <figcaption>сообщения в канале за которым следим</figcaption>
  </figure>
  <figure id="XGvO" class="m_original" data-caption-align="center">
    <img src="https://img4.teletype.in/files/fb/28/fb280881-6ed1-48e4-b8ca-8e495f41d88a.png" width="438" />
    <figcaption>агрегатор</figcaption>
  </figure>
  <p id="RvHc">все кайфи работает йоу! бот успешно пересылает все новые посты из канала в агрегатор. но что если каналов не один, а два?</p>
  <h3 id="3E6B">пересылаем посты из нескольких каналов</h3>
  <p id="P2Ql">для того чтобы пересылать посты из нескольких каналов, нам надо хранить <code>id</code> крайнего сообщения нескольких каналов, тут нам поможет структура данных объект. объект будет выступать некой базой данных для нашего бота. выглядеть это будет так:</p>
  <pre id="scXP" data-lang="javascript">{
  &quot;testruburibotchannel&quot;: 5,
  &quot;kurilka&quot;: 1
}</pre>
  <p id="rIvf">то есть мы храним в ключе ник канала, а в значении — <code>id</code> крайнего поста в нем</p>
  <p id="M9c2">в остальном логика абсолютно одинаковая, единственное что, в интервале нам нужно будет проходиться по всем каналам (по всем ключам в объекте) и чекать посты во всех каналах</p>
  <p id="k8AM">прежде чем начнем писать код, создай второй канал. имей ввиду, что после создания нового канала, <code>id</code> первого поста будет <strong>2</strong>, а не <strong>1</strong>, так как сообщение <strong>Channel created </strong>тоже является своеобразным постом</p>
  <p id="bS26">ник второго канала в моем случае — <a href="https://t.me/testruburos" target="_blank"><strong>@testruburos</strong></a></p>
  <p id="a1tk">теперь давай я напишу весь код заново с нововведениями, и объясню тебе непонятные моменты:</p>
  <pre id="ILpC" data-lang="javascript">import { TelegramClient } from &#x27;telegram&#x27;
import { StringSession } from &#x27;telegram/sessions/index.js&#x27;

const apiId = 666666;
const apiHash = &#x27;hash&#x27;;
const stringSession = new StringSession(&#x27;...token&#x27;);

const AGGREGATOR_USERNAME = &#x27;aggregatorruburi&#x27;;
const db = {
  testruburibotchannel: 7,
  testruburos: 2
};

(async () =&gt; {
  const client = new TelegramClient(stringSession, apiId, apiHash, {
    connectionRetries: 5
  });

  await client.connect();
  setInterval(() =&gt; {
    Object.keys(db).forEach(async (channel) =&gt; {
      const lastMessageId = db[channel];
      const result = await client.invoke(
        new Api.channels.GetMessages({
          channel,
          id: [lastMessageId + 1]
        })
      );

      const message = result.messages[0];
      if (message.className !== &#x27;MessageEmpty&#x27;) {
        db[channel]++;
        await client.invoke(
          new Api.messages.ForwardMessages({
            fromPeer: channel,
            id: [lastMessageId + 1],
            toPeer: AGGREGATOR_USERNAME
          })
        );
      }
    });
  }, 2000);
})();</pre>
  <p id="RK9v">по сути это весь код для бота агрегатора, давай разбираться построчно</p>
  <pre id="4P4r" data-lang="javascript">const AGGREGATOR_USERNAME = &#x27;aggregatorruburi&#x27;;</pre>
  <p id="Uhak">здесь я сохраняю в константу ник канала агрегатора для удобства</p>
  <pre id="uWL9" data-lang="javascript">const db = {
  testruburibotchannel: 7,
  testruburos: 2
};</pre>
  <p id="zPkw">здесь я создаю нашу &quot;базу данных&quot;, куда сохраняю каналы за которыми я хочу следить, и <code>id</code> их самых свежих постов</p>
  <pre id="MHaa" data-lang="javascript">Object.keys(db).forEach(async (channel) =&gt; {</pre>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="LT5i">Object.keys</h3>
    <p id="e2B8"><code>Object.keys</code> используется для того, чтобы получить все ключи объекта в массиве</p>
    <p id="01nX">например:</p>
    <pre id="yWJ3" data-lang="javascript">const obj = {
  a: 1,
  b: 2
};
console.log(Object.keys(obj));
// выведет [&quot;a&quot;, &quot;b&quot;]</pre>
  </section>
  <p id="lcDZ">используя <code>Object.keys</code> в нашем кейсе, я получаю в массиве ники всех каналов за которыми мы следим, затем идет метод массивов <code>forEach</code></p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="enLc">Array.forEach</h3>
    <p id="gKiB">благодаря этому методу ты можешь пройтись по всем значениям массива (например, если тебе нужно сделать что то используя эти значения)</p>
    <p id="Mr5v">например:</p>
    <pre id="UaO6" data-lang="javascript">const arr = [&quot;a&quot;, &quot;b&quot;];
arr.forEach((value, index, array) =&gt; {
  console.log(symbol, index, array);
});
// выведет:
// a 0 [&quot;a&quot;, &quot;b&quot;]
// b 1 [&quot;a&quot;, &quot;b&quot;]</pre>
    <p id="Dkeb">метод <code>forEach</code> принимает аргументом колбек (функция которая будет вызываться для каждого значения в массиве)</p>
    <p id="r0YL">в колбеке ты можешь получить доступ к следующей информации:</p>
    <ol id="hTiR">
      <li id="UaDh">само значение (первый аргумент колбека)</li>
      <li id="nrVP">индекс под которым это значение (второй аргумент колбека)</li>
      <li id="3D0P">сам массив (третий аргумент колбека)</li>
    </ol>
  </section>
  <p id="xeRH">подытоживая этот кусочек кода, я получаю массив ников всех каналов за которыми мы следим, и прохожусь по каждому нику используя <code>forEach</code></p>
  <p id="u8zo">мне нужно проходиться по каждому нику, чтобы я проверил есть ли новое сообщение в том или ином канале</p>
  <pre id="sG0p" data-lang="javascript">Object.keys(db).forEach(async (channel) =&gt; {
  const lastMessageId = db[channel];</pre>
  <p id="3TjI">получаем <code>id</code> крайнего сообщения каждого канала из базы данных и сохраняем его в переменную <code>lastMessageId</code></p>
  <p id="deeX">в конструкции <code>db[channel]</code> вместо <code>channel</code> будет подставляться каждый ник из тех за которыми мы следим</p>
  <pre id="QlXE" data-lang="javascript">const message = result.messages[0];
if (message.className !== &#x27;MessageEmpty&#x27;) {
  db[channel]++;
  await client.invoke(
    new Api.messages.ForwardMessages({
      fromPeer: channel,
      id: [lastMessageId + 1],
      toPeer: AGGREGATOR_USERNAME
    })
  );
}</pre>
  <p id="0Rmf">здесь уже знакомая тебе логика, единственное что, не забываем обновить id крайнего сообщения в канале, где появился новый пост</p>
  <pre id="wDz0" data-lang="javascript">db[channel]++</pre>
  <p id="NB5X">запускаем, постим в каналах и смотрим на результат:</p>
  <figure id="9SUf" class="m_original" data-caption-align="center">
    <img src="https://img3.teletype.in/files/2b/2b/2b2be94f-f926-4a14-963a-232e865fb72d.png" width="484" />
    <figcaption>с кайфом!</figcaption>
  </figure>
  <p id="Yj20">грац! вот так мы с тобой написали бота агрегатора!</p>
  <p id="PQmH">если ты хочешь добавить больше каналов, просто добавляй ник канала и <code>id</code> крайнего сообщения в объект <code>db</code> и бот будет за ними следить</p>
  <h3 id="gPiu">поздравляю! ты написал бот агрегатор каналов!</h3>
  <p id="XL2G">не ну ты ваще молорик йомайо! </p>
  <p id="KKx1">весь код доступен здесь -&gt; <a href="https://file.io/s3sIXxURRiHC" target="_blank"><strong>https://file.io/s3sIXxURRiHC</strong></a></p>
  <figure id="jqkL" class="m_column">
    <img src="https://blobcdn.same.energy/d/c9/d3/c9d3f6ba65846c6eb7a49ece5d2d5444085ef9fd" width="700" />
    <figcaption>чил раслабон теперь</figcaption>
  </figure>
  <hr />
  <h2 id="oQqU">как сделать так, чтобы бот работал всегда?</h2>
  <p id="d3IH">для этой цели тебе понадобится дедик или VPS. суть в том, чтобы запустить бота на дедике — он будет работать всегда (только если дедик не упадет)</p>
  <p id="DSkp">единственное, бота надо будет запустить фоном. для того чтобы запускать какие то скрипты фоном (чтобы они не закрывались при дисконнекте с сервера) нужна ютилита типа <a href="https://losst.pro/komanda-screen-linux" target="_blank"><strong>screen</strong></a></p>
  <hr />
  <h2 id="ciES">заключение</h2>
  <p id="bb2o">спасибо за то что прочитал статью! </p>
  <p id="XjKw">это было немаленькое и надеюсь увлекательное для тебя путешествие! я постарался изложить максимум своих знаний в эту статью. мы написали клона славы и бот агрегатор, думаю получилось круто!</p>
  <p id="KZO4">можно сказать что в эту статью я вложил также немного продолжения статьи по JS так как мы с тобой здесь разбирали больше различных концептов</p>
  <p id="9C9L"><strong>я буду еще писать о разных технических штуках, так что подписывайся на <a href="https://t.me/ruburi" target="_blank">рубури</a>!</strong></p>
  <p id="rq1O">можешь не беспокоиться если чето не запомнилось, это нормально. не отступай и иди к цели. когда я учился я хотел бросить люто масштабно два раза... но не останавливался пон!!!!! я не остановился и ща работаю дворничком (шутка конечно мужики я во вкусно и точка)</p>
  <p id="tyJu"><strong>ебашьте и все будет ахуенно</strong></p>
  <figure id="xdmn" class="m_column">
    <img src="https://s3.gifyu.com/images/IMG_0917.gif" width="848" />
    <figcaption>с кайфом</figcaption>
  </figure>
  <h2 id="76kW">благодарности</h2>
  <p id="jgZ4"><strong>спасибо</strong> тебе за прочтение, <strong>спасибо</strong> тем кто ставит реакции, подпищекам, рыжему, сс ресерч, моей девочке, френдли тагу 52 нгг и всем остальным кто пон мотивирует ебашить <strong>люто жоска</strong></p>
  <p id="Zdew"><strong>и удачи тебе в пути кодинга еба! </strong></p>
  <h2 id="3byj">отзыв</h2>
  <p id="YUnN">если в каком то примере ошибка, или что то не получается вы всегда можете обратиться за вопросом в телегу к рубурику <strong><a href="https://t.me/rubyuroboros" target="_blank">@rubyuroboros</a></strong> или написать прямо в комментариях</p>
  <hr />
  <p id="Rm05">мой канал — <a href="https://t.me/ruburi" target="_blank">https://t.me/ruburi</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rubyuroboros/C1Zlbpve0ul</guid><link>https://teletype.in/@rubyuroboros/C1Zlbpve0ul?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><comments>https://teletype.in/@rubyuroboros/C1Zlbpve0ul?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros#comments</comments><dc:creator>rubyuroboros</dc:creator><title>500</title><pubDate>Wed, 22 Feb 2023 12:21:29 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/de/ff/deff09ed-a518-4ae4-bca0-d4e535e15814.png"></media:content><description><![CDATA[<img src="https://blobcdn.same.energy/d/4f/28/4f28beb9af97c0e79c79d8f048e29876d4292b2d"></img>привет мой дорогой подпищек! 💙]]></description><content:encoded><![CDATA[
  <figure id="s3vi" class="m_retina" data-caption-align="center">
    <img src="https://blobcdn.same.energy/d/4f/28/4f28beb9af97c0e79c79d8f048e29876d4292b2d" width="532" />
  </figure>
  <p id="An4B">привет мой дорогой подпищек! 💙</p>
  <p id="UTpC">наступило знаменательное событие в рубури дао, первый юбилей, первые 500 любимых подпищеков. в честь этого я решил написать небольшую статью о дальнейших планах, мувах, да и просто поговорим по душам</p>
  <p id="Jh4a">я создал паблик спонтанно, предложил сделать мне это рижи, за что я ему очень благодарен ведь без этого действия не было бы щас этой статьи</p>
  <p id="BjZA">за эти 3 месяца что я веду рубури дао я билдил и билжу свое видение в крипте, делюсь классным контентом с подпищеками и просто мы все хорошо проводим время в чатике. ничего особенного или выдающегося пока что не произошло, ключевое слово пока что, все еще впереди!</p>
  <p id="eg26"><strong>спасибо всем кто поддерживает, спасибо всем подпищекам рубури дао! плотный салам летит карочи</strong></p>
  <hr />
  <h2 id="tmmC">мое мнение о некст буллране</h2>
  <p id="8y1T">я постараюсь изложить все свои мысли о крипте, о рынке и так далее под этим заголовком</p>
  <p id="91Bj">если коротко, я прилагаю все усилия чтобы не пропустить эту бычку. мне кажется что эта бычка будет достаточно эффектной и хайповой, когда на крипту обратят внимание куда в разы больше чем в предыдущие булраны. если у тебя все еще нет банка то мой совет тебе это идти фармить его как можно скорее, ирл работой или другими способами</p>
  <h2 id="IZqY">банк</h2>
  <p id="Bbyt">вполне возможно что у чела нет депа, не нужно зацикливаться на одной бычке, на одной крипте. если начать зарабатывать и билдить капитал щас — не упустишь следующую темку в ирл, например бизнес, или другую хорошую возможность вложить ведь у тебя будет капитал. тратить энергию и стрессовать по поводу того что ты упустил какую то темку — бессмысленно, потому что обычно этих активностей бывает как минимум несколько на день</p>
  <p id="djEB">как говорится, готовь сани летом и не прогадаешь</p>
  <h2 id="YT6c">темки</h2>
  <p id="1IDS">на данный момент я рассматриваю следующие возможности поднять грина в крипте:</p>
  <ul id="EHqp">
    <li id="9Cic">нфт, флипы</li>
    <li id="XXPZ">ретродропы</li>
    <li id="ldQx">ноды</li>
    <li id="a8yR">перспективные монеты</li>
    <li id="jOEG">команда</li>
    <li id="1Wiw">продажа знаний ака приватки либо софт</li>
  </ul>
  <h3 id="20cX">нфт, флипы</h3>
  <p id="G0yX">рассказывать тут нечего, давно уже за меня все рассказали. суть проста и ясна. ограничений по банку нет — хорошо</p>
  <h3 id="Ox3N">ретродропы</h3>
  <p id="hcQM">кто то сказал ретродропы? — <a href="https://t.me/ValixDAO" target="_blank">VALIX</a></p>
  <p id="nj4e">валик гем если ты хочешь знать что то про ретродропы и это не реклама а личная рекомендация</p>
  <p id="fzkk">ретродропы — гем, ведь пока кто то дегенит, мало кто хочет сжигать деньги на газ. и хоть в первые квесты оптимизма залетело больше 100к человек, с каждым последующим квестом их все меньше и меньше. мало людей кто делает ретродропы грамотно и с душой. размеры дропов — сами знаете</p>
  <h3 id="WhVn">ноды</h3>
  <p id="G39D">кто то сказал ноды? аптос первое что приходит на ум. ну еще разве что фомоебство. ладно не об этом. давай я расскажу тебе секрет про ноды. но прежде, что это вообще такое и как это может принести деньги?</p>
  <p id="rkkN">все достаточно просто, ты покупаешь дедик (сервер), ставишь туда ноду, запрашиваешь токены с крана и тд — вуаля, ты нодер!</p>
  <p id="UBGM">держателям нод ака валидаторам сыпят. сыпят долго, но много. медленно, но верно. игра в долгую. если ты морально не готов держать сервер достаточно долго без какого либо намека на дроп, а скорее тебе нравится сливать бабки сизому на х50 плече — тебе не сюда</p>
  <p id="8XvU">а что там по секрету? знай, что поставить ноду по гайду и сидеть ждать наград — не всегда достаточно. я бы даже сказал не часто. тебе нужно мониторить соцсети проекта, не проебывать различные квесты, плюшки, формы, обновления и так далее</p>
  <p id="ctnz">формы? формы это гем. ведь кто не заполнил форму в аптос не получил дроп, не так ли?</p>
  <p id="2wqg">например в космофорках (происходящих на основе cosmos) есть активный сет валидаторов. это список нод которые 100% валидируют транзакции, участвуют в сети. а представь теперь что ты просто поставил ноду, вроде бы создал валидатора, но он неактивен. как думаешь, скольким проектам из 10 будет резон дропать тем кто просто смотрел на то как работает блокчейн? особенно если участников десятки, сотни тысяч? пища для мозга</p>
  <h3 id="oeA2">перспективные монеты</h3>
  <p id="3tSG">все еще проще. делаешь ресерч, покупаешь монету, следишь, и если ты попал в точку то год-два-три и пришли неплохие иксы. но все же по моему мнению лучше залетать в ранние активности новых проектов (например тестнеты) и получать монеты таким образом, нежели чем покупать их напрямую</p>
  <h3 id="NCFF">команда</h3>
  <p id="9QVE">ты не сможешь хэндлить кучу дел в крипте. для этого нужна будет команда. безусловно, для команды нужны деньги. хоть какие то финансы. поэтому это темка для тех у кого есть более менее какой то банк. с помощью команды, в которой, например, есть артеры ты можешь лутать влы в различные проекты. если у тебя есть копирайтер, загоняй писать его треды в твиттер либо какие то интересные статьи (привет OpenAI)</p>
  <p id="mYNQ">нанимай людей чтобы загоняли акки в рафлы, преминты и так далее. это гем возможность. пытаться удержать все яйца в корзине соло = рект + выгорание</p>
  <h3 id="TKYz">продажа знаний ака приватка ака софт</h3>
  <p id="AOEq">если ты прогер то можно делать софт и продавать его</p>
  <p id="cLNa">если ты крутой криптан то кроме всех активностей можно продавать свои знания через приватку</p>
  <p id="KPSN">все просто</p>
  <h2 id="9l7B">мои планы / предикты / мувы в крипте</h2>
  <h3 id="oBBs">нфт</h3>
  <p id="aD8B">на данный момент я холжу Applied Primate Scientist Keycard и 1 Kubz</p>
  <p id="Bwno">это два основных проекта (+ YogaPetz) на которые я буду делать упор в ближайший квартал</p>
  <p id="CCrf">я планирую докупить еще 2 Kubz чтобы получить вл в YogaPetz</p>
  <p id="2vCE">тем самым на основе этого мое портфолио ближе к концу весны будет выглядеть так:</p>
  <ul id="W5qx">
    <li id="qI7J">3 Kubz + возможно кучка сундуков (relics)</li>
    <li id="n0Ah">1 YogaPetz</li>
    <li id="1kQE">1 Applied Primate Scientist Keycard</li>
  </ul>
  <p id="KGGt">на данный момент фп кубз в районе 0.7-0.75e, карта получила неплохой буст в цене в последние дни (+40%) и ее фп составляет около 0.7e без трейтов</p>
  <h3 id="H7Pr">ноды</h3>
  <p id="Rpr4">холжу 50 серверов с различными нодами. из интересного на данный момент — Ironfish, Shardeum, Exorde, Nibiru (но глим уже заполнили &gt;10k человек, пока подумываю насчет этого)</p>
  <p id="YIbD">остальное стоит в ожидании инсентив фаз и форм</p>
  <h3 id="auqu">ретродропы</h3>
  <p id="co0k">планирую крутить все ретродропы которые валик любезно публикует в свой паблик</p>
  <h3 id="JOMf">команда</h3>
  <p id="xJGD">мы с рижи создали команду, пока сильно движений нет, так как дела отнимают большую часть времени. но в любом случае этот момент я планирую развивать и не оставлять просто так впустую</p>
  <h3 id="Pehx">продажа знаний ака приватка ака софт</h3>
  <p id="5CzD">у меня нет планов делать приваток, есть планы продавать софт офк</p>
  <hr />
  <figure id="4Srg" class="m_retina" data-caption-align="center">
    <img src="https://blobcdn.same.energy/b/f5/72/f572513bb8aec4dec8703da3f5c75624df9b8566" width="540" />
    <figcaption>всем так хочется на бали дао, но кто делает для этого что-то?</figcaption>
  </figure>
  <h2 id="IwZj" data-align="center">психология / отдых</h2>
  <p id="BQoY">основной двигатель прогресса — <strong>стабильность</strong>, <strong>дисциплина</strong>. если в один день тобой движет невероятная мотивация а на следующий день ты высохший, либо ты засыпаешь с крутыми мыслями а просыпаешься с не очень, пора поменять зону комфорта, поменять привычки. попробуй отказаться от вредных привычек, попробуй внести новые и полезные. если ты не ходишь в зал — попробуй. казалось бы это так очевидно — &quot;зона комфорта&quot;, но сколько же действительно меняется вокруг тебя когда меняешься ты. иногда высасывать энергию могут люди, и вместо того чтобы в очередной раз проебланить час времени на катку в доте, <strong>сядь и поразмышляй</strong> о своей жизни. о прошлом, о настоящем и о будущем. вот просто проскролль все моменты в своей жизни, проанализируй людей вокруг себя. насколько они для тебя полезны, насколько ты правильно поступал в тех или иных ситуациях, почему ты фомоебил, почему упускал, а в том или ином моменте почему все делал вовремя. часто ответ находится внутри нас самих. все вышесказанное можно подытожить одним словом — <strong>медитация</strong></p>
  <p id="wA9w">еще нужно отдыхать. на самом деле нашему организму и мозгу нужен отдых. отдых нужен постоянно. от дел. мы можем не осознавать как нам нужен отдых, но подсознательно он просто очень сильно требуется. пробуй показывать своим глазам новые места каждый месяц, или хотя бы три. путешествуй, не стой на месте. встреча с новыми людьми, новыми местами может открыть в людях качества, мысли или навыки о которых они никогда до этого не задумывались</p>
  <h2 id="wZOe" data-align="center">мантра / благодарность</h2>
  <p id="FS7z">каждый день я просыпаюсь и благодарю жизнь за то что я проснулся и живу еще один прекрасный день в этом мире</p>
  <figure id="Q3l5" class="m_column" data-caption-align="center">
    <img src="https://blobcdn.same.energy/a/47/2a/472adbe603c01e3c61d253390f5300e0fa7f35ec" width="500" />
    <figcaption>wake up thankful everyday, feel like Sydney Portier</figcaption>
  </figure>
  <p id="ZXrc">на самом деле благодарность, и в целом приятные теплые оптимистичные мысли очень влияют на жизнь. ведь мысли материальны. если ты с позитивной и хорошей кармой то жизнь в целом будет к тебе благосклонна. карма для меня это очень важный элемент в жизни, именно поэтому я никогда не буду факаться с чем то если это связано со скамом, обманом или несправедливо плохими последствиями для других людей</p>
  <hr />
  <h2 id="CX0x">заключение</h2>
  <p id="Va1g">спасибо тебе за прочтение этой статьи. в этот раз получился душевный разговор от души душевно в душу 💙</p>
  <p id="qKVG">надеюсь ты почерпнул для себя что то полезное или интересное, увидимся в следующей статье!</p>
  <hr />
  <p id="Rm05">мой канал — <a href="https://t.me/ruburi" target="_blank">https://t.me/ruburi</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rubyuroboros/CWzk3G8-7Ld</guid><link>https://teletype.in/@rubyuroboros/CWzk3G8-7Ld?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><comments>https://teletype.in/@rubyuroboros/CWzk3G8-7Ld?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros#comments</comments><dc:creator>rubyuroboros</dc:creator><title>SELENIUM QUICK START</title><pubDate>Tue, 31 Jan 2023 21:34:19 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/22/37/2237e6d1-83d4-4fad-b83c-f277c501eb25.png"></media:content><description><![CDATA[<img src="https://blobcdn.same.energy/d/93/b7/93b739579242007d2ead5a1dafeac35b52af0d9a"></img>привет другалек! наконец у меня дошли руки написать статью по селениуму. как большинство просило - показать использование селены на реальном примере! бери чипсики чаек плюшки печеньки там шо кушаешь и лфг читать!]]></description><content:encoded><![CDATA[
  <figure id="psTl" class="m_retina" data-caption-align="center">
    <img src="https://blobcdn.same.energy/d/93/b7/93b739579242007d2ead5a1dafeac35b52af0d9a" width="400" />
    <figcaption>опачки а вот и селена</figcaption>
  </figure>
  <p id="GGe8">привет другалек! наконец у меня дошли руки написать статью по селениуму. как большинство просило - показать использование селены на реальном примере! бери чипсики чаек плюшки печеньки там шо кушаешь и лфг читать!</p>
  <p id="Qw9N">приступим!</p>
  <hr />
  <section style="background-color:hsl(hsl(24,  24%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h2 id="MrLy">оглавление</h2>
    <ol id="9bPY">
      <li id="Lxya">что такое селениум и для чего его юзать</li>
      <li id="vCow">подготавливаем среду обитания нашего скрипта</li>
      <li id="pwca">базовые базы селениума</li>
      <li id="od1f">маскируем нашу селеночку</li>
      <li id="lFQq">абузим хуйню?</li>
      <li id="N1cW">заключение</li>
      <li id="RcLj">благодарности + отзыв</li>
    </ol>
  </section>
  <hr />
  <h2 id="2KGL">что такое селениум и для чего его юзать</h2>
  <p id="Plpf">если обьяснять коротко - селениум это инструмент для того чтобы ты мог абузить какую то хуйню или перефразируя автоматизировать дефолт рутинные действия в браузере на кучу акков в любых количествах</p>
  <p id="IpWP">с помощью селениума можно абузить формы, преминты, в общем бля все что можно делать в браузере дефолт юзеру можно делать с селениумом (ну или почти все)</p>
  <hr />
  <h2 id="Yk1N">подготавливаем среду обитания нашего скрипта</h2>
  <p id="vkPA">ты уже должен быть знаком с тем что такое редактор, жиэс и так далее. если ты не знаком прошу любить и жаловать — <a href="https://teletype.in/@rubyuroboros/27w_de2svrO" target="_blank">сюда</a></p>
  <p id="v0VE">убедись что у тебя установлен <strong>nodejs </strong>и <strong>npm </strong>(с nodejs автоматически поставляется и npm)</p>
  <p id="GeZE">и если у тебя все еще нет пакет менеджера <strong>yarn</strong> то установи его</p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="iBOb">как установить yarn</h3>
    <p id="umwh">в терминале вводим:</p>
    <pre id="p9kp">npm i -g yarn</pre>
  </section>
  <p id="IPdz">открывай любимый редактор, открывай терминал и директорию с проектом, затем вводи в терминал:</p>
  <pre id="bjQX" data-lang="bash">yarn init -y
yarn add selenium-webdriver webdriver-manager</pre>
  <p id="3ZGc">и создаем файлик <code>index.js</code></p>
  <p id="qnRk">и вписываем туда базовую базу:</p>
  <pre id="a7PV" data-lang="javascript">const { Builder } = require(&#x27;selenium-webdriver&#x27;)

const driver = new Builder().forBrowser(&#x27;chrome&#x27;).build()
;(async () =&gt; {
  await driver.get(&#x27;https://google.com/ncr&#x27;)
})()</pre>
  <p id="3ys0">запускаем скриптик <code>node index.js</code></p>
  <p id="Wmfy">и у нас открывается браузер с гуглом — ахуенно</p>
  <figure id="Joqz" class="m_column">
    <img src="https://img1.teletype.in/files/8b/f0/8bf08d53-6430-454b-8689-51e89b717995.png" width="2366" />
    <figcaption>ну ебать лфг</figcaption>
  </figure>
  <hr />
  <h2 id="5cjT">базовые базы селениума</h2>
  <p id="Khvy">щас не будет сходу абуз какого то проекта, давай поиграемся с гуглом</p>
  <p id="FJTM">например ты хочешь чтобы бот вводил за тебя в гугле &quot;заряд от ахмеда расулова&quot; и нажимал поиск</p>
  <p id="irOw">давай попробуем это сделать и разберемся с тем как работать с селеной</p>
  <p id="p4mJ">чтобы ввести какой то текст, надо найти элемент в DOM</p>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="kR5L">что такое DOM?</h3>
    <p id="YiIn">DOM (Document Object Model) — дерево элементов. любая страница в интернете состоит из элементов (если ты знаком с хтмл то ты понимаешь о чем я). соответственно во главе дерева стоит элемент <code>html</code>, внутри есть <code>head</code> и <code>body</code>. в <code>body</code> находится вся начинка сайта (то есть все отображающиеся на странице элементы). к чему это я? если ты хочешь ввести что то в инпут селеной, то надо найти этот элемент в DOM</p>
    <p id="z4Jr">примерно это будет выглядеть так:</p>
    <p id="TylI">html &gt; body &gt; div &gt; div &gt; <strong>input</strong></p>
    <p id="JdMk"><strong>^ </strong>инпут который нам нужен вложен в несколько других элементов</p>
  </section>
  <h3 id="oX2Z">как найти элемент в DOM?</h3>
  <p id="zfcG">все просто. жмешь правой кнопкой мыши по желаемому элементу и нажимаешь <strong>&quot;Просмотреть код&quot;</strong> (это на маке, на винде может быть типа просмотреть код элемента и тд)</p>
  <figure id="Emwe" class="m_column">
    <img src="https://img4.teletype.in/files/39/c5/39c58796-7f5a-4806-802f-a1118a8520a7.png" width="1244" />
    <figcaption>последний пункт меню</figcaption>
  </figure>
  <p id="P8bD">после того как ты нажал на нужный пункт открывается следующая ебанина</p>
  <figure id="rtTl" class="m_column">
    <img src="https://img3.teletype.in/files/65/2b/652b8620-fc3a-4338-82ce-45f1369ee15b.png" width="2392" />
    <figcaption>вот это справа это просто супер важная штука для разраба сайтов. называется она консоль</figcaption>
  </figure>
  <p id="FzNB">имей ввиду что имбовее всего искать элементы юзая консоль хром браузера (не оперы или не дай бог амиго)</p>
  <p id="tjb0">консоль дает тебе понять какие элементы вложены в какие и как до них достучаться. если ты наведешься на другие элементы они должны подсвечиваться что дает тебе понять опять же какие элементы где находятся на странице</p>
  <figure id="GI6H" class="m_column">
    <img src="https://img1.teletype.in/files/c9/69/c969427c-d01f-42ee-a44e-fcd63f5c4907.png" width="2322" />
    <figcaption>навелся на инпут пон</figcaption>
  </figure>
  <p id="b7Xh">для того чтобы ты мог ввести какой то текст в элемент тебе нужно искать именно элемент <strong>input</strong> и никакой другой (ну разве что <strong>textarea</strong>, или кастомизированные <strong>div</strong> в которые можно вводить текст, такие есть у твиттера, но пока не вдавайся в подробности о них)</p>
  <h3 id="krWM">я нашел инпут, как заставить бездушную машину ввести текст в него?</h3>
  <p id="ParK">окей это круто ты нашел инпут, теперь нам нужно получить указатель на этот элемент в дереве DOM. сделать это можно кликнув правой кнопкой по элементу в консоли и выбрав <strong>Copy -&gt; Copy selector</strong></p>
  <figure id="Ss8u" class="m_column">
    <img src="https://img4.teletype.in/files/f8/e7/f8e79078-7635-44f6-8eb1-6402a54c900a.png" width="972" />
    <figcaption>вот так вот</figcaption>
  </figure>
  <p id="7BEZ">сохрани эту ебанину и погнали сделаем так чтобы мы ввели заветный текст &quot;заряд от ахмеда расулова&quot; в поиск</p>
  <pre id="q4WK" data-lang="javascript">const { Builder, By } = require(&#x27;selenium-webdriver&#x27;)

const driver = new Builder().forBrowser(&#x27;chrome&#x27;).build()
;(async () =&gt; {
  await driver.get(&#x27;https://google.com/ncr&#x27;)
  const searchInput = await driver.findElement(
    By.css(
      &#x27;body &gt; div.L3eUgb &gt; div.o3j99.ikrT4e.om7nvf &gt; form &gt; div:nth-child(1) &gt; div.A8SBwf &gt; div.RNNXgb &gt; div &gt; div.a4bIc &gt; input&#x27;
    )
  )
  await searchInput.sendKeys(&#x27;заряд от ахмеда расулова&#x27;)
})()</pre>
  <p id="6B41">для того чтобы найти какой либо элемент в селениуме мы используем метод <code>findElement</code> у <code>driver</code>. в качестве аргумента мы должны указать путь до элемента. в данном случае мы ищем элемент по <strong>селектору</strong> (Copy selector). также можно найти элемент по <strong>XPath</strong>, <strong>classname</strong>, <strong>id</strong>, <strong>названию</strong> <strong>тега</strong>, <strong>тексту</strong> <strong>ссылки</strong> и тд</p>
  <p id="zz6u">чтобы указать путь до элемента используя селектор мы вызываем метод <code>css</code> у класса <code>By</code> который помогает нам строить пути до элементов</p>
  <p id="kmnR">метод <code>By.css</code> помогает найти элемент используя селектор, в качестве аргумента передаем непосредственно сам селектор</p>
  <p id="OAPw">вот мы нашли элемент, сохранили его в переменную, теперь давай сделаем так чтобы бот написал туда текст, а здесь мы будем использовать метод <code>sendKeys</code> у найденного элемента, в качестве аргумента передаем текст который мы хотим ввести</p>
  <p id="5kZ5">запускаем скрипт, тестируем и вуаля</p>
  <figure id="CAt5" class="m_column">
    <img src="https://img2.teletype.in/files/98/61/9861e636-df58-4397-833c-a436c0ef3994.png" width="1214" />
    <figcaption>ахмед</figcaption>
  </figure>
  <p id="Pifu">ну, тут осталось только нажать поиск!</p>
  <p id="IML4">в гугле для того чтобы начать поиск необходимо нажать ентер, но в других сайтах возможно тебе придется кликать на кнопку для поиска (соответственно искать кнопку, и кликать на нее, алгоритм такой же)</p>
  <p id="X4jR">чтобы нажать ентер после того как мы ввели текст в инпуте мы просто добавляем</p>
  <pre id="x4hX" data-lang="javascript">await searchInput.sendKeys(&#x27;заряд от ахмеда расулова&#x27;, Key.RETURN)</pre>
  <p id="2Heg"><code>Key.RETURN</code> вторым аргументом и все готово! не забудь только добавить класс Key в импорте селениума</p>
  <pre id="uCZG" data-lang="javascript">const { Builder, By, Key } = require(&#x27;selenium-webdriver&#x27;)</pre>
  <p id="LVVy">запустив скрипт ты увидишь что поиск пошел!</p>
  <figure id="JdXl" class="m_column">
    <img src="https://img1.teletype.in/files/c2/d5/c2d50ecc-9679-4a68-9c8d-2cdcf66ced1e.png" width="1438" />
    <figcaption>с кайфом садоводы</figcaption>
  </figure>
  <p id="slaw">ну и закончим раздел базовых баз тем что мы кликнем на первую попавшуюся ссылку. тут мы будем задействовать клик следственно алгоритм такой:</p>
  <section style="background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <ol id="r8k0">
      <li id="5FXG">ищем элемент</li>
      <li id="cWpw">кликаем на элемент</li>
    </ol>
  </section>
  <p id="Xwix">лфг!</p>
  <p id="1zrh">нам нужна первая ссылка, соответственно нажимаем правой кнопкой по первой ссылке и идем искать нужный элемент</p>
  <figure id="1JRr" class="m_column">
    <img src="https://img4.teletype.in/files/30/da/30da0db1-c226-438d-a09f-89d22c65f45b.png" width="2368" />
    <figcaption>опа элемент</figcaption>
  </figure>
  <p id="7r8K">в дереве дом мы видим элементом выше тег <code>a</code> который отвечает за ссылку в html. в целом нам нужна ссылка, но мы можем кликнуть также на дочерние элементы (элементы которые входят в тег <code>a</code>, то есть ссылки на которую мы хотим кликнуть)</p>
  <p id="0Vvx">проделываем те же действия</p>
  <pre id="XupM" data-lang="javascript">;(async () =&gt; {
  ...code
  
  const firstLink = await driver.findElement(
    By.css(
      &#x27;#rso &gt; div:nth-child(1) &gt; div &gt; div &gt; div.Z26q7c.UK95Uc.jGGQ5e &gt; div &gt; a &gt; h3&#x27;
    )
  )
  await firstLink.click()
})()</pre>
  <p id="NFVa">находим элемент таким же образом как и выше, а для того чтобы кликнуть на элемент мы используем метод <code>click</code> у элемента. таким образом бот кликнет на элемент — все просто</p>
  <figure id="XMsf" class="m_column">
    <img src="https://img1.teletype.in/files/06/17/061759e9-5c84-4b84-8b3f-419887ff9ea5.png" width="1806" />
    <figcaption>но вот незадача...</figcaption>
  </figure>
  <hr />
  <h2 id="zf0v">маскируем нашу селену</h2>
  <p id="ipnQ">ddos guard выше скорее всего оттого что ты юзаешь прокси из датацентра (не резидент) или проще говоря хуевое прокси. соответственно нам нужно подключить не палевное прокси</p>
  <p id="wSPa">для того чтобы нам замаскировать каждый вход/сессию в селене нам нужно периодически менять user agent, proxy, выключить опции которые определяют наш браузер как автоматизированное по, сменить платформу (win/mac/linux), отключить детект WebRTC и тд</p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="YuNv">добавляем прокси в селену</h3>
    <p id="FI2C">на жиэсе селена почему то не очень кормится проксиями через <code>addProxy</code> или <code>addArguments</code> с опцией <code>--proxy-server</code> в хром. поэтому я решил добавить прокси как кастомное расширение в хроме</p>
    <p id="TcW0">создаем файл <code>background.js</code> и <code>manifest.json</code> для нашего кастомного расширения</p>
    <p id="AnyP"><code>background.js</code></p>
    <pre id="aOBY" data-lang="javascript">const PROXY = {
  host: &#x27;zaryadotahmedarassulova.com&#x27;, // proxy host
  port: 1337, // proxy port
  username: &#x27;ahmedrassulov&#x27;, // proxy username (если прокси приват)
  password: &#x27;zaryad228&#x27; // proxy password
}

const getProxyConfig = (host, port) =&gt; {
  mode: &#x27;fixed_servers&#x27;,
  rules: {
    singleProxy: {
      scheme: &#x27;http&#x27;,
      host,
      port
    },
    bypassList: [&#x27;localhost&#x27;] // не стучим с прокси в локалхост
  }
}

chrome.proxy.settings.set({
  value: getProxyConfig(PROXY.host, PROXY.port),
  scope: &#x27;regular&#x27;
}, () =&gt; {})

chrome.webRequest.onAuthRequired.addListener(
  () =&gt; ({
    authCredentials: {
      username: PROXY.username,
      password: PROXY.password
    }
  }),
  { urls: [&#x27;&lt;all_urls&gt;&#x27;] },
  [&#x27;blocking&#x27;]
)</pre>
    <p id="kR9K"><code>manifest.json</code></p>
    <pre id="hlwf" data-lang="javascript">{
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;manifest_version&quot;: 2,
  &quot;name&quot;: &quot;Chrome Proxy&quot;,
  &quot;permissions&quot;: [
    &quot;proxy&quot;,
    &quot;tabs&quot;,
    &quot;unlimitedStorage&quot;,
    &quot;storage&quot;,
    &quot;&lt;all_urls&gt;&quot;,
    &quot;webRequest&quot;,
    &quot;webRequestBlocking&quot;
  ],
  &quot;background&quot;: {
    &quot;scripts&quot;: [&quot;background.js&quot;]
  },
  &quot;minimum_chrome_version&quot;: &quot;22.0.0&quot;
}</pre>
    <p id="Nozp"><code>manifest_version</code> не новая но это не сильно критично тк наше расширение не паблик. для 3 манифест версии я не нашел пермишена <code>webRequestBlocking</code> так что если кто знает инфу буду рад если поделитесь</p>
  </section>
  <p id="BMrH">после чего сжимаем в zip файл эти два файла и переименовываем в <code>proxy.zip</code></p>
  <p id="a0Ql">расширение с прокси готово</p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="Q64X">добавляем расширение для антидетекта webRTC</h3>
    <p id="DMem">теперь давай скачаем готовое <a href="https://chrome.google.com/webstore/detail/webrtc-control/fjkmabmdepjfammlpliljpnbhleegehm" target="_blank">расширение</a> для антидетекта webRTC</p>
    <p id="ED2X">я скачал расширение в zip через chrome web store используя расширение <a href="https://chrome.google.com/webstore/detail/crx-extractordownloader/ajkhmmldknmfjnmeedkbkkojgobmljda" target="_blank">CRX Extractor/Downloader</a></p>
    <p id="pbbc">если тебе лень проделывать все эти шаги и ты хочешь просто скачать расширение — <a href="https://file.io/zULFjWw5tNZY" target="_blank">ссылка на file.io</a></p>
    <p id="DW77">перемещаем zip в директорию с нашим ботом и лфг дальше</p>
  </section>
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="0Tw2">маскируем user agent</h3>
    <p id="VbB1">для этого скачай модуль <code>fake-useragent</code></p>
    <pre id="8No7" data-lang="bash">yarn add fake-useragent</pre>
  </section>
  <p id="ia6q">теперь код</p>
  <h3 id="DUrV">пишем код для маскировки селены (нинзя пон тип 🥷)</h3>
  <pre id="zYSE" data-lang="javascript">const { Builder, Capabilities } = require(&#x27;selenium-webdriver&#x27;)
const { Options } = require(&#x27;selenium-webdriver/chrome&#x27;)
const fakeUseragent = require(&#x27;fake-useragent&#x27;)

// сетапаем наши новые опции
const options = new Options()
  // маскируемся под человека отключая режим автоматизации в хроме
  .excludeSwitches(&#x27;enable-automation&#x27;)
  .addArguments(
    &#x27;disable-popup-blocking&#x27;, // отключаем блок попапов
    &#x27;disable-notifications&#x27;, // отключаем уведомления
    &#x27;no-sandbox&#x27;, // отключаем &quot;песочницу&quot;
    &#x60;user-agent=${fakeUseragent()}&#x60;, // меняем user agent,
    &#x27;start-maximized&#x27; // запускаем браузер в фулл экране
  )
  // добавляем наши расширения
  .addExtensions([&#x27;proxy.zip&#x27;, &#x27;webrtc-control.zip&#x27;])
    
const capabilities = Capabilities().chrome()
  // отключаем возможность устанавливать automation расширения
  // типа CaptureScreenshot и тд
  .set(&#x27;useAutomationExtension&#x27;, false)

const driver = await new Builder()
  .forBrowser(&#x27;chrome&#x27;)
  .setChromeOptions(options) // &lt; добавляем
  .withCapabilities(capabilities) // &lt; добавляем
  .build()
;(async () =&gt; {
  await driver.get(&#x27;https://whatismyip.com&#x27;) // тестим ip
})()</pre>
  <p id="TH6W">вот так ты замаскировал селену!</p>
  <p id="1X1w">пробуем запускать весь код теперь:</p>
  <pre id="gwqg" data-lang="javascript">const { Builder, Capabilities, By, Key } = require(&#x27;selenium-webdriver&#x27;)
const { Options } = require(&#x27;selenium-webdriver/chrome&#x27;)
const fakeUseragent = require(&#x27;fake-useragent&#x27;)

// сетапаем наши новые опции
const options = new Options()
  // маскируемся под человека отключая режим автоматизации в хроме
  .excludeSwitches(&#x27;enable-automation&#x27;)
  .addArguments(
    &#x27;disable-popup-blocking&#x27;, // отключаем блок попапов
    &#x27;disable-notifications&#x27;, // отключаем уведомления
    &#x27;no-sandbox&#x27;, // отключаем &quot;песочницу&quot;
    &#x60;user-agent=${fakeUseragent()}&#x60;, // меняем user agent,
    &#x27;start-maximized&#x27; // запускаем браузер в фулл экране
  )
  // добавляем наши расширения
  .addExtensions([&#x27;proxy.zip&#x27;, &#x27;webrtc-control.zip&#x27;])
    
const capabilities = Capabilities().chrome()
  // отключаем возможность устанавливать automation расширения
  // типа CaptureScreenshot и тд
  .set(&#x27;useAutomationExtension&#x27;, false)

const driver = new Builder()
  .forBrowser(&#x27;chrome&#x27;)
  .setChromeOptions(options) // &lt; добавляем
  .withCapabilities(capabilities) // &lt; добавляем
  .build()
;(async () =&gt; {
  const searchInput = await driver.findElement(
    By.css(
      &#x27;body &gt; div.L3eUgb &gt; div.o3j99.ikrT4e.om7nvf &gt; form &gt; div:nth-child(1) &gt; div.A8SBwf &gt; div.RNNXgb &gt; div &gt; div.a4bIc &gt; input&#x27;
    )
  )
  await searchInput.sendKeys(&#x27;заряд от ахмеда расулова&#x27;, Key.RETURN)

  const firstLink = await driver.findElement(
    By.css(
      &#x27;#rso &gt; div:nth-child(1) &gt; div &gt; div &gt; div.Z26q7c.UK95Uc.jGGQ5e &gt; div &gt; a &gt; h3&#x27;
    )
  )
  await firstLink.click()
})()</pre>
  <figure id="8Qmk" class="m_column">
    <img src="https://img3.teletype.in/files/e5/50/e550c90c-cb3a-473a-9fd5-8141616048c2.png" width="1534" />
    <figcaption>ну лфг</figcaption>
  </figure>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="yJey">кастомный язык в браузере</h3>
    <p id="75pi">можно указать кастомные языки в селене используя <code>setUserPreferences</code></p>
    <pre id="0vXj" data-lang="javascript">const options = new Options()
  .setUserPreferences({
    &#x27;intl.accept_languages&#x27;: &#x27;es,es-ES&#x27; // испанский
  })</pre>
  </section>
  <hr />
  <h2 id="87rU">абузим хуйню?</h2>
  <p id="4nVr">наша цель — вайтлист в <a href="https://obligate.com" target="_blank">obligate</a></p>
  <figure id="FUnJ" class="m_column">
    <img src="https://img1.teletype.in/files/0c/f9/0cf946d1-8f79-4671-8bd0-1de9f1b33502.png" width="2526" />
    <figcaption>выглядит это так примерно</figcaption>
  </figure>
  <p id="qYte">ты можешь быстренько пройтись по флоу join waitlist и ты увидишь что там форма где надо что то вводить, что то тыкать, и там где вводишь — жать ентер после ввода (мы уже с тобой это изучали). в конце есть кнопка сабмит которую просто тыкаем и мы заджойнились в вайтлист. чем не лфг? флоу выглядит просто</p>
  <p id="aL39">давай автоматизируем действия для одного акка — Ahmed Rassulov</p>
  <p id="wMcG">для упрощения я не буду переписывать весь код который был до этого</p>
  <p id="IwaV">для начала тебе надо перейти на сайт и нажать на кнопку Join waitlist, ты уже знаешь как найти ее, соответственно пишем:</p>
  <pre id="UosG" data-lang="javascript">await driver.get(&#x27;https://obligate.com&#x27;)
const joinWaitlistButton = await driver.findElement(
  By.css(
    &#x27;body &gt; div.hero.wf-section &gt; div.html-embed.w-embed.w-iframe.w-script &gt; a&#x27;
  )
)
await joinWaitlistButton.click()</pre>
  <p id="U6JH">после этого начинается загрузка формы</p>
  <figure id="NVjj" class="m_retina" data-caption-align="center">
    <img src="https://img1.teletype.in/files/43/fd/43fd3bc5-8b17-47e5-9b45-965d6017aea2.png" width="459" />
    <figcaption>и тут нам нужно ждать</figcaption>
  </figure>
  <p id="MTK6">прикол в том что нам нужно ждать. кто знает сколько ждать? в целом есть два пути — императивный и декларативный. можно сказать грубый и элегантный. но элегантный путь не всегда работает. в селенимуе можно ждать до тех пор пока элемент появится в зоне видимости (учитывая то что он уже есть в DOM):</p>
  <pre id="0HnR" data-lang="javascript">await driver.wait(until.elementIsVisible(el))</pre>
  <p id="VCkK">код выше будет ждать пока элемент не появится в поле видимости &quot;юзера&quot;</p>
  <p id="fWL6">императивный путь гласит так: мы ждем определенное количество секунд пока прогрузится форма. я так подсчитал что 15 секунд хватает для того чтобы форма прогрузилась (если конечно же у тебя не зафейлится прокси). так как заставить браузер ничего не делать 15 секунд?</p>
  <pre id="Ae22" data-lang="javascript">await driver.sleep(15000) // ждет 15000 мс = 15 сек</pre>
  <p id="Uw8B">вот это кайф, продолжаем</p>
  <figure id="FVbs" class="m_column">
    <img src="https://img4.teletype.in/files/35/c2/35c26040-31c8-45b7-a525-79e39d106dcd.png" width="1678" />
    <figcaption>появляется следующая форма</figcaption>
  </figure>
  <p id="DOXK">казалось бы все просто? ща ищем инпут, и просто юзаем <code>sendKeys</code>.. казалось бы</p>
  <p id="q3bu">дело в том что так сделать не получится потому что прежде тебе нужно переключиться на нужный <code>iframe</code></p>
  <section style="background-color:hsl(hsl(24,  24%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="75Os">что такое <code>iframe</code>?</h3>
    <p id="xNo4"><code>iframe</code> это один из десятков тегов хтмл. но это не просто тег. <code>iframe</code> позволяет встраивать страницы в страницы. то есть грубо говоря HTML файлы в HTML файлы. если ты посмотришь на <code>iframe</code> в консоли то видно как у него внутри есть <code>head</code> и <code>body</code> прям как будто это отдельный хтмл документ</p>
    <p id="WOvZ">так вот для того чтобы нам работать с инпутом и элементами в целом внутри этой маленькой странички нам нужно сфокусировать селену на нем</p>
  </section>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="W5uY">как определить что элемент находится внутри <code>iframe</code>?</h3>
    <p id="eeaF">показываю на примере</p>
    <figure id="Z4D2" class="m_column">
      <img src="https://img4.teletype.in/files/33/c1/33c17c17-07b2-4fac-a11c-b8d2bc4420c2.png" width="2650" />
      <figcaption>наводимся на инпут и жмем просмотреть код</figcaption>
    </figure>
    <p id="b1bk">листаем выше пока не находим такую замечательную конструкцию</p>
    <figure id="Ef5V" class="m_column">
      <img src="https://img4.teletype.in/files/3f/64/3f649f8f-ded0-463d-b692-c541d4d311cd.png" width="2156" />
      <figcaption>это и есть iframe &gt; #document с html, head и body</figcaption>
    </figure>
  </section>
  <section style="background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="8RnV">как сфокусировать селену на <code>iframe</code>?</h3>
    <p id="e5oi">нужно определить на каком <code>iframe</code> ты хочешь сфокусить селену. можно указать либо индекс <code>iframe</code> (то есть его порядковый номер в DOM, он начинается с 0) либо сам <code>iframe</code> найденный через <code>findElement</code></p>
    <pre id="x139" data-lang="javascript">await driver.switchTo().frame(0) // в нашем случае индекс iframe = 0</pre>
    <p id="Lwzj">и начиная отсюда ты можешь искать элементы и юзать их как хочешь</p>
  </section>
  <p id="drhN">заполним мыло, нажмем кнопку ентер и подождем секунду:</p>
  <pre id="Ntcu" data-lang="javascript">const emailInput = await driver.findElement(
  By.css(
    &#x27;#block-dbda6309-71fd-49f4-83b0-a8486f031018 &gt; div &gt; div &gt; div.Root-sc-__sc-1esu8nk-2.beLakw &gt; div &gt; div &gt; div &gt; div &gt; div.SpacerWrapper-sc-__sc-4rs8xl-0.kOpjPh &gt; div.InputWrapper-sc-__sc-26uh88-1.iLBPjJ &gt; input&#x27;
  )
)
await emailInput.sendKeys(&#x27;ahmed_rassulov@mail.ru&#x27;, Key.RETURN)
await driver.sleep(1000) // 1000 мс = 1 секунда</pre>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="o2OX">зачем ждать секунду?</h3>
    <p id="kTKm">если ты заметил то после каждого ввода происходит небольшой переход между шагами который длится около половины секунды. не забудь учитывать такие моменты прежде чем ты попытаешься найти очередной элемент</p>
  </section>
  <p id="xXqC">затем нажмем кнопочку о том что мы простолюдин, а не компания:</p>
  <pre id="xb5z" data-lang="javascript">const individualButton = await driver.findElement(
  By.xpath(
    &#x27;//*[@id=&quot;block-3ab48cdb-19d6-4eb7-a953-2eb72c9864be&quot;]/div/div/div[2]/div/div/div/fieldset/div[2]/div/div[1]/div/div/div[1]/div/div/div[2]/div&#x27;
  )
)
await individualButton.click()
await driver.sleep(1000)</pre>
  <p id="2Xkt">если ты заметил здесь я ищу элемент по XPath. это просто демонстрация того что ты можешь получать элемент по XPath (выбирая <strong>Copy XPath</strong> вместо <strong>Copy selector</strong> в меню элемента в консоли)</p>
  <p id="oE8D">в целом дальше флоу абсолютно понятен и идентичен. в конце ты просто жмешь кнопку Submit и вуаля, Ахмед Рассулов заполнил форму</p>
  <figure id="uuC9" class="m_retina" data-caption-align="center">
    <img src="https://media1.tenor.com/images/9d17fd83d169a4030af2693ed6bcdc85/tenor.gif?itemid=27494734" width="320" />
    <figcaption>рубури дао на связи</figcaption>
  </figure>
  <p id="b8AZ">я прибрался в коде, полную имплементацию можно скачать <a href="https://file.io/qX5YJxyQR70f" target="_blank">здесь</a></p>
  <p id="ooDO">не забудь запустить <code>yarn install</code> до запуска кода чтоб подтянуть нужные зависимости</p>
  <hr />
  <h2 id="Fr1l">заключение</h2>
  <p id="9soU">спасибо за то что прочитал мою статью мужичок/девчонка! схватил приподнял обнял до хруста отпустил 💛</p>
  <p id="YXc3">я думаю у этой статьи, как и в случае статьи с соланой будет продолжение. в продолжении я научу тебя загонять кучу мыл, создавать логи по успешным абузам/зафейленным абузам, чтобы ты мог наблюдать и анализировать сколько акков загнал и скок не загнал и тд. в общем сделаю по красоте для тебя любимый читатель!</p>
  <p id="9C9L"><strong>я буду еще писать о концептах селены более подробно и емко, так что подписывайся на <a href="https://t.me/ruburi" target="_blank">рубури</a>!</strong></p>
  <p id="rq1O">можешь не беспокоиться если чето не запомнилось, это нормально. не отступай и иди к цели. когда я учился я хотел бросить люто масштабно два раза... но не останавливался пон!!!!! я не остановился и ща работаю дворничком (шутка конечно мужики я во вкусно и точка)</p>
  <p id="tyJu"><strong>ебашьте и все будет ахуенно</strong></p>
  <figure id="SlBi" class="m_column" data-caption-align="center">
    <img src="https://s3.gifyu.com/images/IMG_0917.gif" width="848" />
    <figcaption>с кайфом</figcaption>
  </figure>
  <h2 id="76kW">благодарности</h2>
  <p id="jgZ4"><strong>спасибо</strong> тебе за прочтение, <strong>спасибо</strong> тем кто ставит реакции, подпищекам, рыжему, сс ресерч, моей девочке, френдли тагу 52 нгг и всем остальным кто пон мотивирует ебашить <strong>люто жоска</strong></p>
  <p id="Zdew"><strong>и удачи тебе в пути кодинга еба! </strong></p>
  <h2 id="3byj">отзыв</h2>
  <p id="YUnN">если в каком то примере ошибка, или что то не получается вы всегда можете обратиться за вопросом в телегу к рубурику <strong><a href="https://t.me/rubyuroboros" target="_blank">@rubyuroboros</a></strong></p>
  <hr />
  <p id="Rm05">мой канал — <a href="https://t.me/ruburi" target="_blank">https://t.me/ruburi</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rubyuroboros/vpnSASFOcYS</guid><link>https://teletype.in/@rubyuroboros/vpnSASFOcYS?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><comments>https://teletype.in/@rubyuroboros/vpnSASFOcYS?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros#comments</comments><dc:creator>rubyuroboros</dc:creator><title>FUCKAEM SOLANU JAVASCRIPT EDITION</title><pubDate>Fri, 13 Jan 2023 22:12:10 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/e5/fb/e5fb6ef3-1870-4e98-8fec-44a1cd721d84.png"></media:content><description><![CDATA[<img src="https://blobcdn.same.energy/d/43/4e/434e11b023f438864859f93f9a1d7db7c7814f9e"></img>а солане то уже 18 исполнилось...]]></description><content:encoded><![CDATA[
  <figure id="zpYf" class="m_retina" data-caption-align="center">
    <img src="https://blobcdn.same.energy/d/43/4e/434e11b023f438864859f93f9a1d7db7c7814f9e" width="440" />
    <figcaption>GAME OVER?</figcaption>
  </figure>
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <blockquote id="rFtP">а солане то уже 18 исполнилось...</blockquote>
  </section>
  <p id="6SOh">вассааааааап другалек давно не виделись в статьях в телетайпе ебаний его рот не правда ли? давно я тебе обещал статейку, вот завожу по соланочке наваливая жесткую музяку суисайдбойс и не только...</p>
  <hr />
  <p id="2YHZ">если ты давно хотел понять как же сука с соланой играться юзая джс то эта статья для тебя! у соланы есть кукбук так шо если у тебя возникнут вопросы ты всегда можешь обратиться к <a href="https://solanacookbook.com/" target="_blank">кукбуку</a> либо к рубурику. практически все шо есть в статье есть в кукбуке — здесь я просто разжую основные концепты</p>
  <hr />
  <section style="background-color:hsl(hsl(24,  24%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="LIKs"><strong>план статьи:</strong></p>
    <ol id="RuW1">
      <li id="Valu">подготавливаем среду разработки</li>
      <li id="i7lE">коннектимся к рпс</li>
      <li id="UeoD">учимся создавать новый кош, восстанавливать кош по мнемонике и тд</li>
      <li id="kVD6">учимся подписывать сообщения нашим кошем</li>
      <li id="Arob">как получить баланс кошеля и как понять какие нфт на коше</li>
      <li id="efjt">как отправлять соляну и токены и нфт на другой адрес</li>
      <li id="o43f">заключение</li>
    </ol>
  </section>
  <h2 id="WhTv">подготавливаем среду разработки</h2>
  <p id="5Avw">если у тебя все еще нет nodejs (проказник) скачай его <a href="https://nodejs.org/en/download/" target="_blank">тут</a></p>
  <p id="Zfsl">если у тебя не установлен yarn — установи его следующей командой в терминале</p>
  <pre id="7bhC">npm i -g yarn</pre>
  <hr />
  <p id="pVvK">первое шо тебе надо сделать это создать папочку где будет храниться твой новый проектик</p>
  <p id="a3rt">теперь давай установим нужные пакеты и модули для работы с соланой используя команды:</p>
  <pre id="kOqd">yarn init -y
yarn add bip39 bs58 @solana/web3.js @solana/spl-token</pre>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <ul id="pHuD">
      <li id="2p2A">bip39 — конвертер мнемоник кодов</li>
      <li id="qDe1">bs58 — base58 декодер и энкодер</li>
      <li id="6xtk">@solana/... — тулзы соланы</li>
    </ul>
  </section>
  <p id="2nen">создавай файлик <code>index.js</code></p>
  <p id="Inyo">и наконец в файлике <code>package.json</code> прописываем <code>type: &quot;module&quot;</code> как на скрине</p>
  <figure id="5ZqO" class="m_retina">
    <img src="https://img3.teletype.in/files/65/5a/655a7c44-4402-47b0-a9c2-d2c21192ad8c.png" width="239" />
    <figcaption>пали сюда</figcaption>
  </figure>
  <hr />
  <h2 id="ME6X">коннектимся к рпс</h2>
  <p id="fwiN">здесь нам нужна рпс ноды соланы. достать можно в <a href="https://www.alchemy.com/" target="_blank">alchemy</a></p>
  <p id="mLnW">но есть и паблик нода:</p>
  <p id="7nNQ"><a href="https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2" target="_blank">https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2</a></p>
  <p id="eaNO">а теперь лфг писать код</p>
  <hr />
  <p id="BmUw">для того шобы взаимодействовать с блокчейном соланы нам нужно для начала подключиться к каой нибудь ноде которая сможет обрабатывать наши капризы. в данном примере я подрубаюсь к паблик ноде</p>
  <pre id="BGYi" data-lang="javascript">import { Connection } from &quot;@solana/web3.js&quot;;

(async () =&gt; {
  const connection = new Connection(
    &quot;https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2&quot;,
    &quot;confirmed&quot;
  );
  console.log(await connection.getEpochInfo());
})();</pre>
  <p id="mXKR">затем запускаем код командой</p>
  <pre id="tS6F">node index</pre>
  <p id="WTlu">после этого у тебя в консоли должна отобразиться инфа о текущей эпохе епта</p>
  <p id="E41Y">поздравляю! ты законнектился к ноде</p>
  <hr />
  <h2 id="uQ2t">учимся работать с кошаками </h2>
  <p id="Lg7x">после того как мы законектились к ноде мы можем работать с чейном! но к сведению -- для создания коша сам коннект к ноде нам не нужен</p>
  <h3 id="nEEq">как сгенерировать мнемонику</h3>
  <p id="RmVW">ты можешь сгенерировать новую мнемонику а соответственно новый кошелек используя <code>bip39</code></p>
  <pre id="MKOT" data-lang="javascript">import { generateMnemonic } from &#x27;bip39&#x27;;
const mnemonic = generateMnemonic();
console.log(mnemonic);</pre>
  <p id="divR">запустив этот код твоим глазам предстанет новая мнемоника! погнали дальше</p>
  <h3 id="FIpe">как восстановить кош по мнемонике</h3>
  <p id="LzRA">для того чтобы восстановить кош по мнемонике нам нужно конвертнуть мнемонику в сид, а затем создать новую пару ключей (приватный и паблик ключ). так мы и получим наш восстановленный кошелек</p>
  <pre id="PO99" data-lang="javascript">import { Keypair } from &#x27;@solana/web3.js&#x27;;
import { mnemonicToSeedSync } from &#x27;bip39&#x27;;

const mnemonic = &#x27;ruburi dao ebashit&#x27;; // тут твоя мнемоника
const seed = mnemonicToSeedSync(mnemonic);
const keypair = Keypair.fromSeed(seed.subarray(0, 32));
console.log(keypair.publicKey.toBase58());</pre>
  <p id="7Qb8">так ты получишь в консоли адрес своего коша</p>
  <h3 id="D55V">как восстановить кош по приватнику</h3>
  <p id="Leh0">все просто</p>
  <pre id="bUUf" data-lang="javascript">import { Keypair } from &#x27;@solana/web3.js&#x27;;

const keypair = Keypair.fromSecretKey(bs58.decode(&#x27;xuipizda&#x27;)); // вместо &#x60;xuipizda&#x60; твой приватник
console.log(keypair.publicKey.toBase58());</pre>
  <hr />
  <h2 id="03Js">как подписать сообщение используя кош</h2>
  <p id="RdMe">для подписьки сообщений нам пригодятся еще два модуля:</p>
  <pre id="mk8l">yarn add tweetnacl tweetnacl-util</pre>
  <p id="cBjQ">и мы good to go!</p>
  <p id="K3dF">подписываем сообщение уже существующей парой ключей:</p>
  <pre id="QKtD" data-lang="javascript">import { sign } from &#x27;tweetnacl&#x27;;
import { decodeUTF8 } from &#x27;tweetnacl-util&#x27;;

const keypair = ...
  
const message = &#x27;ТЫ ЛУЧШИЙ! СПАСИБО ЗА ТО ЧТО ЧИТАЕШЬ СТАТЬЮ;)&#x27;;
// превращаем нашу строчку в большие буфера (байты проще говоря)
const messageBytes = decodeUTF8(message);
  
const signature = sign.detached(messageBytes, keypair.secretKey);
const result = sign.detached.verify(
  messageBytes,
  signature,
  keypair.publicKey.toBytes()
);

// наше подписанное сообщение
console.log(result);</pre>
  <hr />
  <h2 id="e7bZ">получаем баланс и нфт кошеля</h2>
  <p id="zucr">получить баланс любого адреса можно используя конекшен к ноде. вспоминаем про наш коннект</p>
  <pre id="UfQ0" data-lang="javascript">import { Connection, LAMPORTS_PER_SOL } from &quot;@solana/web3.js&quot;;

(async () =&gt; {
  const connection = new Connection(
    &quot;https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2&quot;,
    &quot;confirmed&quot;
  );

  // получим баланс дегодс енджоера в лампортах
  const lamportBalance = await connection.getBalance(
    &#x27;5KrLikZiv39RNuz66azZqtHSoEiUHCa6oDWyMq64XSmh&#x27;
  );
  // конвертируем его в солану (поделив на количество лампортов в 1 соли)
  const solBalance = lamportBalance / LAMPORTS_PER_SOL;
  // отображаем
  console.log(&#x60;${solBalance} SOL&#x60;);
})();</pre>
  <p id="BSm9">так мы с тобой получили баланс дегодс енджоера. а шо по нфт?</p>
  <p id="DBJ5">для того чтобы получить нфт нам нужно преобразовать адрес аккаунта в паблик ключ. как это сделать? а вот как</p>
  <pre id="1jge" data-lang="javascript">import { Connection, PublicKey } from &quot;@solana/web3.js&quot;;
import { TOKEN_PROGRAM_ID } from &#x27;@solana/spl-token&#x27;; 

(async () =&gt; {
  const connection = new Connection(
    &quot;https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2&quot;,
    &quot;confirmed&quot;
  );

  const owner = new PublicKey(&#x27;5KrLikZiv39RNuz66azZqtHSoEiUHCa6oDWyMq64XSmh&#x27;);
  const { value: tokenAccounts }  = await connection.getParsedTokenAccountsByOwner(owner, {
    programId: TOKEN_PROGRAM_ID,
  });
})();</pre>
  <p id="TMJ0"><code>tokenAccounts</code> — это список всех токенов аккаунта (в общем всего что не соль). это может быть нфт или любой другой токен. возникнет вопрос как отличить нфт от какого то щитка? все токены можно отфильтровывать по минт адресу. в массиве <code>tokenAccounts</code> можно получить минт адрес токена, сколько токенов на аккаунте и <code>decimals</code> (количество знаков после запятой у токена по дефолту, как у эфира допустим 18, тк <code>1 eth = 10**18 wei</code>)</p>
  <p id="wY5i">отличить более менее норм токен от щитка можно через <code><a href="https://www.npmjs.com/package/@solana/spl-token-registry" target="_blank">@solana/spl-token-registry</a></code></p>
  <figure id="SzTw" class="m_column">
    <img src="https://img3.teletype.in/files/ed/68/ed680dbf-6dc3-49b1-8800-cad53ce855b8.png" width="1500" />
    <figcaption>вот так ты можешь получить список не щитков</figcaption>
  </figure>
  <p id="DIOq">щитки в моем понимании это токены без иконки, имени и тд. но насколько мне известно в регистри не записываются нфт типа дегодс. они обычно не состоят в регистри</p>
  <p id="NPNJ">давайте найдем дегодса #9382 у челика выше</p>
  <pre id="G40O" data-lang="javascript">import { Connection, PublicKey } from &quot;@solana/web3.js&quot;;
import { TOKEN_PROGRAM_ID } from &#x27;@solana/spl-token&#x27;; 

(async () =&gt; {
  const connection = new Connection(
    &quot;https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2&quot;,
    &quot;confirmed&quot;
  );

  const owner = new PublicKey(&#x27;5KrLikZiv39RNuz66azZqtHSoEiUHCa6oDWyMq64XSmh&#x27;);
  const { value: tokenAccounts }  = await connection.getParsedTokenAccountsByOwner(owner, {
    programId: TOKEN_PROGRAM_ID,
    mint: new PublicKey(&#x27;qzHFrK32hhWQuPkaFSKKVwbuqWMB2qUK8cbHVZHKvy2&#x27;)
  });
  if (tokenAccounts.length &gt; 0) {
    const degod = tokenAccounts[0];
    console.log(degod.account.data.parsed.info.tokenAmount.amount);
  }
})();</pre>
  <p id="CrZK">выведет нам 1 (если конечно чел не продал все еще его). давай немного разберем код. мы ищем в tokenAccounts тот токен чей минт адрес совпадает с минт адресом <a href="https://solscan.io/token/qzHFrK32hhWQuPkaFSKKVwbuqWMB2qUK8cbHVZHKvy2" target="_blank">DeGod #9382</a></p>
  <figure id="RsS2" class="m_column">
    <img src="https://img3.teletype.in/files/67/ec/67ec62a1-2857-4571-aa40-e9f4f919f2f4.png" width="1136" />
    <figcaption>это нам нада</figcaption>
  </figure>
  <p id="Bydk">ты можешь отфильтровать токены если ты ищешь определенный токен по минт адресу с помощью свойства <code>mint</code> в методе <code>getParsedTokenAccountsByOwner</code></p>
  <p id="TXVa">на выходе мы получаем массив, проверяем что дегодс на месте и выводим количество дегодсов (в данном случае 1)</p>
  <hr />
  <h2 id="mwE1">как отправлять соляну и нфт на другие коши</h2>
  <h3 id="xD0q">как отправлять соляну</h3>
  <pre id="qQzf" data-lang="javascript">import {
  Connection,
  Transaction,
  SystemProgram,
  sendAndConfirmTransaction,
  PublicKey
} from &quot;@solana/web3.js&quot;;

(async () =&gt; {
  const connection = new Connection(
    &quot;https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2&quot;,
    &quot;confirmed&quot;
  );

  // keypair откуда отправляем
  const fromKeypair = ...
  
  // 1 - получаем хэш последнего блока в сети
  const blockhash = (await connection.getLatestBlockhash(&#x27;finalized&#x27;)).blockhash;
  // 2 - создаем транзу
  const transferTransaction = new Transaction({
    // здесь можно указать адрес который платит комсу, нужен именно паблик ключ
    // feePayer: fromKeypair.publicKey
    blockhash
  }).add(
    SystemProgram.transfer({
      fromPubKey: fromKeypair.publicKey,
      // publicKey кому мы отправляем солану (адрес вместо &#x60;wassup&#x60;)
      toPubKey: new PublicKey(&#x27;wassup&#x27;),
      lamports: 100000000 // количество в лампортах (!)
    })
  );
  // 3 - подписываем и отправляем транзу
  await sendAndConfirmTransaction(connection, transferTransaction, [fromKeypair]);
})();</pre>
  <p id="kRKE">этого достаточно для того чтобы отправить соль на другой адрес. тебе нужно будет иметь keypair кошелька откуда ты отправляешь соль и публичный ключ аккаунта куда ты отправляешь</p>
  <h3 id="X1Nt">как отправить токен (нфт)</h3>
  <p id="K7X8">механизм в целом ничем особенным не отличается кроме того в случае токена если под токен на адресе не создан токен аккаунт (дада, в солане нужно создавать токен аккаунт для того чтобы посылать на него какой то токен). а токен аккаунты создаются по минт адресу токена</p>
  <p id="6UVL">проверить создан ли у тебя токен аккаунт под определенный токен можно лишь вызвав <code>getParsedTokenAccountsByOwner</code> из предыдущей секции и получив существующие у тебя токен аккаунты на коше</p>
  <pre id="jBqK" data-lang="javascript"> import {
  Connection,
  transferChecked,
  PublicKey,
  Keypair
} from &quot;@solana/web3.js&quot;;
import { TOKEN_PROGRAM_ID } from &#x27;@solana/spl-token&#x27;;
import { mnemonicToSeedSync } from &#x27;bip39&#x27;; 

(async () =&gt; {
  const connection = new Connection(
    &quot;https://solana-mainnet.g.alchemy.com/v2/QY6qW6UrMVDw8DINgQLqyDZJgAOdJOt2&quot;,
    &quot;confirmed&quot;
  );

  const mnemonic = &#x27;ruburi dao ebashit&#x27;; // тут твоя мнемоника окда
  const seed = mnemonicToSeedSync(mnemonic);
  // keypair откуда отправляем нфт
  const owner = Keypair.fromSeed(seed.subarray(0, 32));
  const fromTokenAccount = new PublicKey(&#x27;lolkek&#x27;);
  const mintAddress = &#x27;sosopaviashvilidao&#x27;
  const toTokenAccount = newPublicKey(&#x27;scammer&#x27;);
  const amount = 1, decimals = 1;
  
  const txHash = await transferChecked(
    connection, // наш коннкешен
    owner, // keypair кто платит комсу
    fromTokenAccount, // publicKey адреса токен аккаунта откуда отправляем
    mintAddress, // publicKey минт адреса отправляемого токена
    toTokenAccount, // publicKey адреса токен аккаунта куда отправляем
    owner, // keypair кошеля овнера токена
    amount, // количество токенов
    decimals // числа после запятых (можно получить в инфе из tokenAccounts)
  );
})();</pre>
  <h3 id="tqDX">создаем токен аккаунт если у коша его нет</h3>
  <pre id="FhHZ" data-lang="javascript">import { ..., PublicKey, createAssociatedTokenAccount } from &#x27;@solana/web3.js&#x27;;

(async () =&gt; {
  ...code
  
  const mint = new PublicKey(&#x27;bulshitmintaddress&#x27;);
  const ata = await createAssociatedTokenAccount(
    connection, // наш коннекшен
    feePayer, // keypair кто платит комсу
    mint, // publicKey (!) минт адреса
    owner.publicKey // publicKey (!) владельца нового токен аккаунта
  );
  console.log(ata.toBase58()); // выводим адрес нового токен аккаунта
})();</pre>
  <p id="iblJ">адрес нового токен аккаунта как раз таки и будет нужен тебе для отправки нужного токена, только не запутайся где <code>publicKey</code> а где <code>keypair</code>!</p>
  <section style="background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <h3 id="uFWz">как преобразовать адрес в publicKey адреса</h3>
    <p id="z6AM">напомню тебе</p>
    <pre id="GBuZ" data-lang="javascript">new PublicKey(&#x27;ADDRESS&#x27;)</pre>
    <p id="xoxf">и не забудь импортировать нужные методы из модулей</p>
  </section>
  <hr />
  <h2 id="7mfJ">заключение</h2>
  <p id="dSXm">вот в принципе все шо я хотел тебе сегодня рассказать и показать о солане на javascript!</p>
  <p id="NEqn">скоро будет статья также по солане как создавать свой токен и минтить его, сжигать, как создавать candy machine, как туда вносить свои нфт и как минтить нфт через candy machine id. в общем будет оч оч гемно нахуй</p>
  <p id="9C9L"><strong>я буду еще писать о концептах js более подробно и емко, так что подписывайся на <a href="https://t.me/ruburidao" target="_blank">рубури дао</a>!</strong></p>
  <p id="rq1O">можешь не беспокоиться если чето не запомнилось, это нормально. не отступай и иди к цели. когда я учился я хотел бросить люто масштабно два раза... но не останавливался пон!!!!! я не остановился и ща работаю дворничком (шутка конечно мужики я во вкусно и точка)</p>
  <p id="tyJu"><strong>ебашьте и все будет ахуенно </strong></p>
  <figure id="GTec" class="m_custom">
    <img src="https://c.tenor.com/1V9b8Eg0nHUAAAAM/dwayne-johnson-the-rock.gif" width="220" />
    <figcaption>мотивация от рубури дао как всегда</figcaption>
  </figure>
  <h2 id="76kW">благодарности</h2>
  <p id="jgZ4"><strong>спасибо</strong> тебе за прочтение, <strong>спасибо</strong> тем кто ставит реакции, подпищекам, рыжему, сс ресерч, моей девочке, френдли тагу 52 нгг и всем остальным кто пон мотивирует ебашить <strong>люто жоска</strong></p>
  <p id="Zdew"><strong>и удачи тебе в пути кодинга еба! </strong></p>
  <h2 id="3byj">отзыв</h2>
  <p id="YUnN">если в каком то примере ошибка, или что то не получается вы всегда можете обратиться за вопросом в телегу к рубурику <strong><a href="https://t.me/rubyuroboros" target="_blank">@rubyuroboros</a></strong></p>
  <hr />
  <p id="Rm05">мой канал — <a href="https://t.me/ruburi" target="_blank">https://t.me/ruburi</a></p>
  <figure id="8t7s" class="m_column">
    <img src="https://img2.teletype.in/files/91/27/9127283d-1e3b-4913-9e71-10526048788a.png" width="2538" />
    <figcaption>это ты чисто и я (рубурик давольный) после того как ты начал жоска воркать в веб3</figcaption>
  </figure>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rubyuroboros/kIHvpV470NB</guid><link>https://teletype.in/@rubyuroboros/kIHvpV470NB?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><comments>https://teletype.in/@rubyuroboros/kIHvpV470NB?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros#comments</comments><dc:creator>rubyuroboros</dc:creator><title>полезная инфа где и как изучать и практиковать web разработку (для чайников пон)</title><pubDate>Wed, 14 Dec 2022 12:29:36 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/b6/e9/b6e97bd5-ebcc-4584-9873-2bc1574eacf5.png"></media:content><description><![CDATA[<img src="https://preview.redd.it/3g63ff4zfin21.png?auto=webp&amp;s=77043ef6656364bb3aed9e6a9f4e52587aae350a"></img>привет друк!]]></description><content:encoded><![CDATA[
  <figure id="iN6T" class="m_column">
    <img src="https://preview.redd.it/3g63ff4zfin21.png?auto=webp&s=77043ef6656364bb3aed9e6a9f4e52587aae350a" width="2380" />
    <figcaption>пиксель артыыыы топпчик особенно с фиолетовым небом purple drank пон yung lean</figcaption>
  </figure>
  <p id="erZF"><strong>привет друк!</strong></p>
  <p id="toUw">сегодня мы с тобой продолжаем путешествие в мире <strong>кодинга</strong> пон! начинали мы со вступительной статеечки основ жиэса и отображения балика в эфире на своем сайте, а щас я оставлю здесь сколько смогу ресурсов для изучения жиэс (не то чтобы соберу солянку из ресурсов, оставлю именно те по которым я учился и которые мне дали знания которые щас уменя есть). в том числе книжки какие то оставлю</p>
  <figure id="QJfR" class="m_original">
    <img src="https://customsitesmedia.usc.edu/wp-content/uploads/sites/59/2020/11/16002124/TFM-WIN20-TMenzel-Computer-working.gif" width="300" />
    <figcaption>изучил прогинг с рубуриком и нехуя непонел баля</figcaption>
  </figure>
  <p id="o5fC"><strong>лфгггггг</strong> 🩸🪓</p>
  <hr />
  <h2 id="erh6">предисловие</h2>
  <p id="bnoD">я не претендую на звание суперпрепода или чела который 100% обладает всегда актуальной инфой в этом. в этой статье ресурсы по которым я когда то учился и которые по сей день не потеряли актуальности. ресурсы могут быть древними (но когда я изучал хтмл по хтмлбуку, он еще тогда считался древним и ничего)</p>
  <p id="MUxs"><strong>еще важно:</strong></p>
  <p id="RSwQ">пожалуйста, не лезь ни в какие курсы нетологий, гикбрейнсов, яндексов, хтмлакадеми и так далее (я про снг сегмент в целом). да, тебя чему то научат (не факт), но это не стоит 15000, 30000, 45000 и тд. по окончанию тебе дадут никому на хуй ненужный на рынке сертификат. даже корочка из шараги и то будет больше тя красить на собесе каком нибудь. ну баля 90% короче этих курсов полная хуйня</p>
  <p id="VXNs">лучше вложи эти деньги в себя, в темки. если ты не можешь никак без курсов — <a href="https://www.freecodecamp.org/" target="_blank">freecodecamp</a>, <a href="https://www.udemy.com/" target="_blank">udemy</a>, <a href="https://www.coursera.org" target="_blank">coursera</a>, <a href="https://ru.khanacademy.org/" target="_blank">khan academy</a>, в общем бери зарубежное (там даже много бесплатного)</p>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="jJ0K">вот несколько правил как стопудово <strong>ебашить</strong> ахуено:</p>
    <ol id="IKhQ">
      <li id="3p1l">после изучения какой то фичи обязательно практикуйся</li>
      <li id="0hFg">не запихивай в себя овер дохуя, если чуешь что мозг уже не вывозит отдыхай потом приходи и вспоминай практикуй то что уже изучил и только потом приступай к новому</li>
      <li id="fkFj">отдыхай чаще реально</li>
      <li id="j7Q7">если чето не получается не думай что это не твое, попробуй 7 раз пон захватить эту крепость пон тока потом делай выводы (на самом деле про 7 раз я ваще ща спиздел и из воздуха взял, но реально отнесись серьезно и если 1-2 раза не получилось тупо не кидай занятие, это нормально если не получается, мы не сверхразумы)</li>
    </ol>
  </section>
  <hr />
  <h2 id="gTzX">HTML</h2>
  <p id="WMHz"><a href="http://htmlbook.ru/" target="_blank">htmlbook</a> — древний сайт но оч полезный для того чтобы посмотреть какие теги есть в хтмл вообще и изучить каждый (в свое время я читал про абсолютно все теги что там есть, полезно)</p>
  <p id="6VBm">вообще по хтмл рекомендую просто гуглить и изучать все что видишь, потому что у разных людей разное, субъективное видение на верстку. типа как расположить элементы по смыслу и так далее, ты ничего не потеряешь если изучишь что то поверх, лишнего в хтмл ничего не будет</p>
  <p id="Vo7a">разве что книги не всегда стоит читать, они гигантские, сухие, неинтересные. лучше бери любые видосы на ютубе, можешь даже взять хауди хо изучаем html за час пон (хауди хо это если что легенда инфобизнеса который учит питону за час , есть еще такой гений гоша дударь, но не будем отвлекаться)</p>
  <figure id="M7Re" class="m_column">
    <img src="https://img1.teletype.in/files/81/3e/813ebf53-7e25-472b-82c1-dfc72e5b5baf.png" width="2152" />
    <figcaption>ну это еще ладно как то... с горем пополам</figcaption>
  </figure>
  <figure id="83OZ" class="m_column">
    <img src="https://img2.teletype.in/files/93/b2/93b27a00-e20e-4a21-a021-181d569d8623.png" width="2228" />
    <figcaption>ну вы поняли, клиника</figcaption>
  </figure>
  <hr />
  <h2 id="PFQf">CSS</h2>
  <p id="Z2jJ">также как и с хтмл, пооставляю не очень (очень) древних ресурсов где обьясняется css</p>
  <p id="8GWL">база — <a href="https://developer.mozilla.org/ru/docs/Learn/CSS/First_steps" target="_blank">mdn</a>, <a href="http://htmlbook.ru/" target="_blank">htmlbook</a>, <a href="https://html5css.ru/css/css_intro.php" target="_blank">html5css</a></p>
  <p id="S2JX">можешь также смотреть видосы рандом инфу короче, лишнего ничего нет, <strong>кроме одного</strong></p>
  <p id="vA6D">наверняка в одном из древних ресурсов ты наткнешься на свойство  <code>float</code></p>
  <p id="oUSF">изучи его, но не юзай для расположения блоков на странице! для этого изучи <code>flex</code> (флексим жоскии) и <code>grid</code></p>
  <p id="pUXj">после изучения основных основ можешь просто заходить <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/all" target="_blank">сюда</a> и смотреть все свойства которые есть (там их много, но why not, тоже будет ультраполезно)</p>
  <hr />
  <h2 id="6MNP">JS</h2>
  <p id="hXzE">вот мы и подошли с тобой к самому интересному где важно в рот говна не набрать и не возиться с хуй пойми чем а нужно найти реально хорошие ресурсы где тебе не льют говна в уши</p>
  <p id="exMp"><a href="https://roadmap.sh/javascript" target="_blank">JavaScript roadmap</a> — гем гемов правда на английском (я фанат роадмапов)</p>
  <p id="YL2T"><a href="https://learn.javascript.ru/" target="_blank">https://learn.javascript.ru/</a> — просто баля Saint Грааль пон ру туториалов. это просто гемчик который ебет жестко, кроме этого тебе больше ничего не надо пон (ну там реально дают понять что такое жаваскрипт от и до, изучив все ты спокойно сможешь отвечать на любые вопросы по жаваскрипту на собесах даже на высоком уровне)</p>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="YeLt"><strong>супер важные правила как изучать:</strong></p>
    <ol id="9kqj">
      <li id="8oMG">не прыгай с раздела в раздел в пределах частей, это нежелательно</li>
      <li id="LUpp">обязательно выполный все задачи, по крайней мере пытайся их выполнить</li>
      <li id="UP0J">не прыгай сразу в какую то другую часть (типа dom), ну только если тебе не супер интересно, чтоб просто удовлетворить интерес. иначе есть риск возникновения в голове лютой каши</li>
      <li id="fP4G">обязательно изучи все, там важно <strong>все </strong>(особенно регулярки)</li>
      <li id="Pgo2">регулярки (3 часть) полностью зубрить необязательно, 80-90% регулярок нужных по работе гуглятся</li>
      <li id="XJMs">зубрить как в школе не нужно, учи и практикуй, нужно кайфовать от этого (это скорее всего сыграет ключевую роль)</li>
    </ol>
  </section>
  <h3 id="YQ1z">TypeScript</h3>
  <p id="afGr">тайпскрипт мастхев штука ее часто требуют в работе, но у начинающих челов могут и не требовать, ты можешь изучить ее непосредственно на опыте, но если тебе ваще норм типа энергии дахуя пон то лфг:</p>
  <p id="HH58"><a href="https://www.jscamp.app/ru/docs/typescript00/" target="_blank">jscamp</a> — прикольный ресурс на русском в приятном цвете</p>
  <p id="ugxb"><a href="https://metanit.com/web/typescript/1.1.php" target="_blank">metanit</a> — древний ресурс по которому я изучал ts, может кому зайдет</p>
  <p id="qp0L"><a href="https://www.typescripttutorial.net/" target="_blank">typescript tutorial</a> — ресурс на английском</p>
  <p id="3i0x"></p>
  <h3 id="x8Re">книги</h3>
  <p id="HVOj">я не сильный фанат книг но книги которые я перечисляю ниже я читал и мне понравилось</p>
  <h3 id="Sua8">после того как ты изучишь js (не ts) из сурсов выше</h3>
  <p id="phtT"><strong>Выразительный JavaScript</strong> от Marijn Haverbeke — мастхев штука после которой я взорвал себе мозг и сильно бустанул свои знания в жиэсе. проверенных сурсов где ее достать у меня прям ща нет, загугли тыкни на удобную тебе ссылку (а то еще скажешь что я тебе тут трояны подкладываю)</p>
  <p id="title"><strong>Beginning Functional JavaScript: Functional Programming with JavaScript Using EcmaScript 6</strong> от Anto Aravinth — заебатая книжечка о том что такое функциональное программирование. само фп поможет тебе мыслить неочевидным путем. написана для жиэсеров</p>
  <h3 id="ghwx">продвинутый лвл</h3>
  <p id="M18D"><strong>Грокаем алгоритмы</strong> от Aditya Bhargava — имба книжка про основные алгоритмы, особенно если хочешь устраиваться в яндекс, мыло и другие большие компании там ебут про алгоритмы прямо как знаешь как будто оказался на олимпиаде по инфе в 9 классе... ну не будем об этом. основные базовые алгоритмы <strong>полезно</strong> знать</p>
  <p id="hFWL"><strong>Высоконагруженные приложения. Программирование, масштабирование, поддержка</strong> от Martin Kleppmann — ахуенная книга о том как проектировать и разрабатывать большие системы</p>
  <p id="GtDA"><strong>Компьютерные сети </strong>от Andrew Tanenbaum — имба книга о том что такое http, https, tcp/ip, udp различные протоколы, osi модель, короче обо всем что происходит под капотом в интернете, вообще в компьютерных сетях. мастхев (но может наскучить)</p>
  <p id="iTEU"></p>
  <h3 id="bvBp">остальное</h3>
  <p id="JFHr"><a href="https://doka.guide/js/architecture-and-design-patterns/" target="_blank">про паттерны проектирования и архитектуру приложений</a></p>
  <p id="ORiC"><a href="https://tproger.ru/translations/design-patterns-simple-words-1/" target="_blank">немного больше про паттерны проектирования</a></p>
  <h3 id="61UO">практика js</h3>
  <p id="kmog">задачи из <a href="https://learn.javascript.ru/" target="_blank">https://learn.javascript.ru/</a></p>
  <p id="Gkj2"><a href="https://www.codewars.com/" target="_blank">codewars</a></p>
  <p id="4331"><a href="https://www.hackerrank.com/" target="_blank">hackerrank</a></p>
  <p id="jOmx"><a href="https://leetcode.com/" target="_blank">leetcode</a></p>
  <p id="Q4UR"><a href="https://www.codingame.com/" target="_blank">codingame</a></p>
  <h3 id="APRz">sandboxes, playgrounds</h3>
  <p id="Vp76">сандбокс или playground — место где ты можешь потыкать и попрактиковать js ( и не только) без необходимости запускать редактор или поднимать среду разработки</p>
  <p id="ncHX"><a href="https://codepen.io/" target="_blank">codepen</a></p>
  <p id="Xt2D"><a href="https://codesandbox.io/" target="_blank">codesandbox</a></p>
  <p id="VXBf"><a href="https://jsfiddle.net/" target="_blank">jsfiddle</a></p>
  <hr />
  <h2 id="55dP">общее</h2>
  <p id="nkty"><a href="https://roadmap.sh/frontend" target="_blank">Frontend Roadmap</a> — гем гемов опять же (инглиш нужен)</p>
  <p id="7AUk"><a href="https://developer.mozilla.org/ru/" target="_blank">MDN</a> — в целом и в общем ахуенный ресурс для того чтобы подсмотреть какие то штуки будь то в html, css или js (мдн регулярно обновляют и добавляют новые особенности, убирают старое и тд). у них даже есть ахуеный <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web" target="_blank">тутор</a> по хтмл, ксс, жиэс</p>
  <hr />
  <h2 id="qRUf">заключение</h2>
  <p id="WYVd">в общем выше я перечислил все что знал про то как изучить хтмл ксс и жиэс. пока не затронул тему библиотек и фреймворков для жиэс, но об этом будет отдельная статья лфг!</p>
  <p id="ReZo">с перечисленными мною ресурсами ты сможешь изи изучать веб разработку и становиться ахуенной крутышкой разраабом пон и делать сайты крути! давай лфг нахуй</p>
  <figure id="8I25" class="m_original">
    <img src="https://media.tenor.com/d6e-Rvp97dEAAAAM/monkey-gangster-monkey.gif" width="220" />
    <figcaption>енто ти крутышка карочи после тово как изучил все</figcaption>
  </figure>
  <hr />
  <h2 id="mgBa">рубрика вопросы подпищеков</h2>
  <figure id="Ccdm" class="m_column">
    <img src="https://img2.teletype.in/files/53/4c/534cbdb9-8338-4b42-8130-d2b3400b6283.png" width="714" />
    <figcaption>yungz0r спрашивает</figcaption>
  </figure>
  <p id="ZiRe">ну пон я ваще разное юзал в своей жизни... <s>гаш меф</s> (асуждаю)</p>
  <p id="VVCY">спонтанно как то к js пришел ну а так, если подумать то по факту мне нравится веб разработка, на питоне ну ты напишешь сервак типа к сайту но не функциональный фронтенд</p>
  <p id="0l90">питон для меня всегда был многофункциональным языком типа для тех кто изучает ии, пишет какие то игрушки, программки и тд. по факту и в жсе ты можешь программировать там роботов, игрушки программки но мне еще питон синтаксисом не очень нравится, ну типа отсутствие скобок, точек с запятой, понимание инструкций чисто по отступам</p>
  <p id="gHq3">ну еще за рыночек питона не шарю, но мне кажется там похуже, да и чаще требуют какую нибудь computer science degree для устройства на работу. не знаю еще есть ли на питоне подобие тайпскрипта, но сам по себе он слабо типизирован (впрочем как и жс, который тайпскрипт спасает хотя бы)</p>
  <p id="4QHA">ну еще в питон лезет каждый второй, с жсом также но все равно мне кажется жс тяжелее для понимания новичкам</p>
  <hr />
  <h2 id="76kW">благодарности</h2>
  <p id="jgZ4"><strong>спасибо</strong> тебе за прочтение, <strong>спасибо</strong> тем кто ставит реакции, подпищекам, рыжему, сс ресерч, моей девочке, френдли тагу 52 нгг и всем остальным кто пон мотивирует ебашить <strong>люто жоска</strong></p>
  <p id="Zdew"><strong>и удачи тебе в пути кодинга еба! </strong></p>
  <hr />
  <h2 id="Gjq0">отзыв</h2>
  <p id="YUnN">если в каком то примере ошибка, или что то не получается вы всегда можете обратиться за вопросом в телегу к рубурику <strong><a href="https://t.me/rubyuroboros" target="_blank">@rubyuroboros</a></strong></p>
  <hr />
  <p id="Rm05">мой канал — <a href="https://t.me/ruburi" target="_blank">https://t.me/ruburi</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rubyuroboros/27w_de2svrO</guid><link>https://teletype.in/@rubyuroboros/27w_de2svrO?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><comments>https://teletype.in/@rubyuroboros/27w_de2svrO?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros#comments</comments><dc:creator>rubyuroboros</dc:creator><title>становимся javascript web3 developerom с рубуриком 👨🏿‍💻</title><pubDate>Sun, 11 Dec 2022 00:44:04 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/9b/14/9b14ea51-de07-4076-9179-ec0ee8c88f67.png"></media:content><description><![CDATA[<img src="https://img.freepik.com/free-vector/pixel-art-mystical-background_52683-87349.jpg?w=2000"></img>всем хаюшки мужичкки сегодня рубрика кодинг ака учим джавускрипт вместе с рубуриком ака учим давить жабу]]></description><content:encoded><![CDATA[
  <figure id="XAAr" class="m_column">
    <img src="https://img.freepik.com/free-vector/pixel-art-mystical-background_52683-87349.jpg?w=2000" width="2000" />
    <figcaption>пиздатый пиксель артик, по заветам товарища рыжего</figcaption>
  </figure>
  <h2 id="BOMN">вступление</h2>
  <p id="rxwv">всем хаюшки мужичкки сегодня рубрика кодинг ака учим джавускрипт вместе с рубуриком ака учим давить жабу</p>
  <section style="background-color:hsl(hsl(24,  24%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="sjyf"><strong>содержание:</strong></p>
    <ol id="Q3Lp">
      <li id="tcs0">из чего состоят сайты и как их пилят</li>
      <li id="yLLy">что такое js и его роль в веб разработке</li>
      <li id="Vy1b">создаем сайт</li>
      <li id="Vkrv">основы синтаксиса js и простейшие конструкции</li>
      <li id="9hh5">подрубаем веб3, коннектим метамаскич и отображаем свои миллионы эфиров на сайте 🤑</li>
    </ol>
  </section>
  <p id="H0vA">постараюсь все обьяснить тебе своими словами и по простому, без различных супер тяжелых слов, сочетаний и университетских терминологий</p>
  <p id="TpHW">какие то моменты были упрощены, я не вдаюсь в лютые подробности чтобы сильно не загружать в начале</p>
  <hr />
  <p id="0WUm">и конечно же ставь реакции ведь когда я вижу их мое сердце тает damn 💜</p>
  <p id="d4zy">это дает мне мотивацию делать для тебя больше контента</p>
  <p id="PjOl"><strong>летс факин снюс гоу!!!!!! 🩸🪓</strong></p>
  <hr />
  <h2 id="lZDO">из чего состоят сайты и как их пилят</h2>
  <p id="DyTT">больший процент сайтов которые ты видишь в вебе это сочетание html + css + js</p>
  <p id="Bl9J">давай представим что твой сайт — это дом</p>
  <h3 id="JW6f">ватафак ис html</h3>
  <p id="UbdB">html — язык гипертекстовой разметки. это не язык программирования</p>
  <p id="htha">в примере с домом html — фундамент, бетон, цемент, двери (неоткрывающиеся, об этом позже) и тд. в общем все благодаря чем дом держится на земле матушке в общем</p>
  <p id="dvsy">разрабы пишут там блоки, составляют фундамент страницы, что где будет расположено по смыслу и тд (пример — вот тут заголовок, там вот параграф, ниже картинка)</p>
  <h3 id="zlei">ватафак ис css</h3>
  <p id="9l13">css — таблицы стилей. это не язык программирования</p>
  <p id="errj">в примере с домом css — цвет дверей, цвет пола, форма окон, в общем все что связано с красотой и грацией визуала. без css дом скучный бесцветный и неинтересный</p>
  <p id="CJQ3">разрабы пишут там стили, придают тексту цвет, располагают блоки, дают отступы (например задают заголовку отступ от параграфа) и тд</p>
  <h3 id="dH0U">ватафак ис js</h3>
  <p id="iboA">вот вишенка на тортике 🍒</p>
  <p id="8hDp">js — язык программирования, используемый в основе своей для того чтобы разрабатывать веб сайты, некоторые сайты можно называть приложениями (app). отсюда и название у веб3 сайтов — dapp — decentralized application</p>
  <p id="1JTh">в примере с домом js — функциональность. то есть без js в доме нельзя открыть и закрыть дверь ведь мы не прикрепили функционал движения двери к ней (то есть дверь просто тупо статична). или же другой пример может быть получше — без js в доме не работало бы электричество. сам факт того что мы можем дернуть включатель и включится свет — js — функциональность</p>
  <p id="0bI4"></p>
  <p id="06gl">в конечном итоге соединяя <strong>html + css + js</strong> получается полноценный функционирующий крутой сайт</p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="XxkT">работает это следующим образом:</p>
    <ol id="MKfL">
      <li id="P03D">создается <strong>html</strong> файл, пишется разметка, фундамент</li>
      <li id="vLH1">фундамент и все остальное украшают с помощью <strong>css</strong>, <strong>css</strong> подключают к html странице</li>
      <li id="ORtq">пишут и также подключают <strong>js</strong> скрипт к html странице и сайт &quot;оживает&quot;</li>
    </ol>
  </section>
  <p id="Ym7Z">лфг в след этап твоего вступления в мир веба!</p>
  <hr />
  <h2 id="Z5DA">что такое js и его роль в веб разработке</h2>
  <p id="yzvA">возвращаясь к примеру с домом — если бы был только html и css то включатель был бы условно говоря розового цвета, и он сам существовал бы (его фундамент, благодаря html), но он не работает без js. потому что надо соединить электрическую цепь для лампы с включателем</p>
  <p id="XWjP">на примере с сайтами — сайты без js не функциональны. в большинстве случаев там нельзя сделать практически ничего, просто смотреть. js позволяет разработчикам получать ввод в текстовых полях от пользователя, реагировать на его клики, даже на движение мышью и так далее. поэтому js — обязательное условие для большинства сайтов. если посмотреть на сайты постарее когда js не был сильно распространен, старые сайты были в основном статичны, а чтобы загрузить туда какую то картинку условно говоря, занимало кучу времени, надо было прямиком на сервер загружать самому файлы и тд. короче ноль автоматизации и максимум неудобства</p>
  <p id="143d">теперь к более интересному — практике!</p>
  <hr />
  <h2 id="arbO">создаем сайт</h2>
  <p id="ZtDq">перво-наперво тебе нужно скачать какой-нибудь редактор кода</p>
  <p id="rObn">два моих любимых варианта: <a href="https://code.visualstudio.com/insiders/" target="_blank">vs code insiders</a> и <a href="https://www.sublimetext.com/download" target="_blank">sublime text</a></p>
  <p id="YUmh">но так то можешь юзать хоть виндос блокнот, хоть vim в unix, главное писать текст</p>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="XEYA">в этой статье я не буду вдаваться в подробности настроек редакторов, под это будет <strong>отдельная статья</strong> где я перечислю список своих любимых расширений для вс код, как его настраивать удобненько, также и с саблайм текстом</p>
    <p id="xei8">для блокнота настроек не будет... прости... (ну только размер шрифта поменять если)</p>
  </section>
  <p id="jD3P">в целом базовое использование двух перечисленных мной редакторов не требует быть хакером пентагона поэтому для этой статьи 100% разберешься как создать папку, открыть ее в редакторе, создавать файлы в редакторе</p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="OEaP">единственное что - тема. кому то она может показаться уебанской (как в сабламе так и в вс коде)</p>
    <p id="pgjo">чтобы поменять тему жмешь на винде <code>Ctrl + Shift + P</code>, на маке <code>Command + Shift + P</code></p>
    <p id="9L5F">после вводишь в поле открывшегося окна &quot;тема&quot; или &quot;theme&quot; если вы из англии</p>
    <figure id="v2x2" class="m_retina">
      <img src="https://img1.teletype.in/files/c4/e9/c4e9a4c9-f066-4be8-b9ae-257a01a4392a.png" width="590" />
      <figcaption>будет там такая хуевина, жмете на нее</figcaption>
    </figure>
    <p id="Beaz">после этого тебе откроется менюшка для выбора темки, выбираешь сочненькую для себя (если все говно, то надо будет инсталлить кастомную)</p>
    <p id="oyHo">из кастомных имхо лучшие:</p>
    <ol id="NcJR">
      <li id="68GS">Dracula</li>
      <li id="z5hI">Atom One Dark</li>
    </ol>
  </section>
  <p id="jS8G">окей потратили времечко на темку пора возвращаться дальше учиться как ебашить. завод уважаем но мы с тобой ведь выходим на новый уровень <strong>лфг </strong></p>
  <p id="1Kxv">создаем папочку, называешь ее как тебе угодно и создаешь в ней три файла:</p>
  <ol id="Cdjv">
    <li id="d6PB"><code>index.html</code></li>
    <li id="tgK9"><code>style.css</code></li>
    <li id="FHD5"><code>script.js</code></li>
  </ol>
  <p id="aslC">ты такой подумал наверное ну ладно один файл называется стайл, потому что стили, другой скрипт потому что джиэс, а че хтмл называется индекс. так вот ответ — <s>пошел нахуй</s> (это шутка если что падпищеки я вас люблю не бейте лучше обосыте..)</p>
  <p id="NAwE"><code>index</code> чаще всего в прогинге — обозначение <strong>главной</strong> программы, <strong>главного</strong> фундамента. в c++ есть <code>main</code> ну вот тут это типа того</p>
  <p id="FK6R">создал значит да? крутышка епта прям как мороженка пон</p>
  <figure id="7lb1" class="m_retina">
    <img src="https://lenta.servicecdn.ru/globalassets/1/-/06/76/05/7002_1.png?preset=fulllossywhite" width="512" />
    <figcaption>признайся захотел? э, руки на стол</figcaption>
  </figure>
  <h3 id="SbjQ">index.html</h3>
  <p id="4oe6">наполняем наш файлик <code>index.html</code> контентиком по этой линке:</p>
  <p id="anzt"><a href="https://pastebin.com/pgXHHVQm" target="_blank">https://pastebin.com/pgXHHVQm</a> (hastebin сука не работает 😞)</p>
  <p id="eK4Q">затем берешь и открываешь этот файлик в хроме или любом другом браузере пон. можно просто перетащить файлик во вкладку в браузере</p>
  <p id="I00S">и твоим глазам открывается <strong>нечто</strong>.....</p>
  <figure id="Jkn2" class="m_column">
    <img src="https://img1.teletype.in/files/42/92/42927278-c1d0-4932-abdb-a70cf0f06e48.png" width="2490" />
    <figcaption>sbf это купил кста у меня за 8 солян</figcaption>
  </figure>
  <p id="UOsk">короче это твой сайт пон точнее его фундамент как ты видишь глазами там есть заголовок и картиночка. не будем вдаваться в подробности html, это потом</p>
  <h3 id="HpgC">script.js</h3>
  <p id="1Z7e">вот он наш скриптик скриптичек наш жаваскриптик любименький кормящий...</p>
  <p id="DcDO">здесь ты пишешь весь js для нашего сайта, не будем медлить и сразу напишем второй magic eden</p>
  <p id="mUcA">начнем с самого простого, давай выведем какое нибудь сообщение будущему юзеру нашего сайта</p>
  <p id="6ig0">пишем в скрипт:</p>
  <pre id="d5dy" data-lang="javascript">alert(&#x27;новиии гот к нам мчитса скора фсе случица сбудица шо снится пон&#x27;);</pre>
  <p id="gni1">сохраняешь обязательно, не забываешь сохранять изменения и бегом обновлять страницу с сайтиком и..... <strong>о боже..........</strong></p>
  <figure id="4Mdn" class="m_retina">
    <img src="https://img4.teletype.in/files/f6/c4/f6c4bc73-def0-4ff8-a173-d25f454547c3.png" width="452" />
    <figcaption>подтвердите действие что новый гот мчица пон</figcaption>
  </figure>
  <p id="ATZa">вывод в разных браузерах может быть разный, выше у меня хром. в сафари вообще по центру ебашит это сообщение</p>
  <p id="38lG"><strong>поздравляю! ты написал строчку жаваскрипта нах</strong></p>
  <p id="2q25">давай дальше нах ✍️</p>
  <hr />
  <h2 id="y1V4">основы синтаксиса и простейшие конструкции</h2>
  <p id="nR1A">ну вот посмотрел ты такой на пример с новим готом, подумал, че за хуйня. зачем скобки, че за нахуй алерт, зачем кавычки вообще так еще и точка с запятой ебанутая какая то. вдыхаем <s>воздух</s> ашкуди... выдыхаем... давай разбирать пошагово</p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="kcWt"><code>alert</code> — это функция для вызова окошка юзеру, после алерт открываются скобки и мы пишем текст, который хотим показать юзеру</p>
    <p id="gr1Y"><code>&#x27;новии гот...&#x27;</code> — весь текст (не цифры) в js как и в большинстве яп пишутся в кавычках</p>
    <p id="DOQe"><code>;</code> — в js обозначает конец определенной инструкции (типа слушай жиэс <s>а чу на... а ни чу на нормально общайся бла</s> после алерта будет идти следующая конструкция)</p>
  </section>
  <p id="lhck">давайте разберемся с тем как передать жаваскрипту что то кроме текста</p>
  <h3 id="kbWG">типы данных в js</h3>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="8syl">в js существует 7 типов данных:</p>
    <ol id="19xc">
      <li id="uFcP">числа (<strong>number</strong>)</li>
      <li id="neLo">строки (<strong>string</strong>) стринги ептааааа..... пошутил типа.... баля кринжа навалил(</li>
      <li id="R2Vr">булевы значения (<strong>boolean</strong>) типа правда или ложь, да или нет, true или false</li>
      <li id="nz6t"><strong>undefined</strong> — специальный тип для неопределенного значения (можете не вникать, об этом позже)</li>
      <li id="Pvvl"><strong>null</strong> — специальный тип для временно неопределенного значения (такая же хуйня как с андефинед, об этом позже)</li>
      <li id="dQZa"><strong>Symbol</strong> — можете даже не задумываться че это такое, и писать не буду, написал чисто чтоб выебнуться что я все знаю (загуглил)</li>
      <li id="xMIX"><strong>BigInt</strong> — для обозначения ооочень больших цифр (потому что обычная цифра типа number не может вместить ооочень большую цифру)</li>
    </ol>
  </section>
  <p id="Z8sv">вот такие типы данных жаваскрипт может понимать от нас человеков</p>
  <h3 id="HdJK">переменные</h3>
  <p id="VwYO">че такое <strong>переменные</strong>? переменка в школе ебать</p>
  <p id="F5nB">приведу пример из жизни че такое <strong>переменная</strong> — представим что ты раскладываешь  какието вещи по коробкам и подписываешь вот в такой то коробке красные труселя, в другой синие. это и есть переменная. типа ты можешь положить какие то данные в переменную чтобы в последствии их достать, ты будешь понимать в какой коробке какие труселя чтобы случайно не вытащить те которые с сердечками пон</p>
  <p id="o1Rd">но это не единственное применение переменных. в жиэсе коробки можно <strong>дюпать, типа переиспользовать</strong>. допустим нам надо вывести одно и то же сообщение дважды. вместо того чтобы копировать его либо писать еще раз если ты мамонт, кладете текст сообщения в переменную, после чего просто пишете название переменной и вместо нее автоматически жаваскрипт подставляет ее содержимое. давай продемонстрирую тебе на деле епта</p>
  <pre id="yKAy" data-lang="javascript">let message = &#x27;новиии гот к нам мчитса скора фсе случица сбудица шо снится пон&#x27;;
alert(message);
alert(message);</pre>
  <p id="sB15">на 1 строке кода мы объявляем переменную message в которой храним текст для вывода юзеру</p>
  <p id="qlvj">после чего мы дважды вызываем уже знакомый нам алерт, который два раза выведет юзеру сообщение про новий гот</p>
  <p id="cvod">видите как круто, вместо того чтобы писать два раза один и тот же текст</p>
  <section style="background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="K2Il">давай разберем конструкцию <strong>переменной</strong>:</p>
    <p id="sogj"><code>let</code> — ключевое слово для определения переменной, все что идет после него жс понимает как название переменной</p>
    <p id="TbzT"><code>message</code> — название переменной</p>
    <p id="gk7S"><code>= &#x27;новиии гот...&#x27;</code> — присваивание переменной какого либо значения, в нашем случае текст</p>
  </section>
  <p id="KZc9"><strong>летс факин гоу ты уже знаешь что такое переменные!! </strong></p>
  <p id="WBdR">давай еще разок:</p>
  <pre id="HBHH" data-lang="javascript">let firstNumber = 69;
let secondNumber = 420;
alert(firstNumber + secondNumber);</pre>
  <p id="GzeR">сохрани это и обнови страницу, ты увидишь..... 489!!!!!!!!! <strong>ахуеть мотемотичька вахуи</strong></p>
  <figure id="6SYp" class="m_retina">
    <img src="https://img3.teletype.in/files/ef/22/ef224d78-0d5f-4e04-8387-ec9ca5be813a.png" width="582" />
    <figcaption>дикси вахуи</figcaption>
  </figure>
  <p id="iWWO">смотри, здесь мы создаем две переменные, называются они <code>firstNumber</code> и <code>secondNumber</code></p>
  <p id="zZyF">возникает резонный вопрос, почему я пишу с большой буквы второе слово в словосочетании &quot;<code>x</code> number&quot;</p>
  <p id="oxWr">такая практика названия переменных называется <code>camelCase</code>. типа <strong>верблюжий горб</strong> пон. ей пользуются разрабы чтоб не ебаться с названием длинных сочетаний и не было такого типа <code>letsfuckingsnusman</code> а было <code>letsFuckingSnusMan</code>. согласитесь, второе намного читабельнее. также есть <code>snake_case</code> и <code>kebab-case</code></p>
  <p id="AOWD">после создания переменных мы в алерте складываем первое и второе числа</p>
  <p id="2A4W"><strong>js пизже твоей школьной математички, он умеет выполнять все что связано с матешей</strong></p>
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="DeeW">список базовых арифметических операций:</p>
    <ul id="I1Oq">
      <li id="hC4j"><code>+</code> - сложение</li>
      <li id="hBZS"><code>-</code> - вычитание</li>
      <li id="P0vA"><code>/</code> - деление</li>
      <li id="CFFg"><code>*</code> - умножение</li>
      <li id="pOtq"><code>**</code> - возведение в степень</li>
    </ul>
  </section>
  <p id="gl5F">окей с арифметикой все давай разберемся для чего нужны булевы значения но прежде познакомимся с еще одной конструкцией похожей на <code>alert</code></p>
  <h3 id="eIyv">prompt</h3>
  <p id="zu4E">если алерт тупо выводил сообщение юзеру, то тут ты можешь получить от юзера какой то ввод в виде текста</p>
  <pre id="jVji" data-lang="javascript">let userNumber = prompt(&#x27;Введите число&#x27;);
alert(userNumber);</pre>
  <p id="MLpL">сохраняем, обновляем, получаем это:</p>
  <figure id="ACwq" class="m_retina">
    <img src="https://img4.teletype.in/files/bb/53/bb53f854-a738-461f-b8d2-605b1f6de188.png" width="442" />
    <figcaption>Подзаголовок</figcaption>
  </figure>
  <p id="alOK">после ввода числа и нажатия ОК о чудо — текст выводится в окошке</p>
  <p id="SaO4">по факту мы сохраняем ввод юзера в переменную <code>userNumber</code>, но зачем нам нужна переменная? <strong>вот еще одна из ролей переменных — туда можно класть промежуточные данные которые ты получаешь от юзера, иначе они улетят в пизду (если их не сохранить)</strong></p>
  <p id="UJnd">если ты дахуя бунтарь и нажмешь кнопку отмена, то выскочит окошко с текстом <code>null</code>. вот тут то мы и приходим к типу данных <code>null</code>. типа жс юзер не ввел ничего — ничего = <code>null</code></p>
  <p id="WHez">а что же такое все таки этот ваш <code>undefined</code> спросишь ты меня?</p>
  <p id="ZAc3">давай попробуем написать это:</p>
  <pre id="xrFw" data-lang="javascript">let userNumber;
alert(userNumber);</pre>
  <p id="qQJZ">сохраняем обновляем, получаем <s>пизды</s></p>
  <figure id="gdVE" class="m_retina">
    <img src="https://img1.teletype.in/files/81/2c/812c7fd3-585a-46e2-8fa5-0004e3467ec4.png" width="440" />
    <figcaption>опана приехали баля...</figcaption>
  </figure>
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="xt8Y"><code>undefined</code> — необъявленная переменная! тогда как <code>null</code> — это ничего (пустышка)</p>
  </section>
  <p id="mqah">надеюсь понятно объяснил, идем дальше к нашему вводу юзера с числом</p>
  <p id="Ocgf">давайте выведем юзеру &quot;Камасутра дао лфг&quot; если он ввел число 69 why not</p>
  <pre id="Id8R" data-lang="javascript">let userNumber = prompt(&#x27;Введи число долбаеб&#x27;);
if (userNumber == 69) {
    alert(&#x27;Камасутра дао лфг&#x27;);
}</pre>
  <p id="GyuF">обновляем страницу, вводим число 69 — получаем наш вывод крутой епта!</p>
  <section style="background-color:hsl(hsl(236, 74%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="2TYK">давай разберем что такое <code>if</code></p>
    <p id="izDK">вкратце это условие типа если то и то и это — то выполняй код который обернут в фигурные скобки</p>
    <p id="Xje6">то есть переводя на русский:</p>
    <pre id="xzNe" data-lang="javascript">если (админДолбаеб) {
    alert(&#x27;Отписка дизлайк&#x27;);
}</pre>
    <p id="DiUC">типа того, только вместо <code>админДолбаеб</code> у нас условие <code>userNumber == 69</code></p>
    <p id="HzQd">два знака равно == позволяют нам сравнить значения в жс, этот оператор возвращает булево значение (помнишь, <code>true</code> или <code>false</code>)</p>
    <p id="sCSV">булевы значения используются в условиях, когда надо что то проверить. лфг!</p>
  </section>
  <hr />
  <p id="fHbH">давай преобразуем пример и будем прибавлять к числу юзера число 1337 и выводить результат</p>
  <pre id="n0kP" data-lang="javascript">let userNumber = prompt(&#x27;Введи число хуйло&#x27;);
alert(userNumber + 1337);</pre>
  <p id="BHdU">казалось бы все так просто но запустив этот код вы получите какую то хуйню, а именно если я введу 69, то:</p>
  <figure id="XPc4" class="m_retina">
    <img src="https://img3.teletype.in/files/62/91/6291b44b-4603-4977-8374-d85b53a3a414.png" width="443" />
    <figcaption>втф мэнчик ты еблан?</figcaption>
  </figure>
  <p id="1kRW">че за хуйня спросишь ты меня уже в сотый раз... объясняю на пальцах:</p>
  <p id="CLdE"><strong>все что юзер вводит в текстовое поле хранится в переменной в типе данных <code>string</code></strong></p>
  <p id="PUMU">соответственно даже если юзер ввел туда число 69, то в переменную сохраняется не <code>69</code>, а <code>&quot;69&quot;</code></p>
  <p id="bqMo">самый прикол в <strong>кавычках</strong>! помнишь, все что в кавычках — это текст, а не числа</p>
  <p id="RSzj">когда жиэс видит в качестве одного из слагаемых строку, он просто соединяет два слагаемых, типа прям берет и соединяет ему <strong>вообще поебать</strong>, получается <code>691337</code></p>
  <p id="Ziyx">так что нам делать? жиэс сложит два числа нормально только если в обоих слагаемых 100% числа. тебе здесь помогут преобразования</p>
  <h3 id="6lMc">преобразования</h3>
  <p id="g9r9">строку можно преобразить в число, и наоборот. например строка <code>&quot;69&quot;</code> может быть преобразована в число <code>69</code> и так далее</p>
  <p id="pqHU">есть два простых способа преобразовать число в строку:</p>
  <pre id="kLvw" data-lang="javascript">let userNumber = prompt(&#x27;Введи число хуйло&#x27;);
// 1.
parseInt(userNumber, 10);
// 2.
+userNumber</pre>
  <section style="background-color:hsl(hsl(170, 33%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="NHZG">все что идет после двух слэшей — <strong>комментарий</strong>. он игнорируется жиэсом, можешь писать туда че хочешь, но мужик лучше используй его для того чтобы описывать че за говно ты пишешь, чтобы другим людям потом было понятно. ты же работать собрался все таки в айтишечке</p>
  </section>
  <p id="0Js7">можете использовать любой удобный, но первый считается более удобочитаемым и общепринятым можно так сказать. но если тяжело запомнить этот ебучий парсеинт то юзайте в начале плюсик</p>
  <p id="KYpl">давай короче починим наш код с прибавлением</p>
  <pre id="vDrA" data-lang="javascript">let userNumber = prompt(&#x27;Введи число хуйло&#x27;);
let parsedUserNumber = parseInt(userNumber, 10);
alert(parsedUserNumber + 1337);</pre>
  <p id="td5l">и летс факинг гоу, <strong>оно работает детка</strong></p>
  <figure id="k3fQ" class="m_retina">
    <img src="https://img2.teletype.in/files/5a/ff/5aff459e-89d6-41a7-b149-c7568ea7632a.png" width="459" />
    <figcaption>крутышки</figcaption>
  </figure>
  <p id="Xobu">давай немного упростим код выше:</p>
  <pre id="j9RW" data-lang="javascript">let userNumber = prompt(&#x27;Введи число хуйло&#x27;);
alert(parseInt(userNumber, 10) + 1337);</pre>
  <p id="0Bfy">а теперь сделаем его лучше, мы ведь хотим преобразовать в число именно то значение что хранится в переменной, а то иначе в переменной так и останется строка:</p>
  <pre id="rtZI" data-lang="javascript">let userNumber = parseInt(prompt(&#x27;Введи число хуйло&#x27;), 10);
alert(userNumber + 1337);</pre>
  <p id="bQ6o">вот так нагляднее. прикол в том что в жс все инструкции выполняются <strong>справа налево</strong></p>
  <p id="WW2c">то есть получается что сначала запрашивается ввод, потом он преобразуется в число (<strong>выполняется внутренняя инструкция первее</strong>)</p>
  <section style="background-color:hsl(hsl(263, 48%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="JH0Z">цифра 10 через запятую в функции <code>parseInt</code> обозначает десятичную систему счисления, можно менять эту цифру и будут получаться ваще разные цифры в итоге</p>
  </section>
  <p id="SarH">окей думаю на этом разделе можно закончить, мы же ща с тобой не собираемся изучить весь жаваскрипт на свете</p>
  <p id="adJH">давай перейдем к подключению кошелька епта мать его лфг</p>
  <hr />
  <h2 id="RZeY">подрубаем веб3, коннектим метамаскич и отображаем свои миллионы эфиров на сайте 🤑</h2>
  <p id="nRFJ">летс факин гоу быстро фастом раш б нахуй</p>
  <p id="qHCS">тута нам надо немного попотеть и будут концептики которые сходу тебе трудно будет понять, но я дам направление для гуглинга</p>
  <ol id="A2S8">
    <li id="vW8x">меняешь содержимое файла <code>index.html</code> на <a href="https://pastebin.com/F5SNsZT6" target="_blank">это</a></li>
    <li id="KZUi">устанавливаешь <a href="https://nodejs.org/en/download/" target="_blank">Node.js</a> (если у тебя его нет, проверить можно в консоли командой <code>node --version</code> — если вылезла версия значит все збс, устанавливать не надо</li>
    <li id="uYPI">открываешь свой проектик в консоли (в вс коде можете нажать <code>Ctrl + &#x60;</code>)</li>
    <li id="CUXZ">вводишь <code>npm init -y</code></li>
    <li id="69Yy">вводишь <code>npm i -g http-server</code></li>
    <li id="slWm">и наконец вводишь <code>http-server</code></li>
  </ol>
  <p id="LWxV">после этого закрываешь старую страницу, вводим в url браузера <code>localhost:8080</code> и ты снова попадаешь на свой сайтик</p>
  <figure id="FCPl" class="m_retina">
    <img src="https://img4.teletype.in/files/fe/67/fe676b3f-8f95-4ee6-95dd-104829975a28.png" width="519" />
    <figcaption>бабизяна на месте - сосиська в тесте</figcaption>
  </figure>
  <p id="nom4">погнали в наш скриптик, ща будем взламывать бинанс чтобы выкачать оттуда всю крипту и сизого!</p>
  <pre id="VzFQ" data-lang="javascript">(async () =&gt; { // 1
    if (typeof window.ethereum != &#x27;undefined&#x27;) { // 2
        const web3 = new Web3(window.ethereum); // 3
        const accounts = await window.ethereum.request({ method: &#x27;eth_requestAccounts&#x27; }); // 4
        web3.eth.getBalance(accounts[0], (error, result) =&gt; { // 5
            if (!error) { // 6
                const balanceInEth = web3.utils.fromWei(result); // 7
                alert(&#x60;Твой баланс - ${balanceInEth} ETH&#x60;); // 8
            }
        });
    }
})();</pre>
  <p id="Y1Kg"><strong>ебать я тут насрал...</strong></p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="HHdc">не паникуй, ща разберем по строчечкам, я же говорил будет потненько...</p>
    <ol id="njv4">
      <li id="dU1W">врубаем асинхронность (поймут те кто уже прогал, если ты не прогал, то забей и не вдавайся в подробности)</li>
      <li id="dhfd">проверяем установлен ли у челика метамаск вообще</li>
      <li id="5ahb">создаем web3 интерфейс (интерфейс это типа в нем всякие функции для взаимодействия с кошелем и не только)</li>
      <li id="3dW4">запрашиваем все аккаунты юзера. возвращает массив, пояснение что такое массив будет ниже</li>
      <li id="pDsp">получаем балик <strong>первого </strong>аккаунта в <strong>wei</strong></li>
      <li id="hyJo">проверяем что нет ошибки (типа у юзера может не быть вообще акков в метамаске), а то мы как долбаебы будем считать баланса в аккаунте которого не существует</li>
      <li id="i8tV">вызываем утилиту интерфейса web3 <code>fromWei</code> которая преобразует балик из wei в eth</li>
      <li id="35gp">выводим баланс в отформатированной строчечке красивенькой</li>
    </ol>
  </section>
  <h3 id="EI4X">массив</h3>
  <p id="iC7c">массив это несколько чего нибудь, типа будь то строк или чисел.</p>
  <p id="GV4n">выглядит так: <code>[1, 2, 3, 4, 5]</code></p>
  <p id="jDyf">в случае строк: <code>[&#x27;hello&#x27;, &#x27;world&#x27;]</code></p>
  <p id="5wui">получить какой либо элемент из массива можно такой конструкцией:</p>
  <pre id="k7b5" data-lang="javascript">const numbers = [1, 2, 3, 4, 5];
alert(numbers[0]); // 0 индекс соответствует 1 элементу, запомни это</pre>
  <h3 id="cyiy">6 строка</h3>
  <p id="Luim"><code>!error</code> — че за восклицательный знак, это че егэ по русскому ебать или че. в жиэсе (и вообще во многих яп) <code>!</code> обозначает &quot;не&quot;. типа <code>!error = не ошибка</code></p>
  <p id="SG3V">также и с не равно: != (в коде обозначается как <code>!=</code>)</p>
  <h3 id="UZai">8 строка</h3>
  <p id="neg6">в жиэсе можно удобно вставлять переменные в строки</p>
  <p id="tskp"><strong>что почитать:</strong> конкатенация строк в javascript; косые кавычки в javascript</p>
  <h3 id="Dqea">непонятные стрелки</h3>
  <p id="GHrI">можешь не вдаваться в подробности</p>
  <p id="InKZ"><strong>что почитать:</strong> функции в javascript; способы объявления функций в javascript</p>
  <hr />
  <p id="1bJ1">короче попотели (ctrl + c и ctrl + v пон) и хватит, давай смотреть че получилось...</p>
  <p id="yb8q">сохраняем обновляем иии...</p>
  <figure id="pnwO" class="m_retina">
    <img src="https://img4.teletype.in/files/b4/62/b462efca-dc86-4d7f-b6ae-bf441edff6b3.png" width="447" />
    <figcaption>баляяяяяяяяяяяяяяяяяяяяя говорили же бичка закончилась</figcaption>
  </figure>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="IbaR">обязательно — обновляйте страницу без кэша (в гугле на винде <code>Ctrl + Shift + R</code>, на маке <code>Command + Shift + R</code>) иначе обновления не будут видны</p>
    <p id="N0Mb">такая мера нужна только тогда когда вы запускаете сайт через <code>http-server</code></p>
  </section>
  <p id="0EZp">короче у тебя там должен балик отобразиться твой пон твоего аккаунта твои милионы эфирчиков пон </p>
  <hr />
  <h2 id="4G8W">заключение</h2>
  <p id="Uhoc">красота получается ебануться! ебать ты молодец если ты все сделал дошел пон до этого моментика ты можешь гордиться ебать собой, в последнем разделе нихуя непонятно правда, но ничего я буду все объяснять в следующих статьях очень очень подробно</p>
  <p id="4vXi"><strong>это лишь вступительная статья где мы сразу быренько намутили с тобой интересненький замут</strong></p>
  <p id="9C9L"><strong>я буду еще писать о концептах js более подробно и емко, так что подписывайся на <a href="https://t.me/ruburidao" target="_blank">рубури дао</a>!</strong></p>
  <p id="rq1O">можешь не беспокоиться если чето не запомнилось, это нормально. не отступай и иди к цели. когда я учился я хотел бросить люто масштабно два раза... но не останавливался пон!!!!! я не остановился и ща работаю дворничком (шутка конечно мужики я во вкусно и точка)</p>
  <p id="tyJu"><strong>ебашьте и все будет ахуенно </strong></p>
  <figure id="GTec" class="m_original">
    <img src="https://c.tenor.com/1V9b8Eg0nHUAAAAM/dwayne-johnson-the-rock.gif" width="220" />
    <figcaption>мотивация от рубурика под финиш статеечки и твоего первого прогресса</figcaption>
  </figure>
  <h2 id="76kW">благодарности</h2>
  <p id="jgZ4"><strong>спасибо</strong> тебе за прочтение, <strong>спасибо</strong> тем кто ставит реакции, подпищекам, рыжему, сс ресерч, моей девочке, френдли тагу 52 нгг и всем остальным кто пон мотивирует ебашить <strong>люто жоска</strong></p>
  <p id="Zdew"><strong>и удачи тебе в пути кодинга еба! </strong></p>
  <h2 id="3byj">отзыв</h2>
  <p id="YUnN">если в каком то примере ошибка, или что то не получается вы всегда можете обратиться за вопросом в телегу к рубурику <strong><a href="https://t.me/rubyuroboros" target="_blank">@rubyuroboros</a></strong></p>
  <hr />
  <p id="Rm05">мой канал — <a href="https://t.me/ruburi" target="_blank">https://t.me/ruburi</a></p>
  <figure id="8t7s" class="m_column">
    <img src="https://img2.teletype.in/files/91/27/9127283d-1e3b-4913-9e71-10526048788a.png" width="2538" />
    <figcaption>это ты чисто и я (рубурик давольный) после того как ты начал жоска воркать в веб3</figcaption>
  </figure>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rubyuroboros/5e-KP4M6wo3</guid><link>https://teletype.in/@rubyuroboros/5e-KP4M6wo3?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><comments>https://teletype.in/@rubyuroboros/5e-KP4M6wo3?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros#comments</comments><dc:creator>rubyuroboros</dc:creator><title>Коннектимся к Ceramic в Clay Testnet</title><pubDate>Wed, 07 Dec 2022 23:51:30 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/b2/a0/b2a0a890-7069-4bd3-a58c-6d74bd7fbd3f.png"></media:content><description><![CDATA[<img src="https://img2.teletype.in/files/5e/39/5e390fb2-5554-4af9-96ac-0871bf478851.png"></img>Всем привет! Гайда я не нашел нигде (наверное потому что все кажется мертвым вокруг этого проектика). В дисе тихо тихо, но в анонсах на днях выкатили депрекейшен какой-то, ну чет работают.]]></description><content:encoded><![CDATA[
  <p id="efzE">Всем привет! Гайда я не нашел нигде (наверное потому что все кажется мертвым вокруг этого проектика). В дисе тихо тихо, но в анонсах на днях выкатили депрекейшен какой-то, ну чет работают.</p>
  <p id="MOFd">Челы в феврале подняли 30 лямов, а это наскок мне известно наравне с Espresso Systems в которых зашли секвойя кэпитал. Говорят фаундеры душнилы, ну видно что они так медленно двигаются. В любом случае я ставлю ноды почти всех более менее живых проектов даже элементарно на случай антифомо. Нода керамика сильно не жрет, поэтому why not.</p>
  <p id="DNT0"><strong>LFG!</strong></p>
  <hr />
  <p id="4tz3">Апдейтимся</p>
  <pre id="6RDV" data-lang="bash">sudo apt update</pre>
  <p id="PdcR">Устанавливаем screen, чтобы работать с нодой в фоне</p>
  <pre id="qAlX" data-lang="bash">sudo apt install screen -y
screen -S ceramic</pre>
  <p id="KVdq">Сетапаем <code>nvm</code> и <code>nodejs</code></p>
  <pre id="hvxu" data-lang="bash">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
source .bashrc
nvm install 16</pre>
  <p id="XCaH">После этого маринуем сервак к установке нпм пакета керамика:</p>
  <pre id="lYcP" data-lang="bash">mkdir &quot;${HOME}/.npm-packages&quot;
npm config set prefix &quot;${HOME}/.npm-packages&quot;

NPM_PACKAGES=&quot;${HOME}/.npm-packages&quot;
echo export PATH=&quot;$PATH:$NPM_PACKAGES/bin&quot; &gt;&gt; .bash_profile
echo export MANPATH=&quot;${MANPATH-$(manpath)}:$NPM_PACKAGES/share/man&quot; &gt;&gt; .bash_profile

source ~/.bash_profile</pre>
  <p id="WNs3"></p>
  <p id="fBaa">Устанавливаем ceramic-cli</p>
  <pre id="x8SY" data-lang="bash">npm install -g @ceramicnetwork/cli</pre>
  <p id="zENT">Подтираемся после себя</p>
  <pre id="Tg1t" data-lang="bash">nvm use --delete-prefix v16.18.1 --silent</pre>
  <p id="x8SY">Запускаем демона</p>
  <pre id="1ThK" data-lang="bash">ceramic daemon</pre>
  <p id="VoVh">Адекватные логи:</p>
  <figure id="sy1U" class="m_retina">
    <img src="https://img2.teletype.in/files/5e/39/5e390fb2-5554-4af9-96ac-0871bf478851.png" width="955" />
    <figcaption>В конце логов должно быть это</figcaption>
  </figure>
  <p id="VYwT">Выходим из <code>screen</code> — <code>Ctrl + A + D</code></p>
  <h2 id="cvGU">Дополнительно</h2>
  <h3 id="1MTc">Удаление ноды</h3>
  <pre id="NPLC" data-lang="bash">npm uninstall -g @ceramicnetwork/cli</pre>
  <hr />
  <p id="D8sC">Поздравлямба! Ты запустил ноду керамик в клей тестнете!</p>
  <p id="b4gf"></p>
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="Tum1"><code>big love💜CC RESEARCH fam🩸🪓</code></p>
  </section>
  <p id="R5pF">Мой канал — <a href="https://t.me/ruburi" target="_blank">ruburi</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@rubyuroboros/RigBRnzH-jy</guid><link>https://teletype.in/@rubyuroboros/RigBRnzH-jy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros</link><comments>https://teletype.in/@rubyuroboros/RigBRnzH-jy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=rubyuroboros#comments</comments><dc:creator>rubyuroboros</dc:creator><title>дегенская выжимка по NODEESSSS LFG епта</title><pubDate>Tue, 06 Dec 2022 00:47:08 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/66/26/662692fc-73e9-4167-92b8-dbb919ef161e.png"></media:content><description><![CDATA[<img src="https://img4.teletype.in/files/70/e0/70e0c821-cacb-40d6-86b4-8e7077788111.png"></img>big love💜CC RESEARCH fam🩸🪓]]></description><content:encoded><![CDATA[
  <section style="background-color:hsl(hsl(0,   0%,  var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="ELQB"><code>big love💜CC RESEARCH fam🩸🪓</code></p>
  </section>
  <h2 id="K8Ag">предисловие</h2>
  <p id="Y8lD">в этой выжимочке я собрал следующую инфу:</p>
  <ul id="mCC9">
    <li id="co2N">все ноды, которые стоят у меня</li>
    <li id="Gtz6">ноды, которые я еще планирую ставить</li>
    <li id="Q3DY">ноды, которые я буду жоска мультик делат</li>
  </ul>
  <p id="7u9X">никакого ресерчика и прочей мозговой активности онли ноды и гайдики по их установке плюс возможные подводные камни которые я набрал когда устанавливал некоторые ноды. подводных камней хоть и немного но они были.</p>
  <p id="WcC0">ресерчик какой то мб захуярю в некст статейку тк увидел интересные проектики</p>
  <p id="Y9S2"><strong>предупреждение: я в нодах нуб, только начинаю, поэтому могут возникнуть проблемы с установкой</strong></p>
  <hr />
  <p id="mRLm">мой шаблон Notion для нод</p>
  <p id="DAuz"><a href="https://striped-alfalfa-de4.notion.site/8cae50e37d164700aed4f6e0ade7a942" target="_blank">https://striped-alfalfa-de4.notion.site/8cae50e37d164700aed4f6e0ade7a942</a></p>
  <p id="NtJR">жмете Duplicate в правом верхнем углу и лфг 🪓</p>
  <hr />
  <h2 id="E06b">все ноды, которые стоят у меня</h2>
  <ol id="qrZd">
    <li id="eSdW">bundlr</li>
    <li id="wqN9">minima</li>
    <li id="mEHx">massa</li>
    <li id="quSJ">sui</li>
    <li id="PTE4">nibiru</li>
    <li id="ihsE">oasys</li>
    <li id="c4GZ">celestia</li>
    <li id="yCgF">subspace</li>
    <li id="2IOL">gear</li>
    <li id="i3Eg">defund</li>
    <li id="tvdd">espresso</li>
    <li id="831L">chainflip</li>
    <li id="TehK">exorde</li>
    <li id="QNq6">penumbra</li>
    <li id="RXxO">gitopia</li>
  </ol>
  <h2 id="LxNX">Инфа перед установкой</h2>
  <p id="evkS">В основном все команды можете прям все копировать и вставлять, они будут выполняться сами (кроме последней скопированной команды, на ней надо будет нажать ентер она должна быть у вас в строке вставлена после выполнения всего остального)</p>
  <p id="puW9">Команды у которых на конце косая черта \ обязательно копируйте полностью все</p>
  <figure id="Bqx9" class="m_retina">
    <img src="https://img4.teletype.in/files/70/e0/70e0c821-cacb-40d6-86b4-8e7077788111.png" width="722" />
    <figcaption>Вот такие команды надо 100% полностью копировать</figcaption>
  </figure>
  <p id="TqHs">Прежде чем качать снапшоты нод убедитесь что у вас есть место на диске командой:</p>
  <p id="iq4c"><code>df -H</code></p>
  <p id="z5gd">Интересовать будет раздел <code>/dev/sda3 Used/Avail</code></p>
  <hr />
  <h2 id="GEAb">Bundlr</h2>
  <p id="0xnQ">Гайд — <a href="https://cyberomanov.tech/bundlr?cda=#EG4a" target="_blank">https://cyberomanov.tech/bundlr?cda=#EG4a</a></p>
  <p id="Evwa">Для крана нужен Twitter</p>
  <figure id="YARF" class="m_retina">
    <img src="https://img1.teletype.in/files/45/7e/457e31d4-9327-4a4b-8557-5c0c5c7dc301.png" width="704" />
    <figcaption>Интересует фрилайнер только</figcaption>
  </figure>
  <p id="772v">Сделайте бэкап:</p>
  <p id="Qw1L"><code>$HOME/bundlr/validator-rust/wallet.json</code></p>
  <figure id="kLjW" class="m_retina">
    <img src="https://img2.teletype.in/files/18/90/189080d9-625b-4cea-9cdf-b7fe0e77076e.png" width="704" />
    <figcaption>Кран</figcaption>
  </figure>
  <hr />
  <h2 id="x5Sd">Minima</h2>
  <p id="svoR">Гайд — <a href="https://teletype.in/@letskynode/Minima" target="_blank">https://teletype.in/@letskynode/Minima</a></p>
  <p id="Jy4T">Скипаем парт с андроидом нам сразу нужна вот эта часть и далее:</p>
  <figure id="N5zN" class="m_retina">
    <img src="https://img3.teletype.in/files/21/12/21122d2b-4cd7-4cb1-99b2-d35dae1fe3e7.png" width="725" />
  </figure>
  <p id="exCS">Привязывайте реварды через Terminal (не через Web Browser)</p>
  <p id="AhuN">Реварды у вас должны отображться тут — <a href="https://incentive.minima.global/home/pages/rewards" target="_blank">https://incentive.minima.global/home/pages/rewards</a></p>
  <p id="vDmm">Сутки после того как вы поставили ноду, должны обновиться реварды на +1 и так далее ежедневно</p>
  <hr />
  <h2 id="xO2j">Massa</h2>
  <p id="BeqJ">Гайд — <a href="https://teletype.in/@doubletop_slivky/TkSo5JZS5VP" target="_blank">https://teletype.in/@doubletop_slivky/TkSo5JZS5VP</a></p>
  <p id="Ifew">Идите по гайду, игнорируйте какие то варнинги, в гайде все последовательно объясняется</p>
  <p id="52wR">Свой score чекать через дискорд бота массы командой <code>info</code> в личку боту</p>
  <hr />
  <h2 id="vlNE">Sui</h2>
  <p id="WBmH">Не знаю, запустилась ли новая фаза, я просто поставил ее и она афк у меня</p>
  <p id="agK6">Гайд — <a href="https://nodes.guru/sui/setup-guide/en" target="_blank">https://nodes.guru/sui/setup-guide/en</a> (скрипт для quick installation)</p>
  <p id="7LHB">После установки прочекайте ноду командой Check Node из раздела Additional</p>
  <hr />
  <h2 id="76Mk">Nibiru</h2>
  <p id="WtSM">Гайд — <a href="https://nodejumper.io/nibiru-testnet/installation" target="_blank">https://nodejumper.io/nibiru-testnet/installation</a></p>
  <p id="7585">Ебашим строку из раздела Automatic Installation, после создаем кошель и регаем валидатора. <strong>Прежде чем просить токены из крана проверьте что нода засинкалась</strong></p>
  <figure id="nVWV" class="m_retina">
    <img src="https://img3.teletype.in/files/e5/24/e5245066-ef70-4045-a728-40502885baa1.png" width="533" />
    <figcaption>Команда для чека</figcaption>
  </figure>
  <p id="AfuY">После запроса денях из крана возможно надо подождать прежде чем появится балик, регаем валика</p>
  <figure id="LZ4p" class="m_retina">
    <img src="https://img1.teletype.in/files/08/62/0862a70d-6662-4dd6-ad86-701cb706fdd4.png" width="661" />
    <figcaption>Проверяйте что валик появился, может пройти время прежде чем он появится, но у вас не должно быть ошибки когда он появится. Если все ок - значит все работает</figcaption>
  </figure>
  <p id="tXLV">Если балик долго не появляется, скорее всего нода не может засинкаться. Если она долго не синкается, скачайте снапшот — <a href="https://nodejumper.io/nibiru-testnet/sync" target="_blank">https://nodejumper.io/nibiru-testnet/sync</a> из раздела Snapshot</p>
  <p id="HY1M">State Sync не трогаем, после снапшота должно быть все ок</p>
  <hr />
  <h2 id="VFte">Oasys</h2>
  <p id="epEi">Гайд — <a href="https://nodera.org/oasys_installation_guide" target="_blank">https://nodera.org/oasys_installation_guide</a></p>
  <p id="1rcl">Как настроите ноду не беспокойтесь о логах где нода пытается найти пиров, ща валика создать нельзя, так и должно быть (вроде как)</p>
  <hr />
  <h2 id="vpOD">Celestia</h2>
  <p id="zZmy">Гайд — <a href="https://nodejumper.io/celestia-testnet/installation" target="_blank">https://nodejumper.io/celestia-testnet/installation</a></p>
  <p id="fDrZ">Такая же темка как с Nibiru. Качаем <a href="https://nodejumper.io/celestia-testnet/sync" target="_blank">снапшот</a> если балик не показывается или нода не синкается</p>
  <hr />
  <h2 id="8b0i">Subspace</h2>
  <p id="iH7C">Тут пока нет смысла ставить, ждем новую фазу, но на всякий:</p>
  <p id="AB9g">Откройте порт 9955:</p>
  <p id="eZx1"><code>sudo ufw allow 9955</code></p>
  <p id="S98u">Гайд — <a href="https://blog.bombermine.xyz/subspace-node-docker" target="_blank">https://blog.bombermine.xyz/subspace-node-docker</a></p>
  <p id="WYxr">После установки чекайте телеметрию <a href="https://telemetry.subspace.network/#/0x43d10ffd50990380ffe6c9392145431d630ae67e89dbc9c014cac2a417759101" target="_blank">тут</a></p>
  <p id="fK3O">Имя вашей ноды должно появиться в телеметрии (лично у меня пока тишина, <strong>возможно гайд неправильный или старый</strong>)</p>
  <hr />
  <h2 id="LRvA">Gear</h2>
  <p id="Q1tE">Гайд — <a href="https://teletype.in/@promint/GearNode" target="_blank">https://teletype.in/@promint/GearNode</a></p>
  <p id="4SHj">После подключения к серваку сразу идите в раздел с установкой</p>
  <p id="e8YU">После установки убедитесь что ваша нода появляется в телеметрии (именно в Gear Staging Testnet 4)</p>
  <hr />
  <h2 id="yhQc">Defund</h2>
  <p id="vpRF">Гайд — <a href="https://nodejumper.io/defund-testnet/installation" target="_blank">https://nodejumper.io/defund-testnet/installation</a></p>
  <p id="zIgK">Такая же тема как с нибиру и целестией. Снапшот тут — <a href="https://nodejumper.io/defund-testnet/sync" target="_blank">https://nodejumper.io/defund-testnet/sync</a></p>
  <hr />
  <h2 id="cpNz">Espresso</h2>
  <p id="y3JP">Гайд — <a href="https://talented-hawk-a5a.notion.site/Espresso-032bd5364ef9464591b6ddebfe673775" target="_blank">https://talented-hawk-a5a.notion.site/Espresso-032bd5364ef9464591b6ddebfe673775</a></p>
  <hr />
  <h2 id="LSZb">Chainflip</h2>
  <p id="UeDn">Гайд — <a href="https://teletype.in/@pronodes/bNbVr7SQysH" target="_blank">https://teletype.in/@pronodes/bNbVr7SQysH</a></p>
  <hr />
  <h2 id="ICcr">Exorde</h2>
  <p id="pnD3">Гайд — <a href="https://teletype.in/@smarthamster_bykulikova/OEWxVOVfSjc" target="_blank">https://teletype.in/@smarthamster_bykulikova/OEWxVOVfSjc</a></p>
  <hr />
  <h2 id="76jF">Penumbra</h2>
  <p id="qvco">Устанавливаем Rust если не установлен</p>
  <p id="Epor"><code>curl --proto &#x27;=https&#x27; --tlsv1.2 -sSf <a href="https://sh.rustup.rs" target="_blank">https://sh.rustup.rs</a> | sh</code></p>
  <p id="dvMd">Устанавливаем Go если не установлен</p>
  <pre id="rqms">curl -O https://dl.google.com/go/go1.19.3.linux-amd64.tar.gz
sha256sum go1.19.3.linux-amd64.tar.gz
sudo tar -xvf go1.19.3.linux-amd64.tar.gz -C /usr/local
sudo chown -R root:root /usr/local/go
echo export GOPATH=\&quot;\$HOME/go\&quot; &gt;&gt; ~/.bash_profile
echo export PATH=\&quot;\$PATH:\$GOPATH/bin\&quot; &gt;&gt; ~/.bash_profile
source ~/.bash_profile
git clone https://github.com/tendermint/tendermint.git
cd tendermint
git checkout v0.34.23
make install
tendermint version # должно вывести версию тендерминта</pre>
  <p id="Airb">Заходим сюда — <a href="https://guide.penumbra.zone/main/pcli/install.html" target="_blank">https://guide.penumbra.zone/main/pcli/install.html</a></p>
  <p id="L6d5">Выполняем команды для Linux до конца</p>
  <p id="CkPf">Идем в пункт 1.2, генерируем кошель, получаем токены в дискорде</p>
  <p id="QsK1">Далее идем сюда <a href="https://guide.penumbra.zone/main/pd/build.html" target="_blank">https://guide.penumbra.zone/main/pd/build.html</a></p>
  <p id="aylq">Нас интересует раздел <strong>Building pd </strong>и все</p>
  <p id="5U9Z">Идем сюда <a href="https://guide.penumbra.zone/main/pd/join-testnet.html" target="_blank">https://guide.penumbra.zone/main/pd/join-testnet.html</a></p>
  <p id="Wo7U">Выполняем <strong>Resetting state</strong> и <strong>Generating configs</strong></p>
  <p id="i0FF">После, убедитесь что вы в папке с репозиторием пенумбры и выполните:</p>
  <p id="LyuI"><code>docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build</code></p>
  <p id="v3vn">Долго надо ждать, но потом поставится</p>
  <p id="ygDr">Затем нас интересует раздел ниже <a href="https://guide.penumbra.zone/main/pd/join-testnet.html#joining-as-a-validator" target="_blank">Joining as a validator</a></p>
  <p id="Z6U4">Выполняем команды без <code>\$</code></p>
  <p id="B00N">Когда вы получите вывод типа:</p>
  <p id="Fze1"><code>{ &quot;identity_key&quot;: &quot;penumbravalid1g2huds8klwypzczfgx67j7zp6ntq2m5fxmctkf7ja96zn49d6s9qz72hu3&quot;, &quot;consensus_key&quot;: &quot;Fodjg0m1kF/6uzcAZpRcLJswGf3EeNShLP2A+UCz8lw=&quot;, &quot;name&quot;: &quot;&quot;, &quot;website&quot;: &quot;&quot;, &quot;description&quot;: &quot;&quot;, &quot;enabled&quot;: false, &quot;funding_streams&quot;: [ { &quot;address&quot;: &quot;penumbrav1t1mw8270qtpgjy628fg97p2px45e860jtlw0nl3w5y7vq67qx697py9t8ppp3mhwfxv8kegg8wuny64nf60z966krx85cqznjpshqtngffpwnywtzqjklkg3qh7anxk368ywac9l&quot;, &quot;rate_bps&quot;: 100 } ], &quot;sequence_number&quot;: 0 }</code></p>
  <p id="qXUx">, поменяйте <code>identity_key</code> на свой адрес валидатора, а также поставьте имя ноды, ну и любое описание. Поменяйте флаг <code>enabled</code> с false на true</p>
  <p id="Rjgt">Получите свой <code>consensus_key</code> на тот что выходит командой:</p>
  <p id="uiUE"><code>grep -A3 pub_key ~/.penumbra/testnet_data/node0/tendermint/config/priv_validator_key.json</code></p>
  <p id="6jpu">Интересует поле <code>value</code></p>
  <p id="L2sU">После того как вы отредактировали в текстовом редакторе или в дискорде где угодно содержимое этого файлика:</p>
  <p id="8O4X"><code>nano validator.json</code></p>
  <p id="2laT">Уберите все содержимое оттуда и вставьте свое</p>
  <p id="d7Vv">После этого следуйте разделу <a href="https://guide.penumbra.zone/main/pd/join-testnet.html#uploading-a-definition" target="_blank">Uploading a definition</a></p>
  <p id="wQWC">Затем <a href="https://guide.penumbra.zone/main/pd/join-testnet.html#delegating-to-your-validator" target="_blank">Delegating to your validator</a></p>
  <p id="aG2o">Последний раздел можно не трогать</p>
  <p id="ejxz">Вроде все, должно поставиться</p>
  <p id="cxnn">Вопросы спрашивайте, нода капризная и дискорд полумертвый</p>
  <hr />
  <h2 id="o0Zx">Gitopia</h2>
  <p id="OexK">Гайд — <a href="https://teletype.in/@lesnik13utsa/K4wEQmEMj3W" target="_blank">https://teletype.in/@lesnik13utsa/K4wEQmEMj3W</a></p>
  <p id="uJ4Y">Переходите к разделу <strong>Подготовка сервера</strong> ниже и далее</p>
  <p id="fZMQ">После установки ноды я заполнял форму на валидатора — <a href="https://airtable.com/shrMQFJxcsMD0XV2M" target="_blank">https://airtable.com/shrMQFJxcsMD0XV2M</a></p>
  <p id="lwwu">Из опционального я ставил прунинг</p>
  <figure id="61HW" class="m_retina">
    <img src="https://img1.teletype.in/files/ce/f4/cef43864-992d-4208-9785-17dd545de968.png" width="738" />
    <figcaption>Прунинг</figcaption>
  </figure>
  <p id="OMUL">После установки ноды также проверьте статус:</p>
  <p id="8CTd"><code>gitopiad status 2&gt;&amp;1 | jq .&quot;SyncInfo&quot;.&quot;latest_block_height&quot;</code></p>
  <p id="RD1b">Должна вылезти цифра не нулевая и не ошибка</p>
  <p id="7hmn">Если будете выполнять тестнет, по статусу на вчерашний день у челиков не работает пуш в репозиторий, но рекомендую выполнить их <a href="https://telegra.ph/Guide-Gitopia-TESTNET-05-02" target="_blank">тестнет</a>. Проектик норм темка</p>
  <hr />
  <h2 id="mPdl">Заключение</h2>
  <p id="11C2">Скоро добавлю ноды Terp, Ceramic, Starknet, Nois и Zeeka</p>
  <p id="2itY">А также будет отдельный пост как делать бэкапы и как защитить серв от брутфорса и прочей херни которая может возникнуть</p>
  <p id="dpr6">Если будут вопросы спрашивайте - @rubyuroboros</p>

]]></content:encoded></item></channel></rss>