<?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: suntong</title>
    <description>The latest articles on DEV Community by suntong (@suntong).</description>
    <link>https://dev.to/suntong</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%2F164126%2F942170cc-cbbb-47d6-aad6-21c679b96e98.png</url>
      <title>DEV Community: suntong</title>
      <link>https://dev.to/suntong</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suntong"/>
    <language>en</language>
    <item>
      <title>Google Docs no longer take free spaces in Google Drive</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Sun, 06 Nov 2022 01:27:44 +0000</pubDate>
      <link>https://dev.to/suntong/google-docs-no-longer-take-free-spaces-in-google-drive-1kha</link>
      <guid>https://dev.to/suntong/google-docs-no-longer-take-free-spaces-in-google-drive-1kha</guid>
      <description>&lt;p&gt;Everyone believes that their Google Docs sizes are not counted into the total 15G free spaces allocated, but it is no longer true!!&lt;/p&gt;

&lt;p&gt;I found out today and it is quite a surprise to me and I have to triple-validate it before posting it here.&lt;/p&gt;

&lt;p&gt;Google never said anything about it and it seems that most people aren't unaware of such new situation. Take &lt;a href="https://www.reviewgeek.com/117723/heres-how-you-can-free-up-more-space-in-google-drive/"&gt;this article&lt;/a&gt; for example, which is only published this year at MAY 25, 2022, still believe otherwise:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;These Things Do Not Count&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Google &lt;em&gt;does not&lt;/em&gt; count any word documents you create in &lt;em&gt;Google Docs&lt;/em&gt;, any spreadsheets from &lt;em&gt;Google Sheets&lt;/em&gt;, any presentation slideshows from &lt;em&gt;Google Slides&lt;/em&gt; (thankfully), any forms or surveys from &lt;em&gt;Google Forms&lt;/em&gt;, or any information for Google Sites. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Moreover, as of Saturday, November 05, 2022, this is what wikipedia says about &lt;a href="https://en.wikipedia.org/wiki/Google_Drive"&gt;Google Drive&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Google gives every user 15 GB (1 GB = 1 billion bytes) of free storage through &lt;a href="https://en.wikipedia.org/wiki/Google_One"&gt;Google One&lt;/a&gt;. &lt;a href="https://en.wikipedia.org/wiki/Google_Docs"&gt;Google Docs&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Google_Sheets"&gt;Google Sheets&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Google_Slides"&gt;Google Slides&lt;/a&gt; files &lt;em&gt;do not&lt;/em&gt; count towards the storage limit.&lt;a href="https://en.wikipedia.org/wiki/Google_Drive#cite_note-:1-35"&gt;&lt;sup&gt;[35]&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bTCbwLt---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gc69vhc3x7ygswlonkno.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bTCbwLt---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gc69vhc3x7ygswlonkno.png" alt="Image description" width="796" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;YET, they &lt;strong&gt;&lt;em&gt;do&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;now&lt;/em&gt;! &lt;/p&gt;

&lt;p&gt;Be aware!&lt;/p&gt;

</description>
      <category>google</category>
    </item>
    <item>
      <title>st - the suckless simple terminal, v0.9</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Sun, 16 Oct 2022 19:43:38 +0000</pubDate>
      <link>https://dev.to/suntong/st-the-suckless-simple-terminal-v09-4klf</link>
      <guid>https://dev.to/suntong/st-the-suckless-simple-terminal-v09-4klf</guid>
      <description>&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;p&gt;This Debian package &lt;em&gt;does&lt;/em&gt; provide a scrollback buffer, it also supports color emoji, and it shows Chinese beautifully:&lt;/p&gt;

&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%2Fd2barkcj6r304aqg63yj.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%2Fd2barkcj6r304aqg63yj.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why bother
&lt;/h3&gt;

&lt;p&gt;For decades, I settled with &lt;code&gt;urxvt&lt;/code&gt; to display Chinese, despite all its quirks, like surprising hot-keys and not supporting color emoji.&lt;/p&gt;

&lt;p&gt;However, it is its &lt;em&gt;"helpful"&lt;/em&gt; anti-aliasing font effect under WSL that become the last straw that broke the camel's back: &lt;/p&gt;

&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%2Fo7rsy9kpa1meupdgp3ws.jpg" 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%2Fo7rsy9kpa1meupdgp3ws.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As I was not able to get rid of the above anti-aliasing effect under WSL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not Alacritty
&lt;/h3&gt;

&lt;p&gt;I agree with the comment from &lt;a href="https://www.reddit.com/r/suckless/comments/to61qy/dont_use_kitty_terminal/" rel="noopener noreferrer"&gt;reddit&lt;/a&gt; that:&lt;/p&gt;

&lt;p&gt;It's Ok to use Alacritty,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;if you really want something a bit more bloated, and don't mind using rust software.&lt;/p&gt;

&lt;p&gt;Alacritty&lt;br&gt;
Like GNOME, it may look nice, but it consumes way too much RAM for a barebone terminal emulator IMO.&lt;/p&gt;

&lt;p&gt;$ ps -eo comm,rss,pcpu | grep -E 'xterm|alacritty'&lt;/p&gt;

&lt;p&gt;xterm 13052 0.0&lt;br&gt;
alacritty 38884 0.1&lt;/p&gt;

&lt;p&gt;Depending on your distribution, the packaged alacritty may be fatter than others. Here on Fedora (rawhide) is the new GNOME 42 terminal...&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ps -eo comm,rss,pcpu | grep -E 'terminal|kitty|st'
kitty           83668  0.5
alacritty       69668  1.3
gnome-terminal- 61260  6.4
st              10172  0.3 (unpatched)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I don't mind it is 4+ the size of &lt;code&gt;st&lt;/code&gt; as long as I can get a precompiled Debian/Ubuntu package (as I really don't want to compile any packages myself). However, I gave up &lt;code&gt;alacritty&lt;/code&gt; for the exact reason posted under &lt;a href="https://www.reddit.com/r/archlinux/comments/bg2nfd/whats_your_minimalist_terminal_emulator_of_choice/" rel="noopener noreferrer"&gt;here&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Something to note when using a gpu based terminal. Having the terminal emulator open will make the gpu ramp up a few power states. My 1080ti goes into power state 3, which results in an extra ~30 watts at the wall over using st, urxvt, etc.&lt;br&gt;
Don't get me wrong, alacritty is amazing, but it's not worth the extra power draw for me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I.e., despite how amazing it is, I'm not willing to let my laptop run hot all the time and reduce its battery time just for some fancy visual effects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not sticking to the official precompiled Debian/Ubuntu package?
&lt;/h3&gt;

&lt;p&gt;Despite how I dislike compiling packages myself, I cannot bear with the official precompiled Debian/Ubuntu package because it does &lt;em&gt;not&lt;/em&gt; provide a scrollback buffer, and it crashes when displaying color emojis.&lt;/p&gt;

&lt;h3&gt;
  
  
  My precompiled Ubuntu package
&lt;/h3&gt;

&lt;p&gt;Because I really don't want to compile any packages myself, and because the only way to get &lt;code&gt;st&lt;/code&gt; is to compile it yourself, I'm providing this precompiled Ubuntu package in hoping that it'll help someone like me. It is built right from source git repo, thus it now supports color emoji, and it'll always give you the latest version. Besides, I added the patch so it &lt;em&gt;does&lt;/em&gt; provide a scrollback buffer.&lt;/p&gt;

&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%2F9e5e9yte7a093ah7gq1q.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%2F9e5e9yte7a093ah7gq1q.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is how to get it installed under Debian 11 bullseye (Ubuntu would be similar but simpler):&lt;/p&gt;

&lt;p&gt;Check out &lt;code&gt;ppa:suntong001/ppa&lt;/code&gt; at &lt;a href="https://launchpad.net/%7Esuntong001/+archive/ubuntu/ppa:" rel="noopener noreferrer"&gt;https://launchpad.net/~suntong001/+archive/ubuntu/ppa:&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This PPA can be added to your Debian 11 system manually by copying the lines below and adding them to your system's software sources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deb https://ppa.launchpadcontent.net/suntong001/ppa/ubuntu focal main 
deb-src https://ppa.launchpadcontent.net/suntong001/ppa/ubuntu focal main 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, after &lt;code&gt;apt update&lt;/code&gt;, do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt-cache policy stterm libxft2
apt install stterm libxft2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recheck:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ apt-cache policy stterm libxft2
stterm:
  Installed: 0.9.1~20221004~ubuntu20.04.1
  Candidate: 0.9.1~20221004~ubuntu20.04.1
  Version table:
 *** 0.9.1~20221004~ubuntu20.04.1 500
        500 http://ppa.launchpad.net/suntong001/ppa/ubuntu focal/main amd64 Packages
        100 /var/lib/dpkg/status
     0.8.5-1 500
        500 http://deb.debian.org/debian bookworm/main amd64 Packages
     0.8.4-1 500
        500 http://deb.debian.org/debian bullseye/main amd64 Packages
     0.8.2-1 500
        500 http://deb.debian.org/debian buster/main amd64 Packages

