<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Programming and Stuff]]></title><description><![CDATA[Programming and Stuff]]></description><link>https://tonyistomin.xyz/</link><image><url>https://tonyistomin.xyz/favicon.png</url><title>Programming and Stuff</title><link>https://tonyistomin.xyz/</link></image><generator>Ghost 4.29</generator><lastBuildDate>Wed, 29 Nov 2023 08:32:36 GMT</lastBuildDate><atom:link href="https://tonyistomin.xyz/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[About me]]></title><description><![CDATA[<p>Hi, my name is Anton Istomin. I am a senior JS/TS, Node.js, React full-stack software developer with eight years of experience. </p><p>If you are looking for my CV, you can find it here: <a href="https://drive.google.com/file/d/10MuI2s3kR-8J9Vo1DVtRA_qmzp7LIjzc/view">https://drive.google.com/file/d/10MuI2s3kR-8J9Vo1DVtRA_qmzp7LIjzc/view</a></p><p>You can contact me via Telegram</p>]]></description><link>https://tonyistomin.xyz/about-me/</link><guid isPermaLink="false">64ac798fd2bbd3000136dcc7</guid><dc:creator><![CDATA[Anton Istomin]]></dc:creator><pubDate>Mon, 10 Jul 2023 23:12:07 GMT</pubDate><content:encoded><![CDATA[<p>Hi, my name is Anton Istomin. I am a senior JS/TS, Node.js, React full-stack software developer with eight years of experience. </p><p>If you are looking for my CV, you can find it here: <a href="https://drive.google.com/file/d/10MuI2s3kR-8J9Vo1DVtRA_qmzp7LIjzc/view">https://drive.google.com/file/d/10MuI2s3kR-8J9Vo1DVtRA_qmzp7LIjzc/view</a></p><p>You can contact me via Telegram here <a href="https://t.me/tony_ist">https://t.me/tony_ist</a></p><p>Other useful links: <a href="https://tonyistomin.xyz/links/">https://tonyistomin.xyz/links/</a></p>]]></content:encoded></item><item><title><![CDATA[Macbook touch bar for git in iTerm2]]></title><description><![CDATA[<p>I would like to share with you my settings for git in iTerm2.</p><p>You can use <code>git status</code>, <code>git add .</code>, <code>git commit -m &quot;&quot;</code>, <code>git pull</code>, <code>git push</code>, <code>git switch main</code>, <code>git switch master</code> and <code>git switch develop</code> just by clicking one of these cuties.</p><p>Configuration is pretty straightforward,</p>]]></description><link>https://tonyistomin.xyz/macbook-touch-bar-in-iterm2/</link><guid isPermaLink="false">623e46c629b9140001571b1c</guid><dc:creator><![CDATA[Anton Istomin]]></dc:creator><pubDate>Fri, 25 Mar 2022 23:03:34 GMT</pubDate><media:content url="https://tonyistomin.xyz/content/images/2022/03/iterm-touch-bar-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://tonyistomin.xyz/content/images/2022/03/iterm-touch-bar-1.jpg" alt="Macbook touch bar for git in iTerm2"><p>I would like to share with you my settings for git in iTerm2.</p><p>You can use <code>git status</code>, <code>git add .</code>, <code>git commit -m &quot;&quot;</code>, <code>git pull</code>, <code>git push</code>, <code>git switch main</code>, <code>git switch master</code> and <code>git switch develop</code> just by clicking one of these cuties.</p><p>Configuration is pretty straightforward, but it can take some time to figure out the first time you try it. So here is a little guide.</p><p>Open <code>Profiles</code> -&gt; <code>Open profiles</code> -&gt; Choose a profile -&gt; <code>Edit profiles</code> -&gt; <code>Keys</code>.</p><figure class="kg-card kg-image-card"><img src="https://tonyistomin.xyz/content/images/2022/03/image.png" class="kg-image" alt="Macbook touch bar for git in iTerm2" loading="lazy" width="1810" height="1332" srcset="https://tonyistomin.xyz/content/images/size/w600/2022/03/image.png 600w, https://tonyistomin.xyz/content/images/size/w1000/2022/03/image.png 1000w, https://tonyistomin.xyz/content/images/size/w1600/2022/03/image.png 1600w, https://tonyistomin.xyz/content/images/2022/03/image.png 1810w" sizes="(min-width: 720px) 720px"></figure><p> Then choose <code>Add Touch Bar Item</code>, label it <code>git status</code>, choose action <code>Send text with vim special characters</code>. Then write <code>git status\n</code> in the bottom field.</p><figure class="kg-card kg-image-card"><img src="https://tonyistomin.xyz/content/images/2022/03/image-1.png" class="kg-image" alt="Macbook touch bar for git in iTerm2" loading="lazy" width="894" height="320" srcset="https://tonyistomin.xyz/content/images/size/w600/2022/03/image-1.png 600w, https://tonyistomin.xyz/content/images/2022/03/image-1.png 894w" sizes="(min-width: 720px) 720px"></figure><p>Repeat for every other git command you want. For <code>git commit</code> write <code>git commit -m &quot;&quot;\u0002</code> in the bottom field. This will send the text <code>git commit -m &quot;&quot;</code> to the console and then send a left arrow so the cursor is inside the quotes. Then you can write the commit message and press <code>Enter</code>.</p><p>Then choose <code>View</code> -&gt; <code>Customize Touch Bar...</code> and drag new commands to the touch bar. </p><p>That is all! Hope you find it useful.</p>]]></content:encoded></item><item><title><![CDATA[Integer partitions and threshold graphs]]></title><description><![CDATA[<p>In this post we are going to explore integer partitions and its Ferrer (Young) diagram properties and introduce integer partition lattice. Also we are going to explore graphical integer partitions (for which there exists a graph), their position in a lattice and threshold graphs which correspond to maximal graphical partitions.</p>]]></description><link>https://tonyistomin.xyz/integer-partitions-and-threshold-graphs/</link><guid isPermaLink="false">61b9f04685b074000123a9cd</guid><dc:creator><![CDATA[Anton Istomin]]></dc:creator><pubDate>Sun, 30 May 2021 12:58:43 GMT</pubDate><media:content url="https://tonyistomin.xyz/content/images/2020/08/Natural-Partition-Lattice-NPL--logo4-.png" medium="image"/><content:encoded><![CDATA[<img src="https://tonyistomin.xyz/content/images/2020/08/Natural-Partition-Lattice-NPL--logo4-.png" alt="Integer partitions and threshold graphs"><p>In this post we are going to explore integer partitions and its Ferrer (Young) diagram properties and introduce integer partition lattice. Also we are going to explore graphical integer partitions (for which there exists a graph), their position in a lattice and threshold graphs which correspond to maximal graphical partitions. Kohnert&apos;s criterion is used to determine if a partition is graphical and in edge cases maximal (corresponding to threshold graph). The C++ library which is based on the material discussed in this post includes algorithms that find threshold graph from specified graph, maximal graphical integer partition from specified graphical partition, shortest maximizing chain and other. These algorithms use increasing edge rotation for graphs.</p><h1 id="integer-partitions">Integer partitions</h1><p>What is integer partition? The definition is extremely simple: it is sum of numbers resulting in an integer: \( 10 = 1+3+6\)</p><p>You can also write it down as a descending sequence of numbers \( (6, 3 , 1)\). So for arbitrary integer n its integer partition is:</p><p>\[ (a_1, a_2, a_3, ..., a_k), where &#xA0;n = a_1 + a_2 + a_3 + ... + a_k &#xA0;and &#xA0;a_1 \geq a_2 \geq a_3 \geq ... \geq a_k\]</p><p>Ferrers or Young diagram for integer partition is a sequence of columns consisting of blocks, where first column corresponds to \(a_1\), second to \(a_2\) and so on.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/06/image.png" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>Ferrers diagram for (6, 3, 1)</figcaption></figure><p>An ascending block movement is an operation which transforms one valid integer partition into another in a specific way:</p><p>\[ (a_1, ..., a_i + 1, ..., a_j - 1, ..., a_k), where &#xA0;a_1 \geq a_2 \geq a_3 \geq ... \geq a_k &#xA0;and &#xA0;i &lt; j \]</p><p>For example: \( (6, 3, 1) \rightarrow (7, 3) \)</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/Screenshot-2020-08-15-at-21--2-.png" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>Ascending block movement</figcaption></figure><p>A basic ascending block movement is that which cannot be split into two or more ascending block movements. The block movement above was not basic as it can be split in two ascending block movements: \((6, 3, 1) \rightarrow (6, 4) \rightarrow (7, 3)\). An example of a basic block movement is: \( (2, 1, 1, 1) \rightarrow (2, 2, 1) \):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/image.png" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>Basic ascending block movement</figcaption></figure><p>Note that moving the fourth block to the third position is impossible since it would give us invalid integer partition \( (2, 1, 2, 1) \). It is invalid because \( a_2 = 1 &lt; a_3 = 2 \). Obviously, the same way we can define descending basic block movement. I will skip definition for brevity.</p><p>Now let&apos;s define partial order on the integer partitions set. Let \( \lambda_1 \) and \( \lambda_2 \) be integer partitions for some number \( n \). </p><p>\[ \lambda_1 \leq \lambda_2 \Leftrightarrow \exists m_1, ..., m_k: m_1(\lambda_1) = a_2, m_2(a_2) = a_3, ..., m_k(a_k) = \lambda_2 \]</p><p>where \( m_1, ..., m_k \) &#x2013; basic ascending block movements and \(a_2, ..., a_k \) &#x2013; valid integer partitions of \( n \). This partially ordered set will also be a natural partition lattice for \(n\) which we will call \(NPL(n)\).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/NPL-10-.PNG" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>\(NPL(10)\)</figcaption></figure><p>The green marked elements are called maximal graphical partitions, which will be described in details later. If we define an operation of adding the block in the end like this:</p><p>\[ (a_1, a_2, ..., a_k) \longrightarrow (a_1, a_2, ...,a_k, 1) \]</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/partition1.PNG" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>Operation of adding the block in the end of a partition</figcaption></figure><p>And extend operator \(\leq\) like this:</p><p>\[ \lambda_1 \leq \lambda_2 \Leftrightarrow \exists f_1, ..., f_k: f_1(\lambda_1) = a_2, f_2(a_2) = a_3, ..., f_k(a_k) = \lambda_2 \]</p><p>where \(\lambda_1\) and \(\lambda_2\) are integer partitions for some integers \(n\) and \(m\), &#xA0;\(f_1...f_k\) each is either ascending basic block movement or block addition to the right side and \(a_2...a_k\) are valid integer partitions. </p><p>Then we get natural partition lattice for all integers (\(NPL\)):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/Natural-Partition-Lattice-NPL.PNG" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>Natural Partition Lattice (\(NPL\))</figcaption></figure><p>Now let&apos;s explore some properties of Ferrer&apos;s diagrams of integer partitions:</p><p>The largest square of blocks contained in a Ferrer&apos;s diagram is called &quot;Durfee square&quot;.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/Durfee-square.png" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>Durfee square</figcaption></figure><p>The top row of the Durfee square and above is called &quot;head&quot; and is denoted as \(hd(\lambda)\) of the integer partition.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/head-1.png" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>Head</figcaption></figure><p>The blocks to the right of the Durfee square are called &quot;conjugate tail&quot;. This is denoted as \(tl^{\ast}(\lambda)\).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/conjugate-tail.png" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>Conjugate tail</figcaption></figure><p>A conjugate integer partition is a partition that you get if you mirror the original partition across bottom-left to top-right diagonal. Conjugate to \(\lambda = (6, 3 , 1, 1)\) would be \(\lambda^{\ast} = (4, 2, 2, 1, 1, 1)\). And the tail of the \(\lambda = (6, 3 , 1, 1)\) then would be \((2)\). In other words \(tl(\lambda) = (2)\).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/conjugate.png" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>The conjugate to the partition \(\lambda\)</figcaption></figure><p>We call the partition <em>graphical</em> if there exists graph \(G\) such that \((v_1, v_2, ..., v_k)\) is a valid integer partition where \(v_i\) are degrees of vertices of \(G\) and \(v_1 \geq v_2 \geq ... \geq v_k\). The most interesting fact is probably the Kohnert&apos;s criterion and its consequences. </p><h1 id="kohnert-s-criterion">Kohnert&apos;s criterion</h1><p>An even integer partition \(\lambda\) is graphical if and only if \(hd(\lambda) \leq tl(\lambda)\).</p><p>Also, \(\lambda\) is called maximal graphical partition if \(hd(\lambda) = tl(\lambda)\). Scroll up to \(NPL(10)\) and look at the highlighted partitions: they are all maximal graphical.</p><h1 id="threshold-graphs">Threshold graphs</h1><p>By definition a threshold graph is a graph that can be constructed from a one-vertex graph by repeated applications of the following two operations:</p><ol><li>Addition of a single isolated vertex to the graph.</li><li>Addition of a single dominating vertex to the graph, i.e. a single vertex that is connected to all other vertices.</li></ol><p>Let&apos;s define simple operations on graphs called edge rotations:</p><figure class="kg-card kg-image-card"><img src="https://tonyistomin.xyz/content/images/2020/08/edge_rotation.png" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"></figure><p>A triple of vertices \(A, B, C\) in a graph \(G = &lt;V, E&gt;\) such that \(AB \in E\) and &#xA0; &#xA0; \(BC \not\in E\) is called increasing (or lifting) if \(deg(A) \leq deg(C)\) and decreasing (or lowering) if \(deg(A) \geq 2 + deg(C)\).</p><p>If there is no increasing edge rotation in graph \(G\) it comes out that \(G\) is a threshold graph. If we consider integer partition corresponding to G we will find out that it is maximal graphical.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/image--1-.png" class="kg-image" alt="Integer partitions and threshold graphs" loading="lazy"><figcaption>Threshold graph and its partition</figcaption></figure><p>In the example above the head of the integer partition is equal to its tail therefore it is maximal graphical and corresponds to the threshold graph.</p><h1 id="algorithm">Algorithm</h1><p>The question rises whether we can transform a given graph into a threshold graph using increasing edge rotations, and if we can what is the shortest sequence of such transformations. </p><p>It comes out we can always do that because increasing edge rotation always corresponds to ascending block movement and transforms given graphical partition into greater (in the lattice).</p><p>Using simple <a href="https://github.com/ReFruity/threshold-graph/blob/master/algorithm.cpp#L350">breadth first search</a> (BFS) and increasing edge rotation we can find every shortest transformation sequence that converts our graph into a threshold graph.</p><p>You can find implementation of this algorithm and others in this C++ <a href="https://github.com/ReFruity/threshold-graph">threshold graph and integer partition library</a>.</p><h1 id="references">References</h1><ol><li><a href="http://www.mathnet.ru/php/archive.phtml?wshow=paper&amp;jrnid=semr&amp;paperid=1216&amp;option_lang=eng">On maximal graphical partitions that are the nearest to a given graphical partition</a> (in russian language) - <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=22902">V. A. Baransky</a>, <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=66357">T. A. Senchonok</a></li><li><a href="https://drive.google.com/file/d/1AVsJY_IrHT1AQmgjmbmqaUQf37JtjTVe/view?usp=sharing">On threshold graphs and implementation of graphical partitions</a> (in russian language) - <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=22902">V. A. Baransky</a>, <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=66357">T. A. Senchonok</a></li><li><a href="https://drive.google.com/file/d/1SJOO708xH3A-mSMhpyhnZlGu_Rw7L1E8/view?usp=sharing">On natural number partition lattice (2015)</a> (in russian language) - <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=22902">V. A. Baransky</a>, <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=66357">T. A. Senchonok</a>, T. A. Koroleva</li><li><a href="https://drive.google.com/file/d/127z7UpyfBf_JiaIdhJGHgfZCxOvpyXuk/view?usp=sharing">On lattice of partitions of all natural numbers (2016)</a> (in russian language) - <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=22902">V. A. Baransky</a>, <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=66357">T. A. Senchonok</a>, T. A. Koroleva</li><li><a href="https://drive.google.com/file/d/17293FWI2ayGlf8MTYe5Mo0IDbM72hkzH/view?usp=sharing">New algorithm of generation of graphical sequences (2016)</a> (in russian language) - <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=22902">V. A. Baransky</a>, <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=66357">T. A. Senchonok</a>, T. I. Nadymova</li><li><a href="https://drive.google.com/file/d/1Ll3U0WxcTSmTMAg08FMVfvCf53f56Yk8/view?usp=sharing">On maximal graphical partitions (2017)</a> (in russian language) - <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=22902">V. A. Baransky</a>, <a href="http://www.mathnet.ru/php/person.phtml?option_lang=eng&amp;personid=66357">T. A. Senchonok</a></li><li><a href="https://drive.google.com/file/d/1h47yr5toQlzFaDUsrqlXzR2m2Nx6m2Dl/view?usp=sharing">Natural numbers partitions and chromatic uniqueness of graphs (2008)</a> (in russian language) - T. A. Koroleva</li><li><a href="https://drive.google.com/file/d/1ftyh93q56EYV_U2EXMGF7AxLYOm82wN0/view?usp=sharing">Graphical sequences and their generation algorithms (2016)</a> (in russian language) - T. I. Nadymova </li></ol><p>Wikipedia: <a href="https://en.wikipedia.org/wiki/Threshold_graph">Threshold graph</a>, <a href="https://en.wikipedia.org/wiki/Partition_(number_theory)">Integer partition</a>, <a href="https://en.wikipedia.org/wiki/Lattice_(order)#Lattices_as_partially_ordered_sets">Lattices as partially ordered sets</a></p>]]></content:encoded></item><item><title><![CDATA[A little update]]></title><description><![CDATA[<p>I write this post to inform you that this blog is not dead :) I now have 2 side-projects which we will talk about in this blog later.</p><p>First one is my unfinished master&apos;s degree work on graphical integer partitions and threshold graphs. Here is little spoiler (natural partition</p>]]></description><link>https://tonyistomin.xyz/a-little-update/</link><guid isPermaLink="false">61b9f04685b074000123a9cf</guid><category><![CDATA[update]]></category><dc:creator><![CDATA[Anton Istomin]]></dc:creator><pubDate>Tue, 25 Aug 2020 19:10:01 GMT</pubDate><media:content url="https://tonyistomin.xyz/content/images/2020/08/facebook-cover-horizon-space.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://tonyistomin.xyz/content/images/2020/08/facebook-cover-horizon-space.jpg" alt="A little update"><p>I write this post to inform you that this blog is not dead :) I now have 2 side-projects which we will talk about in this blog later.</p><p>First one is my unfinished master&apos;s degree work on graphical integer partitions and threshold graphs. Here is little spoiler (natural partition lattice for number 10):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/NPL-10-.PNG" class="kg-image" alt="A little update" loading="lazy"><figcaption>NPL(10)</figcaption></figure><p>Second one is basically semi-automatic problem generator for the game of Go. It uses <a href="http://fuego.sourceforge.net/">fuego</a> as it&apos;s engine and tries to generate a game tree using minimax algorithm. Then you can upload this file to <a href="goproblems.com">goproblems.com</a> and it will work.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2020/08/image-1.png" class="kg-image" alt="A little update" loading="lazy"><figcaption>Go problem for you. Black to move.</figcaption></figure><p>That&apos;s all for now folks. See you soon!</p><p>Follow telegram channel for updates: <a href="https://t.me/refruity_xyz">t.me/refruity_xyz</a></p>]]></content:encoded></item><item><title><![CDATA[Game of Life and AssemblyScript]]></title><description><![CDATA[Step by step tutorial to writing Game of Life in typescript then compiling it using AssemblyScript. ]]></description><link>https://tonyistomin.xyz/assembly-script/</link><guid isPermaLink="false">61b9f04685b074000123a9cb</guid><category><![CDATA[assemblyscript]]></category><category><![CDATA[webassembly]]></category><category><![CDATA[tutorial]]></category><category><![CDATA[game of life]]></category><category><![CDATA[typescript]]></category><dc:creator><![CDATA[Anton Istomin]]></dc:creator><pubDate>Sun, 11 Aug 2019 12:56:44 GMT</pubDate><media:content url="https://tonyistomin.xyz/content/images/2019/08/1280px-LLVM_Logo.svg.png" medium="image"/><content:encoded><![CDATA[<img src="https://tonyistomin.xyz/content/images/2019/08/1280px-LLVM_Logo.svg.png" alt="Game of Life and AssemblyScript"><p>Originally I planned to write about <a href="https://wasi.dev/">WASI</a> (that&apos;s why <a href="https://en.wikipedia.org/wiki/LLVM">LLVM</a> logo is in background). It is system interface for WebAssembly. Basically a means to run <code>wasm</code> files without browser and give them access to system stuff. But it turned out that it was kind of boring topic to write about. Just use <a href="https://github.com/CraneStation/wasmtime">wasmtime</a> (which I could not compile) or <a href="https://github.com/wasmerio/wasmer">wasmer</a> (which I ran successfully with two commands) and execute <code>wasm</code> files if you desire so.</p><p>But today we are going to explore the paths of <a href="https://github.com/AssemblyScript/assemblyscript">AssemblyScript</a> and <a href="https://webassembly.org/">WebAssembly</a>. We are going to learn how to compile <a href="https://www.typescriptlang.org/">TypeScript</a> into WebAssembly and also compare performance of compiled JavaScript and WebAssembly by implementing <a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Game of Life</a>. &#xA0;We will use Ubuntu 18.04 as our OS and <a href="https://webpack.js.org/">webpack</a> as our module bundler.</p><p>tl;dr here is codepen with examples:</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_ymPdpo" src="https://codepen.io/ReFruity/embed/preview/ymPdpo?height=300&amp;slug-hash=ymPdpo&amp;default-tabs=js,result&amp;host=https://codepen.io" title="Game of Life" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" style="width: 100%; overflow: hidden;"></iframe></figure><p>Run the pen and you will see that WebAssembly gives around 60 FPS, whereas JS gives only 32 FPS. You can also click and drag to add extra chaos to the field.</p><p>Alright, back to the tutorial. Let&apos;s start with dependencies. You can install latest node using <a href="https://github.com/creationix/nvm#installation-and-update">nvm</a>. Then initialize new repo by adding <code>package.json</code>:</p><pre><code class="language-javascript">{
  &quot;name&quot;: &quot;assemblyscript-game-of-life&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;main&quot;: &quot;src/index.js&quot;,
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;webpack-dev-server&quot;,
    &quot;build&quot;: &quot;npm run asbuild &amp;&amp; webpack-cli&quot;,
    &quot;asbuild&quot;: &quot;asc assembly/index.ts -b compiled/gameoflife.wasm --validate --optimize --importMemory --use Math=JSMath&quot;
  },
  &quot;license&quot;: &quot;ISC&quot;,
  &quot;devDependencies&quot;: {
    &quot;assemblyscript&quot;: &quot;github:AssemblyScript/assemblyscript&quot;,
    &quot;copy-webpack-plugin&quot;: &quot;^5.0.4&quot;,
    &quot;wasm-loader&quot;: &quot;^1.3.0&quot;,
    &quot;webpack&quot;: &quot;^4.38.0&quot;,
    &quot;webpack-cli&quot;: &quot;^3.3.6&quot;,
    &quot;webpack-dev-server&quot;: &quot;^3.7.2&quot;
  },
  &quot;dependencies&quot;: {}
}</code></pre><p>Here we see <code>start</code> script which is used for developing the application, it opens webpack-dev-server on port <code>9000</code>. Also we see two build scripts, first is <code>build</code> and it tells webpack to compile it&apos;s <code>bundle.js</code>, second is <code>asbuild</code> which tells AssemblyScript to compile <code>ts</code> file into <code>wasm</code> file. Let&apos;s stop for a minute on the second script. It has <a href="https://docs.assemblyscript.org/details/compiler">couple of arguments</a>. Interesting ones are <code>importMemory</code> and <code>use Math</code>. Former will allow us to import memory object and use it inside and outside <code>wasm</code> file, latter is needed to import <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math">Math</a></code> object.</p><p>Now you can run <code>npm install</code> to install dependencies. Create files <code>assembly/index.ts</code> and <code>src/index.ts</code>. Also create following <code>webpack.config.js</code>:</p><pre><code class="language-javascript">const path = require(&apos;path&apos;);
const CopyWebpackPlugin = require(&apos;copy-webpack-plugin&apos;);

