<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Vit Gordon on Medium]]></title>
        <description><![CDATA[Stories by Vit Gordon on Medium]]></description>
        <link>https://medium.com/@xpl?source=rss-3972c774cf5d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*3tM4ldpgJaayJjQ9k1i7cg.jpeg</url>
            <title>Stories by Vit Gordon on Medium</title>
            <link>https://medium.com/@xpl?source=rss-3972c774cf5d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Fri, 13 Nov 2026 23:42:13 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@xpl/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[The Apple AWDL Bug That Ruins Cloud Gaming on Mac]]></title>
            <link>https://medium.com/@xpl/the-apple-awdl-bug-that-ruins-cloud-gaming-on-mac-c5195bf18784?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/c5195bf18784</guid>
            <category><![CDATA[boosteroid]]></category>
            <category><![CDATA[game-streaming]]></category>
            <category><![CDATA[geforce-now]]></category>
            <category><![CDATA[macos]]></category>
            <category><![CDATA[cloud-gaming]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Wed, 01 Apr 2026 20:10:04 GMT</pubDate>
            <atom:updated>2026-04-01T20:17:40.060Z</atom:updated>
            <content:encoded><![CDATA[<p>We recently bought a Mac Mini M4. Around the same time, Google Fiber upgraded our setup from the older Nest router to the new Wi‑Fi 7 router.</p><p>Instead of getting better, it got dramatically worse!</p><p>Boosteroid <em>(a cloud gaming app)</em> became borderline unusable over Wi‑Fi, with latency spiking into the <strong>100–300 ms</strong> range in a very regular pattern.</p><p>The weird part was that everything else looked normal: speed tests were fine, Wi‑Fi was fine, but inside Boosteroid the stream kept hitching, freezing, and stuttering hard enough to make gaming miserable.</p><p>After a lot of digging, the actual culprit turned out to be <strong>AWDL</strong> — not Boosteroid itself.</p><h3>What AWDL Is</h3><p>AWDL stands for <strong>Apple Wireless Direct Link</strong>. It powers nearby Apple features like <strong>AirDrop, Handoff, AirPlay</strong>, and other continuity features.</p><p>The likely reason it causes these spikes is that your Mac has one Wi‑Fi radio, and AWDL makes it periodically hop off your normal Wi‑Fi channel onto Apple’s peer-to-peer channel to listen for or talk to nearby devices. While that is happening, normal traffic can get delayed because the radio is briefly busy elsewhere.</p><p>That is why the pattern is so odd: the connection can look fine overall, but real-time traffic like cloud gaming, voice chat, or remote desktop gets hit by regular bursts of latency, jitter, packet delay, and short freezes.</p><p>The usual workaround is to disable the awdl0 interface while gaming. The problem is that <strong>macOS can turn it back on by itself after a while</strong>, so disabling it once is often not enough. And you probably do not want it permanently off anyway, because it can interfere with useful Apple features.</p><p>This is a long-standing macOS bug. There is <strong>no proper fix</strong>, only workarounds like temporarily disabling AWDL while you play — so here we are…</p><h3>The Fix We Used</h3><p>I started from this Reddit post:</p><p><a href="https://www.reddit.com/r/GeForceNOW/comments/195l8ff/stuttering_issues_with_geforce_now_on_macos_over/"><em>Stuttering issues with GeForce NOW on MacOS over WiFi solved with this simple script</em></a></p><p>And then I adapted it for Boosteroid and made it a bit better and cleaner for this use case.</p><p>The original script keeps AWDL disabled while GeForce NOW is open. What I changed was adapting it for Boosteroid, adding AWDL restoring on quit, and making the script close itself when Boosteroid exits.</p><p>So it works as a <em>small Boosteroid launcher with a watchdog</em>, not just a one-off toggle. What it basically does:</p><ul><li>disables awdl0</li><li>launches Boosteroid</li><li>keeps checking whether macOS silently turned awdl0 back on</li><li>disables it again if needed</li><li>restores awdl0 when Boosteroid closes</li></ul><h3>Step 1: Add the Sudoers Rule or the Script Will Not Work</h3><p>This part is required. The script uses sudo -n, which means it <strong>cannot stop and ask for your password</strong>. Without this rule, it just fails.</p><p>We are allowing only these two exact commands without a password, nothing else.</p><p>Edit sudoers safely with visudo. Open <strong>Terminal</strong> and run:</p><pre>EDITOR=nano sudo visudo</pre><p>Enter your password when asked. Then find this section:</p><pre># root and users in group wheel can run anything on any machine as any user<br>root            ALL = (ALL) ALL<br>%admin          ALL = (ALL) ALL</pre><p><strong>Add the new line directly after that block, not before it. </strong>Paste this, replacing &lt;your-user-name&gt; <em>with your actual macOS username:</em></p><pre>&lt;your-user-name&gt; ALL=(root) NOPASSWD: /sbin/ifconfig awdl0 down, /sbin/ifconfig awdl0 up</pre><h3>How to Save and Exit Nano</h3><ul><li>Press <strong>Control + O</strong> to write the file</li><li>Press <strong>Enter</strong> to confirm</li><li>Press <strong>Control + X</strong> to exit</li></ul><h3>Step 2: Create the Boosteroid Launcher Script</h3><p>Open <strong>Script Editor</strong> via Spotlight, create a new script, and paste this in:</p><pre>property shouldMonitor : false<br>property isShuttingDown : false<br>property awdlWasDisabled : false<br><br>on set_awdl0(state)<br> try<br>  do shell script &quot;sudo -n /sbin/ifconfig awdl0 &quot; &amp; state<br>  return true<br> on error errMsg<br>  if not isShuttingDown then<br>   display notification (&quot;Failed to set awdl0 &quot; &amp; state &amp; &quot;: &quot; &amp; errMsg) with title &quot;Boosteroid&quot;<br>  end if<br>  return false<br> end try<br>end set_awdl0<br><br>on boosteroid_is_running()<br> try<br>  do shell script &quot;/usr/bin/pgrep -x Boosteroid &gt;/dev/null&quot;<br>  return true<br> on error<br>  return false<br> end try<br>end boosteroid_is_running<br><br>on awdl0_is_active()<br> try<br>  set awdl0Status to do shell script &quot;/sbin/ifconfig awdl0&quot;<br>  return awdl0Status contains &quot;status: active&quot;<br> on error<br>  return false<br> end try<br>end awdl0_is_active<br><br>on begin_shutdown()<br> set isShuttingDown to true<br> set shouldMonitor to false<br> quit<br>end begin_shutdown<br><br>on run<br> if set_awdl0(&quot;down&quot;) then<br>  set awdlWasDisabled to true<br>  set shouldMonitor to true<br>  display notification &quot;awdl0 is now disabled.&quot; with title &quot;Boosteroid&quot;<br>  <br>  tell application &quot;Boosteroid&quot;<br>   activate<br>  end tell<br> else<br>  display notification &quot;Could not disable awdl0.&quot; with title &quot;Boosteroid&quot;<br>  set isShuttingDown to true<br>  quit<br> end if<br>end run<br><br>on idle<br> if isShuttingDown then return 60<br> if not shouldMonitor then return 1<br> <br> if not boosteroid_is_running() then<br>  begin_shutdown()<br>  return 60<br> end if<br> <br> if awdl0_is_active() then<br>  if set_awdl0(&quot;down&quot;) then<br>   display notification &quot;awdl0 was re-enabled. Disabling again...&quot; with title &quot;Boosteroid&quot;<br>  end if<br> end if<br> <br> return 1<br>end idle<br><br>on quit<br> set isShuttingDown to true<br> set shouldMonitor to false<br> <br> if awdlWasDisabled then<br>  set_awdl0(&quot;up&quot;)<br>  set awdlWasDisabled to false<br> end if<br> <br> continue quit<br>end quit</pre><h3>Step 3: Save It as an App</h3><p>In Script Editor:</p><ul><li>click <strong>File → Export</strong></li><li>name it something like <strong>Boosteroid Without AWDL</strong></li><li>set <strong>File Format</strong> to <strong>Application</strong></li><li>enable <strong>Stay open after run handler</strong></li><li>save it to your <strong>Applications</strong> folder</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DTelOoBefUDFg3RRwcQ17Q.png" /></figure><p>After that, launch <strong>that app</strong> whenever you want to use Boosteroid.</p><h3>What Changed for Us</h3><p>In our case, the difference was immediate. The regular latency spikes were gone, and Boosteroid finally became usable again over Wi‑Fi!</p><p>It is a ridiculous fix, but it works.</p><h3>The Bigger Point</h3><p>Boosteroid and other cloud gaming apps should probably add this as a built-in option on macOS until Apple fixes the underlying problem.</p><p>Most people are not going to edit sudoers or build a small launcher app just to get stable latency. A simple <strong>temporarily disable AWDL while streaming</strong> toggle would help a lot.</p><p>And this is also something they should keep escalating to Apple, because a background Apple wireless feature should not be able to wreck cloud gaming like this!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c5195bf18784" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Everything Will Change]]></title>
            <link>https://medium.com/@xpl/everything-will-change-28169e9c736c?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/28169e9c736c</guid>
            <category><![CDATA[gpt]]></category>
            <category><![CDATA[future]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Tue, 19 Mar 2024 00:30:11 GMT</pubDate>
            <atom:updated>2024-06-23T05:42:51.618Z</atom:updated>
            <content:encoded><![CDATA[<p>In my field, many people are wondering what the future of the software development will be — arguing about whether AI will replace engineers and to what extent.</p><p>But why just “software development”? People should really think of the endgame. <em>Everything</em> will change.</p><p>I mean, what business, science, art, and even politics are all essentially? Just a clever optimization process against the real world. Throw ideas/hypotheses on the wall and see what sticks.</p><p>Computers are very good at optimization! No reason to believe it won’t all be solved in N years, with like 100x more efficient compute and a couple more cool math tricks.</p><p>Give future “GPT-10” interfaces for interacting with the real world, and it could do everything — no human supervision/”prompting” needed at all. Humans would only be an unneeded bottleneck in that optimization process.</p><p>There will be <em>big</em> companies consisting only of their founder and no one else. And I am <em>not sure</em> there will be many such companies (so like “everyone could have one”) — no, it is more likely that due to economies of scale, there will be only a few megacorps, owning all the compute.</p><p>What we should worry about is how to avoid the <em>extreme</em> wealth disparity/centralization that seems imminent in that future…</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=28169e9c736c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fucking Insane]]></title>
            <link>https://medium.com/@xpl/fucking-insane-b3ba22a6f83a?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/b3ba22a6f83a</guid>
            <category><![CDATA[massacre]]></category>
            <category><![CDATA[war]]></category>
            <category><![CDATA[russia]]></category>
            <category><![CDATA[ukraine]]></category>
            <category><![CDATA[bucha]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Sun, 03 Apr 2022 15:21:17 GMT</pubDate>
            <atom:updated>2022-04-05T19:20:16.271Z</atom:updated>
            <content:encoded><![CDATA[<p>This was supposed to be a blog about programming, but fuck programming. The war was disgusting from the very start. But what happened in <a href="https://en.wikipedia.org/wiki/Bucha_massacre">Bucha</a> is fucking insane, it’s unspeakable. I cried yesterday when I knew. This is devastating. It can’t be <em>my country </em>doing this, but it fucking <em>is</em>.</p><p>I truly, deeply hate it.</p><p>—</p><p>P.S. I am a Russian citizen, and you need to know that for this words I can be criminally prosecuted, because it is a crime in Russia to call things what they are. This gets you up to <strong>15 years</strong> of sentence in prison, due to recent law changes. Don’t worry about me — I’m out of their reach (hopefully). But there are <strong>millions</strong> of my fellow Russian people who are forced to keep their mouth shut. Don’t let this fool you — lots of people do not support the war, but they are too scared to tell openly about that, they are too scared even to participate in anonymous polls, and this is the reason of those “73% of Russians support the war” numbers. This is a lie, because people just can’t tell the truth.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b3ba22a6f83a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Coding Interview With GPT-3]]></title>
            <link>https://medium.com/@xpl/a-coding-interview-with-gpt-3-ca301acf4f26?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/ca301acf4f26</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[gpt-3]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[neural-networks]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Sat, 25 Jul 2020 21:38:04 GMT</pubDate>
            <atom:updated>2020-07-25T23:37:44.347Z</atom:updated>
            <content:encoded><![CDATA[<h4>Could a newest AI get a job at Google? Let’s find out!</h4><p><a href="https://openai.com/blog/openai-api/">GPT-3</a>, a newest and biggest OpenAI’s language model is all the hype right now. If you have missed the train, here’s <a href="https://www.gwern.net/GPT-3#what-benchmarks-miss-demos">a list of cool demos</a> that people already make using the private beta access.</p><p>I unfortunately don’t possess the API keys, but there is a nice text adventure game <a href="https://play.aidungeon.io/">AI Dungeon</a>, which can be used as a “backdoor” for hacking around with GPT-3, for a modest price. I don’t know whether it’s a full model or some fine-tuned version of it trained on text-based RPG scripts, but it’s surprisingly good at coding, to the point of making me a bit nervous ;)</p><p>To find out, I launched the game with a “custom” preset and put the “<em>Randomness</em>” setting near minimal (I used <em>0.2</em>) —as you generally don’t do drugs at a coding interview, we don’t want the AI to output some incoherent garbage in our little experiment!</p><p>From now on, my input is <strong>bold</strong>, and the AI’s response is <em>italic.</em></p><h3>The Interview</h3><blockquote><strong><em>You are a senior programmer at Google and you are having a phone screening interview with a candidate. You are going to ask him a couple of coding questions.</em></strong></blockquote><blockquote><strong><em>You say, “Hello, who are you?”</em></strong></blockquote><blockquote>The candidate says, “I’m John Doe.”</blockquote><blockquote><strong><em>You say “Are you ready to write some JavaScript code?”</em></strong></blockquote><blockquote>“Yes!” he exclaims.</blockquote><blockquote><strong><em>You say “Can you write a function that filters odd numbers from an array?”</em></strong></blockquote><blockquote>“Sure,” he says.</blockquote><blockquote>He types for a few seconds and shows you the following code:</blockquote><pre>function filterOdd(array) {<br>return array.filter(function(value) {<br>return value % 2 === 1;</pre><blockquote>“What do you think?” he asks.</blockquote><p>Okay, but that wasn’t quite unexpected. It surely could just have pulled it off from its vast memory, as there are tons of StackOverflow answers with the relevant code. A search engine could do the same.</p><p>There are also some minor issues with indentation and with the closing curly braces — but it’s highly likely an issue with the AI Dungeon’s HTML output (like ignoring the whitespace), so I didn’t bother. Let’s ask it to do some non-trivial stuff rather than fixing the formatting!</p><blockquote><strong><em>You say “Great! Could you use arrow function in the filter callback?”</em></strong></blockquote><blockquote>“Sure,” he says. He types for a few seconds and shows you the following code:</blockquote><pre>function filterOdd(array) {<br>return array.filter(value =&gt; value % 2 === 1);</pre><blockquote>“What do you think?” he asks.</blockquote><blockquote><strong><em>You say “What if we want to filter even numbers instead?”</em></strong></blockquote><blockquote>“OK,” he says. He types for a few seconds and shows you the following code:</blockquote><pre>function filterOdd(array) {<br>return array.filter(value =&gt; value % 2 === 0);</pre><blockquote><strong><em>You say “You forgot to change the name of the function to </em></strong><strong><em>filterEven. Can you fix that?”</em></strong></blockquote><blockquote>“Sure,” he says. He types for a few seconds and shows you the following code:</blockquote><pre>function filterEven(array) {<br>return array.filter(value =&gt; value % 2 === 0);</pre><blockquote><strong><em>You say “Good! Can you now make </em></strong><strong><em>filterEven an arrow function as well?”</em></strong></blockquote><blockquote>“OK,” he says. He types for a few seconds and shows you the following code:</blockquote><pre>let filterEven = (array) =&gt; array.filter(value =&gt; value % 2 === 0);</pre><blockquote><strong><em>You say “Amazing! And how about making it a </em></strong><strong><em>const instead of </em></strong><strong><em>let?</em></strong></blockquote><blockquote>“OK,” he says. He types for a few seconds and shows you the following code:</blockquote><pre>const filterEven = (array) =&gt; array.filter(value =&gt; value % 2 === 0); </pre><blockquote>“What do you think?” he asks.</blockquote><blockquote><strong><em>You say “Enough for now, I see you can write code :) We’ll contact you soon for a more technical interview.”</em></strong></blockquote><blockquote>“OK, thank you!” he says.</blockquote><h3>Conclusion</h3><p>So could it get a job? Probably not yet — if you make more complex inquiries, it won’t be able to answer, outputting broken code with silly mistakes, not being able to capture the full depth of what you’re asking for. But it certainly understands the basic grammar and the syntax of many popular programming languages, and it also appears that it has memorized <em>a lot</em> of stuff from the internet, being able to creatively recombine it according to the context you provide to it. Somewhat similar to what humans do, just at not that level of sophistication. Yet :)</p><p>So if not <a href="https://en.wikipedia.org/wiki/Artificial_general_intelligence">AGI</a>, it could certainly be a next generation of search — it would be very nice to have such a “smart all-encompassing assistant” at a hand that understands the context and does not require a structured input — you just ask it politely, just as you would’ve done it with a human.</p><p>Can’t wait to see the applications of it.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ca301acf4f26" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[My Two Cents About IOTA]]></title>
            <link>https://medium.com/@xpl/my-two-cents-about-iota-41e3163bc3f8?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/41e3163bc3f8</guid>
            <category><![CDATA[decentralization]]></category>
            <category><![CDATA[ethereum]]></category>
            <category><![CDATA[blockchain]]></category>
            <category><![CDATA[cryptocurrency]]></category>
            <category><![CDATA[iota]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Sat, 16 Jun 2018 21:17:36 GMT</pubDate>
            <atom:updated>2020-02-25T22:50:22.808Z</atom:updated>
            <content:encoded><![CDATA[<h4>And Why I Don’t Like It</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lfhkjsKczp51CZi0vu5-sg.jpeg" /></figure><ol><li>They’re essentially a centralized tech, pretending to be decentralized. They have failed to solve the theoretical problems, patchworking it with a central server (“the Coordinator”) that settles the transaction order. My guess is that they honestly tried to solve the essential problems with DAGs, but when they realized that it’s not gonna happen, they have invented their “Coordinator”, claiming that one day they will figure how to get rid of it… I wouldn’t believe them, because their tech is not built “from first principles” (like ZK-SNARKs in ZCash, as an example of some credible science) — I mean, there is no solid theoretical background, which is really required to solve the problems they faced. As far as I know, there is no coin yet that solves the <a href="https://github.com/ethereum/wiki/wiki/Sharding-FAQs#this-sounds-like-theres-some-kind-of-scalability-trilemma-at-play-what-is-this-trilemma-and-can-we-break-through-it">“scalability trilemma”</a>. If it was, it would be a major breakthrough. “Extraordinary claims require extraordinary evidence”!</li><li>On the low level, they use ternary (base-3) for encoding their data structures, which is a <em>complete nonsense</em> unless you have a ternary computer (we don’t). It adds a significant overhead, unnecessarily complexifying the whole system. This is an extreme case of the so-called <a href="https://en.wikipedia.org/wiki/Not_invented_here">“NIH (not invented here) syndrome”</a>.</li><li>They rolled their own hash function — which is a major no-no in cryptography, unless you are an academic expert with a lifetime’s experience in (de)constructing hash functions and finding vulnerabilities in them. Needless to say, their hash function was cracked, putting all their system to risk. Good for them is that the crack was performed by MIT scientists — they’re “white hat hackers” so they reported the vulnerability instead of exploiting it for stealing the users’ money. Here’s a blog post about this (by the scientists who have found the vulnerability): <a href="https://medium.com/@neha/cryptographic-vulnerabilities-in-iota-9a6a9ddc4367">https://medium.com/@neha/cryptographic-vulnerabilities-in-iota-9a6a9ddc4367</a></li></ol><p>To me, these mistakes cannot be justified, when talking about multi-billion dollar business. We all make mistakes, but these ones are usually being made by young careless amateurs, who don’t really think about the reliability and security of their system — it is more important to them to explore things (by re-inventing the wheel) and to prove themselves (and the world) that they are competent in building complex stuff. This is perfectly OK when you’re young and inexperienced (in fact, we often become experienced by doing this), but I would not put a cent in this kind of “currency” — the risk is too high.</p><p>The funny thing is that V. Buterin and his creation (ETH) is also subject to this kind of criticism. They have their own hash function (Ethash) and also their own programming language (Solidity) — which is a mistake (NIH syndrome again).. But Vitalik is really a smart and wise person and he’s learning fast. Maybe I just like him because I’m also “Vitalik” :) But really the most important thing is that in contrast to IOTA creators, he doesn’t act like an asshole… Take a look at this, for example (if it’s true, then IOTA creators are complete assholes, and if it’s not, then they are pathetic liars — in either way, it doesn’t add credibility to them):</p><blockquote>Next, and in my mind most damningly, Sergey Ivancheglo, Iota’s cofounder, claims that the flaws in the Curl hash function were in fact deliberate; that they were inserted as ‘copy protection’, to prevent copycat projects, and to allow the Iota team to compromise those projects if they sprang up.</blockquote><p>See more here: <a href="https://hackernoon.com/why-i-find-iota-deeply-alarming-934f1908194b">https://hackernoon.com/why-i-find-iota-deeply-alarming-934f1908194b</a></p><p><strong>UPD:</strong> see also <a href="https://www.reddit.com/r/CryptoCurrency/comments/95kvee/leaked_internal_iota_foundation_conversationjust/">the recently leaked internal IOTA Foundation conversation</a>, which clearly reveals the immaturity of the key people behind IOTA.</p><p>UPD<strong>: </strong><a href="https://ihodl.com/topnews/2019-11-11/iota-co-founder-sells-all-his-coins-and-leaves-project/"><strong>IOTA Co-Founder Sells All His Coins and Leaves Project</strong></a></p><p>UPD<strong>: </strong><a href="https://www.coindesk.com/iota-being-shut-off-is-the-latest-chapter-in-an-absurdist-history"><strong>IOTA Being Shut Off Is the Latest Chapter in an Absurdist History</strong></a></p><h3>About the Author</h3><p>I’m a member of the developer team behind the open-source cross-language <a href="https://github.com/ccxt-dev/ccxt">CCXT Library</a> (available for JavaScript, Python or PHP). The library is used to connect and trade with more than 100 cryptocurrency exchanges worldwide.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=41e3163bc3f8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[JavaScript: Creating Custom Error Classes That Work After Transpiling To ES5]]></title>
            <link>https://medium.com/@xpl/javascript-deriving-from-error-properly-8d2f8f315801?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/8d2f8f315801</guid>
            <category><![CDATA[es5]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[error-handling]]></category>
            <category><![CDATA[nodejs]]></category>
            <category><![CDATA[babeljs]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Sat, 11 Nov 2017 03:18:56 GMT</pubDate>
            <atom:updated>2017-11-11T07:37:51.200Z</atom:updated>
            <content:encoded><![CDATA[<p>TL/DR: here’s a nice hack that we use in <a href="https://github.com/ccxt/ccxt#ccxt--cryptocurrency-exchange-trading-library">CCXT</a>:</p><pre>class <strong>MyError</strong> extends <strong>Error</strong> {</pre><pre><strong>   constructor</strong> (message) {</pre><pre><strong>      super</strong> (message)</pre><pre><strong>      this</strong>.constructor = <strong>MyError</strong><br>      <strong>this</strong>.__proto__   = <strong>MyError</strong>.prototype<br>      <strong>this</strong>.message     = message<br>   }<br>}</pre><p>The above is necessary in many popular frameworks. The popularcreate-react-app framework, for example, forces us to transpile everything down to ES5 when building for production. This is required by some outdated dependencies like Uglify, that don’t even recognize classes despite the broad adoption of ES6 in modern browsers…</p><p>…and the instanceof just stops working after that. Here’s a simple test:</p><pre>// test.js</pre><pre>class <strong>MyError</strong> extends <strong>Error</strong> {}<br>let myerr = new <strong>MyError</strong> ()</pre><pre>console.log (myerr <strong>instanceof</strong> <strong>MyError</strong>)</pre><p>Guess what happens if you run it? It prints true, obviously. But after your code goes through Babel with ES5 preset enabled (in order to meet the popular frameworks’ requirements), the outcome isn’t true anymore:</p><pre>babel <strong>test.js</strong> --out-file <strong>test.es5.js</strong> --presets=es2015<br>node <strong>test.es5.js</strong></pre><p>Will print false, which is quite unexpected… The problem described above can be easily solved by adding a hack shown in the beginning of this article.</p><p>Happy coding!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8d2f8f315801" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Curious Case Of .length == 2]]></title>
            <link>https://medium.com/@xpl/a-curious-case-of-length-2-f69b22674273?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/f69b22674273</guid>
            <category><![CDATA[console]]></category>
            <category><![CDATA[command-line]]></category>
            <category><![CDATA[terminal]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[unicode]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Sat, 07 Oct 2017 18:19:34 GMT</pubDate>
            <atom:updated>2017-10-07T18:19:34.542Z</atom:updated>
            <content:encoded><![CDATA[<p>I was debugging a very strange case with one of my Node.js projects recently. It prints my output formatted (with the <a href="https://github.com/xpl/as-table#as-table">as-table</a> module) into a nicely-looking ASCII table layout:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Df5YUj_Uvx75Myo_mZVypA.png" /></figure><p>For the sake of even greater niceness, I tried replacing that <em>“time”</em> title with the 🕑 symbol from Unicode…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4wX70MjK1AhuyvjQW8GRiQ.png" /></figure><p>Whoa. Something wrong happened, obviously. Quite quickly I discovered that the computed length of symbol 🕑 turned out to be 2!</p><p>Initially, I suspected a bug in the module that incorrectly determined the true optical length of a string (it’s the <a href="https://github.com/xpl/printable-characters/#printable-characters">printable-characters</a> that does the job, BTW). WTF? Looks like you can’t rely on str.length to get its rendered length: you have to strip zero-width characters and ANSI escape sequences first, otherwise your string might end up being wider than it actually is!</p><p>So, I thought that 🕑.length could be erroneously computed as 2, and that miscalculation lead to an observed disruption of the table’s layout. That happens because the “clock”-symbol occupies multiple Unicode code points or something, and the built-in .length just isn’t smart enough to manage it. Here’s a thorough explanation of the issue and I highly recommend reading it:</p><p><a href="http://blog.jonnew.com/posts/poo-dot-length-equals-two">Jonathan New | &quot;💩&quot;.length === 2</a></p><p>…but then, suddenly, I realized one more thing. The actual visible width of 🕑 <em>might</em> be “2” indeed, from VSCode:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/378/1*vIGQPFUSGdoBPJId2OpCRg.png" /><figcaption>A screenshot from the VSCode editor</figcaption></figure><p>But not quite… As you can see, it is not <em>exactly</em> 2 nor 1(and that puts things out of alignment). But how do various console terminals render it? Check it out in VSCode’s Integrated Terminal:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/126/1*yqcN_tH9VM1BcAgA-82C7A.png" /><figcaption>I’ve highlighted the “🕑” with the text selection</figcaption></figure><p>…and the built-in terminal app from MacOS:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/138/1*26Jv3O152yoRh6my676Q0Q.png" /><figcaption>I put my cursor at “🕑” to highlight it’s location.</figcaption></figure><p>It seems that popular terminals render everything strictly monospaced, and it’s up to the <em>user</em> himself to put an empty space after each of those new fancy Unicode glyphs, to make room for them in a monospaced grid, manually:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/144/1*-WGh5KTVTUFvInq5W2g1-Q.png" /><figcaption>Same thing with a whitespace added after the “🕑”</figcaption></figure><p>Thus, our initial suggestion must have been true, and we should’ve patched <a href="https://github.com/xpl/printable-characters/#printable-characters">printable-characters</a>, enabling it to comprehend those symbols. The article referenced above helped me a lot with that task. So all essential bits required for a proper ASCII layout now work like a charm without breaking on zero-width characters, Emojis and ANSI escape codes:</p><pre>// determining the real length of a string<br>strlen (&#39;💩&#39;) === 1</pre><pre>// getting first N visible symbols<br>first  (&#39;💩23456789&#39;, 3) === &#39;💩23&#39;</pre><pre>// filling with whitespace<br>blank  (&#39;\t💩foo&#39;) === &#39;\t    &#39;</pre><p>Yay! Now the <a href="https://github.com/xpl/as-table#as-table">as-table</a> is capable of rendering those fancy characters nicely:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/814/1*kGvYb5PvPPygHrobFnYxRQ.png" /></figure><p><a href="https://github.com/xpl/as-table">xpl/as-table</a></p><h3>About the Author</h3><p>I’m a member of the developer team behind the open-source cross-language <a href="https://github.com/ccxt-dev/ccxt">CCXT Library</a> (available for JavaScript, Python or PHP). The library is used to connect and trade with more than 85 cryptocurrency exchanges worldwide.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f69b22674273" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Protecting Python Sources With Cython]]></title>
            <link>https://medium.com/@xpl/protecting-python-sources-using-cython-dcd940bb188e?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/dcd940bb188e</guid>
            <category><![CDATA[vagrant]]></category>
            <category><![CDATA[obfuscation]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[intellectual-property]]></category>
            <category><![CDATA[cython]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Fri, 01 Sep 2017 05:01:23 GMT</pubDate>
            <atom:updated>2020-07-26T00:38:24.186Z</atom:updated>
            <content:encoded><![CDATA[<h4>Distributing Python Programs As Compiled Binaries: How-To</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TrsTLdxnYt8SG5psRe0pjg.png" /></figure><p>Protecting your Python sources from unwanted readers is easier said than done, because <strong>.pyc</strong> bytecode is <a href="https://github.com/rocky/python-uncompyle6">decompileable</a> and the obfuscation is easily reverse-engineered. It took me a while to figure out a proper way to hide Python code…</p><p>Meet <a href="http://cython.org/"><strong>Cython</strong></a><strong>, </strong>an <strong>optimizing static compiler </strong>that takes your .py modules and translates them to high-performant C files. Resulting C files can be compiled into native binary libraries with no effort. When the compilation is done there’s no way to reverse compiled libraries back to readable Python source code! Cython supports both Python 2 and 3, including the modern <strong>async/await</strong> syntax. From my experience, the only thing it couldn’t do is asynchronous generators.</p><h3>1. Install Cython</h3><p>Installation is as easy as typing pip install cython or pip3 install cython (for Python 3).</p><h3>2. Add compile.py</h3><p>Add the following script to your project folder (as compile.py). It will act as a “makefile” for the build:</p><pre>from distutils.core import setup<br>from distutils.extension import Extension<br>from Cython.Distutils import build_ext</pre><pre>ext_modules = [<br>    Extension(&quot;mymodule1&quot;,  [&quot;mymodule1.py&quot;]),<br>    Extension(&quot;mymodule2&quot;,  [&quot;mymodule2.py&quot;]),</pre><pre>#   ... all your modules that need be compiled ...</pre><pre>]</pre><pre>setup(<br>    name = &#39;My Program Name&#39;,<br>    cmdclass = {&#39;build_ext&#39;: build_ext},<br>    ext_modules = ext_modules<br>)</pre><p>The script should explicitly enumerate files that you want to be compiled. You can also leave some files uncompiled as well, if you want. Those will still remain importable from binary modules.</p><h3>3. Add main.py</h3><p>Make the entry point Python file for your application. You will import and launch all the compiled logic from there. An entry point file is required because Cython does not generate executable binaries by default (though it is capable to), so you will need a dummy Python file, where you simply import all the compiled logic and run it. It can be as simple as:</p><pre>from logic import main      # this comes from a compiled binary<br>main ()</pre><h3>4. Run compile.py</h3><p>Depending on the Python version you use, run:</p><pre>python compile.py build_ext --inplace</pre><p>…or, for Python 3:</p><pre>python3 compile.py build_ext --inplace</pre><p>The above command will generate .so and .c files next to your .py source files:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/506/1*KQCTp5cE9R84Ku_0oaG1Cw.png" /></figure><p>The .c files are intermediate sources used to generate .so files, which are binary modules you want to distribute. When building on Windows these files will probably have the .dll extension (<strong>UPD</strong>: in the comments people suggest that they actually have the .pyd extension on Windows).</p><p>You can delete .c and .py files after a successful build and keep the .so files only.</p><p>Note that .so-files contain the target platform in their names (e.g. darwin on my MacOS). Obviously, the compiled modules are not cross-platform. If you distribute your program to Ubuntu Linux users, you should compile it on Linux. Otherwise you won’t be able to load these binaries. So you’ll have to compile a platform-specific version of your code for each of your targeted platforms.</p><p>Luckily, there are tools like <a href="https://www.vagrantup.com/">Vagrant</a> that can help reduce all the OS installation burden to a couple of simple commands…</p><h3>Setting Up a Different OS Environment Using VirtualBox and Vagrant</h3><p>Here’s an example of how I’ve managed to compile my project on Ubuntu 16.04, while using MacOS.</p><ol><li>Install <a href="https://www.virtualbox.org/wiki/Downloads">VirtualBox</a> and <a href="https://www.vagrantup.com/">Vagrant</a>.</li><li>Run export VAGRANT_DEFAULT_PROVIDER=virtualbox (you can add it to your Bash startup script at ~/.bash_profile for convenience).</li><li>Choose an OS here: <a href="https://app.vagrantup.com/boxes/search">https://app.vagrantup.com/boxes/search</a>. Then click the <em>New</em> tab in “How to use” section. You’ll find setup instructions and commands there. Run those commands in your Python project folder:</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*s4uPRId_oMQAFqSV1j4WjQ.png" /></figure><p>Finally, run vagrant ssh to get into a freshly installed Ubuntu console (type exit to exit):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/932/1*V5nAJ1gFlWbFTxpOPFg8Lw.png" /></figure><p>cd to the /vagrant folder to see your project files. Then perform steps 1, 4 from this manual, and you’re done:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/602/1*peFjOUpkICaIxgvMpXv6VA.png" /></figure><p>For projects with a short build/release cycle, multi-plaform builds could be automated using a CI (Continuous Integration) service, like <a href="https://travis-ci.org/">TravisCI</a>, but that’s a story for another article.</p><h4><strong>About The Author</strong></h4><p>Check out my other stuff:</p><p>👉 <strong>LinkedIn:</strong> <a href="https://linkedin.com/in/xpl/">https://linkedin.com/in/xpl/</a><br>👉 <strong>GitHub:</strong> <a href="https://github.com/xpl">https://github.com/xpl</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=dcd940bb188e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[JavaScript: Did you know about the comma operator?]]></title>
            <link>https://medium.com/@xpl/javascript-did-you-know-about-the-comma-operator-ff9b511cc33?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/ff9b511cc33</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[comma-operator]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Mon, 29 May 2017 08:17:49 GMT</pubDate>
            <atom:updated>2017-05-29T15:33:55.440Z</atom:updated>
            <content:encoded><![CDATA[<pre>return (a, b, …, <strong>z</strong>)</pre><p>It will return z, evaluating a, b, ... first. At first it seems not very useful, but consider this example:</p><pre>const <strong>fun</strong> = x =&gt; x + 1</pre><p>What if you want to add a console.log call before x + 1 ? With comma operator, adding <em>side-effects</em> to functional expressions is simple:</p><pre>const fun = x =&gt; (<strong>console.log (x)</strong>, x + 1)</pre><p>And in comparison with…</p><pre>const fun = x =&gt; { console.log (x);<strong> </strong>return<strong> </strong>x + 1 }</pre><p>…it requires fewer modifications.</p><p>P.S. you could actually create a wrapper over console.log that returns its first argument:</p><pre>const fun = x =&gt; log (x) + 1</pre><p>There’s even a library that does that (and much more): <a href="https://github.com/xpl/ololog">Ololog</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ff9b511cc33" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hot Reloading for Chrome Extensions]]></title>
            <link>https://medium.com/@xpl/hot-reloading-for-chrome-extensions-3da296916286?source=rss-3972c774cf5d------2</link>
            <guid isPermaLink="false">https://medium.com/p/3da296916286</guid>
            <category><![CDATA[hot-reloading]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[chrome-extension]]></category>
            <dc:creator><![CDATA[Vit Gordon]]></dc:creator>
            <pubDate>Fri, 12 May 2017 04:07:42 GMT</pubDate>
            <atom:updated>2020-07-25T20:22:02.873Z</atom:updated>
            <content:encoded><![CDATA[<h4><a href="https://github.com/xpl/crx-hotreload">github.com/xpl/crx-hotreload</a></h4><p>Finally, someone did it ;)</p><ol><li>Drop <a href="https://github.com/xpl/crx-hotreload/blob/master/hot-reload.js">hot-reload.js</a> to your extension&#39;s directory.</li><li>Add it to your background scripts section in the manifest.json file:</li></ol><pre>&quot;background&quot;: { &quot;scripts&quot;: [&quot;hot-reload.js&quot;] }</pre><p>After startup, it will watch for file changes in the extension’s directory. When a change detected, it will reload itself, refreshing the active tab (to re-trigger updated content scripts).</p><p>And there’s no need to manually de-activate it before publishing, as it disables itself <em>automagically</em>™ in the production configuration!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kE6lUKZ7kITBpn1aNpd9fQ.png" /></figure><p>The script is amazingly simple, everything fits into just ~<strong>50</strong> lines of code. Here’s also a blog post explaining the internals:</p><p><a href="https://60devs.com/hot-reloading-for-chrome-extensions.html">Hot Reloading for Chrome Extensions</a></p><p><a href="https://habrahabr.ru/post/314766/"><em>…in Russian @ habrahabr.ru</em></a></p><p>P.S. You can also simply clone the <a href="https://github.com/xpl/crx-hotreload">GitHub repository</a> and use it as a boilerplate for your extension.</p><h4>About the author</h4><p>Check out my other stuff:</p><p>👉 <strong>LinkedIn:</strong> <a href="https://linkedin.com/in/xpl/">https://linkedin.com/in/xpl/</a><br>👉 <strong>GitHub:</strong> <a href="https://github.com/xpl">https://github.com/xpl</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3da296916286" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>