libxft2:
  Installed: 2.3.6-1
  Candidate: 2.3.6-1
  Version table:
 *** 2.3.6-1 500
        500 http://deb.debian.org/debian bookworm/main amd64 Packages
        100 /var/lib/dpkg/status
     2.3.6-1~202209251622~ubuntu20.04.1 500
        500 http://ppa.launchpad.net/suntong001/ppa/ubuntu focal/main amd64 Packages
     2.3.2-2 500
        500 http://deb.debian.org/debian bullseye/main amd64 Packages
        500 http://deb.debian.org/debian buster/main amd64 Packages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Enjoy 😃.&lt;/p&gt;

</description>
      <category>terminal</category>
      <category>emoji</category>
      <category>linux</category>
      <category>wsl</category>
    </item>
    <item>
      <title>Transforming json data with easygen</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Fri, 31 Dec 2021 04:00:35 +0000</pubDate>
      <link>https://dev.to/suntong/transforming-json-data-with-easygen-4g2i</link>
      <guid>https://dev.to/suntong/transforming-json-data-with-easygen-4g2i</guid>
      <description>&lt;h3&gt;
  
  
  Filtering
&lt;/h3&gt;

&lt;p&gt;Take a look at the vast amount of data a github API may return, e.g.: &lt;a href="https://api.github.com/search/repositories?q=go" rel="noopener noreferrer"&gt;https://api.github.com/search/repositories?q=go&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If there is only few key data that we want, then the first thing to do is to filter out the unwanted. Can &lt;code&gt;easygen&lt;/code&gt; do that? Yes, of course. Given the power of Go template engine, everything is possible. However, such filtering is &lt;em&gt;imperative&lt;/em&gt; programming if done in &lt;code&gt;easygen&lt;/code&gt;, especially when doing vertically filtering (skipping unwanted records). So it is better to use the &lt;em&gt;declarative&lt;/em&gt; approach, using tools like &lt;code&gt;jp&lt;/code&gt; or &lt;code&gt;jq&lt;/code&gt; instead. Since that is outside of the scope of this article, we'll skip it and move on to the next section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Presenting
&lt;/h3&gt;

&lt;p&gt;Take a look at the end result first, at &lt;a href="https://github.com/go-sqlparser/current/wiki/List:-Currently-Collected-Projects:" rel="noopener noreferrer"&gt;https://github.com/go-sqlparser/current/wiki/List:-Currently-Collected-Projects:&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&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%2Fuser-images.githubusercontent.com%2F422244%2F147801349-ade37b3d-56c5-4276-a8d7-296d27362c9f.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%2Fuser-images.githubusercontent.com%2F422244%2F147801349-ade37b3d-56c5-4276-a8d7-296d27362c9f.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is what happening behind the scene -- the mark down source code that renders above:&lt;/p&gt;

&lt;blockquote&gt;
&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%2Fuser-images.githubusercontent.com%2F422244%2F147801476-97638ea8-28c6-4a1d-88f5-403e711f3214.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%2Fuser-images.githubusercontent.com%2F422244%2F147801476-97638ea8-28c6-4a1d-88f5-403e711f3214.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note that &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the project name keyword has been repeated five times in the mark down source code. &lt;/li&gt;
&lt;li&gt;there is a TOC index that links directly to the detailed content. I.e., each project is repeated twice, first listed briefly in the TOC/index section, then full details in the following section.&lt;/li&gt;
&lt;li&gt;the PrimaryLanguage is therefore need to be repeated in two sections as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Such repetitive tasks are best  leave to tools to automate it, and &lt;code&gt;easygen&lt;/code&gt; is such code/text auto generating tools. The mark down code generation template is as simple as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;repos.tmpl 
&lt;span class="c"&gt;## Currently Collected Projects&lt;/span&gt;