module.exports = {
  entry: &apos;./src/index.js&apos;,
  devtool: &apos;source-map&apos;,
  resolve: {
    extensions: [ &apos;.js&apos; ]
  },
  module: {
    defaultRules: [
      {
        type: &quot;javascript/auto&quot;,
        resolve: {}
      },
      {
        test: /\.json$/i,
        type: &quot;json&quot;
      }
    ],
    rules: [
      {
        test: /\.wasm$/,
        use: &apos;wasm-loader&apos;
      }
    ],
  },
  output: {
    filename: &apos;bundle.js&apos;,
    path: path.resolve(__dirname, &apos;dist&apos;)
  },
  plugins: [
    new CopyWebpackPlugin([{ from: path.resolve(__dirname, &apos;index.html&apos;), to: path.resolve(__dirname, &apos;dist&apos;) }])
  ],
  devServer: {
    contentBase: path.join(__dirname, &apos;dist&apos;),
    compress: true,
    port: 9000
  }
};</code></pre><p><code>defaultRules</code> is shamelessly copy-pasted from this <a href="https://github.com/webpack/webpack/issues/6725">github issue</a>. I have no idea how that works but that&apos;s not the point. The point is: we can now import <code>wasm</code> files!</p><p>But let&apos;s start simple. Create <code>index.html</code>:</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;Game of Life&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;bundle.js&quot;&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>In <code>src/index.js</code> write:</p><pre><code class="language-javascript">import GameOfLife from &apos;../compiled/gameoflife.wasm&apos;

