<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yuval Greenfield</title>
    <description>The latest articles on DEV Community by Yuval Greenfield (@ubershmekel).</description>
    <link>https://dev.to/ubershmekel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F393120%2F2f2ae2d6-8ef6-4c05-a670-323ca068f0b6.jpeg</url>
      <title>DEV Community: Yuval Greenfield</title>
      <link>https://dev.to/ubershmekel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ubershmekel"/>
    <language>en</language>
    <item>
      <title>I made release date db to predict when anime seasons will come out</title>
      <dc:creator>Yuval Greenfield</dc:creator>
      <pubDate>Wed, 14 May 2025 05:40:23 +0000</pubDate>
      <link>https://dev.to/ubershmekel/i-made-release-date-db-to-predict-when-anime-seasons-will-come-out-4ep6</link>
      <guid>https://dev.to/ubershmekel/i-made-release-date-db-to-predict-when-anime-seasons-will-come-out-4ep6</guid>
      <description>&lt;p&gt;I got the idea from the &lt;a href="https://buyersguide.macrumors.com/#iPhone-16" rel="noopener noreferrer"&gt;macrumors buying guide&lt;/a&gt; which helps you decide whether or not to buy an iphone or wait for the next generation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frshb5aubnnzd80lmqwt6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frshb5aubnnzd80lmqwt6.png" alt="macrumors example iphone release dates" width="800" height="1002"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But I couldn't find this data or a visualization like it anywhere for any other products. I wanted to know how this would look for a pixel phone, mario games, gta 6, one punch man seasons, etc. So this is what I came up with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3t10zh5mg965tyrdgrfz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3t10zh5mg965tyrdgrfz.png" alt="Release date db for mario" width="624" height="1396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a simple Vue 3, Vue router, page you can see at &lt;a href="https://github.com/ubershmekel/release-date-db" rel="noopener noreferrer"&gt;https://github.com/ubershmekel/release-date-db&lt;/a&gt;. The release date data was generated by chat gpt into these yaml files: &lt;a href="https://github.com/ubershmekel/release-date-db/blob/main/data/games/mario.yml" rel="noopener noreferrer"&gt;https://github.com/ubershmekel/release-date-db/blob/main/data/games/mario.yml&lt;/a&gt; and I have the build script generate a json file so the landing page knows which yaml files exist and to link to them.&lt;/p&gt;

&lt;p&gt;I hope y'all like it. Do let me know if you have feedback, or ideas for what other books/games/movies/devices to track. It's at &lt;a href="https://release-date-db.netlify.app/" rel="noopener noreferrer"&gt;https://release-date-db.netlify.app/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>vue</category>
      <category>data</category>
    </item>
    <item>
      <title>Python's "batteries included" was a bad idea</title>
      <dc:creator>Yuval Greenfield</dc:creator>
      <pubDate>Thu, 20 Feb 2025 07:45:26 +0000</pubDate>
      <link>https://dev.to/ubershmekel/pythons-batteries-included-was-a-bad-idea-1l0n</link>
      <guid>https://dev.to/ubershmekel/pythons-batteries-included-was-a-bad-idea-1l0n</guid>
      <description>&lt;p&gt;20 years ago I thought Python was a brilliant language for including so many useful libraries in its distribution. This "batteries included" motto was well known and described in &lt;a href="https://web.archive.org/web/20120420010049/http://www.python.org/about/" rel="noopener noreferrer"&gt;the Python about page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But today it's clear to me that including batteries in a coding language is a deadly flaw. Because of the packaging hurdle and because of library rot. Details follow.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why include libraries? Why have a larger standard library?
&lt;/h1&gt;

&lt;p&gt;Batteries included implies that you don't need to worry about downloading or depending on external packages to get stuff done. You can just go. Yes, with Python I did many times find myself productive without worrying about downloading packages. No &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;go get&lt;/code&gt; necessary.&lt;/p&gt;

&lt;p&gt;Another important benefit of batteries included is that they make libraries more likely to be interoperable. Packages want to support standard library usage patterns and types. It's better if there's an official &lt;code&gt;set&lt;/code&gt; and &lt;code&gt;Promise&lt;/code&gt; so there isn't an ecosystem battle over such things.&lt;/p&gt;

&lt;h1&gt;
  
  
  The rotting flaw
&lt;/h1&gt;