&lt;span class="c"&gt;### List&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt;range .Data.RepositoryOwner.Repositories.Edges&lt;span class="o"&gt;}}&lt;/span&gt;
- &lt;span class="o"&gt;[{{&lt;/span&gt;.Node.Name&lt;span class="o"&gt;}}&lt;/span&gt; &lt;span class="o"&gt;({{&lt;/span&gt;.Node.PrimaryLanguage.PrimaryLanguage&lt;span class="o"&gt;}})](&lt;/span&gt;&lt;span class="c"&gt;#{{.Node.Name}}){{end}}&lt;/span&gt;

&lt;span class="c"&gt;### Details&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt;range .Data.RepositoryOwner.Repositories.Edges&lt;span class="o"&gt;}}&lt;/span&gt;
&amp;lt;a &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{.Node.Name}}"&lt;/span&gt;/&amp;gt;&lt;span class="k"&gt;**&lt;/span&gt;&lt;span class="o"&gt;{{&lt;/span&gt;.Node.Name&lt;span class="o"&gt;}}&lt;/span&gt;&lt;span class="k"&gt;**&lt;/span&gt; &lt;span class="o"&gt;({{&lt;/span&gt;.Node.PrimaryLanguage.PrimaryLanguage&lt;span class="o"&gt;}})&lt;/span&gt;  
&lt;span class="o"&gt;{{&lt;/span&gt;.Node.Url&lt;span class="o"&gt;}}&lt;/span&gt;  
&lt;span class="o"&gt;{{&lt;/span&gt;.Node.Description&lt;span class="o"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt;end&lt;span class="o"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  To put them together
&lt;/h3&gt;

&lt;p&gt;So in order to come up with the above end result, I need to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;download &lt;code&gt;json&lt;/code&gt; data via API&lt;/li&gt;
&lt;li&gt;filter the &lt;code&gt;json&lt;/code&gt; data with the &lt;a href="https://github.com/go-jsonfile/jp/releases/tag/v0.2.2" rel="noopener noreferrer"&gt;&lt;code&gt;jp&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;then present the &lt;code&gt;json&lt;/code&gt; data in human friendly mark down format with the new &lt;code&gt;easygen&lt;/code&gt; that can read from &lt;code&gt;stdin&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;in the human friendly form, if I need to convert the long number of project size from bytes to the size in KB or MB, and I can make use of &lt;code&gt;easygen&lt;/code&gt;'s built in &lt;a href="https://github.com/go-easygen/easygen/issues/25#cal" rel="noopener noreferrer"&gt;calculation in Go template&lt;/a&gt; supports. &lt;/li&gt;
&lt;li&gt;there are lots of other transformation support functions already builtin inside &lt;code&gt;easygen&lt;/code&gt;, check out the full list with sample usage and results &lt;a href="https://github.com/go-easygen/easygen/issues/25" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;project size added to list details:&lt;/p&gt;

&lt;blockquote&gt;
&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%2Fuser-images.githubusercontent.com%2F422244%2F147834144-4fbac511-9f50-4b66-946f-8f80e7b33da4.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%2Fuser-images.githubusercontent.com%2F422244%2F147834144-4fbac511-9f50-4b66-946f-8f80e7b33da4.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and here is the updated code generation template:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cat repos.tmpl 
## Currently Collected Projects

### List
{{range .Data.RepositoryOwner.Repositories.Edges}}
- [{{.Node.Name}} ({{.Node.PrimaryLanguage.PrimaryLanguage}})](#{{.Node.Name}}){{end}}

### Details
{{range .Data.RepositoryOwner.Repositories.Edges}}{{$mb := sprintf "%.2f" (divide .Node.Size 1024)}}
&amp;lt;a name="{{.Node.Name}}"/&amp;gt;**{{.Node.Name}}** ({{.Node.PrimaryLanguage.PrimaryLanguage}}, {{.Node.Size}}KB/{{$mb}}MB)  
{{.Node.Url}}  
{{ coalesce .Node.Description "No description" }}
{{end}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Credit
&lt;/h3&gt;

&lt;p&gt;The cover image is obtained from &lt;a href="https://www.imd.org/contentassets/11a6ae4d75ce4d4a83c9a8e87b3944e4/iai_07-18_big-teaser758x334.jpg" rel="noopener noreferrer"&gt;imd.org&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>json</category>
      <category>transform</category>
      <category>easygen</category>
      <category>generator</category>
    </item>
    <item>
      <title>What is the "XSLT" equivalent for JSON? Here is the new answer</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Thu, 30 Dec 2021 04:33:55 +0000</pubDate>
      <link>https://dev.to/suntong/what-is-the-xslt-equivalent-for-json-here-is-the-new-answer-7la</link>
      <guid>https://dev.to/suntong/what-is-the-xslt-equivalent-for-json-here-is-the-new-answer-7la</guid>
      <description>&lt;h3&gt;
  
  
  Prefix
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;What is the "XSLT" equivalent for JSON?&lt;/em&gt;  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the question that people had been asking &lt;a href="https://stackoverflow.com/questions/1618038/xslt-equivalent-for-json"&gt;more than 10 years ago&lt;/a&gt;. By then the &lt;code&gt;xslt&lt;/code&gt; is still the number one answer.&lt;br&gt;&lt;br&gt;
It's high time to take a look at the new kids in town now.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is "XSLT"?
&lt;/h3&gt;

&lt;p&gt;XSLT stands for XSL Transformation. It is used to transform XML documents into into various other types of document (like transforming XML into HTML).&lt;/p&gt;

&lt;p&gt;It's most important purpose is transform data, from XML form into a format more presentable to human beings.&lt;br&gt;&lt;br&gt;
XSL is to XML is similar as CSS is to HTML. XSLT can be viewed as the rendering engine.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the new choices now?
&lt;/h3&gt;

&lt;p&gt;The second choice in the above answer had been &lt;a href="https://stedolan.github.io/jq/"&gt;&lt;code&gt;jq&lt;/code&gt;&lt;/a&gt;, and I agree that it is very powerful.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;jq is like sed for JSON data - you can use it to slice and filter and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text. There are install packages for different OS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But comparing to &lt;code&gt;jsonpath&lt;/code&gt; it is more difficult to learn to most people, which brings us to the first tool to recommend this time -- &lt;a href="https://github.com/go-jsonfile/jp/"&gt;&lt;code&gt;jp&lt;/code&gt;&lt;/a&gt;, because&lt;/p&gt;

&lt;p&gt;&lt;code&gt;jp&lt;/code&gt; is as simple as &lt;code&gt;jsonpath&lt;/code&gt; but as powerful as &lt;code&gt;jq&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How about the rendering engine part?
&lt;/h3&gt;

&lt;p&gt;The problem of both &lt;code&gt;jq&lt;/code&gt; or &lt;code&gt;jp&lt;/code&gt; is that although they can do data projection in any direction (doing data filtering in any way), their purpose are still focusing on data transformation, but when talking about rendering &lt;code&gt;json&lt;/code&gt; data into a format more presentable to human beings, then there is no better tools than &lt;a href="https://github.com/go-easygen/easygen/"&gt;&lt;code&gt;easygen&lt;/code&gt;&lt;/a&gt;. In fact, the &lt;code&gt;easygen&lt;/code&gt; is a universal code/text generator that not only works on &lt;code&gt;json&lt;/code&gt; data but it can take in data defined in YAML format as well. It can be used as any text (or html, or any other forms) generator for arbitrary purposes with arbitrary data and templates. It is built on top of the powerful Go template engine.&lt;/p&gt;

&lt;h3&gt;
  
  
  To put them together
&lt;/h3&gt;

&lt;p&gt;So the other day, I&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;download &lt;code&gt;json&lt;/code&gt; data via API&lt;/li&gt;
&lt;li&gt;filter the &lt;code&gt;json&lt;/code&gt; data with the &lt;a href="https://github.com/go-jsonfile/jp/releases/tag/v0.2.2"&gt;&lt;code&gt;jp&lt;/code&gt;&lt;/a&gt; that supports filtering by regular expression (&lt;em&gt;hint: do you know any json filter that when given a video's file name, can tell a tv-series apart from a movie?&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;then present the &lt;code&gt;json&lt;/code&gt; data in human friendly format with the new &lt;code&gt;easygen&lt;/code&gt; that can read from &lt;code&gt;stdin&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;in the human friendly form, I need to convert the long number of size in bytes to the size in MB and GB, and I had to search for how to do calculation in Go template, but then was &lt;em&gt;delighted&lt;/em&gt; to realized that &lt;code&gt;easygen&lt;/code&gt; &lt;em&gt;already&lt;/em&gt; supports the &lt;a href="https://github.com/go-easygen/easygen/issues/25#cal"&gt;calculation in Go template&lt;/a&gt; long time ago.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll give a more concrete example in the next article.&lt;/p&gt;

&lt;p&gt;To me now,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;easygen&lt;/code&gt; is to &lt;code&gt;json&lt;/code&gt; what &lt;code&gt;xslt&lt;/code&gt; is to &lt;code&gt;xml&lt;/code&gt;, but much more powerful and versatile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Credit
&lt;/h3&gt;

&lt;p&gt;The cover image is obtained from &lt;a href="https://www.imd.org/contentassets/11a6ae4d75ce4d4a83c9a8e87b3944e4/iai_07-18_big-teaser758x334.jpg"&gt;imd.org&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>json</category>
      <category>transform</category>
      <category>easygen</category>
      <category>generator</category>
    </item>
    <item>
      <title>Maintenance free system multi booting</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Fri, 29 Oct 2021 03:18:03 +0000</pubDate>
      <link>https://dev.to/suntong/maintenance-free-system-multi-booting-1dpk</link>
      <guid>https://dev.to/suntong/maintenance-free-system-multi-booting-1dpk</guid>
      <description>&lt;h2&gt;
  
  
  The journey continues
&lt;/h2&gt;

&lt;p&gt;First, recap from the &lt;a href="https://dev.to/suntong/journey-towards-a-maintenance-free-system-booting-3613#conclusion"&gt;previous article&lt;/a&gt;, a single &lt;code&gt;grub&lt;/code&gt; boot menu entry can be as simple as:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With it, we don't need to hunt for the UUIDs, and we don't need to remember to mount boot partition and update the boot entries any more. It can boot to whatever latest kernel it is, and it will still work even we reformat the partition and install a new Linux, and it will still work even we change the distro from Debian, to Mint, Arch, Fedora, or openSUSE etc.&lt;/p&gt;

&lt;p&gt;In this article, we'll first look at those few more boilerplates that enable you to only write the above few lines and everything will work out magically. Then we'll move on to how to make things even simpler, with the help of &lt;a href="https://github.com/go-easygen/easygen/wiki"&gt;easygen&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The supporting files
&lt;/h2&gt;

&lt;p&gt;To break free from the rigid format requirement of &lt;code&gt;40_custom&lt;/code&gt; and allow people only write the above few lines, or to &lt;strong&gt;order boot entries&lt;/strong&gt; in the order we want, instead of being &lt;em&gt;determined by their partition orders&lt;/em&gt;, we need to build our &lt;code&gt;grub.cfg&lt;/code&gt; file from ground up ourselves. And, it is not that scary either and could be really straightforward. Here are all the code it needs:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;grub.cfg&lt;/code&gt; file that replace &lt;code&gt;grub&lt;/code&gt;s default &lt;code&gt;.cfg&lt;/code&gt; file. Deliberately made so simple so that it can be easily restored if it was accidentally overwritten.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;grub-main.cfg&lt;/code&gt; that the &lt;code&gt;grub.cfg&lt;/code&gt; file actually calls. The idea comes from &lt;a href="https://grml.org"&gt;grml&lt;/a&gt;. We can see that it is sourcing a header, a footer, and the main/real &lt;code&gt;.cfg&lt;/code&gt; files, like the entry shown above. &lt;/p&gt;

&lt;p&gt;Arrange those &lt;code&gt;.cfg&lt;/code&gt; files so that their order show up in the order you want in the grub menu. For example, this is how I arrange my grub menu:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZLOySLni--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/422244/139169315-432b6d5f-2951-4f08-9189-36c7aa9a59f0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZLOySLni--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/422244/139169315-432b6d5f-2951-4f08-9189-36c7aa9a59f0.png" alt="image" width="658" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I.e., in my preference, I want my grub menu to be in the order of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My current Linux&lt;/li&gt;
&lt;li&gt;Live Linux from ISO, in case I need to check/repair anything&lt;/li&gt;
&lt;li&gt;My Windows&lt;/li&gt;
&lt;li&gt;My old Linux versions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are ordered from most probably used to the least probably used. Changing the order is simple, just shift them around in the &lt;code&gt;.cfg&lt;/code&gt; text file.&lt;/p&gt;

&lt;p&gt;The grub menu's look-and-feel is defined in the header, and the "Shutdown / Reboot" is defined in footer, showing below respectively.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ISO Booting
&lt;/h2&gt;

&lt;p&gt;The bonus and &lt;a href="https://en.wikiquote.org/wiki/The_Prestige_(film)"&gt;prestige&lt;/a&gt; of the whole article, here is how ISO files are automatically discovered and listed:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;It can automatically discover and list whatever ISO available on disk:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pyPhDB_f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/422244/139169388-8e85f402-06fa-49bf-9e91-60bc97bd1540.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pyPhDB_f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/422244/139169388-8e85f402-06fa-49bf-9e91-60bc97bd1540.png" alt="image" width="658" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and boot from them:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qd4wUSJW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/422244/139169415-e2ec398c-6adb-48eb-a96a-e6f28e3950a8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qd4wUSJW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/422244/139169415-e2ec398c-6adb-48eb-a96a-e6f28e3950a8.png" alt="image" width="658" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The red background color is chosen for the grub menu, to symbolize the &lt;strong&gt;&lt;em&gt;live&lt;/em&gt;&lt;/strong&gt; system, and also as the notification sign that this will be the last grub menu level, after which the system will be in booting mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can it be even simpler
&lt;/h2&gt;

&lt;p&gt;So far, we can see that using some simple scripts/configs, we can let the grub to show whatever we want it to show, in whatever order we want as well. Now, &lt;/p&gt;

&lt;p&gt;Can it be even simpler?&lt;/p&gt;

&lt;p&gt;As pointed out in the &lt;a href="https://dev.to/suntong/journey-towards-a-maintenance-free-system-booting-3613#conclusion"&gt;"Conclusion"&lt;/a&gt; section in the last article, the only things that matter in a grub menu entry are the &lt;code&gt;'Debian GNU/Linux'&lt;/code&gt; and the &lt;code&gt;'hd0,gpt2'&lt;/code&gt;, the rest are just the boilerplate that don't normally need to be changed.&lt;/p&gt;

&lt;p&gt;What if I only want to specify the &lt;code&gt;'Debian GNU/Linux'&lt;/code&gt; and the &lt;code&gt;'hd0,gpt2'&lt;/code&gt; part, and let the machine to generate the grub menu entry/entries for me? -- Not a problem, if with the help of &lt;a href="https://github.com/go-easygen/easygen/wiki"&gt;easygen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is all what you need to specify:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Feed that to &lt;code&gt;easygen&lt;/code&gt; as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;easygen os2grub-1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;then you'll get:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The secret is the easygen's template:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Customize it to whatever you like.&lt;/p&gt;

&lt;p&gt;But, most people not just has a single boot menu. How do you deal with that? Simple -- with another small tool of &lt;code&gt;grub2yaml.sh&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Just run it with &lt;/p&gt;

&lt;p&gt;&lt;code&gt;grub2yaml.sh /boot/grub/grub.cfg | tee /tmp/myOSs.cfg&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Slightly edit it, and you'll get more entries like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;With multiple entries like that, &lt;code&gt;easygen&lt;/code&gt; really starts to shine. You can get the following without a drop of sweat:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Enjoy
&lt;/h2&gt;

&lt;p&gt;IMHO, the way &lt;code&gt;grub2&lt;/code&gt; generates boot entries automatically, at least as of this article is written, is still a big mess. You may not agree with that, but I do enjoy my grub menu system to be plain and simple,  straightforward and out of my way. And, I enjoy my freedom to hand-craft my own boot menus again, just like the good old days, but without an extra spare letter to waste. &lt;/p&gt;

&lt;p&gt;Hope you enjoy that as well. &lt;/p&gt;

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

</description>
      <category>grub</category>
      <category>boot</category>
      <category>menu</category>
      <category>efi</category>
    </item>
    <item>
      <title>Journey towards a maintenance free system multi booting</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Thu, 28 Oct 2021 00:05:35 +0000</pubDate>
      <link>https://dev.to/suntong/journey-towards-a-maintenance-free-system-booting-3613</link>
      <guid>https://dev.to/suntong/journey-towards-a-maintenance-free-system-booting-3613</guid>
      <description>&lt;h2&gt;
  
  
  Problem statement and goal
&lt;/h2&gt;

&lt;p&gt;This article tries to simply the situation for people who dual boot/multi boot their computer systems, be them Debian, Mint, Arch, Fedora, openSUSE, etc, or Windows.&lt;/p&gt;

&lt;p&gt;For multi booting all the operation systems, I have a standalone boot partition as well as an UEFI ESP partition. From there, any operation systems on my disk can be booted. A Debian boot entry looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let me stress again that this is just one single entry. There are also several &lt;em&gt;"Advanced options"&lt;/em&gt; that goes with each Linux system, so my multi-boot &lt;code&gt;grub.cfg&lt;/code&gt; file looks scary, because it is humongous. But that's not the only problem.&lt;/p&gt;

&lt;p&gt;Problem #1: Because it is in a standalone boot partition, I normally don't need to mount it, but whenever I got my kernel manually or automatically upgraded, I have to remember to &lt;em&gt;mount this partition and  update the boot entries&lt;/em&gt; there. Otherwise, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I will not be able to boot up my system again, if the old kernels are somehow/automatically purged.&lt;/li&gt;
&lt;li&gt;I will not be able to take advantage of the new kernel, even if they have been installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Problem #2: I like to &lt;strong&gt;bring my &lt;code&gt;40_custom&lt;/code&gt; up to the top&lt;/strong&gt; of my menu selection, instead of &lt;em&gt;down at the bottom&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;Problem #3: I like to &lt;strong&gt;order my boot entries&lt;/strong&gt; in the order I want, instead of being &lt;em&gt;determined by their partition orders&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Although &lt;code&gt;grub&lt;/code&gt; can generate boot entries automatically,  all above problem are blind spots of &lt;code&gt;grub&lt;/code&gt;, and you have to come up with your own ways of dealing with them. &lt;/p&gt;

&lt;p&gt;The good news is that the &lt;code&gt;grub.cfg&lt;/code&gt; file does not have to be so humongous, scary, and messy. At the end of this article, you'll find that things can be pretty simple. &lt;strong&gt;Scroll to the bottom&lt;/strong&gt; to see if you don't want to go through the discovery journey that leads towards it. I.e. you'll find that &lt;/p&gt;

&lt;p&gt;Things can be so simple that people can start writing/maintaining the grub boot menu by hands now. And in the next blog, we can see that things can be even more simpler, with the help of &lt;a href="https://github.com/go-easygen/easygen/wiki"&gt;easygen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let the journey begin -- we'll going to go through a series of steps to simplify the &lt;code&gt;grub.cfg&lt;/code&gt; file so that in the end, they can be edited manually. Now, step number one,&lt;/p&gt;



&lt;h2&gt;
  
  
  Remove the "Advanced options"
&lt;/h2&gt;

&lt;p&gt;Let's take a look how big my &lt;code&gt;grub.cfg&lt;/code&gt; file is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ wc /boot/grub/grub.cfg
  355  1338 15006 /boot/grub/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Over 350 lines! Let's first simplify the &lt;code&gt;grub.cfg&lt;/code&gt; file by remove the "Advanced options" menu entries, as I've been using Linux for over 20 years, and not a single chance had I ever need to dip into those options. Moreover, the grub menu can be easily edited if I want, say to boot into single mode. They can go for sure:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'/^submenu .Advanced options for /,/^}/d'&lt;/span&gt; /boot/grub/grub.cfg | &lt;span class="nb"&gt;wc
    &lt;/span&gt;183     581    5602
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The file size almost dropped in half and now is under 200 lines. &lt;/p&gt;


&lt;h2&gt;
  
  
  Remove the unnecessary if conditions
&lt;/h2&gt;

&lt;p&gt;Look at the following lines in the above posted grub boot menu:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Has anyone ever wondering what it is doing?&lt;/p&gt;

&lt;p&gt;Well, &lt;a href="https://askubuntu.com/a/1177035/843820"&gt;it turns out&lt;/a&gt; that&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;the conditional code checking for this feature is pointless in all modern Linux distributions&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So why still keep it around?&lt;/p&gt;

&lt;p&gt;These &lt;code&gt;if&lt;/code&gt; conditions are second that need to go. After that, a single boot entry will look like:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Remove the unnecessary module loading
&lt;/h2&gt;

&lt;p&gt;Now, why are there so many &lt;code&gt;insmod&lt;/code&gt; statements in &lt;strong&gt;&lt;em&gt;each&lt;/em&gt;&lt;/strong&gt; boot entry? My computer contains either Linux or Windows, and they reside all in GPT, as ext4 partitions. I.e.,&lt;/p&gt;

&lt;p&gt;All my Linux will need the same modules, so it doesn't make sense to repeat every one of them in &lt;strong&gt;&lt;em&gt;each&lt;/em&gt;&lt;/strong&gt; individual boot entry. &lt;/p&gt;

&lt;p&gt;Can I &lt;strong&gt;load all the modules I need only once&lt;/strong&gt; at the beginning, and save each individual boot entries from &lt;em&gt;repeating themselves&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;It turns out that I can. So now my Linux boot entry looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  A little help please
&lt;/h2&gt;

&lt;p&gt;It'll be tedious to go through each boot entry and do the above clean up, so a little help from a script will definitely be the way to go, and &lt;a href="https://gist.github.com/suntong/cafb2fc8eaaeb77871927abae16c54f0#file-grub2clean-sed"&gt;here&lt;/a&gt; it is:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Toward maintenance free booting
&lt;/h2&gt;

&lt;p&gt;Now it is time to tackle Problem #1 -- whenever my kernel is upgraded, I don't want to &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mount my boot partition, and&lt;/li&gt;
&lt;li&gt;update the boot entries there&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I want my boot partition's boot entries to be able to survive such change and always boot to the latest kernel, whatever they are. Is that possible? Well,&lt;/p&gt;

&lt;p&gt;It sure can, using the trick like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Maintenance free, at last!
&lt;/h2&gt;

&lt;p&gt;Look at the &lt;code&gt;linux /vmlinuz&lt;/code&gt; line, there is still a &lt;code&gt;root=UUID=xxx&lt;/code&gt; parameter there. Now what if I reformat the partition and install a new Linux? The &lt;code&gt;UUID&lt;/code&gt; will surely change and the above boot entry will surely not be able to survive such change.&lt;/p&gt;

&lt;p&gt;This hurdle is the most difficult of all. Luckily someone has already looked into such problem, but sadly, nobody else even care, judging from the up-votes from the SO question and answer. Anyway, here, the &lt;a href="https://en.wikiquote.org/wiki/The_Prestige_(film)"&gt;prestige&lt;/a&gt; of the whole article, here is the solution:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;probe -u $root --set=rootuuid&lt;/code&gt; line will set the &lt;code&gt;$rootuuid&lt;/code&gt; variable, then it get passed to the next &lt;code&gt;linux /vmlinuz&lt;/code&gt; line. &lt;/p&gt;

&lt;p&gt;Hooray~~, problem solved!!&lt;/p&gt;

&lt;h2&gt;
  
  
  One step further
&lt;/h2&gt;

&lt;p&gt;Now, take a closer look at the &lt;code&gt;search --no-floppy --fs-uuid ...&lt;/code&gt; line.&lt;br&gt;&lt;br&gt;
What does it do? &lt;/p&gt;

&lt;p&gt;It actually set the &lt;code&gt;$root&lt;/code&gt; grub variable according to a &lt;strong&gt;&lt;em&gt;fixed&lt;/em&gt;&lt;/strong&gt; &lt;code&gt;UUID&lt;/code&gt; value on that line, and therefore change the boot partition, which will &lt;em&gt;undermine the whole effort&lt;/em&gt; of our above attempt. &lt;/p&gt;

&lt;p&gt;That will surely need to go away.&lt;/p&gt;
&lt;h2&gt;
  
  
  Summary of the journey
&lt;/h2&gt;

&lt;p&gt;The above discovery journey was a step by step one and it has been logged &lt;a href="https://gist.github.com/suntong/cafb2fc8eaaeb77871927abae16c54f0#file-os0_default-cfg"&gt;here&lt;/a&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The boot entries were build from the ground up and move step by step to the top. All entries are verified to be working fine.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Once upon a time, people write their own boot menu. But &lt;code&gt;grub2&lt;/code&gt; came alone and people just gave up such practice and rely solely on the machine.&lt;/p&gt;

&lt;p&gt;The journey in this article show that things do not have to be that way as the only way -- we can still write our own boot menu, just do not let the humongous file size scare you off, as a single boot menu entry now can be as simple as:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Most of which are boilerplate that don't need to be changed. I.e., the only things that matter are the &lt;code&gt;'Debian GNU/Linux'&lt;/code&gt; and the &lt;code&gt;'hd0,gpt2'&lt;/code&gt;. We don't need to hunt for the UUIDs, and we don't need to remember to mount boot partition and update the boot entries any more. It can boot to whatever latest kernel it is, and it will still work even we reformat the partition and install a new Linux, and it will still work even we change the distro from Debian, to Mint, Arch, Fedora, or openSUSE etc.&lt;/p&gt;

&lt;p&gt;There are a few more boilerplates that need to be in place so that you can only write the above few lines and everything will work out magically, which will be covered in next article, with the help of &lt;a href="https://github.com/go-easygen/easygen/wiki"&gt;easygen&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>grub</category>
      <category>boot</category>
      <category>menu</category>
      <category>efi</category>
    </item>
    <item>
      <title>Settling the editors key bindings war</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Sun, 20 Jun 2021 04:34:59 +0000</pubDate>
      <link>https://dev.to/suntong/settling-the-key-bindings-war-46jc</link>
      <guid>https://dev.to/suntong/settling-the-key-bindings-war-46jc</guid>
      <description>&lt;p&gt;This SO question, &lt;a href="https://softwareengineering.stackexchange.com/questions/28468/key-bindings-war-in-my-brain"&gt;Key bindings war in my brain&lt;/a&gt;, best summarized the problem I'm facing and am trying to solve:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How many key bindings are there in your brain? I personally use Intellij Idea as my primary IDE for development, but sometimes switch to Eclipse and Netbeans a bit, and sometimes I use Jedit, Notepad++, Emacs, Vim.&lt;/p&gt;

&lt;p&gt;I am always trying to find a perfect key bindings that I can use crossing all the editors. What's your idea to solve this problem?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The question was asked over 10 years ago, and there is still no perfect solution to the problem. What's worse is that there is now another big player in the field now -- we need to add Microsoft Code to the above long list as well now. &lt;/p&gt;

&lt;p&gt;There may be no perfect solution for anyone, but for me, having to constantly switch between Emacs, Jed, Goland, IntelliJ Idea, and Microsoft Code, I'm going to let them all to use the same keyboard mapping and bindings. &lt;/p&gt;

&lt;p&gt;The most difficult part is not Goland, IntelliJ Idea, and Microsoft Code, contrary to people might think, but Emacs itself, as Emacs itself has no official standard for key mapping and bindings. For example, the other day I just realized that I have three different way for comment-or-uncomment: &lt;code&gt;C-c ;&lt;/code&gt;, &lt;code&gt;M-#&lt;/code&gt;, and &lt;code&gt;M-;&lt;/code&gt;. Same for indents lines  and/or region, I have defined at least three different ways as well. &lt;/p&gt;

&lt;p&gt;Both Microsoft Code and IntelliJ has Emacs compatible mode which use Emacs key bindings. This post just collect them into a single place and put them side by side (if dev.to is restricting the blog width so you cannot see the full table width, you can also view it &lt;a href="https://gist.github.com/suntong/a8fd09192dd7354c2fb8a9cfd4e7edc0"&gt;here&lt;/a&gt;): &lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;PS. &lt;/p&gt;

&lt;p&gt;If you are interested in how these key bindings are collected, check out&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/go-easygen/easygen/wiki/Advanced-Templating-1,-List-Awesome-Emacs-Keymaps"&gt;Collecting Awesome-Emacs Keymaps&lt;/a&gt;, and&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/go-easygen/easygen/wiki/Advanced-Templating-2,-IntelliJ-Emacs-Keymaps"&gt;Collecting IntelliJ-Emacs Keymaps&lt;/a&gt; which covers combining the two as well&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>editor</category>
      <category>keyboard</category>
      <category>keymap</category>
      <category>binding</category>
    </item>
    <item>
      <title>How to Install Google Services Bundle Yourself</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Mon, 26 Oct 2020 02:52:08 +0000</pubDate>
      <link>https://dev.to/suntong/how-to-install-google-services-bundle-yourself-14co</link>
      <guid>https://dev.to/suntong/how-to-install-google-services-bundle-yourself-14co</guid>
      <description>&lt;p&gt;When I got my new Xiaomi phone, I wasn't prepared for the fact that installing Google Play and Google services would be this hard, because almost every youtube video, every blog, every technical article shows you that it is really simple to do so. All of them shows similar steps &lt;a href="https://www.techadvisor.co.uk/how-to/mobile-phone/install-google-play-xiaomi-3676150/" rel="noopener noreferrer"&gt;like this&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Launch the Mi App Store&lt;/li&gt;
&lt;li&gt;Search for Google&lt;/li&gt;
&lt;li&gt;Scroll down to the bottom of the list and select this option: &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.techadvisor.co.uk/cmsdata/features/3676150/search_mi_app_store.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.techadvisor.co.uk%2Fcmsdata%2Ffeatures%2F3676150%2Fsearch_mi_app_store.jpg" alt="Install Google Play on Xiaomi phone"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install the Google Installer app from its icon, and follows the prompts for the rest of the steps. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the first thing that I did, however Google Installer app complains that my phone is not rooted yet, so it will not go any further.&lt;/p&gt;

&lt;p&gt;Unlike other blogs, I don't thing the following are possible ways out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Return the phone to sender and purchase a Global model&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techadvisor.co.uk/how-to/mobile-phone/how-flash-miui-global-rom-on-xiaomi-phone-3787283/" rel="noopener noreferrer"&gt;Unlock the bootloader and install a Global ROM&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&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%2Fi.stack.imgur.com%2FLJcJR.jpg" 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%2Fi.stack.imgur.com%2FLJcJR.jpg" alt="img"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the only option I have is to Install Google services myself. It looks really intimidating, but having done that, I realized that it is not a big deal at all, and will not be afraid to buy Chinese phone that don't have Google services pre-installed any more.&lt;/p&gt;

&lt;p&gt;The phone that I have is a Redmi 10X 4g running MIUI 12. The steps will be similar for all Xiaomi/Redmi phones, and now I believe even for Huawei phones as well. &lt;/p&gt;

&lt;p&gt;The most important trick is&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to installed with the correct minimum set of required apps, &lt;/li&gt;
&lt;li&gt;in the correct order&lt;/li&gt;
&lt;li&gt;and from the correct package with correct version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of above is not right, then you might not have a good installation in the end. So here is the log of my attempt that works in the end.&lt;/p&gt;

&lt;p&gt;In short, install  the following  required services in this order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.apkmirror.com/?s=Google+Services+Framework&amp;amp;post_type=app_release&amp;amp;searchtype=apk" rel="noopener noreferrer"&gt;Google Services Framework&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.apkmirror.com/?s=Google+Account+Manager&amp;amp;post_type=app_release&amp;amp;searchtype=apk" rel="noopener noreferrer"&gt;Google Account Manager&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.apkmirror.com/?s=Google+Play+Services&amp;amp;post_type=app_release&amp;amp;searchtype=apk" rel="noopener noreferrer"&gt;Google Play Services&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.apkmirror.com/?s=Google+Calendar+Sync&amp;amp;post_type=app_release&amp;amp;searchtype=apk" rel="noopener noreferrer"&gt;Google Calendar Sync (must)&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.apkmirror.com/?s=Google+Contacts+Sync&amp;amp;post_type=app_release&amp;amp;searchtype=apk" rel="noopener noreferrer"&gt;Google Contacts Sync (must)&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;and finally the &lt;a href="https://www.apkmirror.com/?s=Google+Play+Store&amp;amp;post_type=app_release&amp;amp;searchtype=apk" rel="noopener noreferrer"&gt;Google Play Store&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All are available from&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.apkmirror.com/apk/google-inc/" rel="noopener noreferrer"&gt;https://www.apkmirror.com/apk/google-inc/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only problem is that when you get to the above download pages, most people would be intimidated by the selection of device’s DPI, architecture, screen size, and other specs. Luckily, apkmirror has that covered as well:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.apkmirror.com/faq/#How_can_I_find_out_my_device8217s_DPI_architecture_screen_size_and_otherspecs" rel="noopener noreferrer"&gt;How can I find out my device’s DPI, architecture, screen size, and other specs?&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After trying numerous system info apps, we are currently recommending &lt;a href="http://www.apkmirror.com/apk/inkwired/droid-hardware-info/droid-hardware-info-1-0-3-release/" rel="noopener noreferrer"&gt;Droid Hardware Info&lt;/a&gt;. It contains the DPI (Device tab), architecture (System tab), Android OS version (Device tab) as well as a plethora of other info.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So get that installed first (&lt;code&gt;com.dama.hardwareinfo.apk&lt;/code&gt;), and know your device. The rest will be easier. &lt;/p&gt;

&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%2Fi.stack.imgur.com%2FTTyha.jpg" 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%2Fi.stack.imgur.com%2FTTyha.jpg" alt="img"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next problem is to choose &amp;amp; get the correct package with correct version. Here is mine. I believe it will work for all &lt;em&gt;new&lt;/em&gt; Xiaomi/Redmi phones, and even &lt;em&gt;new&lt;/em&gt; &lt;code&gt;arm&lt;/code&gt; based Huawei phones as well. Here is the list, the package name, download url, and the actual &lt;code&gt;.apk&lt;/code&gt; that I downloaded (which shows the architecture, dpi, and version).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Google Services Framework, &lt;a href="https://www.apkmirror.com/apk/google-inc/google-services-framework/" rel="noopener noreferrer"&gt;https://www.apkmirror.com/apk/google-inc/google-services-framework/&lt;/a&gt;, &lt;code&gt;com.google.android.gsf_10-6475670-29_minAPI29(nodpi)_apkmirror.com.apk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Google Account Manager, &lt;a href="https://www.apkmirror.com/apk/google-inc/google-account-manager/" rel="noopener noreferrer"&gt;https://www.apkmirror.com/apk/google-inc/google-account-manager/&lt;/a&gt;, &lt;code&gt;com.google.android.gsf.login_7.1.2-25_minAPI23(nodpi)_apkmirror.com.apk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Google Play Services, &lt;a href="https://www.apkmirror.com/apk/google-inc/google-play-services/" rel="noopener noreferrer"&gt;https://www.apkmirror.com/apk/google-inc/google-play-services/&lt;/a&gt;, &lt;code&gt;com.google.android.gms_20.42.14_(120400-338133832)-204214037_minAPI29(arm64-v8a,armeabi-v7a)(nodpi)_apkmirror.com.apk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Google Calendar Sync (must), &lt;a href="https://www.apkmirror.com/apk/google-inc/google-calendar-sync/" rel="noopener noreferrer"&gt;https://www.apkmirror.com/apk/google-inc/google-calendar-sync/&lt;/a&gt;, &lt;code&gt;com.google.android.syncadapters.calendar_6.0.44-267540251-release-2016267990_minAPI21(nodpi)_apkmirror.com.apk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Google Contacts Sync (must), &lt;a href="https://www.apkmirror.com/apk/google-inc/google-contacts-sync/" rel="noopener noreferrer"&gt;https://www.apkmirror.com/apk/google-inc/google-contacts-sync/&lt;/a&gt;, &lt;code&gt;com.google.android.syncadapters.contacts_10-5771379-29_minAPI29(nodpi)_apkmirror.com.apk&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;and finally the Google Play Store, &lt;a href="https://www.apkmirror.com/apk/google-inc/google-play-store/" rel="noopener noreferrer"&gt;https://www.apkmirror.com/apk/google-inc/google-play-store/&lt;/a&gt;, &lt;code&gt;com.android.vending_22.4.28-21_0_PR_338099147-82242810_minAPI21(armeabi,armeabi-v7a,mips,mips64,x86,x86_64)(nodpi)_apkmirror.com.apk&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you get everything right, then you will sure to have a good installation in the end.&lt;/p&gt;

&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%2Fi.stack.imgur.com%2Ftt4r3.jpg" 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%2Fi.stack.imgur.com%2Ftt4r3.jpg" alt="img"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One thing though, I was having a bit trouble installing Google Maps.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The current default is called &lt;em&gt;Google Maps to Go&lt;/em&gt;, and it runs only in the browser. It was super slow, even on my brand new phone of the latest module, and I read review people are also saying it is slow, and recommends the classic Google Maps instead. &lt;/li&gt;
&lt;li&gt;Thus I went with the classic Google Maps instead, however, it crashes by itself soon after it is launched. I read review and it is happening to other people as well.&lt;/li&gt;
&lt;li&gt;So I have to rely on apkmirror.com again for an older version of Google Maps.&lt;/li&gt;
&lt;li&gt;The first old version (2nd in total) that I tried, is version 10.50.4, but it crashes as well.&lt;/li&gt;
&lt;li&gt;Only when I went back to version 10.49.3, did it start without crashing. &lt;/li&gt;
&lt;li&gt;I.e., overall, the &lt;code&gt;.apk&lt;/code&gt; that I kept is, &lt;code&gt;com.google.android.apps.maps_10.49.3-1049301244_minAPI21(arm64-v8a)(400,560,480,640dpi)_apkmirror.com.apk&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. &lt;/p&gt;

&lt;p&gt;Good luck!&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>google</category>
      <category>app</category>
      <category>install</category>
    </item>
    <item>
      <title>Are you still coding go cli handling by hand?</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Thu, 15 Oct 2020 14:10:25 +0000</pubDate>
      <link>https://dev.to/suntong/are-you-still-coding-go-cli-handling-by-hand-5g2h</link>
      <guid>https://dev.to/suntong/are-you-still-coding-go-cli-handling-by-hand-5g2h</guid>
      <description>&lt;p&gt;Are you still coding your go cli handling by hand? Time to stop and rethink better ways to do it now. &lt;/p&gt;

&lt;p&gt;Take a look at this go command line handling file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The help text &lt;em&gt;"path to serve files from"&lt;/em&gt; shows up three times:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;grep&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;serve&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="n"&gt;OpenSesame_cliDef&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
        &lt;span class="n"&gt;Port&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="c"&gt;// listening port&lt;/span&gt;
        &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="c"&gt;// path to serve files from&lt;/span&gt;
        &lt;span class="n"&gt;Help&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;   &lt;span class="c"&gt;// show usage help&lt;/span&gt;
&lt;span class="o"&gt;--&lt;/span&gt;
        &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Opts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"./"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"path to serve files from"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BoolVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Opts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Help&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;--&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;usageSummary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"  -port&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;listening port (OPENSESAME_PORT)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;  -path&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;path to serve files from (OPENSESAME_PATH)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;  -help&lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt;show usage help (OPENSESAME_HELP)&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;Details:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If coding by hand, most probably the first occurrence will be omitted. But that's kind of pity, as the help text is helpful in explaining what exactly the &lt;code&gt;Path string&lt;/code&gt; variable is for:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;        &lt;span class="n"&gt;Path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="c"&gt;// path to serve files from&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Also, if coding by hand, the second and third occurrences will very easily get out of sync if not be taken care of all the time. &lt;/p&gt;

&lt;p&gt;All these violate the DRY (Don't Repeat Yourself) principle. How to avoid it? The answer is this file:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;from which we can see that the help text &lt;em&gt;"path to serve files from"&lt;/em&gt; is defined only once but get automatically put into three different proper places.&lt;/p&gt;

&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%2Fi.stack.imgur.com%2FBrotW.jpg" 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%2Fi.stack.imgur.com%2FBrotW.jpg" alt="success"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the go cli handling code auto generation we are talking about. Look at the above two files, which one is more easier to maintain? With cli handling code auto generation feature out there, don't code it manually next time when you do cli handling again. &lt;/p&gt;

&lt;p&gt;What if you already have a manually written cli handling code? Well, converting it to automatically generated is not that hard at all. Here are just two simple steps,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/go-ego/gpy/pull/19/commits/a7066d8aac389ff8e2525175620450e505bc7a15" rel="noopener noreferrer"&gt;introduce config.go&lt;/a&gt;, which &lt;strong&gt;&lt;em&gt;ports&lt;/em&gt;&lt;/strong&gt; the existing cli handling from existing code into auto-generated &lt;code&gt;config.go&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/go-ego/gpy/pull/19/commits/530ac85adc94068dc17f3d375e33a973bd5d609f" rel="noopener noreferrer"&gt;implemented -d, -c, &amp;amp; -help&lt;/a&gt;, which &lt;strong&gt;&lt;em&gt;adds&lt;/em&gt;&lt;/strong&gt; more business logic handling for the newly added command line flags/parameters.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Very simple, no sweat at all. All thanks to the auto-generated &lt;code&gt;config.go&lt;/code&gt; file.&lt;/p&gt;

&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%2Fi.stack.imgur.com%2FvmJhi.jpg" 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%2Fi.stack.imgur.com%2FvmJhi.jpg" alt="success"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OK, now comes to the question, &lt;a href="https://github.com/suntong/gpy/commit/e3190cbaa3924d5edcfa60a830a7177085859dc3" rel="noopener noreferrer"&gt;how is the &lt;code&gt;config.go&lt;/code&gt; file auto-generated&lt;/a&gt;? Let me answer it with another example, that starts everything from the beginning, with &lt;a href="https://github.com/go-easygen/wireframe/wiki/Command-line-flag-handling-code-auto-generation#opensesame" rel="noopener noreferrer"&gt;all the following explanation borrowed from here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This section will work through every steps how the program is created. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/suntong/OpenSesame/commit/70ef318ab9ad0fdacb131a84b4be7bfecc64d189" rel="noopener noreferrer"&gt;Initialize an empty project&lt;/a&gt;.
The &lt;code&gt;_proj.yaml&lt;/code&gt; file will later be used to 

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/go-easygen/wireframe#github-create-repo---create-repository-in-github" rel="noopener noreferrer"&gt;Create Repository in Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/go-easygen/wireframe#github-create-release---create-release-in-github" rel="noopener noreferrer"&gt;Create Release in Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/go-easygen/wireframe#binary-releases" rel="noopener noreferrer"&gt;Create Binary releases using CI/CD&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/suntong/OpenSesame/commit/71be01c711a6110d5873323c3eb38985ffe9af90" rel="noopener noreferrer"&gt;Initialize project wireframe&lt;/a&gt; using the standard Go &lt;code&gt;flag&lt;/code&gt; package, by

&lt;ol&gt;
&lt;li&gt;Edit the &lt;code&gt;_cli.yaml&lt;/code&gt; cli arguments definition file&lt;/li&gt;
&lt;li&gt;Then do &lt;code&gt;go generate&lt;/code&gt; (enabled &lt;a href="https://github.com/suntong/OpenSesame/commit/af07c1acebf4002f79e57290244d1351685469ab" rel="noopener noreferrer"&gt;like this&lt;/a&gt;), or directly invoke the &lt;code&gt;_cliGen.sh&lt;/code&gt; script&lt;/li&gt;
&lt;li&gt;Finally do &lt;code&gt;go build&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/suntong/OpenSesame/commit/45c16f97da8f3aa0614a69261c347c695c13cc1b" rel="noopener noreferrer"&gt;Provide the initial OpenSesame functionality&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href="https://github.com/suntong/OpenSesame/commit/4e640c90f756d4f4c1169c9602f37a7846208d42" rel="noopener noreferrer"&gt;Update OpenSesame code to make use of the auto-generated cli wireframe&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;The auto-generated cli wireframe code are not set in stones, they can later be further amended, just like the real-world cases. For e.g.

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/suntong/OpenSesame/commit/b5e96447f7d85a5e54763b8c5108eac1f5760836" rel="noopener noreferrer"&gt;Update cli definition&lt;/a&gt; of &lt;code&gt;port&lt;/code&gt; value&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/suntong/OpenSesame/commit/177e34b3224abf84f1f27397b5d7dcce161d8aac" rel="noopener noreferrer"&gt;Update usage doc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/suntong/OpenSesame/commit/fec5406dacce680c8e7e802531d0b4aa13ed486b" rel="noopener noreferrer"&gt;Enable &lt;code&gt;UsageSummary&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;This finished a full &lt;code&gt;Initialize&lt;/code&gt; -&amp;gt; &lt;code&gt;Make use&lt;/code&gt; -&amp;gt; &lt;code&gt;More changes to cli definitions&lt;/code&gt; cycle. &lt;/p&gt;

&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%2Fi.stack.imgur.com%2FDR4wz.jpg" 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%2Fi.stack.imgur.com%2FDR4wz.jpg" alt="success"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure to check out the rest of the above quoted wiki, &lt;a href="https://github.com/go-easygen/wireframe/wiki/Command-line-flag-handling-code-auto-generation" rel="noopener noreferrer"&gt;Go command line flag handling code auto generation&lt;/a&gt;, from which you can see that using the same &lt;code&gt;.yaml&lt;/code&gt; driven file, not only the go standard &lt;code&gt;flag&lt;/code&gt; command line handling code can be automatically generated, but &lt;code&gt;viper&lt;/code&gt; and &lt;code&gt;cobra&lt;/code&gt; as well, and all the way to the full-featured cli code that can &lt;a href="https://github.com/go-easygen/wireframe/wiki/Command-line-flag-handling-code-auto-generation#priorities" rel="noopener noreferrer"&gt;set the argument values at three different levels&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;So the priority of setting the &lt;code&gt;Host&lt;/code&gt; value is, from lowest priority to the highest:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;self-config file&lt;/li&gt;
&lt;li&gt;environment variable&lt;/li&gt;
&lt;li&gt;command line&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Three different levels.&lt;/p&gt;

</description>
      <category>go</category>
      <category>cli</category>
      <category>code</category>
    </item>
    <item>
      <title>Sprint start your wechat bot with wechaty padplus</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Thu, 26 Mar 2020 04:03:42 +0000</pubDate>
      <link>https://dev.to/suntong/sprint-start-your-wechat-bot-with-wechaty-padplus-38lb</link>
      <guid>https://dev.to/suntong/sprint-start-your-wechat-bot-with-wechaty-padplus-38lb</guid>
      <description>&lt;p&gt;Almost all online chatting apps provide APIs to access their functionalities, but &lt;a href="https://en.wikipedia.org/wiki/WeChat"&gt;wechat&lt;/a&gt; is an exception. There are no official functionalities/supports on either APIs or bots. But that doesn't deter people from trying to automate those repetitive tasks in wechat with bots, all thanks to those people who had jumped through the hoops backward to provide programmable access to wechat functionalities. One of the best of such platform is &lt;a href="https://github.com/wechaty/wechaty-puppet-padplus"&gt;padplus&lt;/a&gt; under the &lt;a href="https://github.com/wechaty/wechaty-getting-started"&gt;wechaty&lt;/a&gt; framework (believe me, I know it the hard way). &lt;/p&gt;

&lt;p&gt;This article will illustrate how easy to get started with wechat bot programming using wechaty padplus. The existing documentation is already very helpful, please check out the following two if you haven't done so:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/wechaty/wechaty-getting-started"&gt;Getting started with wechaty&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/wechaty/wechaty-puppet-padplus"&gt;The readme/easy-start doc for padplus&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are very good, so what covered there will not be repeated here. Instead, we'll dive directly into practical aspect to get you hit the road and run. &lt;/p&gt;

&lt;p&gt;The padplus readme gives a generic typescript code as a guideline on how to start your script. You cannot directly run it as there are still customization you need to make before stating it( e.g., replacing the padplus &lt;code&gt;token&lt;/code&gt; with yours). To make it even more simpler, here is a code that you can grab and run right away:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;What it does is to get the padplus &lt;code&gt;token&lt;/code&gt; from the environment variable &lt;code&gt;WECHATY_PADPLUS_TOKEN&lt;/code&gt;, so all you need to do is to set it before running the script. To set and run in one step, here is how to do it under linux:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WECHATY_PADPLUS_TOKEN=puppet_padplus_xxxxx ts-node starter-padplus-bot.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N8sW9RSt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.vim-cn.com/ed/89b005e1cb960d6f145b75eca8958a7ae81bfd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N8sW9RSt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.vim-cn.com/ed/89b005e1cb960d6f145b75eca8958a7ae81bfd.png" alt="screenshot" title="screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Me personally don't like TypeScript very much. I know it is good for corporation that help preventing people from shooting themselves in the foot, but I still prefer the plain old JavaScript, the ES6 actually, as I believe with proper tools (like &lt;code&gt;eslint&lt;/code&gt;, &lt;code&gt;'use strict'&lt;/code&gt;, etc) ES6 can be a good language under the care of a &lt;em&gt;good&lt;/em&gt; programmer. The extra bell-and-whistles, and thus the extra overhead of TypeScript do not appeal to me much, as I write only for myself. &lt;/p&gt;

&lt;p&gt;If you prefer JavaScript as well, I've prepared the JavaScript version of the &lt;code&gt;starter-padplus-bot&lt;/code&gt; file (based on &lt;a href="https://github.com/wechaty/wechaty-getting-started/blob/master/examples/basic/ding-dong-bot.js"&gt;ding-dong-bot.js&lt;/a&gt;):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;As you can see it is very close to a full-fledged bot script. It&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;has the shebang so that it can be started as a command under Linux.&lt;/li&gt;
&lt;li&gt;has all the essential event handler examples&lt;/li&gt;
&lt;li&gt;has logging code builtin and ready to be used&lt;/li&gt;
&lt;li&gt;has logged all incoming message on console so that you can start dealing with them right away&lt;/li&gt;
&lt;li&gt;has interactive behavior builtin so that people can check from the wechat end to verify if the bot is alive or not&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is how to start it (under xterm, somehow I cannot get the small version of qrcode working, but only the normal sized, as shown in the picture. I think it might be a bug BTW):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SSfx5DRJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.vim-cn.com/3e/b1dc17d0c10f5e3ff320676d2f2c1572b1b6fa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SSfx5DRJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.vim-cn.com/3e/b1dc17d0c10f5e3ff320676d2f2c1572b1b6fa.png" alt="screenshot" title="screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you can automate things for wechat, the application scenarios are endless. So start automate your wechat and make it alive! &lt;/p&gt;

&lt;p&gt;And last but not least, the highlight of the whole article, if you are willing to contribute your code back to the wechaty community as open source project, you should be able to &lt;a href="https://github.com/wechaty/wechaty-puppet-padplus#notice"&gt;get a padplus token for free&lt;/a&gt; as long as you continue to contribute using many different ways including just blogging it.&lt;/p&gt;

</description>
      <category>chat</category>
      <category>bot</category>
      <category>wechat</category>
      <category>weixin</category>
    </item>
    <item>
      <title>Your favorite online chart and embedding them to dev.to</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Sat, 04 Jan 2020 14:37:00 +0000</pubDate>
      <link>https://dev.to/suntong/your-favorite-online-chart-and-embedding-them-to-dev-to-2h9o</link>
      <guid>https://dev.to/suntong/your-favorite-online-chart-and-embedding-them-to-dev-to-2h9o</guid>
      <description>&lt;p&gt;First of all, here are some links to embedding charts online:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.flex.io/blog/embed-live-refreshable-d3-js-chart-github-pages"&gt;How to Embed a Live, Refreshable D3.js Chart into GitHub Pages&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://towardsdatascience.com/how-to-create-a-plotly-visualization-and-embed-it-on-websites-517c1a78568b"&gt;How To Create a Plotly Visualization And Embed It On Websites
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="//datavizforall.org/iframe-github.html"&gt;Embed an Iframe in GitHub Pages | Data Visualization for All
&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, after carefully examining the situation, I found that we cannot do any of above here at dev.to -- my conclusion is that people are not able to embed online charts to dev.to yet, not even HTML iframes, see:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/thepracticaldev/dev.to/issues/1445"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--i3JOwpme--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg"&gt;
      &lt;span class="issue-title"&gt;
        HTML Embeds for Dev.to posts
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#1445&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/bnb"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--tXxsWrKN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars3.githubusercontent.com/u/502396%3Fv%3D4" alt="bnb avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/bnb"&gt;bnb&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/thepracticaldev/dev.to/issues/1445"&gt;&lt;time&gt;Jan 02, 2019&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;&lt;strong&gt;Describe the solution you'd like:&lt;/strong&gt;
I'd like to see HTML embeds in addition to social sharing, along the lines of how you can embed Tweets or YouTube videos with simple HTML (plus a script or iframe, respectively).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Describe alternatives you've considered:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding oembed, Embedly, etc.
&lt;ul&gt;
&lt;li&gt;Isn't viable for every site, especially not ones that I contribute to but don't own.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Hand coding a pretty embed
&lt;ul&gt;
&lt;li&gt;Not enough of a reason on the user end to do this.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Additional context:&lt;/strong&gt;
Would love to include a pretty dev.to embed in a blog post that is being posted in a couple days but unfortunately it doesn't currently exist.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/thepracticaldev/dev.to/issues/1445"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;However, charts are the most powerful way to convey ideas -- they say a picture is worth a thousand words. &lt;/p&gt;

&lt;p&gt;Hope we can have online charts in our posts soon. &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>online</category>
      <category>chart</category>
      <category>embedding</category>
    </item>
    <item>
      <title>hiccup -- Edit will always bring me back to an older version</title>
      <dc:creator>suntong</dc:creator>
      <pubDate>Sun, 21 Jul 2019 20:44:18 +0000</pubDate>
      <link>https://dev.to/suntong/hiccup-edit-will-always-bring-me-back-to-an-older-version-3had</link>
      <guid>https://dev.to/suntong/hiccup-edit-will-always-bring-me-back-to-an-older-version-3had</guid>
      <description>&lt;p&gt;Please take a look at &lt;br&gt;
&lt;a href="https://dev.to/suntong/grub4dos-to-boot-iso-disk-image-57ho"&gt;https://dev.to/suntong/grub4dos-to-boot-iso-disk-image-57ho&lt;/a&gt;&lt;br&gt;
in which there are three reference entries at the bottom. &lt;/p&gt;

&lt;p&gt;However, if I do "Edit" from that page, &lt;/p&gt;

&lt;p&gt;the reference will become my first attempt:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Ref: https://ubuntuforums.org/showthread.php?t=2398574&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Tried many times, including closing it and opening it in a new browser window, but the results are always the same.&lt;/p&gt;

&lt;p&gt;What is so special about my this post, or there is a system wise hiccup in dev.to? Thanks&lt;/p&gt;

</description>
      <category>help</category>
      <category>question</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