async function start() {
  const memory = new WebAssembly.Memory({ initial: 256 })
  const importObject = {
    env: {
      abort: () =&gt; {},
      memory
    },
    imports: { f }
  }

  const game = await GameOfLife(importObject)
  const { add } = game.instance.exports

  function f(x) {
    console.log(&apos;f&apos;, x)
  }

  console.log(add(12, 30))
}

start()</code></pre><p>To be sure, <code>f</code> is a bad name for a function. But on each step of building this project it helped me so much that it grew on me and I don&apos;t want to change it now. Now for <code>assembly/index.ts</code>:</p><pre><code class="language-javascript">@external(&apos;imports&apos;, &apos;f&apos;)
declare function f(x: i32): void

f(1)

export function add(x: i32, y: i32): i32 {
  return x + y
}</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2019/08/Screenshot-from-2019-08-05-20-53-46.png" class="kg-image" alt="Game of Life and AssemblyScript" loading="lazy"><figcaption>This is the file structure we will be using for our project</figcaption></figure><p>The moment of truth: run <code>npm run asbuild</code>, then <code>npm start</code> and open <code>localhost:9000</code> in your favorite (not IE) browser. Open developers tools (F12 in chrome) and look at the result.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://tonyistomin.xyz/content/images/2019/08/Screenshot-from-2019-08-05-21-43-47.png" class="kg-image" alt="Game of Life and AssemblyScript" loading="lazy"><figcaption>Glorious</figcaption></figure><p>The reason this result is important is that we were able to use core mechanics like import function <code>f</code> from js to wasm and run that function, export and run function <code>add</code> from <code>wasm</code> and also load <code>wasm</code> file using <a href="https://github.com/ballercat/wasm-loader">wasm-loader</a>.</p><p>Do you like modules? I do! Let&apos;s extract <code>index.js</code> as a separate <code>GameOfLifeWebAssembly.js</code> module. Create a new file with:</p><pre><code class="language-javascript">import GameOfLife from &apos;../compiled/gameoflife.wasm&apos;