&lt;p&gt;The problem with including libraries in Python is that the language itself has to evolve carefully and slowly. But what happens when inevitably there's a new way to do something? A new and better library is created - and now the batteries you included are suboptimal this year, and a decade later your batteries are actual trash you lug around.&lt;/p&gt;

&lt;p&gt;Backwards compatibility is critical. I don't want to fix my code once a year when the new Python version rolls out. Moving from Python 2 to 3 sucked for everyone. Even the main language designer Guido was still &lt;a href="https://youtu.be/Oiw23yfqQy8?si=WSWoAFXprdp5dmPA&amp;amp;t=1520" rel="noopener noreferrer"&gt;talking about the painful transition&lt;/a&gt; 10 years later.&lt;/p&gt;

&lt;p&gt;So you can't just rip out a standard library and replace it with a new one. If you include a library in your core language distribution - you're either married to it for FOREVER, or you've come to terms with eventually causing your users great pain in updates of old code they don't remember they wrote.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rotting examples
&lt;/h1&gt;

&lt;p&gt;Python's standard library has 3 option parsing libraries: &lt;code&gt;getopt&lt;/code&gt;, &lt;code&gt;optparse&lt;/code&gt;, and &lt;code&gt;argparse&lt;/code&gt;. I personally voted to include &lt;code&gt;argparse&lt;/code&gt; because at the time I thought that was a good idea.&lt;/p&gt;

&lt;p&gt;Python includes the &lt;code&gt;urllib.request&lt;/code&gt; module though most folks nowadays prefer the &lt;code&gt;requests&lt;/code&gt; library for making HTTP requests.&lt;/p&gt;

&lt;p&gt;There are a few xml parsing libraries in the standard library I'm aware of (&lt;code&gt;xml.dom.minidom&lt;/code&gt;, &lt;code&gt;xml.sax&lt;/code&gt;, &lt;code&gt;xml.parsers.expat&lt;/code&gt;, &lt;code&gt;etree&lt;/code&gt;) but folks today often go for &lt;code&gt;BeautifulSoup&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I'm sure there are many more examples.&lt;/p&gt;

&lt;h1&gt;
  
  
  The packaging hurdle
&lt;/h1&gt;

&lt;p&gt;Aside from the eventual rot of libraries - coders that rely on included batteries are incentivized to avoid the packaging system entirely if they can. That's the whole value you get out of the batteries, right? So your helloworld app does not include a "get packages" step. But then that results in fewer developers engaging with the packaging system.&lt;/p&gt;

&lt;p&gt;But packaging is really where every piece of software ends up. By incentivizing devs to avoid it, by causing devs to want to use the batteries, we are getting a less battle-tested, and lower quality packaging system.&lt;/p&gt;

&lt;h1&gt;
  
  
  Counter-argument - the JS package explosion
&lt;/h1&gt;

&lt;p&gt;Almost every package you &lt;code&gt;npm install&lt;/code&gt; today will cause thousands of files and dependencies to show up in your &lt;code&gt;node_modules&lt;/code&gt; folder. If Python's standard library didn't have a &lt;code&gt;math&lt;/code&gt; module then every complicated enough package would end up having to depend on all of the popular math packages transitively because each dependency might use a different one. I'm not sure how to incentivize library creators to reduce this problem.&lt;/p&gt;

&lt;h1&gt;
  
  
  The confusing state of Python packaging
&lt;/h1&gt;

&lt;p&gt;What happens when I &lt;code&gt;import abc&lt;/code&gt;? I honestly don't know. The package &lt;code&gt;abc&lt;/code&gt; might be a local file (&lt;code&gt;py&lt;/code&gt; or &lt;code&gt;pyc&lt;/code&gt;) or folder in my &lt;code&gt;$PATH&lt;/code&gt;, next to my script, pip-installed, or already somehow in memory.&lt;/p&gt;

&lt;p&gt;What is &lt;code&gt;import abc.xyz&lt;/code&gt;? Is &lt;code&gt;xyz&lt;/code&gt; a function in the package? A sub-folder?&lt;/p&gt;

&lt;p&gt;This isn't just confusing for the user, it's also confusing for the library builders setting up their package for distribution, and for package system authors.&lt;/p&gt;