export default async () =&gt; {
  const memory = new WebAssembly.Memory({ initial: 256 })
  const importObject = {
    env: {
      abort: () =&gt; {},
      memory
    },
    imports: { f }
  }

  const game = await GameOfLife(importObject)
  const { add } = game.instance.exports

  function f(x) {
    console.log(&apos;f&apos;, x)
  }

  return { add }
}</code></pre><p>And also introduce <code>Main</code> module in <code>index.js</code>:</p><pre><code class="language-javascript">import GameOfLifeWebAssembly from &apos;./GameOfLifeWebAssembly&apos;

async function Main() {
  const game = await GameOfLifeWebAssembly()
  console.log(game.add(12, 30))
}

window.addEventListener(&apos;load&apos;, Main)</code></pre><p>You can run the application again to make sure it produces the same output as before the refactoring. Now add a canvas to your <code>index.html</code> <code>&lt;body&gt;</code>:</p><pre><code class="language-html">&lt;canvas id=&quot;canvas&quot;&gt;&lt;/canvas&gt;</code></pre><p>We will need this canvas to display alive and dead cells. 1 cell = 1 pixel on the canvas. Some js code will be needed to display <code><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array">Uint32Array</a></code> on the canvas. In your <code>index.js</code>:</p><pre><code class="language-javascript">  const width = 100
  const height = 100

  const canvas = document.getElementById(&apos;canvas&apos;)
  canvas.width  = width
  canvas.height = height

  const context = canvas.getContext(&apos;2d&apos;)
  const imageData = context.createImageData(width, height)
  const imageDataView = new Uint32Array(imageData.data.buffer)

  imageDataView[0] = 0xFF000000

  context.putImageData(imageData, 0, 0)</code></pre><p>We create new <a href="https://developer.mozilla.org/en-US/docs/Web/API/ImageData">ImageData</a> and set first value to <code>0xFF000000</code>. <code>uint32</code> stands for 32 bit unsigned integer. Unsigned means that first bit does not indicate its sign, so every <code>uint32</code> ranges from <code>0</code> to <code>2^32 - 1 = 4294967295</code>. Each <code>uint32</code> in array represents a pixel on the canvas and is in format <code>ABGR</code> which stands for Alpha, Blue, Green, Red. Alpha channel is the transparency of the color, where <code>0xFF</code> means opaque. To sum it up we get an opaque black pixel. Open <code>localhost:9000</code> and look at the black pixel in the top left of your screen.</p><p>Calling external js functions from wasm is slower than writing and reading shared memory. From js side we will need a memory view in <code>GameOfLifeWebAssembly.js</code>:</p><pre><code class="language-javascript">const memory = new WebAssembly.Memory({ initial: 256 })
const memoryView = new Uint32Array(memory.buffer)
...
return { memoryView }</code></pre><p>From wasm side we will need functions <code>store&lt;u32&gt;</code> and <code>load&lt;u32&gt;</code> in <code>index.ts</code>:</p><pre><code class="language-javascript">@external(&apos;imports&apos;, &apos;width&apos;)
declare const WIDTH: i32

@external(&apos;imports&apos;, &apos;height&apos;)
declare const HEIGHT: i32

@external(&apos;imports&apos;, &apos;f&apos;)
declare function f(x: i32): void

const BLACK = 0xFF000000
const WHITE = 0

function set(x: i32, y: i32): void {
  store&lt;u32&gt;(toPointer(x, y), BLACK)
}

function toPointer(x: i32, y: i32): i32 {
  return (y * WIDTH + x) * 4
}

set(0, 0)
set(0, 1)
</code></pre><p>Don&apos;t forget to import width and height. Also in <code>index.js</code> we will need to copy data from shared memory to canvas. To do this try:</p><pre><code class="language-javascript">  const imageDataView = new Uint32Array(imageData.data.buffer)

  imageDataView.set(game.memoryView.slice(0, width * height))

  context.putImageData(imageData, 0, 0)</code></pre><p>Now open <code>localhost:9000</code> and look carefully. You should be able to spot 2 black pixels in the top left corner.</p><p>Now grab <code><a href="https://github.com/ReFruity/assemblyscript-game-of-life/blob/master/assembly/index.ts">index.ts</a></code> from my github repo, modify <code>GameOfLifeWebAssembly.js</code> like that:</p><pre><code class="language-javascript">import GameOfLife from &apos;../compiled/gameoflife.wasm&apos;