&lt;p&gt;Setting up a package for distribution in Python, and downloading packages is terribly complicated. I love NodeJS's &lt;code&gt;npm&lt;/code&gt; even though it has its own flaws and competitors. Everyone agrees to use &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;node_modules&lt;/code&gt; as the "virtual env". &lt;code&gt;npm&lt;/code&gt; covers all the ground of installing code and binary dependencies on all platforms and generally just works. But with Python, &lt;code&gt;pip&lt;/code&gt; is only one step in a longer process - you probably need a virtualenv, uv, poetry, conda, chocolatey, apt-get, winget, or something else to avoid version conflicts with other Python scripts on your system, and to install binary packages.&lt;/p&gt;

&lt;p&gt;Part of why this packaging story is so confusing is because Python does not include it in its "helloworld". If Python did show everyone the packaging story - then it would get fixed.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;A language's standard library should really just provide the bare minimum it can. The bare minimum is probably:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A packaging system&lt;/li&gt;
&lt;li&gt;Operating system APIs&lt;/li&gt;
&lt;li&gt;Types (numbers, strings, arrays, promises, etc)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A core language distribution should only contain what's necessary to install packages, and for packages to be compatible with each other. Leave all the rest to downloadable packages. I hope Python 4 standardizes the packaging circus on a common data structure like &lt;code&gt;package.json&lt;/code&gt; did for NodeJS, and that most of today's standard library packages will be removed from the executable distribution and posted on PyPI.&lt;/p&gt;

&lt;p&gt;Cheers.&lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>A Python script to see my most watched YouTube videos</title>
      <dc:creator>Yuval Greenfield</dc:creator>
      <pubDate>Fri, 22 Sep 2023 21:33:12 +0000</pubDate>
      <link>https://dev.to/ubershmekel/what-did-i-watch-most-on-youtube-1ol2</link>
      <guid>https://dev.to/ubershmekel/what-did-i-watch-most-on-youtube-1ol2</guid>
      <description>&lt;p&gt;I use YouTube Music and I was wondering which songs I've listened to the most. You can't find that information in the YouTube Music app. But luckily, Google keeps a complete history at Google Takeout. So I can get the list of my most played songs. Here are the steps to do that.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Download YouTube Music takeout data
&lt;/h2&gt;

&lt;p&gt;Go to &lt;a href="https://takeout.google.com/settings/takeout"&gt;https://takeout.google.com/settings/takeout&lt;/a&gt; and deselect all takeouts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BE_OvoAd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dw7wbfjt6qeqrkqly556.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BE_OvoAd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dw7wbfjt6qeqrkqly556.png" alt="Deselect all the takeouts" width="800" height="896"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Select YouTube and configure the export
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6hBgEg5L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f9oqyexa5tvfgonfiduj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6hBgEg5L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f9oqyexa5tvfgonfiduj.png" alt="YouTube takeout" width="800" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Deselect all YouTube content options
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QC9UGVLY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vmq9t16tv0zeqzs6ylv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QC9UGVLY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vmq9t16tv0zeqzs6ylv0.png" alt="Deselect all YouTube content options" width="644" height="626"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Select just "history" content option
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--akpjXtfx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7gtswjstzkzy4um0kbb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--akpjXtfx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7gtswjstzkzy4um0kbb.png" alt='Select just "history" content option' width="612" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Export JSON, not HTML
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--To8n6OP---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rv0zyws8kskhfa6zmbcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--To8n6OP---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rv0zyws8kskhfa6zmbcj.png" alt="Export JSON, not HTML" width="800" height="1148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Create the export
&lt;/h2&gt;

&lt;p&gt;After this step, you will be emailed a link with a zip file that has your history.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1Vdf_V7r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7iffulah16d9dn0mxiv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1Vdf_V7r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7iffulah16d9dn0mxiv.png" alt="Create the export" width="800" height="905"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Unzip the file
&lt;/h2&gt;

&lt;p&gt;If you're on a Mac, that's just double-clicking the zip file.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Place the Python code next to watch-history.json
&lt;/h2&gt;

&lt;p&gt;In the new folder that was unzipped, you'll find &lt;code&gt;watch-history.json&lt;/code&gt; inside a few folders. In my case the path was &lt;code&gt;Downloads/YouTube and YouTube Music/history/watch-history.json&lt;/code&gt; so I developed the script at &lt;code&gt;Downloads/YouTube and YouTube Music/history/top_yt.py&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Python code
&lt;/h2&gt;