export default async (width, height) =&gt; {
  const memory = new WebAssembly.Memory({ initial: 256 })
  const memoryView = new Uint32Array(memory.buffer)
  const importObject = {
    env: {
      abort: () =&gt; {},
      memory
    },
    imports: { f, width, height },
    Math
  }

  const game = await GameOfLife(importObject)

  console.log(game)
  const { randomize, step } = game.instance.exports

  function f(x) {
    console.log(&apos;f&apos;, x)
  }

  return { randomize, step, memoryView }
}</code></pre><p>To add game loop we will need <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame</a></code> function. In <code>index.js</code>:</p><pre><code class="language-javascript">  game.randomize()

  function cycle() {
    game.step()
    imageDataView.set(game.memoryView.slice(0, width * height))
    context.putImageData(imageData, 0, 0)
    requestAnimationFrame(cycle)
  }

  cycle()</code></pre><p>Run <code>npm run build</code>. Voila! You have 100x100 working Game of Life on <code>localhost:9000</code>.</p><p>Also to further address performance questions, I added a simple <a href="https://github.com/ReFruity/assemblyscript-game-of-life/blob/master/src/benchmark.js">benchmark</a> in my repo. I make game&apos;s <code>step</code> couple of times on randomized board and measure milliseconds it takes to complete. Results are:</p><figure class="kg-card kg-image-card"><img src="https://tonyistomin.xyz/content/images/2019/08/Screenshot-from-2019-08-10-12-19-44.png" class="kg-image" alt="Game of Life and AssemblyScript" loading="lazy"></figure><p>JS takes twice as much time as WebAssembly to calculate. This benchmark is representative because rendering on canvas is identical for JS and WebAssembly code.</p><p>Final version with JS/WebAssembly comparison and also painting feature is available on my <a href="https://github.com/ReFruity/assemblyscript-game-of-life">github</a>.</p><p>Fun fact: before <code>@inline</code>-ing some functions in wasm its FPS was comparatively lower than FPS of JS code.</p><p>Important note: official AssemblyScript repository has <a href="https://assemblyscript.github.io/assemblyscript/examples/game-of-life/">Game of Life</a> already implemented. <a href="https://github.com/AssemblyScript/assemblyscript/tree/master/examples/game-of-life">Here</a> is their source code. I learned some mechanics by reading this code. There are <a href="https://medium.com/@carlosbaraza/hopefully-simple-webassembly-starting-guide-9300f5a1c0d7">other</a> <a href="https://blog.openbloc.fr/webassembly-first-steps/#part1">tutorials</a> that helped.</p><p>P.S. Look at <a href="https://jtiscione.github.io/webassembly-wave/index.html">this cool demo</a> with simulation of the wave equation.</p>]]></content:encoded></item><item><title><![CDATA[Writing Discord Bot With Speech Recognition]]></title><description><![CDATA[Automate your discord server using discord bot. Simple step by step tutorial on how to create a bot with voice commands.]]></description><link>https://tonyistomin.xyz/writing-discord-bot/</link><guid isPermaLink="false">61b9f04685b074000123a9c8</guid><category><![CDATA[discord]]></category><category><![CDATA[bot]]></category><category><![CDATA[node]]></category><category><![CDATA[speech recognition]]></category><category><![CDATA[role]]></category><category><![CDATA[assignment]]></category><category><![CDATA[tutorial]]></category><dc:creator><![CDATA[Anton Istomin]]></dc:creator><pubDate>Wed, 06 Mar 2019 12:00:00 GMT</pubDate><media:content url="https://tonyistomin.xyz/content/images/2019/03/Bastion_portrait.png" medium="image"/><content:encoded><![CDATA[<img src="https://tonyistomin.xyz/content/images/2019/03/Bastion_portrait.png" alt="Writing Discord Bot With Speech Recognition"><p>Bots provide a lot of versatility to discord. You can automate certain tasks using them. For example, imagine a server where voice channels correspond to games. Our bot will join user&apos;s voice channel when user starts playing a game and ask him if he wants to be transferred to the right channel. We will be using <a href="https://nodejs.org">node</a> version 8.10.0, <a href="https://cloud.google.com/speech-to-text/">Google speech recognition</a>, <a href="https://www.johnvansickle.com/ffmpeg/">ffmpeg</a> and <a href="https://discord.js.org/">discord.js</a>. You can install node 8.10.0 using <a href="https://github.com/creationix/nvm#installation-and-update">nvm</a>. Also I recommend using latest Ubuntu OS.</p><p>First things first, we want discord API token. There are <a href="https://github.com/reactiflux/discord-irc/wiki/Creating-a-discord-bot-&amp;-getting-a-token">some</a> <a href="https://github.com/Chikachi/DiscordIntegration/wiki/How-to-get-a-token-and-channel-ID-for-Discord">tutorials</a> on the Internet on how to get it. Also you will need to add your discord bot user to your discord server. Then create a file named <code>config.json</code> and paste your API token there:</p><!--kg-card-begin: markdown--><pre><code class="language-javascript">{
  &quot;discordApiToken&quot;: &quot;your-token-here&quot;
}
</code></pre>
<!--kg-card-end: markdown--><p>Then create <code><a href="https://docs.npmjs.com/files/package.json">package.json</a></code> file and add dependencies: </p><!--kg-card-begin: markdown--><pre><code class="language-javascript">{
  &quot;name&quot;: &quot;myawesomebot&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;Discord bot with speech recognition&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;node index.js&quot;
  },
  &quot;dependencies&quot;: {
    &quot;@google-cloud/speech&quot;: &quot;^2.1.1&quot;,
    &quot;discord.js&quot;: &quot;https://github.com/discordjs/discord.js.git#123713305ad5a6aa1e5205a53713494009740aef&quot;,
    &quot;node-opus&quot;: &quot;^0.3.1&quot;
  },
  &quot;license&quot;: &quot;ISC&quot;
}
</code></pre>
<!--kg-card-end: markdown--><p>Create <code>index.js</code> file:</p><!--kg-card-begin: markdown--><pre><code class="language-javascript">const Discord = require(&apos;discord.js&apos;)
const config = require(&apos;./config&apos;)

const discordClient = new Discord.Client()

discordClient.on(&apos;ready&apos;, () =&gt; {
  console.log(`Logged in as ${discordClient.user.tag}!`)
})