&lt;p&gt;Paste the following into &lt;code&gt;top_yt.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pprint&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pprint&lt;/span&gt;

&lt;span class="n"&gt;watched&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'watch-history.json'&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;"titleUrl"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Watched a video that has been removed
&lt;/span&gt;        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"titleUrl"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; @&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;watched&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="n"&gt;pprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;watched&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;most_common&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the code, seeing the result
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;python3&lt;/span&gt; &lt;span class="n"&gt;top_yt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;
&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s"&gt;'Watched Here Comes The Sun (Remastered 2009) @&amp;gt; '&lt;/span&gt;
  &lt;span class="s"&gt;'https://www.youtube.com/watch?v=xUNqsfFUwhY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;334&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Watched Guess Who Is Back @&amp;gt; https://www.youtube.com/watch?v=OZrh6U4CyCw'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;65&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Watched The Rumbling (TV Size) @&amp;gt; '&lt;/span&gt;
  &lt;span class="s"&gt;'https://www.youtube.com/watch?v=KHCIO7a3jSI'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Watched ətˈæk 0N tάɪtn @&amp;gt; https://www.youtube.com/watch?v=zroFzv7sFis'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'Watched Omokage (produced by Vaundy) @&amp;gt; '&lt;/span&gt;
  &lt;span class="s"&gt;'https://www.youtube.com/watch?v=jg-uSq64Ru8'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For me, the top result wasn't a song I liked too much, but it was my alarm clock for almost a year. Of these songs, I recommend you check out this one: &lt;a href="https://www.youtube.com/watch?v=jg-uSq64Ru8"&gt;Omokage by milet, Aimer, Lilas Ikuta, Vaundy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you find this script useful. Cheers.&lt;/p&gt;

</description>
      <category>python</category>
      <category>youtube</category>
    </item>
    <item>
      <title>Terraform vs Pulumi</title>
      <dc:creator>Yuval Greenfield</dc:creator>
      <pubDate>Mon, 24 Jul 2023 15:47:24 +0000</pubDate>
      <link>https://dev.to/ubershmekel/terraform-vs-pulumi-4887</link>
      <guid>https://dev.to/ubershmekel/terraform-vs-pulumi-4887</guid>
      <description>&lt;p&gt;On the face of it Terraform and Pulumi are the same thing. They let you write code that defines your cloud setup. When you modify that code - they will update your cloud setup accordingly. &lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform vs Pulumi on Github
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://star-history.com/#pulumi/pulumi&amp;amp;hashicorp/terraform&amp;amp;Date"&gt;https://star-history.com/#pulumi/pulumi&amp;amp;hashicorp/terraform&amp;amp;Date&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(for some reason &lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sopbu5qstrt2fm0nyr1z.png"&gt;this image&lt;/a&gt; is looking broken when I embed it)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/pulumi/pulumi"&gt;https://github.com/pulumi/pulumi&lt;/a&gt; - Infrastructure as Code in any programming language. Build infrastructure intuitively on any cloud using familiar languages&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/hashicorp/terraform"&gt;https://github.com/hashicorp/terraform&lt;/a&gt; - Terraform enables you to safely and predictably create, change, and improve infrastructure. It is an open source tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The subtle lock-in difference
&lt;/h2&gt;

&lt;p&gt;Pulumi allows you to write the code in your programming language of choice, which is going to be far more expressive. Terraform requires you use a simplistic configuration language.&lt;/p&gt;

&lt;p&gt;A consequence of this difference is that it's easy to migrate from Terraform configuration files to Pulumi. But it's going to be extremely difficult to migrate from Pulumi to anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats and conclusions
&lt;/h2&gt;

&lt;p&gt;I  personally only used Terraform and it was a bit tricky to learn at the time. Pulumi's idea of using a more capable language to manage infrastructure intrigues me. It seems the idea is so powerful that it might be worth it to take the risk of never being able to migrate off of it. I'll post an update after I try it. Please let me know of lessons  you already have from real life experiences with these two.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>infrastructureascode</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Github page, which version are you anyway?</title>
      <dc:creator>Yuval Greenfield</dc:creator>
      <pubDate>Mon, 06 Sep 2021 21:13:06 +0000</pubDate>
      <link>https://dev.to/ubershmekel/github-page-which-version-are-you-anyway-44f0</link>
      <guid>https://dev.to/ubershmekel/github-page-which-version-are-you-anyway-44f0</guid>
      <description>&lt;p&gt;I was working on my game and couldn't figure out which version was deployed to github pages. So I &lt;a href="https://github.com/ubershmekel/nihongo-shooter/blob/c7c02c37d2f2e62e1e2b2be89fbad365537ee619/.github/workflows/main.yml#L36"&gt;added this&lt;/a&gt; to my github deploy action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: save version.json file
  run: &amp;gt;
    echo '{ "hash": "'$(git rev-parse HEAD)'" }' &amp;gt; dist/version.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now I can see the git hash of the live version at &lt;a href="https://ubershmekel.github.io/nihongo-shooter/version.json"&gt;https://ubershmekel.github.io/nihongo-shooter/version.json&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I could probably also include more information like a label and show it in the game. But this is good enough for my needs. I'll probably include that line in all my github page deploys. Note you may or may not need to store the &lt;code&gt;version.json&lt;/code&gt; in a &lt;code&gt;dist&lt;/code&gt; folder. Cheers.&lt;/p&gt;

</description>
      <category>github</category>
      <category>ci</category>
      <category>versions</category>
      <category>pages</category>
    </item>
    <item>
      <title>I built a game with Vite</title>
      <dc:creator>Yuval Greenfield</dc:creator>
      <pubDate>Thu, 29 Apr 2021 01:25:44 +0000</pubDate>
      <link>https://dev.to/ubershmekel/i-built-a-game-with-vite-42le</link>
      <guid>https://dev.to/ubershmekel/i-built-a-game-with-vite-42le</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfsngyt4x1iqhcscglcx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyfsngyt4x1iqhcscglcx.png" alt="Where is Bob is a game made in 48 hours"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As part of Ludum Dare, a competition for making a game in 48 hours, I like experimenting with new tech. It's always painful to experiment while under time pressure, but it's also a great opportunity to time constrain a learning experience.&lt;/p&gt;

&lt;p&gt;Last year I tried to use Rollup, Phaser, and TypeScript based on an existing template. When I tried to &lt;code&gt;npm install&lt;/code&gt; an audio library (Howler) - it &lt;a href="https://github.com/geocine/phaser3-rollup-typescript/issues/1#issuecomment-715410600" rel="noopener noreferrer"&gt;broke&lt;/a&gt; in such a way that I needed to debug a convoluted asset build configuration. I couldn't figure out how to fix it. In the end I decided to ditch the build system entirely and go pure JavaScript. &lt;/p&gt;

&lt;p&gt;This year I tried out Vite, Phaser, and TypeScript. I was able to throw in different odd libraries and it all just worked. There were just 2 issues which were straightforward to debug:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The inlining of assets into URL encoding that Vite does was incompatible with Phaser. Luckily the relevant Vite docs popped up when I searched for the issue. After a small config &lt;a href="https://github.com/ubershmekel/ld48/blob/7b6a1185e9f5e773500f4c12b3e3e9373e404aba/vite.config.js#L7" rel="noopener noreferrer"&gt;change&lt;/a&gt; of &lt;code&gt;assetsInlineLimit&lt;/code&gt; to zero,  I was on my way. &lt;/li&gt;
&lt;li&gt;GitHub pages are hosted in a subfolder, so I had to add &lt;code&gt;base: './',&lt;/code&gt; to the &lt;code&gt;vite.config.js&lt;/code&gt; as well. Perhaps this should be the default setting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The game is pretty simple, you can &lt;a href="https://ubershmekel.github.io/ld48/" rel="noopener noreferrer"&gt;play "Where is Bob"&lt;/a&gt; if you like. I also made a &lt;a href="https://github.com/ubershmekel/vite-phaser-ts-starter" rel="noopener noreferrer"&gt;vite-phaser-typescript template&lt;/a&gt; if you'd like to start such a project from scratch. The main goal of this post if to just say thank you to &lt;a class="mentioned-user" href="https://dev.to/yyx990803"&gt;@yyx990803&lt;/a&gt; and the Vite team for such a smooth build system that mostly just worked.&lt;/p&gt;

</description>
      <category>vite</category>
      <category>gamedev</category>
      <category>phaser</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