discordClient.login(config.discordApiToken)
</code></pre>
<!--kg-card-end: markdown--><p>Now we want to test if our bot is set up correctly. Run <code>npm install</code> and <code>npm start</code> and look in your console. There should be message starting with <code>Logged in as</code> and the bot should come online in your discord server. Congratulations! You wrote your first discord bot. But now this bot does nothing so let&apos;s add some functionality. To do this we will need to learn about <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async functions</a> which will helps us reduce nesting and make our code prettier:</p><!--kg-card-begin: markdown--><pre><code class="language-javascript">discordClient.on(&apos;presenceUpdate&apos;, async (oldPresence, newPresence) =&gt; {
  console.log(&apos;New Presence:&apos;, newPresence)

  const member = newPresence.member
  const presence = newPresence
  const memberVoiceChannel = member.voice.channel

  if (!presence || !presence.activity || !presence.activity.name || !memberVoiceChannel) {
    return
  }

  const connection = await memberVoiceChannel.join()

  connection.on(&apos;speaking&apos;, (user, speaking) =&gt; {
    if (speaking) {
      console.log(`I&apos;m listening to ${user.username}`)
    } else {
      console.log(`I stopped listening to ${user.username}`)
    }
  })
})
</code></pre>
<!--kg-card-end: markdown--><p>Now try joining a voice channel and then starting a game. The bot should join you and log your presence which includes the name of the game. Also it should detect when you are speaking.</p><p>So far so good. Time for some real speech recognition. To do this we will need <a href="https://cloud.google.com/speech-to-text/docs/quickstart-client-libraries">Google speech API credentials</a> (read the first item in &quot;before you begin&quot; section). Save your credentials in <code>google-credentials.json</code> file in your project folder. After that you can either use <code><a href="https://www.npmjs.com/package/dotenv">dotenv</a></code> or start your app with</p><!--kg-card-begin: markdown--><pre><code>GOOGLE_APPLICATION_CREDENTIALS=&quot;[PATH]&quot; npm start
</code></pre>
<!--kg-card-end: markdown--><p>where <code>[PATH]</code> is a full path to your <code>google-credentials.json</code> file. </p><p>If you use <code>dotenv</code> then create <code>.env</code> file</p><!--kg-card-begin: markdown--><pre><code>GOOGLE_APPLICATION_CREDENTIALS=&quot;google-credentials.json&quot;
</code></pre>
<!--kg-card-end: markdown--><p> in your project folder after installing the package and then add &#xA0; </p><!--kg-card-begin: markdown--><pre><code class="language-javascript">require(&apos;dotenv&apos;).config()
</code></pre>
<!--kg-card-end: markdown--><p>at the start of your <code>index.js</code>.</p><p>Nice. Now let&apos;s try recognizing your beautiful voice. To do this we need one more thing. <code>Discord.js</code> function <code><a href="https://discord.js.org/#/docs/main/stable/class/VoiceReceiver?scrollTo=createPCMStream">createPCMStream</a></code> creates a 16-bit signed PCM, stereo 48KHz stream, but Google speech recognition takes mono input, i.e. 1 channel. So we have to convert 2 channel stream to 1 channel stream. We achieve it by creating a <a href="https://nodejs.org/api/stream.html#stream_implementing_a_transform_stream">transform stream</a>:</p><!--kg-card-begin: markdown--><pre><code class="language-javascript">const { Transform } = require(&apos;stream&apos;)

function convertBufferTo1Channel(buffer) {
  const convertedBuffer = Buffer.alloc(buffer.length / 2)

  for (let i = 0; i &lt; convertedBuffer.length / 2; i++) {
    const uint16 = buffer.readUInt16LE(i * 4)
    convertedBuffer.writeUInt16LE(uint16, i * 2)
  }

  return convertedBuffer
}

class ConvertTo1ChannelStream extends Transform {
  constructor(source, options) {
    super(options)
  }

  _transform(data, encoding, next) {
    next(null, convertBufferTo1Channel(data))
  }
}
</code></pre>
<!--kg-card-end: markdown--><p>We are ready to implement voice recognition:</p><!--kg-card-begin: markdown--><pre><code class="language-javascript">const googleSpeech = require(&apos;@google-cloud/speech&apos;)

const googleSpeechClient = new googleSpeech.SpeechClient()

discordClient.on(&apos;presenceUpdate&apos;, async (oldPresence, newPresence) =&gt; {
  console.log(&apos;New Presence:&apos;, newPresence)

  const member = newPresence.member
  const presence = newPresence
  const memberVoiceChannel = member.voice.channel

  if (!presence || !presence.activity || !presence.activity.name || !memberVoiceChannel) {
    return
  }

  const connection = await memberVoiceChannel.join()
  const receiver = connection.receiver

  connection.on(&apos;speaking&apos;, (user, speaking) =&gt; {
    if (!speaking) {
      return
    }

    console.log(`I&apos;m listening to ${user.username}`)

    // this creates a 16-bit signed PCM, stereo 48KHz stream
    const audioStream = receiver.createStream(user, { mode: &apos;pcm&apos; })
    const requestConfig = {
      encoding: &apos;LINEAR16&apos;,
      sampleRateHertz: 48000,
      languageCode: &apos;en-US&apos;
    }
    const request = {
      config: requestConfig
    }
    const recognizeStream = googleSpeechClient
      .streamingRecognize(request)
      .on(&apos;error&apos;, console.error)
      .on(&apos;data&apos;, response =&gt; {
        const transcription = response.results
          .map(result =&gt; result.alternatives[0].transcript)
          .join(&apos;\n&apos;)
          .toLowerCase()
        console.log(`Transcription: ${transcription}`)
      })

    const convertTo1ChannelStream = new ConvertTo1ChannelStream()

    audioStream.pipe(convertTo1ChannelStream).pipe(recognizeStream)

    audioStream.on(&apos;end&apos;, async () =&gt; {
      console.log(&apos;audioStream end&apos;)
    })
  })
})

</code></pre>
<!--kg-card-end: markdown--><p>Start the bot, join voice channel, start any game and then say something in English. You should see transcription of your words in console. For now we will only be needing words &quot;yes&quot; and &quot;no&quot; to command our bot. </p><p>Note here: it may now seem that the bot doesn&apos;t hear you and doesn&apos;t recognize your words. In <a href="https://github.com/discordjs/discord.js/issues/2929">this github issue</a> they say that discord had (or has) a bug that doesn&apos;t allow for bots to listen to you until you&apos;ve played any sound. So just proceed with the tutorial, we will implement playing sounds before recognition.</p><p>The bot is silent right now, we need it to ask user a question:</p><!--kg-card-begin: markdown--><pre><code class="language-javascript">async function playFile(connection, filePath) {
  return new Promise((resolve, reject) =&gt; {
    const dispatcher = connection.play(filePath)
    dispatcher.setVolume(1)
    dispatcher.on(&apos;start&apos;, () =&gt; {
      console.log(&apos;Playing&apos;)
    })
    dispatcher.on(&apos;end&apos;, () =&gt; {
      resolve()
    })
    dispatcher.on(&apos;error&apos;, (error) =&gt; {
      console.error(error)
      reject(error)
    })
  })
}
...
  const connection = await memberVoiceChannel.join()
  const receiver = connection.receiver

  await playFile(connection, &apos;wrongChannelEn.mp3&apos;)

  connection.on(&apos;speaking&apos;, (user, speaking) =&gt; {
...
</code></pre>
<!--kg-card-end: markdown--><p>You can download <code><a href="https://github.com/ReFruity/EzBot/blob/master/audio/wrongChannelEn.mp3">wrongChannelEn.mp3</a></code> or record your own voice line. If the audio is not playing for you then it is probably because of the missing <code>ffmpeg</code> binaries. You can download them <a href="https://www.johnvansickle.com/ffmpeg/">here</a> for your system. This <a href="https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz">link</a> is for Ubuntu x64. Decompress them and put <code>ffmpeg</code> file in your <code>Path</code>, e.g. <code>/usr/bin</code> folder.</p><p>The last step is to create a mapping between games and channels and to tell our bot to transfer people to the right channel on &quot;yes&quot;. To copy the voice channel ID use earlier <a href="https://github.com/Chikachi/DiscordIntegration/wiki/How-to-get-a-token-and-channel-ID-for-Discord#get-the-channel-id-of-the-discord-text-channel">guide</a>. Since I&apos;m using Ubuntu, I will use &quot;Mines&quot; as the game for this demonstration.</p><!--kg-card-begin: markdown--><pre><code class="language-javascript">const GamesAndChannels = {
  Mines: &apos;[VoiceChannelID]&apos;
}

discordClient.on(&apos;presenceUpdate&apos;, async (oldMember, newMember) =&gt; {
  const memberVoiceChannel = newMember.voiceChannel
  
  if (!newMember.presence || !newMember.presence.game || !memberVoiceChannel) {
    return
  }

  const channelId = GamesAndChannels[newMember.presence.game]
  
  if (!channelId) {
    return
  }
  
  const connection = await memberVoiceChannel.join()
  const receiver = connection.createReceiver()

  await playFile(connection, &apos;wrongChannelEn.mp3&apos;)

  setTimeout(() =&gt; {
    memberVoiceChannel.leave()
  }, 30000)

  connection.on(&apos;speaking&apos;, (user, speaking) =&gt; {
    if (!speaking) {
      return
    }

    console.log(`I&apos;m listening to ${user.username}`)

    // this creates a 16-bit signed PCM, stereo 48KHz stream
    const audioStream = receiver.createPCMStream(user)
    const requestConfig = {
      encoding: &apos;LINEAR16&apos;,
      sampleRateHertz: 48000,
      languageCode: &apos;en-US&apos;
    }
    const request = {
      config: requestConfig
    }
    const recognizeStream = googleSpeechClient
      .streamingRecognize(request)
      .on(&apos;error&apos;, console.error)
      .on(&apos;data&apos;, response =&gt; {
        const transcription = response.results
          .map(result =&gt; result.alternatives[0].transcript)
          .join(&apos;\n&apos;)
          .toLowerCase()
        console.log(`Transcription: ${transcription}`)

        if (transcription === &apos;yes&apos;) {
          connection.channel.members.array().forEach(member =&gt; {
            if (member.user.id !== discordClient.user.id) {
              console.log(`Moving member ${member.displayName} to channel ${channelId}`)
              member.edit({ channel: channelId }).catch(console.error)
              memberVoiceChannel.leave()
            }
          })
        } else if (transcription === &apos;no&apos;) {
          memberVoiceChannel.leave()
        }
      })

    const convertTo1ChannelStream = new ConvertTo1ChannelStream()

    audioStream.pipe(convertTo1ChannelStream).pipe(recognizeStream)

    audioStream.on(&apos;end&apos;, async () =&gt; {
      console.log(&apos;audioStream end&apos;)
    })
  })
})
</code></pre>
<!--kg-card-end: markdown--><p>Done. Now join a wrong voice channel (not with the ID you specified earlier), fire up &quot;Mines&quot; and tell the bot &quot;yes&quot;. You (and your buddies in the voice channel) should be transferred to the voice channel with the specified ID. If you tell the bot &quot;no&quot;, it just leaves the voice channel with sadness on his metal face. Final version of the code is available via <a href="https://gist.github.com/ReFruity/cd09a986fad15f06b83573fecbadf892">this gist</a>.</p><p>In this tutorial I demonstrated a simplified version of EzBot, a bot we developed specifically for our discord server. It is open source and is under ISC license (use however you want). You can find it on my <a href="https://github.com/ReFruity/EzBot">github</a>. It requires MongoDB, has useful commands, internationalization (only EN/RU currently), sends new users welcome messages and also has a feature to assign people their roles using emote dashboard. This project was created in collaboration with my friend <a href="https://github.com/JustMrPhoenix">MrPhoenix</a>.</p><p>UPDATE 26.11.2019: Because of some breaking change in Discord API stuff in the article stopped working. There is <a href="https://github.com/discordjs/discord.js/pull/3578/files#diff-04c6e90faac2675aa89e2176d2eec7d8R38">pull request</a> that solves the problems, but we need to update to latest discord.js (master branch). I will rewrite the article when this pull request is merged. I updated the mentioned gist for now though.</p><p>UPDATE 07.01.2020 <a href="https://github.com/discordjs/discord.js/pull/3578">Pull request</a> was merged. Now you can use main branch of discord.js to make it work. I rewrote the article to comply to new API introduced in the main branch of discord.js</p><p>UPDATE 04.03.2022 <a href="https://github.com/discord/discord-api-docs/discussions/4510">Discord will shut off API versions 6 and 7</a>, so RIP discord.js v11 &amp; v12. I will update this article or write a new one to show the new ways of discord.js.</p>]]></content:encoded></item><item><title><![CDATA[First Post]]></title><description><![CDATA[<p>Well, I finally started up my own programming blog. Occasionally, when I have time &#xA0;(and use more productively than playing StarCraft II) I will write something here. For now look at this cute picture of Zeratul.</p><figure class="kg-card kg-image-card"><img src="https://tonyistomin.xyz/content/images/2019/03/zerathul.jpg" class="kg-image" alt loading="lazy"></figure>]]></description><link>https://tonyistomin.xyz/first-post/</link><guid isPermaLink="false">61b9f04685b074000123a9c7</guid><dc:creator><![CDATA[Anton Istomin]]></dc:creator><pubDate>Tue, 19 Feb 2019 18:44:56 GMT</pubDate><content:encoded><![CDATA[<p>Well, I finally started up my own programming blog. Occasionally, when I have time &#xA0;(and use more productively than playing StarCraft II) I will write something here. For now look at this cute picture of Zeratul.</p><figure class="kg-card kg-image-card"><img src="https://tonyistomin.xyz/content/images/2019/03/zerathul.jpg" class="kg-image" alt loading="lazy"></figure>]]></content:encoded></item></channel></rss>