<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[The Awesome Dude]]></title><description><![CDATA[Thoughts, stories and ideas of Jon Kartago Lamida]]></description><link>https://blog.lamida.org/</link><image><url>https://blog.lamida.org/favicon.png</url><title>The Awesome Dude</title><link>https://blog.lamida.org/</link></image><generator>Ghost 4.7</generator><lastBuildDate>Sun, 12 Apr 2026 21:29:57 GMT</lastBuildDate><atom:link href="https://blog.lamida.org/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Days at The Morisaki Bookshop Review]]></title><description><![CDATA[<p>Note: there will be no spoiler so feel free to read to the end of the post.</p><p>The main reason I am getting this book is because of the cover. It is so nice, looks calming, and has a strong, good anime vibe. It is just like a movie poster.</p>]]></description><link>https://blog.lamida.org/days-at-the-morisaki-bookshop-review/</link><guid isPermaLink="false">679064f05ed5fc3d8d13e70b</guid><category><![CDATA[Review]]></category><category><![CDATA[Books]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Wed, 22 Jan 2025 03:26:56 GMT</pubDate><media:content url="https://blog.lamida.org/content/images/2025/01/20250122_112212.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.lamida.org/content/images/2025/01/20250122_112212.jpg" alt="Days at The Morisaki Bookshop Review"><p>Note: there will be no spoiler so feel free to read to the end of the post.</p><p>The main reason I am getting this book is because of the cover. It is so nice, looks calming, and has a strong, good anime vibe. It is just like a movie poster. This book also introduced me to quite a few Japanese novels that seem to be booming recently. There are quite a lot of Japanese novels that have been translated into English, and they are easier to read than Haruki Murakami novels (to be honest, I only read 1Q84, and I feel it is too abstract for me).</p><p>So why do I like this book? It has a nice cover, as I mentioned above! Had the publisher or writer used a different cover, it might not have caught my eye. The book is also short and very easy to read. However, it has a sequel called &quot;More Days at Morisaki Bookshop,&quot; which I haven&apos;t read but that is also quite short. The story also doesn&apos;t have too many characters or complicated plots.</p><p>Next, the story revolves around a bookshop. I can say that one thing I want to do in my life later, if I have enough money, is to have my own cozy bookshop. Although I am not a super heavy reader, I like to hoard books and I enjoy the convenience of grabbing an interesting book anytime I want. You can visit my house to see shelves and shelves full of unread books.</p><p>I wish I could open a good bookshop in a good place with many nice collections of books. Hopefully, it can generate enough money to sustain the business too. Despite the advancement of digital media such as ebooks and, of course, short videos, which have taken over our shorter attention spans, some people, including me, still enjoy physical books. Many recent studies have also found that physical books are a better medium for focused information consumption with no distractions.</p><p>Third, the reason why I like this book is that there is some family value in the story. The novel mainly tells the relationship between the main character Takako and her uncle, Satoru. In the beginning, they are not that close. But at the end, their relationship grows closer after Takako gets to know her unconventional uncle better. Satoru has been spending his life managing the bookshop and traveling instead of living a conventional life, such as becoming a salaryman.</p><p>All in all, it was a good read that you can finish just in 2-3 hours. As an additional note, besides the rise of many Japanese novels among international readers (by having them translated into English or other languages), I also noticed there are plenty of book-themed novels. Another one that is quite popular too is &quot;The Midnight Library,&quot; which is next on my reading list.</p>]]></content:encoded></item><item><title><![CDATA[The Last 11 Years]]></title><description><![CDATA[<p>This is the story of the last 11 years. Of two people which now becomes four. Neither they are an angel nor a devil. Just human beings who continuously learn to be a better version of themselves. This is the story of me and her. This is a story to</p>]]></description><link>https://blog.lamida.org/11-years/</link><guid isPermaLink="false">6376c3df5ed5fc3d8d13e4fc</guid><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Fri, 18 Nov 2022 01:13:50 GMT</pubDate><content:encoded><![CDATA[<p>This is the story of the last 11 years. Of two people which now becomes four. Neither they are an angel nor a devil. Just human beings who continuously learn to be a better version of themselves. This is the story of me and her. This is a story to remember.</p><p>In year 0, a promise was made. For the two people to be together. As God has said: And We created pairs of all things so perhaps you would be mindful.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image.png" class="kg-image" alt loading="lazy" width="800" height="481" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image.png 600w, https://blog.lamida.org/content/images/2022/11/image.png 800w" sizes="(min-width: 720px) 720px"><figcaption>November 2011</figcaption></figure><p>Still year 0, but a bit later. Once, I said to her &#x201C;I like to go to places. To see mountains and beaches. To ride a motorbike or to drive a car. To sit in an airplane or to be a boat passenger. Previously, I go everywhere alone. From now on, do you want to go to places with me? I really want to see the world&#x201D;</p><p>She answered with a smile. An implicit reply of a yes.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-4.png" class="kg-image" alt loading="lazy" width="1200" height="1600" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-4.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-4.png 1000w, https://blog.lamida.org/content/images/2022/11/image-4.png 1200w" sizes="(min-width: 720px) 720px"><figcaption>Malang - 24 January 2012</figcaption></figure><p>Year 1 . She went to study in a faraway country. She likes to send presents even when she is away. Not like the ignorant me. In year 1, the flower and the cake accompany me, celebrating our first anniversary. She was in Germany. I was in Singapore here. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-8.png" class="kg-image" alt loading="lazy" width="816" height="612" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-8.png 600w, https://blog.lamida.org/content/images/2022/11/image-8.png 816w" sizes="(min-width: 720px) 720px"><figcaption>Singapore - 19 November 2012</figcaption></figure><p>Year 1 continues. From time to time, we would meet. We still liked to go to places. Maybe just crossing to another island from Singapore. To find good foods to eat or just to see the city. After short meet we will be away again until another couple of months gap.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-10.png" class="kg-image" alt loading="lazy" width="2000" height="2667" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-10.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-10.png 1000w, https://blog.lamida.org/content/images/size/w1600/2022/11/image-10.png 1600w, https://blog.lamida.org/content/images/size/w2400/2022/11/image-10.png 2400w" sizes="(min-width: 720px) 720px"><figcaption>Batam - 14 September 2013</figcaption></figure><p>The year 2 anniversary was coming. We were still not in the same place. She wrote me another beautiful note and a present.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-9.png" class="kg-image" alt loading="lazy" width="816" height="612" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-9.png 600w, https://blog.lamida.org/content/images/2022/11/image-9.png 816w" sizes="(min-width: 720px) 720px"><figcaption>Singapore - 19 November 2013</figcaption></figure><p>Yes, she is also the greatest thing that happened in my life.</p><p>Year 2 continues. It was hard to be away. We then made a plan. As she finished her degree, I told her. &quot;Let&apos;s see the world now. Let&apos;s go to the country we haven&apos;t gone to before. Let&apos;s see the city we haven&apos;t seen before.&quot; </p><p>Off we go. &#xA0;We went to Frankfurt, Brussels, Amsterdam, Oslo, Bergen, Stockholm, Helsinki, Tallin, Riga, Prague, Budapest, Rome, Venice, Barcelona, and Paris. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-11.png" class="kg-image" alt loading="lazy" width="768" height="1366" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-11.png 600w, https://blog.lamida.org/content/images/2022/11/image-11.png 768w" sizes="(min-width: 720px) 720px"><figcaption>Paris - 26 February 2014</figcaption></figure><p>It was year 3. We were together again. No more long-distance calls. No more annoyance due to different time zones. We were building our life in Lion city.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-12.png" class="kg-image" alt loading="lazy" width="1032" height="581" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-12.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-12.png 1000w, https://blog.lamida.org/content/images/2022/11/image-12.png 1032w" sizes="(min-width: 720px) 720px"><figcaption>19 November 2014 - Singapore</figcaption></figure><p>Year 4. &quot;Let&apos;s see down under&quot;. I asked her. &quot;Let&apos;s drive from Sydney to Melbourne, then go to Great Ocean Road, and then back to Sydney again via Canberra. Let&apos;s drive the biggest car we can get. Let&apos;s sleep and camp in the car. Let&apos;s stop in many good places.&quot;</p><p>&quot;Sure, let&apos;s go.&quot; She said. An explicit reply of a yes.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-13.png" class="kg-image" alt loading="lazy" width="1228" height="690" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-13.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-13.png 1000w, https://blog.lamida.org/content/images/2022/11/image-13.png 1228w" sizes="(min-width: 720px) 720px"><figcaption>19 November 2015 - Sydney</figcaption></figure><p>Year 5. She likes to eat sushi. Sometimes we will cross to the north of the country and stay for one night in a good hotel. We shop, we eat and we go back down to Singapore.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-14.png" class="kg-image" alt loading="lazy" width="640" height="480" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-14.png 600w, https://blog.lamida.org/content/images/2022/11/image-14.png 640w"><figcaption>Johor - 19 November 2016</figcaption></figure><p>Year 5 continues. She asked, &quot;We have been only two for these years. Let&apos;s go on a pilgrimage journey.&quot;</p><p>I said, &quot;Yes we definitely should go and pray for even more asks. Let&apos;s ask The All-Mighty for all of our wishes. Pray for forgiveness for all of our mistakes. Pray for beautiful and righteous children. Pray for good wealth that brings peace. Pray for sharp minds and warm hearts for us. Pray for a long healthy life. Pray to be a good person with a good life.&quot;</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-16.png" class="kg-image" alt loading="lazy" width="756" height="1008" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-16.png 600w, https://blog.lamida.org/content/images/2022/11/image-16.png 756w" sizes="(min-width: 720px) 720px"><figcaption>Mecca - 21 December 2016</figcaption></figure><p>Year 5 was a long year. Not long after the pilgrimage journey, she was expecting. Unfortunately, the baby was never born. We were still just two. It was a sad year.</p><p>I asked her, &quot;Let&apos;s go on a camping trip to a side of a lake. It&apos;s gonna be expensive but perhaps it can cover sad memories with some sweet memories.&quot; </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-15.png" class="kg-image" alt loading="lazy" width="1228" height="690" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-15.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-15.png 1000w, https://blog.lamida.org/content/images/2022/11/image-15.png 1228w" sizes="(min-width: 720px) 720px"><figcaption>Lake Pukaki - 10 May 2017</figcaption></figure><p>Year 5 was a long year, but eventually, it seemed to turn into something good. Another baby was coming. &quot;Will we become three after this?&quot; I was wondering.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-17.png" class="kg-image" alt loading="lazy" width="1008" height="756" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-17.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-17.png 1000w, https://blog.lamida.org/content/images/2022/11/image-17.png 1008w" sizes="(min-width: 720px) 720px"><figcaption>Singapore - 30 September 2017</figcaption></figure><p>Year 6 plus. Yes, we became three. It was a girl. We named her A.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-18.png" class="kg-image" alt loading="lazy" width="1008" height="756" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-18.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-18.png 1000w, https://blog.lamida.org/content/images/2022/11/image-18.png 1008w" sizes="(min-width: 720px) 720px"><figcaption>Singapore - January 2018</figcaption></figure><p>Year 7. We still continue to go to places. We like to eat different foods and go to different cities. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-19.png" class="kg-image" alt loading="lazy" width="1600" height="1200" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-19.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-19.png 1000w, https://blog.lamida.org/content/images/2022/11/image-19.png 1600w" sizes="(min-width: 720px) 720px"><figcaption>Singapore - 19 November 2018</figcaption></figure><p>Year 8. &quot;Let&apos;s go to the down under again with the little girl.&quot; I asked. No need for any reply. Both the girls agreed. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-20.png" class="kg-image" alt loading="lazy" width="1008" height="567" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-20.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-20.png 1000w, https://blog.lamida.org/content/images/2022/11/image-20.png 1008w" sizes="(min-width: 720px) 720px"><figcaption>Somewhere near Brisbane - 19 November 2019</figcaption></figure><p>Year 9. It was a strange year. It was a year when many people are locked in their houses. Many unfortunate souls were taken on during these times. Families separated away in different countries and cities.</p><p>We and our family were more than grateful to be spared. We hope so much the pandemi will finally be really ended. No more face need to be masked or excessive hand sanitizer to be applied.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-21.png" class="kg-image" alt loading="lazy" width="1008" height="567" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-21.png 600w, https://blog.lamida.org/content/images/size/w1000/2022/11/image-21.png 1000w, https://blog.lamida.org/content/images/2022/11/image-21.png 1008w" sizes="(min-width: 720px) 720px"><figcaption>Singapore - 19 November 2020</figcaption></figure><p>It is still year 9 of us being together. We waited 6 years to get the little girl. We were not putting too much hope in another little soul. But he was coming at the beginning of October. We now became four. We named the boy R.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-22.png" class="kg-image" alt loading="lazy" width="579" height="772"><figcaption>Singapore - October 2021</figcaption></figure><p>It is a decade together. 10 years. Like a blink of an eye. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-23.png" class="kg-image" alt loading="lazy" width="772" height="579" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-23.png 600w, https://blog.lamida.org/content/images/2022/11/image-23.png 772w" sizes="(min-width: 720px) 720px"><figcaption>Singapore - 19 November 2021</figcaption></figure><p>Year 10 is also the year we finally got our own shelter. Somewhere we really can call home. The place to raise our two little souls. The place where warm memories collected and infinite dreams materialized. A part of the wealth that we hope can bring peace to our hearts and minds. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-25.png" class="kg-image" alt loading="lazy" width="1000" height="563" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-25.png 600w, https://blog.lamida.org/content/images/2022/11/image-25.png 1000w" sizes="(min-width: 720px) 720px"><figcaption>Singapore - 10 July 2022</figcaption></figure><p>Finally, year 11 is here. It was just like yesterday when the two rings were ordered from the shop and a vow was declared. </p><p>From one becomes two. From two becomes three. From three then now we are four. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.lamida.org/content/images/2022/11/image-24.png" class="kg-image" alt loading="lazy" width="992" height="558" srcset="https://blog.lamida.org/content/images/size/w600/2022/11/image-24.png 600w, https://blog.lamida.org/content/images/2022/11/image-24.png 992w" sizes="(min-width: 720px) 720px"><figcaption>Melaka - 21 August 2022</figcaption></figure><p>The last 11 years was beautiful. I wish the next many years to come will be even more beautiful. </p><p>Happy 11 years anniversary to the person I feel is closest to me, more than anyone.</p><p>Brussels, 18 November 2022.</p>]]></content:encoded></item><item><title><![CDATA[LLVM dot-callgraph generates output dotfiles outside of the current directory]]></title><description><![CDATA[<p>LLVM dot-callgraph is one of the LLVM passes that will generate dot files of the program graph. Apart from dot-callgraph, there are also the following passes:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>dot pass name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>dot-callgraph</td>
<td>Print call graph to &apos;dot&apos; file</td>
</tr>
<tr>
<td>dot-cfg</td>
<td>Print CFG of function to &apos;dot&apos; file</td>
</tr>
<tr>
<td>dot-cfg-only</td></tr></tbody></table>]]></description><link>https://blog.lamida.org/llvm-dot-callgraph-generates-output-dotfiles-not-in-the-current-directory/</link><guid isPermaLink="false">60d2a78d2078021b4257cfc2</guid><category><![CDATA[llvm]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Wed, 23 Jun 2021 03:54:01 GMT</pubDate><content:encoded><![CDATA[<p>LLVM dot-callgraph is one of the LLVM passes that will generate dot files of the program graph. Apart from dot-callgraph, there are also the following passes:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>dot pass name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>dot-callgraph</td>
<td>Print call graph to &apos;dot&apos; file</td>
</tr>
<tr>
<td>dot-cfg</td>
<td>Print CFG of function to &apos;dot&apos; file</td>
</tr>
<tr>
<td>dot-cfg-only</td>
<td>Print CFG of function to &apos;dot&apos; file (with no function bodies)</td>
</tr>
<tr>
<td>dot-dom</td>
<td>Print dominance tree of function to &apos;dot&apos; file</td>
</tr>
<tr>
<td>dot-dom-only</td>
<td>Print dominance tree of function to &apos;dot&apos; file (with no function bodies)</td>
</tr>
<tr>
<td>dot-postdom</td>
<td>Print postdominance tree of function to &apos;dot&apos; file</td>
</tr>
<tr>
<td>dot-postdom-only</td>
<td>Print postdominance tree of function to &apos;dot&apos; file (with no function bodies)</td>
</tr>
<tr>
<td>dot-regions</td>
<td>Print regions of function to &apos;dot&apos; file</td>
</tr>
<tr>
<td>dot-regions-only</td>
<td>Print regions of function to &apos;dot&apos; file (with no function bodies)</td>
</tr>
<tr>
<td>dot-scops</td>
<td>Polly - Print Scops of function</td>
</tr>
<tr>
<td>dot-scops-only</td>
<td>Polly - Print Scops of function (with no function bodies)</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>I just noticed today that in LLVM 13, dot callgraph is generating the output in the location of the IR ll files instead of the in the current directory. However, all other dot-* passes are still generating the dot files in the current directory. Hence this is an inconsistent behaviour which should be fixed, in my opinion. The changes must be happening between version 10 and 13. I will try to look where and how the changes happen.</p><p>This is the output from LLVM 13.</p><figure class="kg-card kg-image-card"><img src="https://blog.lamida.org/content/images/2021/06/image-1.png" class="kg-image" alt loading="lazy" width="705" height="175" srcset="https://blog.lamida.org/content/images/size/w600/2021/06/image-1.png 600w, https://blog.lamida.org/content/images/2021/06/image-1.png 705w"></figure><p>This is the output from LLVM 10.</p><figure class="kg-card kg-image-card"><img src="https://blog.lamida.org/content/images/2021/06/image-2.png" class="kg-image" alt loading="lazy" width="668" height="202" srcset="https://blog.lamida.org/content/images/size/w600/2021/06/image-2.png 600w, https://blog.lamida.org/content/images/2021/06/image-2.png 668w"></figure>]]></content:encoded></item><item><title><![CDATA[Register xdg-open for xdot in WSL]]></title><description><![CDATA[<p>I have been using <a href="https://llvm.org/">LLVM </a>control-flow graph (CFG) pass for my static analysis research. Normally, I should be able to see the CFG of the <a href="https://llvm.org/docs/LangRef.html">intermediate representation of the program (IR)</a> by running:</p><pre><code>opt file.ll -passes=view-cfg</code></pre><p>Instead of opening xdot that will view the CFG, opt opened Google</p>]]></description><link>https://blog.lamida.org/register-xdg-open-for-xdot/</link><guid isPermaLink="false">60cfc2f42078021b4257cf1a</guid><category><![CDATA[llvm]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Sun, 20 Jun 2021 23:12:55 GMT</pubDate><content:encoded><![CDATA[<p>I have been using <a href="https://llvm.org/">LLVM </a>control-flow graph (CFG) pass for my static analysis research. Normally, I should be able to see the CFG of the <a href="https://llvm.org/docs/LangRef.html">intermediate representation of the program (IR)</a> by running:</p><pre><code>opt file.ll -passes=view-cfg</code></pre><p>Instead of opening xdot that will view the CFG, opt opened Google Chrome and downloaded the file. Previously I just work around this by using the dot-cfg pass and then run xdot manually.</p><pre><code>opt file.ll -passes=dot-cfg</code></pre><p>However, I am getting curious this morning because I want to reduce the additional step of generating dot files and running xdot. Apparently, the issue must be around mime typing. This is also might be caused by I am running the view-cfg pass inside WSL which doesn&apos;t have a desktop environment, instead of full Linux distribution, hence the mime typing is not handled automatically. I have configured the X server so the issue is not because xdot won&apos;t open. In fact, chrome can open easily and I also have been using different Jebtrains IDE from my WSL. There is plenty of guide in the internet for anyone who want to run desktop from WSL.</p><p>The terminal programs, such as opt, will open desktop applications using xdg-open. xdg-open decides which program to open using the mime type. First, I want to see what is the mime type of the dot file is identified by xdg-open.</p><pre><code>$ xdg-mime query filetype .main.dot
application/text</code></pre><p>It is clear now the reason why xdg-open decided to open Chrome. It might be a fallback for any application/text file.</p><p>Next, I will need to register xdot as a desktop application that will handle *.dot file. We can do it by adding desktop in a new file under <code>~/.local/share/applications/xdot.desktop</code>. I am getting this guide from <a href="http://chenyuanfang.blogspot.com/2016/03/use-xdg-open-to-open-file.html">this blog</a>.</p><pre><code>[Desktop Entry]                                                               
Name=Xdot                                                                     
Exec=/usr/bin/xdot                                                            
MimeType=text/vnd.graphviz                                                     
Type=Application</code></pre><p>However, we still need one more additional step. Which is to register that *.dot file will be having <code>text/vnd.graphviz</code> mime. Following the guide <a href="https://github.com/frasercrmck/dotfiles/blob/master/howtos/dot-mimetype.md">here</a>, we need to install <code>libfile-mimeinfo-perl</code>. Then add the following file in <code>/usr/share/mime/packages/xdot.xml</code>.</p><pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;mime-info xmlns=&quot;http://www.freedesktop.org/standards/shared-mime-info&quot;&gt;
  &lt;mime-type type=&quot;text/vnd.graphviz&quot;&gt;
    &lt;glob weight=&quot;100&quot; pattern=&quot;*.dot&quot;/&gt;
  &lt;/mime-type&gt;
&lt;/mime-info&gt;</code></pre><p>Then, we run <code>update-mime-database /usr/share/mime</code> and check again the mime type.</p><pre><code>$ xdg-mime query filetype .main.dot
text/vnd.graphviz
</code></pre><p>It is working now. Last, we will run <code>view-cfg</code> pass again.</p><pre><code>opt file.ll -passes=view-cfg</code></pre><figure class="kg-card kg-image-card"><img src="https://blog.lamida.org/content/images/2021/06/image.png" class="kg-image" alt loading="lazy" width="1453" height="1380" srcset="https://blog.lamida.org/content/images/size/w600/2021/06/image.png 600w, https://blog.lamida.org/content/images/size/w1000/2021/06/image.png 1000w, https://blog.lamida.org/content/images/2021/06/image.png 1453w" sizes="(min-width: 720px) 720px"></figure><p>There is &quot;800 permission denied error&quot; that appeared in the terminal. But I decided to ignore it because at least the xdot can open the dot file now.</p>]]></content:encoded></item><item><title><![CDATA[How not to procrastinate in 3 steps]]></title><description><![CDATA[<p>I often always be intimidated by my to-do list. Usually, I procrastinate, hoping post deferments I will feel better and can finish the task. It is a silly thing to do because deferment will make me feel much more horrible. I know what the issue is and how to work</p>]]></description><link>https://blog.lamida.org/how-not-to-procrastinate-in-3-steps/</link><guid isPermaLink="false">5fb41d3bd8a5b22a204bbaf7</guid><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Tue, 17 Nov 2020 19:34:41 GMT</pubDate><media:content url="https://blog.lamida.org/content/images/2020/11/karim-manjra-dtSCKE9-8cI-unsplash.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://blog.lamida.org/content/images/2020/11/karim-manjra-dtSCKE9-8cI-unsplash.jpg" alt="How not to procrastinate in 3 steps"><p>I often always be intimidated by my to-do list. Usually, I procrastinate, hoping post deferments I will feel better and can finish the task. It is a silly thing to do because deferment will make me feel much more horrible. I know what the issue is and how to work around it. But procrastination is always on the way and is still my default reaction.</p><p>Tackling procrastination are obvious yet not so obvious. Enough <a href="https://hn.algolia.com/?q=procrastinate">articles </a>are discussing procrastination. I put my pieces here, which some based on those existing ideas in countless articles and books. So here we go, the steps on how not to procrastinate, so that I can always refer back here if any of my current or future tasks resort to procrastination.</p><ol><li>Eat the elephant, split big tasks into smaller</li><li>Write first awful draft and iterate</li><li>Beat the resistance by just starting out</li></ol><h2 id="eat-the-elephant">Eat The Elephant</h2><p>Eat the elephant is the first step. Many tasks feel big because... it is big. Split it into manageable chunks. As one person working in software industries for more than a decade, this should be natural for me. One starts with writing <a href="https://en.wikipedia.org/wiki/User_story">a story</a>. Then define tasks to accomplish the story. Define subtasks if needed. The intuition is, an elephant is too big. You can&apos;t eat it in one swallow. But it will be edible if you eat piece by piece where you can chew it chunk by chunk. </p><p>Example: writing a thesis. The one task that I am starting. It is so big&#x2014;so many tasks. I am beginning frozen. I don&apos;t know what to do first. Break the ideas of the tasks as a starter. I am starting again to use mindmap recently, and it is quite helpful in breaking up ideas and actions to take. I use <a href="http://gitmind.com/">gitmind</a>, the best of a few I have tried. Following is the very first version of my thesis mindmap. It is still big, but I can see the manageable chunks, which I can try to chew bit by bit.</p><figure class="kg-card kg-image-card"><img src="https://blog.lamida.org/content/images/2020/11/image.png" class="kg-image" alt="How not to procrastinate in 3 steps" loading="lazy"></figure><p>As additional note, in conventional school, an advisor will give you manageable milestones that help you further in eating the elephant.</p><h2 id="write-the-first-awful-first-version-draft">Write The First Awful First Version Draft</h2><p>This idea is not always necessary only about writing. I often want to procrastinate because I keep hoping that I will continuously produce an excellent first version. First version awesome blog post. First version great software piece. I wish I can always create something amazing all the time, but I feel that it shouldn&apos;t be the case. I believe even some great people wouldn&apos;t always produce a masterpiece. That&apos;s why they call it a masterpiece. If a masterpiece is all over, we will not call it a masterpiece anymore.</p><p>In an article about writing that I don&apos;t remember which one is, it tells to aim to write awful writing once a day. Or, in other words, write a daily crappy writing. Accept the fact that your first output will most probably always be awful. However, do iteration based on a feedback loop. See what went well, and keep it up. See what can be improved and make small chunks of improvement. The more you do it, your first draft wouldn&apos;t be so awful anymore.</p><p>One example is this blog post. This is the first time I am writing directly in the Ghost editor without overthinking how awful my post will be. I just want to write points to clarify my thoughts to refer to again in the future.</p><h2 id="beat-the-resistance">Beat The Resistance</h2><blockquote>&#x201C;If you find yourself asking yourself (and your friends), &quot;Am I really a writer? Am I really an artist?&quot; chances are you are. The counterfeit innovator is wildly self-confident. The real one is scared to death.&#x201D;&#x2015; Steven Pressfield, The War of Art: Break Through the Blocks &amp; Win Your Inner Creative Battles</blockquote><p>Even after understanding and accepting your first version (be it writing, software, work in progress task) will be awful. You need to start. To start, you need to beat what Steven Pressfield called resistance. How to beat resistance? Just start. Yes, this is cyclic. To break the cycle, you just need to start.</p><p>According to many procrastination books (sorry, I can&apos;t quote because I don&apos;t remember the specific reference), anticipating to start a task often much more difficult than actually starting the task itself.</p><p>For example, I have been procrastinating my <a href="https://istd.sutd.edu.sg/courses/mssd/machine-learning/">Machine Learning</a> homework that dues tomorrow because I just feel not good about starting for multiple reasons. I still don&apos;t understand most of the concepts in the past three lectures. I wish I can start after I know all of them. This blog post is one way for me to defer myself from doing my homework. I am pretty sure that once I start, it won&apos;t be so bad.</p><h2 id="sometime-you-just-need-to-procrastinate">Sometime You Just Need to Procrastinate</h2><p>This statement is based on a conversation with my friend. He has done his PhD and advice on tackling procrastination from PhD is always the best one.</p><blockquote>Productivity is a wave! Don&apos;t feel guilty when you are in an antinode and take care of your wellbeing when you are in a node!</blockquote><p>That&apos;s what he said referring to this twitter post.</p><!--kg-card-begin: html--><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Productivity as wave. We often think people are doing much better than us. Spoiler alert&#x26A0;&#xFE0F;: they aren&apos;t - their wave is probably out of phase of our own.<br><br>We need to make sure to be kind to ourselves, and not compare ourselves with others.<a href="https://twitter.com/hashtag/AcademicMentalHealth?src=hash&amp;ref_src=twsrc%5Etfw">#AcademicMentalHealth</a> <a href="https://twitter.com/hashtag/AcademicChatter?src=hash&amp;ref_src=twsrc%5Etfw">#AcademicChatter</a> <a href="https://t.co/COgjFlGTOu">pic.twitter.com/COgjFlGTOu</a></p>&#x2014; Dr Zo&#xEB; Ayres (@ZJAyres) <a href="https://twitter.com/ZJAyres/status/1280536086322786304?ref_src=twsrc%5Etfw">July 7, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script><!--kg-card-end: html--><p>So there is a time when one will feel not good to start. Don&apos;t feel guilty too much about it. But don&apos;t wait for the perfect starting time. Just try to start, even if you feel good a bit. It wouldn&apos;t be so bad once you start.</p><p>Post image is taken from <a href="https://unsplash.com/photos/dtSCKE9-8cI">here</a>.</p>]]></content:encoded></item><item><title><![CDATA[Python Coding Workflow]]></title><description><![CDATA[<p>So far, I have never been using Python too much. However, I always want to understand it in and out for every day uses such as quick prototyping and complex scripting. Python is used a lot in some domain such as machine learning. Python has many libraries in different domains</p>]]></description><link>https://blog.lamida.org/python-coding-workflow/</link><guid isPermaLink="false">5e31ad1b887f98036501abb1</guid><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Wed, 29 Jan 2020 16:14:02 GMT</pubDate><content:encoded><![CDATA[<p>So far, I have never been using Python too much. However, I always want to understand it in and out for every day uses such as quick prototyping and complex scripting. Python is used a lot in some domain such as machine learning. Python has many libraries in different domains as well. When I took cryptography course I also use Python with it excellent <a href="https://pycryptodome.readthedocs.io/en/latest/">pycryptodome</a> library.</p><p>This post is a reference that I will use the typical workflow when you want to code in python. </p><h2 id="version">Version</h2><p>Which python version to use? My quick answer is focus on Python 3 and forget Python 2.</p><h2 id="editor-ide">Editor/IDE</h2><p>I am using vim so far. But I have never optimised the editor usage by installing plugins that can improve productivity. As a comparison, I am very comfortable writing Golang using vim-go and writing Java or Kotlin using Intellij Idea. However, I am still not finding ideal setup for Python.</p><h2 id="package-manager">Package Manager</h2><p>By default python will install library to its system folder. Therefore it will be difficult if we need to use different libraries with conflicting dependencies. The easy solution is pipenv.</p><p>In MacOS, we can install it easy using brew.</p><!--kg-card-begin: markdown--><pre><code>brew install pipenv
</code></pre>
<!--kg-card-end: markdown--><p>Once pipenv installed, we just need to navigate to working directory that we want to use. For example, we want to install pandas.</p><!--kg-card-begin: markdown--><pre><code>pipenv install pandas
</code></pre>
<!--kg-card-end: markdown--><p>pipenv will install pandas library locally. Next we just need to invoke shell command so that python script or python shell will run in the pipenv context.</p><!--kg-card-begin: markdown--><pre><code>pipenv shell
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Enabling MathJax in Ghost]]></title><description><![CDATA[<p>This short post will share of how to enable <a href="https://www.mathjax.org">MathJax</a> in Ghost blog. MathJax is Javascript display engine to render mathematics equation. The equation is written using LaTex syntax.</p><p>The only setup that we have to do is to load MathJax script in all pages of our blog. In Ghost</p>]]></description><link>https://blog.lamida.org/enabling-mathjax-in-ghost/</link><guid isPermaLink="false">5db1a4b6887f98036501aba6</guid><category><![CDATA[mathjax]]></category><category><![CDATA[latex]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Thu, 24 Oct 2019 13:29:20 GMT</pubDate><content:encoded><![CDATA[<p>This short post will share of how to enable <a href="https://www.mathjax.org">MathJax</a> in Ghost blog. MathJax is Javascript display engine to render mathematics equation. The equation is written using LaTex syntax.</p><p>The only setup that we have to do is to load MathJax script in all pages of our blog. In Ghost that setup can be done from Code Injection menu as can be seen below.</p><figure class="kg-card kg-image-card"><img src="https://blog.lamida.org/content/images/2019/10/Screen-Shot-2019-10-24-at-9.23.11-PM.png" class="kg-image" alt loading="lazy"></figure><p>The code to be injected will be as follow. Or else just go to MathJax documentation to refer to the latest way of injecting the script.</p><!--kg-card-begin: markdown--><pre><code>&lt;script src=&quot;https://polyfill.io/v3/polyfill.min.js?features=es6&quot;&gt;&lt;/script&gt;
&lt;script id=&quot;MathJax-script&quot; async src=&quot;https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js&quot;&gt;&lt;/script&gt;
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Let&apos;s enter this sample code that will render quadratic equation formula.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><pre><code>&lt;p&gt;
  When \(a \ne 0\), there are two solutions to \(ax^2 + bx + c = 0\) and they are
  \[x = {-b \pm \sqrt{b^2-4ac} \over 2a}.\]
&lt;/p&gt;

</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><p>Following is how the above latex script will be rendered.</p>
<!--kg-card-end: markdown--><!--kg-card-begin: html--><p>
  When \(a \ne 0\), there are two solutions to \(ax^2 + bx + c = 0\) and they are
  \[x = {-b \pm \sqrt{b^2-4ac} \over 2a}.\]
</p>
<!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Multi Machine Setup in Vagrant]]></title><description><![CDATA[<h1 id="vagrant-is-tools-to-automate-development-and-testing-environment-it-helps-to-setup-virtual-machines-from-declarative-configuration-file-sometime-ago-i-wrote-a-very-quick-introduction-about-vagrant-this-post-will-go-further-by-explaining-how-to-setup-multiple-vms-">Vagrant is tools to automate development and testing environment. It helps to setup virtual machines from declarative configuration file. Sometime ago I wrote a very quick <a href="https://blog.lamida.org/vagrant-in-5-minutes/">introduction about vagrant</a>. This post will go further by explaining how to setup multiple VMs.</h1><h2 id="what-is-the-problem">What is The Problem?</h2><p>Why we need to bother</p>]]></description><link>https://blog.lamida.org/multi-machine-in-vagrant/</link><guid isPermaLink="false">5d183f9e00d8210c018789bd</guid><category><![CDATA[vagrant]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Sun, 30 Jun 2019 05:04:14 GMT</pubDate><content:encoded><![CDATA[<h1 id="vagrant-is-tools-to-automate-development-and-testing-environment-it-helps-to-setup-virtual-machines-from-declarative-configuration-file-sometime-ago-i-wrote-a-very-quick-introduction-about-vagrant-this-post-will-go-further-by-explaining-how-to-setup-multiple-vms-">Vagrant is tools to automate development and testing environment. It helps to setup virtual machines from declarative configuration file. Sometime ago I wrote a very quick <a href="https://blog.lamida.org/vagrant-in-5-minutes/">introduction about vagrant</a>. This post will go further by explaining how to setup multiple VMs.</h1><h2 id="what-is-the-problem">What is The Problem?</h2><p>Why we need to bother setting up multiple VMs? In today software development world, most system is deployed as part of distributed systems. The simplest form is two tier monolith service and data store. However, nowadays people have been breaking down the monolith into multiple microservices. Put also into the equation that some integration point is being setup asynchronously using various kind of messaging or log system. Also since data is so ubiquitous, we have big data processing infrastructures either using batch or streaming. I always excited of how the things work in that distributed systems setup. We can learn and investigate the characteristic of those distributed systems in our local computer. It is cheaper than if spawn the same instance in the cloud provider.</p><p>We will do step by step process of having the multi machine setup. The complete Vagrantfile configuration can be downloaded in <a href="https://github.com/lamida/notebook/blob/master/vagrant/Vagrantfile">my github</a>.</p><h2 id="step-0-setup">Step 0: Setup</h2><p>We only need two applications in setting up multiple VMs in local guest operating system:</p><ul><li>VM provider such as VirtualBox</li><li>Vagrant to automate the provisioning of the VMs</li></ul><h2 id="step-1-create-vagrantfile">Step 1: Create Vagrantfile</h2><p>We can use <code>vagrant init</code> command that will generate default file with many configuration example. Or we can just create a new empty <code>Vagrantfile</code>. Let&apos;s add this first content:</p><pre><code>Vagrant.configure(&quot;2&quot;) do |config|
  # setup and provisioning will be added here
end
</code></pre><p>Vagrantfile is written in Ruby. Underestanding Ruby will help but not mandatory, unless we want to make complex customisation or provisioning. Vagrantfile will start with the configure method. <code>&quot;2&quot;</code> in the configure argument is the vagrant configuration version. I don&apos;t see any reason why we want to use version other than 2. The configuration will pass the <code>config</code> object in the lambda argument.</p><h2 id="step-2-configure-provider-setting">Step 2: Configure provider setting</h2><pre><code>config.vm.provider &quot;virtualbox&quot; do |v|
  v.memory = 256
end
</code></pre><p>We might want to limit the VMs hardware resource just to make sure it doesn&apos;t overwhelme the host operating system. In the configuration above, we limit the VM RAM to 256MB.</p><h2 id="step-3-create-a-single-machine">Step 3: Create a single machine</h2><pre><code>config.vm define &quot;box_1 do |box|
  box.vm.box = &quot;ubuntu/bionic64&quot;
  box.vm.network &quot;private_network&quot;, ip: &quot;192.168.51.1&quot;
  box.vm.provision &quot;shell&quot;, inline: &quot;echo &apos;hello world&apos;&quot;
end
</code></pre><p>We are creating one VM box with that given IP and box type passed to <code>box.vm.box</code> variable. We are setting the network to private and pass the static ip address in the ip argument. In the provision part we are passing a simple shell inline script that just echoing &quot;hello world&quot;.</p><h2 id="step-4-create-multiple-machines">Step 4: Create multiple machines</h2><pre><code>box_name = &quot;ubuntu/bionic64&quot;

base_ip = 100
base_ip_addresses = &quot;192.168.51&quot;

ip_addresses = (1..number_of_machines).map{ |i| &quot;#{base_ip_addresses}.#{base_ip + i}&quot; }

script = &lt;&lt;-SCRIPT
  echo &quot;hello world&quot;
SCRIPT

config.vm.provider &quot;virtualbox&quot; do |v|
  v.memory = 256
end

(1..number_of_machines).each do |i|
  config.vm.define &quot;box_#{i}&quot; do |box|
    box.vm.box = box_name
    box.vm.network &quot;private_network&quot;, ip: &quot;#{ip_addresses[i-1]}&quot;

    box.vm.provision &quot;shell&quot;, inline: &quot;#{script}&quot;
  end
end

</code></pre><p>The configuration of multiple machine is just the extension from the single machine setup. Fundamentally we are just looping the configuration to the number of machine that we want to create.</p><p>In the Vagrantfile fragment above, the only dynamic configuration for each machine is we want to make sure no machine has the same IP address conflict. The easy way we can just use dhcp. But we want to know the IP for each machine in a static way, hence we generate the IP address by enumerating it based on how many devices we want to create. In this example we will start with starting address of <code>192.168.58.100</code>. Since we want to make two boxes, therefore we assign <code>192.168.58.101</code> to the first box and <code>192.168.58.102</code> to the second box.</p><h2 id="step-5-customize-the-provisioning">Step 5: Customize the provisioning</h2><p>When provisioning the box for the first time, there might be a need to configure some initial setup. Such as installing apps or copying files. Vagrant provide different provisioners such as shell as the simplest to using Ansible. In this example we are just echoing &quot;hello world&quot; when the box is provisioned.</p><p>Once more, the complete of Vagrantscript from this post is available <a href="https://github.com/lamida/notebook/blob/master/vagrant/Vagrantfile">here</a>.</p><p>Then the last step concludes this post. I am pretty sure will use this post when exploring clustering configuration for some distributed system out there.</p>]]></content:encoded></item><item><title><![CDATA[Go Modules in Action]]></title><description><![CDATA[<p>In Golang there was no official approach of how to manage dependency. Hence, in the early days of golang until recently, there were different ways in managing dependencies. In the beginning there is go get. It help to download package from the internet to your local directory which can be</p>]]></description><link>https://blog.lamida.org/go-modules-in-action/</link><guid isPermaLink="false">5cdf745200d8210c018789ad</guid><category><![CDATA[golang]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Sun, 19 May 2019 15:19:06 GMT</pubDate><content:encoded><![CDATA[<p>In Golang there was no official approach of how to manage dependency. Hence, in the early days of golang until recently, there were different ways in managing dependencies. In the beginning there is go get. It help to download package from the internet to your local directory which can be imported into your source code. Go get doesn&apos;t have any knowledge of version. It is always try to download the latest. Then, there are some attempts to manage dependency such as glide, dep and some others. Dep is an official proof of concept where go core team try to find the best solution of managing dependencies. Glide and dep after all are very similar with other package manager in different platform such as npm, cargo and also pipenv. But at the end, go module, which started as proof of concept vgo, comes as the official dependency management tool for Golang. </p><p>There was a time when I was slightly feel annoyed with Golang introducing different approaches of dependency management in very short period of time. I was starting a project using glide. Then I migrated it to dep, because I was told, it is the official approach. Only then I learned, go moved to go module. It only makes sense after I watched very clear explanation of <a href="https://www.youtube.com/watch?v=F8nrpe0XWRg">Russ Cox in Gophercon 2018</a>. The reason of introducing go module is to have build tool with this principles:</p><ol><li>Compatibility</li><li>Repeatability</li><li>Cooperation</li></ol><p>Russ Cox &#xA0;has also written <a href="https://research.swtch.com/vgo">multiple blog posts</a> in elaborating the arguments which culminate in the <a href="https://blog.golang.org/using-go-modules">official blog post</a> in the Golang blog. </p><p>This blog post doesn&#x2019;t try to repeat what that has clearly explained in documentation, the original blog post and Russ Cox&apos;s blog and video. I just want to synthesize my understanding and try to give personal example so that I can internalize the reason and understand how go module works. Go module has preliminary support </p><h2 id="dependency">Dependency </h2><p>In the beginning your code will be simple without any 3rd party dependencies.</p><!--kg-card-begin: markdown--><pre><code>// main.go
package main

import (
  &quot;fmt&quot;
)

func main() {
  fmt.Println(greet())
}

func greet() string {
  return &quot;Hello World&quot;
}
</code></pre>
<!--kg-card-end: markdown--><p>&#x200C;Now let&apos;s extract this simple functionality into its own package within the same source three. The structure will be look like following.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo $ tree
.
&#x251C;&#x2500;&#x2500; cmd
&#x2502;   &#x2514;&#x2500;&#x2500; main.go
&#x2514;&#x2500;&#x2500; greeter
    &#x2514;&#x2500;&#x2500; greeter.go
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><pre><code>// greeter.go
package greeter
func Greet() string {
  return &quot;Hello There!&quot;
}
</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><pre><code>// main.go
package main
import (
  &quot;fmt&quot;

  &quot;github.com/lamida/gomoddemo/greeter&quot;
)
func main() {
  fmt.Println(greeter.Greet())
}
</code></pre>
<!--kg-card-end: markdown--><h2 id="publish-the-package">Publish The Package</h2><p>As example, we want to extract the Greet() functionality into its own golang package. Of course in real world, there is a very rare occasion to have too simple library like this. We want to use this just for example. </p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemolib $ tree
.
&#x2514;&#x2500;&#x2500; greeter
    &#x2514;&#x2500;&#x2500; greeter.go
</code></pre>
<!--kg-card-end: markdown--><p>What we will do is just pushing the greeter package into its own <a href="https://github.com/lamida/gomoddemolib">git repo</a>. </p><p>After that, we also can delete that gomoddemolib above project from our local disk. Please note that when publishing the package to git repo, there is no need to make the package as go modules package. For our example, one greeter.go file under greeter folder is enough.</p><p>At the same time, we will remove package greeter from gomoddemo project. Hence the project structure now just become like this.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo$ tree
.
&#x2514;&#x2500;&#x2500; cmd
    &#x2514;&#x2500;&#x2500; main.go
</code></pre>
<!--kg-card-end: markdown--><p>In the main.go we have to make sure to import the greeter from the new path.</p><!--kg-card-begin: markdown--><pre><code>// main.go
package main

import (
  &quot;fmt&quot;
  // this import is from the new repo
  &quot;github.com/lamida/gomoddemolib/greeter&quot;
)

func main() {
  fmt.Println(greeter.Greet())
}

</code></pre>
<!--kg-card-end: markdown--><p>If we try to build this, we will get error like this.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo $ go build
main.go:6:2: cannot find package &quot;github.com/lamida/gomoddemolib/greeter&quot; in any of:
        /snap/go/3739/src/github.com/lamida/gomoddemolib/greeter (from $GOROOT)
        /home/lamida/go/src/github.com/lamida/gomoddemolib/greeter (from $GOPATH)
</code></pre>
<!--kg-card-end: markdown--><p>That happens because gomoddemo project can&apos;t find dependency to gomoddemolib since we have deleted that from our local disk.</p><p>We need to enable go modules for gomoddemo so that go can manage the dependency for us.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo $ go mod init github.com/lamida/gomoddemo
go: creating new go.mod: module github.com/lamida/gomoddemo
</code></pre>
<!--kg-card-end: markdown--><p>Let&apos;s see what is inside go.mod file.</p><!--kg-card-begin: markdown--><pre><code>// go.mod
module github.com/lamida/gomoddemo

go 1.12
</code></pre>
<!--kg-card-end: markdown--><p>It is just module declaration and go version. Next we can run go build for the main package under cmd folder.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo $ cd cmd
user@machine: ~/go/src/github.com/lamida/gomoddemo $ go build
go: finding github.com/lamida/gomoddemolib/greeter latest
go: finding github.com/lamida/gomoddemolib latest
user@machine: ~/go/src/github.com/lamida/gomoddemo $ ./cmd
Hello from module
</code></pre>
<!--kg-card-end: markdown--><p>go build command automatically scan import in our codes and download the dependency directly. When we execute the binary named cmd under the cmd folder, it shows the output as what we import from the external package.</p><h2 id="go-sum">go.sum</h2><p>After running go build, we also discover that there is a new file added in the root folder of the project.</p><!--kg-card-begin: markdown--><pre><code>//go.sum
github.com/lamida/gomoddemolib v0.0.0-20190518042331-b7c7cf7d5429/go.mod h1:ql3STdRmz950+yGEEso1wDner5pLOa1keXBZ77ZkT0w=
</code></pre>
<!--kg-card-end: markdown--><p>As we can read from golang wiki go.sum serves this function: </p><blockquote>For validation purposes, <code>go.sum</code> contains the expected cryptographic checksums of the content of specific module versions.</blockquote><p>To test the checksum, let&apos;s modify the sum by appending it with some random text. We can do so by using go mod verify command.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo $ go mod verify
verifying github.com/lamida/gomoddemolib@v0.0.0-20190518042331-b7c7cf7d5429/go.mod: checksum mismatch
        downloaded: h1:ql3STdRmz950+yGEEso1wDner5pLOa1keXBZ77ZkT0w=
        go.sum:     h1:ql3STdRmz950+yGEEso1wDner5pLOa1keXBZ77ZkT0wX=
</code></pre>
<!--kg-card-end: markdown--><h2 id="updating-the-package">Updating The Package</h2><p>The library we are importing are coming without any version metadata. Hence go module just pulls the latest commit from the master branch. Let&apos;s test to update the gomoddemolib another commit to the master branch. I am updating the greet message from &quot;Hello from module&quot; to &quot;Hello from module updated&quot;. If we run go build after that, nothing is changed. </p><h3 id="updating-patch-version">Updating Patch Version</h3><p>The most easiest way to update this is to update release tag to gomodlib. </p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemolib $ git tag v0.0.1
user@machine: ~/go/src/github.com/lamida/gomoddemolib $ git push origin v0.0.1
Total 0 (delta 0), reused 0 (delta 0)
To github.com:lamida/gomoddemolib
 * [new tag]         v0.0.1 -&gt; v0.0.1
</code></pre>
<!--kg-card-end: markdown--><p>Next we update the version in go.mod in gomoddemo project to point to this new version. But instead of pointing to the specific patch version, we will just set it to major version v0.</p><!--kg-card-begin: markdown--><pre><code>// go.mod
module github.com/lamida/gomoddemo

go 1.12

require github.com/lamida/gomoddemolib v0
</code></pre>
<!--kg-card-end: markdown--><p>Running go build will fetch the latest version.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo/cmd $ go build
go: finding github.com/lamida/gomoddemolib v0.0.1
go: downloading github.com/lamida/gomoddemolib v0.0.1
go: extracting github.com/lamida/gomoddemolib v0.0.1
user@machine: ~/go/src/github.com/lamida/gomoddemo/cmd $ ./cmd
Hello from module updated
</code></pre>
<!--kg-card-end: markdown--><p>We can push another patch version from gomodlib.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemolib $ git tag v0.0.2
user@machine: ~/go/src/github.com/lamida/gomoddemolib $ git push origin v0.0.2
Total 0 (delta 0), reused 0 (delta 0)
To github.com:lamida/gomoddemolib
 * [new tag]         v0.0.2 -&gt; v0.0.2
</code></pre>
<!--kg-card-end: markdown--><p>Running go build will automatically fetch another patch version. </p><h3 id="updating-minor-version">Updating Minor Version</h3><p>This also applicable if the library updates the minor version.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemolib $ git tag v0.1.0
user@machine: ~/go/src/github.com/lamida/gomoddemolib $ git push origin v0.1.0
Total 0 (delta 0), reused 0 (delta 0)
To github.com:lamida/gomoddemolib
 * [new tag]         v0.1.0 -&gt; v0.1.0
</code></pre>
<!--kg-card-end: markdown--><p>On running go build in the client code, the latest version of the dependency will be fetched.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo/cmd $ go build
go: finding github.com/lamida/gomoddemolib v0.1.0
go: downloading github.com/lamida/gomoddemolib v0.1.0
go: extracting github.com/lamida/gomoddemolib v0.1.0
</code></pre>
<!--kg-card-end: markdown--><h3 id="updating-major-version">Updating Major Version</h3><p>There are a different semantic for major version though. Let say after the library got stable, it releases v1 and then after that v2.</p><p>Updating to v1 is as simple as updating the go.mod to point to v1.</p><pre><code>// go.mod
module github.com/lamida/gomoddemo

go 1.12

require github.com/lamida/gomoddemolib v1
</code></pre><p>However if you update to v2, go build will still fetch the latest update but the client code wouldn&apos;t directly run the v2 library.</p><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo/cmd $ go build
go: finding github.com/lamida/gomoddemolib v2.0.0+incompatible
go: downloading github.com/lamida/gomoddemolib v2.0.0+incompatible
go: extracting github.com/lamida/gomoddemolib v2.0.0+incompatible
$ ./cmd
Hello from module v1.0.0
</code></pre>
<!--kg-card-end: markdown--><p>We would have to enable the v2 by explicitly importing it in the client code.</p><!--kg-card-begin: markdown--><pre><code class="language-lang-go">// main.go
package main

import (
	&quot;fmt&quot;

	v2 &quot;github.com/lamida/gomoddemolib/v2/greeter&quot;
)

func main() {
	fmt.Println(v2.Greet())
}

</code></pre>
<!--kg-card-end: markdown--><!--kg-card-begin: markdown--><pre><code>user@machine: ~/go/src/github.com/lamida/gomoddemo/cmd $ go build
go: finding github.com/lamida/gomoddemolib v2.0.0+incompatible
go: downloading github.com/lamida/gomoddemolib v2.0.0+incompatible
go: extracting github.com/lamida/gomoddemolib v2.0.0+incompatible
$ ./cmd
Hello from module v2.0.0
</code></pre>
<!--kg-card-end: markdown--><p>If you saw error of module can&apos;t be found, make sure to update the version in the go.mod file to v2 and re-run go build or run command.</p><!--kg-card-begin: markdown--><pre><code>// go.mod
module github.com/lamida/gomoddemo

go 1.12

require github.com/lamida/gomoddemolib v2
</code></pre>
<!--kg-card-end: markdown--><p>The example concludes how we use go modules. </p><p>The code example used in this blog post is available in this <a href="https://github.com/lamida/gomoddemolib">git repo</a>.</p>]]></content:encoded></item><item><title><![CDATA[Super Late Personal OKR for 2018]]></title><description><![CDATA[<p>The past one year is a really horrible year. I am performing horribly and I achieve minimally. This post is one of the indication. If one would like to set goal annually, he should set it by the beginning of the year. I am defeated by the power of procrastination.</p>]]></description><link>https://blog.lamida.org/super-late-personal-okr-for-2018/</link><guid isPermaLink="false">5cdaf57300d8210c018789a6</guid><category><![CDATA[Personal]]></category><category><![CDATA[Resolution]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Tue, 14 May 2019 17:16:48 GMT</pubDate><content:encoded><![CDATA[<p>The past one year is a really horrible year. I am performing horribly and I achieve minimally. This post is one of the indication. If one would like to set goal annually, he should set it by the beginning of the year. I am defeated by the power of procrastination. But still with the spirit better late than never, I am writing another resolution note again this year. There is a slight modification though, start from this year I want to use OKR approach, instead of mouthful and too fine grain resolution approach. </p><h2 id="resolution-notes-from-previous-years"><strong>Resolution Notes from Previous Years</strong></h2><ol><li><a href="https://blog.lamida.org/late-resolution-note-2017">2017 resolution note</a></li><li><a href="https://blog.lamida.org/resolution-note-of-2016/">2016 resolution note</a></li><li><a href="https://blog.lamida.org/a_late_resolution_note_of_2015/">2015 personal note</a></li><li><a href="http://www.lamida.net/2014/12/end-of-twenties-note-evaluate-backward.html">2014 personal note</a></li><li><a href="http://www.lamida.net/2013/12/another-self-reflection-of-age-increment.html">2013 personal note</a></li><li><a href="http://www.lamida.net/2012/12/a-short-reflection-of-age-increment.html">2012 personal note</a></li><li><a href="http://lamida.wordpress.com/2011/12/12/age26/">2011 personal note</a></li><li><a href="http://www.lamida.net/2010/12/age.html">2010 personal note</a></li></ol><h2 id="last-year-review"><strong>Last Year Review</strong></h2><p>Like usual let&apos;s start with what I wanted &#xA0;to do by last year. [Y] means achieved, [N] means not achieved.</p><ul><li>[N] Completing at least&#xA0;6&#xA0;2 MOOC courses: I don&apos;t do any course at all. I signed many of them but almost don&apos;t finish any week for any course at all</li><li>[N] Take a&#xA0;GRE&#xA0;PTE test: I don&apos;t do any test</li><li>[N] Launch&#xA0;Work consistently on <a href="travelogee.com">Travelogee</a> project: There is no new post in Travelogee for the past one year.</li><li>[Y] Raise a happy, healthy and smart kid. At least focus play with the kid minimum 30 minutes a day on weekday and 1 hour on weekend: Alula is 15 months old now. She is growing up very well. Although I am not tracking in detail, but I can say that I am quite on track in this goal. I play with her definetely more than 30 minutes a day and in some weekend I spent time almost whole day with her. Hurray!</li><li>[N] Reach Tech Lead position in the new work place: there are some career ups and downs with some sweet and bitter lessons. But at the end I am back with normal coding.</li><li>[N] Weight no more than&#xA0;65&#xA0;60 Kg: I don&apos;t dare to weight myself but It was more than 70 Kg last time.</li><li>[Y] Read minimum a book per 2 months and make a review on it: I have been trying to fix my reading habit by really consciously absorbing the information when reading by taking notes and review the book. I have read at least 8 books for the past 5 months. It is clearly above the goal I set.</li><li>[N] Write a book about Golang: Nothing happen on this yet.</li><li>[N] Speak in a country level technical conference: Even I don&apos;t speak anywhere at all.</li><li>[N] Long duration travel to uncommon destination country such as Central Asia: no major travel for the past 2 years.</li><li>[Y] Get Singapore Class 2 Motorbike license: Yes I am Class 2 license holder now!</li><li>[N] Touring using big motorbike for at least to distance like from Sydney to Melbourne: Maybe next time.</li><li>[N} Speak English fluently to the level of IELTS 8 band score: I haven&apos;t taken any IELTS test yet and my English seems stagnant because I don&apos;t speak so much.</li><li>[N]&#xA0;Resume to study German to basic communication level or more: I even didn&apos;t start anything.</li><li>[N] Finish marathon sub 4 hours: I am couch potato which hasn&apos;t been running at all for the past 15 months</li><li>[N] Exercise every day: no</li><li>[N] Do&#xA0;SAVERS&#xA0;every day: no!</li></ul><p>Ok let&apos;s set objective for this year. I wouldn&apos;t re-explain what OKR is. For anyone who are not familiar to it, can read <a href="https://www.goodreads.com/book/show/39286958-measure-what-matters">Measure What Matters</a> by John Doerr. Usually OKR is set quarterly or at most half yearly. But I will set objective for 1 year (technically 7 months from now, because now is already May).</p><p>I have divided my life into 6 aspects to help me in setting objectives and todos. This is an somehow abrupt experimental classification which might change in future. What I am going to do is to set at least one objective in each that life aspect with at least one key result in each objective.</p><ul><li>Soul: To make it easy, for me soul is about being religious, mindfulness, something that make you calm, something non material.</li><li>Relationship: Family, friends and other social circles.</li><li>Mind: About learning and how to optimise your brain.</li><li>Wealth: Financial, materialistic possession.</li><li>Fitness: Health, exercise and diet.</li><li>Impact: How I can contribute, writing books, speaking in conference, be an influencer.</li></ul><h2 id="-soul-be-more-religious-mindful-and-calm-individual">(Soul) Be more religious, mindful and calm individual</h2><ul><li>Memorise at least 5 additional surah in Juz 30 of Quran by the end of year</li><li>Read 1 new <a href="https://en.wikipedia.org/wiki/Hadith">hadith</a> per week</li><li>At least have one mindful praying without too much mind wandering per day. To follow on this key result, I am devising a praying score metric. For each prayer, I will score my prayer from 0-5. 0 means total mind wandering where even I can forgot in which rakaat I am at. 5 means total mindfulness where I am in the flow without any mind wandering at all.</li><li>Write daily journal, at least one paragraph per day</li><li>Write a grateful note every night before sleep</li></ul><h2 id="-relationship-be-closer-to-family-care-more-and-spend-time-more-with-them-and-increase-social-circle">(Relationship) Be closer to family, care more and spend time more with them and increase social circle</h2><ul><li>Call mom at least once a month </li><li>Spend specifically dedicated non-distracted time for wife at least 15 minutes a day</li><li>Play with Lulu at least 30 minutes a day in weekday and 2 hours in weekend</li></ul><h2 id="-mind-learning-a-specific-thing-deeply-and-focus">(Mind) Learning a specific thing deeply and focus</h2><ul><li>Finish one Coursera cloud computing course</li><li>Do 1 German Duolingo session per day</li><li>Read 2 books per month</li></ul><h2 id="-wealth-increase-financial-literacy-and-portfolio">(Wealth) Increase financial literacy and portfolio</h2><ul><li>Get average return of investment for 6% by the end of the year</li><li>Read 5 financial/FIRE movement&apos;s books</li></ul><h2 id="-fitness-be-more-healthy-and-fit">(Fitness) Be more healthy and fit</h2><ul><li>Do push up 5 times per day</li><li>Run at least 15 minutes per week</li><li>Drink not more than 300ml sweet drink per day</li></ul><h2 id="-impact-screw-impostor-syndrome-let-me-share-to-the-world">(Impact) Screw impostor syndrome, let me share to the world</h2><ul><li>Speak in at least local meetup by the end of the year</li><li>Write a book draft about Kotlin by the end of the year by writing at least one page per week</li><li>Contribute 1 pull request to any open source project</li></ul><p>Then that&apos;s all. I will try to review this at least monthly and add comments or notes as required.</p>]]></content:encoded></item><item><title><![CDATA[Getting Started with emacs in 30 Minutes]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Emacs is a very extensible text editor that was started as far as 1970s. I have never really explored this editor much but somehow recently become interested to get to know this tool a bit more. This post will share a very quick journey of how setting up emacs and</p>]]></description><link>https://blog.lamida.org/getting-started-with-emacs-in-30-minutes/</link><guid isPermaLink="false">5b41b595006a9b03a990bce2</guid><category><![CDATA[unix]]></category><category><![CDATA[golang]]></category><category><![CDATA[emacs]]></category><category><![CDATA[editor]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Sun, 08 Jul 2018 12:48:27 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Emacs is a very extensible text editor that was started as far as 1970s. I have never really explored this editor much but somehow recently become interested to get to know this tool a bit more. This post will share a very quick journey of how setting up emacs and getting started to do some basic tasks approximately in 30 minutes.</p>
<p>In this post, we are going to cover these points:</p>
<ul>
<li>Checking emacs version</li>
<li>Installation</li>
<li>Starting emacs</li>
<li>Exiting emacs</li>
<li>Emacs Tutorial</li>
<li>Emacs Packages</li>
<li>Evaluating LISP</li>
</ul>
<h1 id="checkingversion">Checking Version</h1>
<p>Emacs is included in macOS by default, but not from the latest version. In my laptop this is the version.</p>
<pre><code>$ emacs --version
GNU Emacs 22.1.1
Copyright (C) 2007 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.
</code></pre>
<p>At the time of this writing from <a href="https://www.gnu.org/software/emacs/manual/html_node/efaq/Latest-version-of-Emacs.html">this link</a> the current version of emacs is 26.1. We will get that latest version, instead of the old default version.</p>
<h1 id="installingemacs">Installing Emacs</h1>
<p>There are several options to install the latest version of emacs. My preference usually is to use brew, so that it is easier to manage the instalation, uninstalation and update.</p>
<p>Run this brew command to install the gui version of emacs.</p>
<pre><code>$ brew cask install emacs
</code></pre>
<p>After the installation we can check quickly the updated version. Make sure to switch the terminal to ensure the PATH will pick the latest installed emacs instead of the old one.</p>
<pre><code>$ emacs --version
GNU Emacs 26.1
Copyright (C) 2018 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.
</code></pre>
<p>We have seen the installation run successfully.</p>
<h1 id="startingemacs">Starting Emacs</h1>
<p>Since we install emacs using brew cask, brew will add emacs to application folder, therefore the apps can be started from macOS launchpad. However, if you plan to use come emacs internal command, we might want to start it from command line because somehow starting emacs from the launchpad doesn&apos;t carry the PATH and environment variable setup in your bash_profile or your terminal profile. I am figuring out how to fix this issue. But for now, I just start emacs from terminal.</p>
<p><img src="https://blog.lamida.org/content/images/2018/07/Screen-Shot-2018-07-08-at-3.09.41-PM.png" alt="Screen-Shot-2018-07-08-at-3.09.41-PM" loading="lazy"></p>
<h1 id="exitingemacs">Exiting Emacs</h1>
<p>Many people getting stuck from <a href="https://stackoverflow.blog/2017/05/23/stack-overflow-helping-one-million-developers-exit-vim/">exiting vim</a>. I believe there will be less number of people that can&apos;t exit emacs since at least there are no different editing and view mode in emacs such as in vim. In emacs GUI, just click the close window button. Or the more canonical way using keyboard binding is to use <code>C-x C-c</code>. See next section to understand what that key binding means.</p>
<h1 id="emacstutorial">Emacs Tutorial</h1>
<p>No I will not redo excellent tutorial that available inside the application. For you that really never used emacs before, spend your next 30 minutes to do the emacs tutorial that accessible from emacs welcome screen above. Alternatively you can press this key combination to access that <code>C-h t</code>.</p>
<h1 id="emacspackages">Emacs Packages</h1>
<p>The power of emacs is of how extendable it is. To see available and installed package, enter these keys <code>M-x list-packages</code>. By default list-packages will show only package maintained by emacs developer.</p>
<p>Sometime a package is hosted elsewhere. <a href="https://melpa.org/#/">Melpa</a> is one well known emacs package archieve. For an example, let us try to install <a href="https://github.com/dominikh/go-mode.el">go-mode package</a> which is available in melpa.</p>
<p>To enable melpa in emacs is described in <a href="https://melpa.org/#/getting-started">its getting started guide</a>. Let us add the init setup using emacs itself. Enter <code>C-x C-f</code> to visit file and enter <code>~/.emacs.d/init.el</code> in the input prompt which means we want to edit or create that init file. That file will be read by emacs everytime it starts up. Paste the content of package initializer file as follow in the file.</p>
<pre><code>(require &apos;package)
(let* ((no-ssl (and (memq system-type &apos;(windows-nt ms-dos))
                    (not (gnutls-available-p))))
       (proto (if no-ssl &quot;http&quot; &quot;https&quot;)))
  ;; Comment/uncomment these two lines to enable/disable MELPA and MELPA Stable as desired
  (add-to-list &apos;package-archives (cons &quot;melpa&quot; (concat proto &quot;://melpa.org/packages/&quot;)) t)
  ;;(add-to-list &apos;package-archives (cons &quot;melpa-stable&quot; (concat proto &quot;://stable.melpa.org/packages/&quot;)) t)
  (when (&lt; emacs-major-version 24)
    ;; For important compatibility libraries like cl-lib
    (add-to-list &apos;package-archives &apos;(&quot;gnu&quot; . (concat proto &quot;://elpa.gnu.org/packages/&quot;)))))
(package-initialize)
</code></pre>
<p>Then press <code>C-x C-s</code> to save and <code>C-x C-c</code> to quit. Start emacs again to reinit emacs with package initialiser above. Then enter <code>M-x list-packages</code> again. We should see some packages from melpa have already been added.</p>
<p><img src="https://blog.lamida.org/content/images/2018/07/Screen-Shot-2018-07-08-at-3.51.02-PM.png" alt="Screen-Shot-2018-07-08-at-3.51.02-PM" loading="lazy"></p>
<h2 id="installinggomode">Installing go-mode</h2>
<p>To install go-mode, we can either search the package from the list or use this command: <code>M-x package-install</code>, then type <code>go-mode</code>. To see the installation status, switch to <code>*Messages*</code> buffer by pressing <code>C-x C-b</code> and select the <code>*Messages*</code> buffer.</p>
<p>To test the mode, we will create a new file called <code>main.go</code> in folder under <code>$GOPATH</code>. I am assuming reader understand go setup and what <code>$GOPATH</code> means.</p>
<p>Since we have installed <code>go-mode</code> emacs will automatically switch to that mode when editing go source file that ends with <code>.go</code> extension.</p>
<p><img src="https://blog.lamida.org/content/images/2018/07/Screen-Shot-2018-07-08-at-8.30.56-PM.png" alt="Screen-Shot-2018-07-08-at-8.30.56-PM" loading="lazy"></p>
<p>With go-mode some extended commands are also added to our emacs installation.</p>
<p><img src="https://blog.lamida.org/content/images/2018/07/Screen-Shot-2018-07-08-at-8.32.23-PM.png" alt="Screen-Shot-2018-07-08-at-8.32.23-PM" loading="lazy"></p>
<p>To run the go source file, we also can leverage shell access directly from emacs. To open shell from emacs, type <code>M-x</code> and type <code>shell</code>. From the shell we can run <code>go run main.go</code> the execute the above go hello world example.</p>
<p>I will not go to more details of how setup go development in emacs because there are already <a href="https://johnsogg.github.io/emacs-golang">some good blog post</a> <a href="http://tleyden.github.io/blog/2014/05/22/configure-emacs-as-a-go-editor-from-scratch/">about that</a>.</p>
<h1 id="evaluatinglisp">Evaluating LISP</h1>
<p>Emacs provides a buffer called <code>*scratch*</code> that can be used as scratchpad and also to evalute LISP expression. I will not discuss any LISP detail topic here. But if there is a need to quickly evaluate lisp expression, you can go to your emacs installation.</p>
<p>To open <code>*scratch*</code> buffer, type <code>C-x C-b</code> and select the <code>*scratch*</code> buffer name. A very simple lisp expression is <code>(+ 2 4)</code> which basically adding 2 and 4. Just write that expression in the buffer and press <code>C-j</code> to make the evaluation result printed in the next line. For an alternative way, select the lisp expression that you want to evaluate and press <code>C-x C-e</code>. For this approach the evaluation result will be printed in the echo area.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Mocking in Golang Using Testify]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I have used golang for sometime but only recently I finally understand how to do object mocking in a golang test. Since I came from Java, the way of how mocking an object in golang was not really clear for me. This post is my self documentation of how I</p>]]></description><link>https://blog.lamida.org/mocking-in-golang-using-testify/</link><guid isPermaLink="false">5b3e40aa006a9b03a990bcd3</guid><category><![CDATA[golang]]></category><category><![CDATA[testing]]></category><category><![CDATA[testify]]></category><category><![CDATA[mockery]]></category><category><![CDATA[mocking]]></category><category><![CDATA[go]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Thu, 05 Jul 2018 17:00:49 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I have used golang for sometime but only recently I finally understand how to do object mocking in a golang test. Since I came from Java, the way of how mocking an object in golang was not really clear for me. This post is my self documentation of how I reached to my current understanding. In this post, I am using mocking feature from <a href="https://github.com/stretchr/testify">testify</a>. I would assume that reader will be familiar with basic golang to understand this post.</p>
<p>As example, I will create a very simple service like this:</p>
<p><img src="https://blog.lamida.org/content/images/2018/07/Screen-Shot-2018-07-06-at-12.11.41-AM.png" alt="Screen-Shot-2018-07-06-at-12.11.41-AM" loading="lazy"></p>
<p>GreeterService is a service that allows you to give a greeting. There are two greeting methods:</p>
<ul>
<li>Greet() will greet you depends on what language you set when creating the service</li>
<li>GreetDefaultMessage() will greet you using default message and doesn&apos;t care of the language</li>
</ul>
<p>Internally, Greet() will call db.FetchMessage(lang) and GreetDefaultMessage() will call db.FetchDefaultMessage(). In real world we will imagine, DB class is class that calls a real database. Therefore, we need a mock in our test to avoid our test calling the actual database. There is no class in golang but we can consider struct behaviour to be equivalent with class.</p>
<h1 id="implementation">Implementation</h1>
<p>Let see the implementation that we will write in a package called <code>service</code>. First we define the package.</p>
<pre><code>package service
</code></pre>
<p>Then we will create a <code>db</code> struct and its interface that we name as <code>DB</code>.</p>
<pre><code>type db struct{}

// DB is fake database interface.
type DB interface {
	FetchMessage(lang string) (string, error)
	FetchDefaultMessage() (string, error)
}
</code></pre>
<p>After that we will create <code>GreeterService</code> interface and <code>greeter</code> struct that implements the interface which has dependency to the <code>DB</code> interface. <code>greeter</code> struct also receives <code>lang</code> parameter in its 2nd argument&apos;s constructor.</p>
<pre><code>type greeter struct {
	database DB
	lang     string
}

// GreeterService is service to greet your friends.
type GreeterService interface {
	Greet() string
	GreetInDefaultMsg() string
}
</code></pre>
<p>To make <code>db</code> struct implicity implement <code>DB</code> interface, we will add the required methods and set <code>*db</code> as the receiver.</p>
<pre><code>func (d *db) FetchMessage(lang string) (string, error) {
    // in real life, this code will call an external db
    // but for this sample we will just return the hardcoded example value
	if lang == &quot;en&quot; {
		return &quot;hello&quot;, nil
	}
	if lang == &quot;es&quot; {
		return &quot;holla&quot;, nil
	}
	return &quot;bzzzz&quot;, nil
}

func (d *db) FetchDefaultMessage() (string, error) {
	return &quot;default message&quot;, nil
}
</code></pre>
<p>Next we will need to implement the actual greeter methods, <code>Greet()</code> and <code>GreetInDefaultMsg()</code>.</p>
<pre><code>func (g greeter) Greet() string {
	msg, _ := g.database.FetchMessage(g.lang) // call database to get the message based on the lang
	return &quot;Message is: &quot; + msg
}

func (g greeter) GreetInDefaultMsg() string {
	msg, _ := g.database.FetchDefaultMessage() // call database to get the default message
	return &quot;Message is: &quot; + msg
}
</code></pre>
<p>Above, the greeter methods is calling <code>DB</code> to get the actual message.</p>
<p>It will be helpful to create a factory function for the Greeter and DB.</p>
<pre><code>func NewDB() DB {
	return new(db)
}

func NewGreeter(db DB, lang string) GreeterService {
	return greeter{db, lang}
}
</code></pre>
<p>Last part of the implementation, we will write a main function to run the service.</p>
<pre><code>package main

import (
	&quot;fmt&quot;
	&quot;testify-mock/service&quot;
)

func main() {
	d := service.NewDB()

	g := service.NewGreeter(d, &quot;en&quot;)
	fmt.Println(g.Greet()) // Message is: hello
	fmt.Println(g.GreetInDefaultMsg()) // Message is: default message

	g = service.NewGreeter(d, &quot;es&quot;)
	fmt.Println(g.Greet()) // Message is: holla

	g = service.NewGreeter(d, &quot;random&quot;)
	fmt.Println(g.Greet()) // Message is: bzzzz
}
</code></pre>
<p>The output after running that will be as follow.</p>
<pre><code>$ go run main.go
Message is: hello
Message is: default message
Message is: holla
Message is: bzzzz
</code></pre>
<h1 id="testandmock">Test and Mock</h1>
<p>After having the implementation above, we will write write a test and mock <code>DB</code> dependency. As stated in the beginning, we want to prevent calling actual database when running the test.</p>
<p>To achieve that goal, we will mock the <code>DB</code> interface. Unfortunately the way how mock is created in golang is not as straight forward as in java. In java using mockito, mocking can be as simple as this:</p>
<pre><code>GreetingService mock = Mockito.mock(GreetingService.class);
</code></pre>
<p>But in golang we need to create a new struct and embed a testify mock object in it like this:</p>
<pre><code>type dbMock struct {
	mock.Mock
}
</code></pre>
<p>Then to make that mock object to comply with <code>DB</code> interface, we need to implement all the methods of the interface. Also there is a specific call need to be done inside the implemented method. The first one is we need to call method <code>Mock.Called(args)</code> and passing the arguments if the method we want to mock has some arguments.</p>
<p>In the example below, the call is <code>d.Called(lang)</code>. Then return value of that call will be used as return value the method that we want to mock. Both method are returning <code>(string, error)</code>. Therefore the return statement of the method are <code>return args.String(0), args.Error(1)</code>. The pattern of how we should write the return statement in the mocked methods is, <code>args.&lt;ReturnValueType&gt;(&lt;index&gt;)</code>. Index is started from zero.</p>
<pre><code>func (d *dbMock) FetchMessage(lang string) (string, error) {
	args := d.Called(lang)
	return args.String(0), args.Error(1)
}

func (d *dbMock) FetchDefaultMessage() (string, error) {
	args := d.Called()
	return args.String(0), args.Error(1)
}
</code></pre>
<p>If we want to mock a method with return signature of <code>(int, string, bool)</code>, the return statement we need to write is <code>return args.Int(0), args.String(1), args.Bool(2)</code>.</p>
<p>If the return signature is not a simple object, the return should be written using type assertion like <code>return args.Get(0).(*MyObject), args.Get(1).(*AnotherObjectOfMine)</code>. See <a href="https://godoc.org/github.com/stretchr/testify/mock">testify godoc</a> for some more extra information.</p>
<p>After creating the mocking object, we can use it in our test.</p>
<h2 id="mockingmethodwithoutargument">Mocking Method Without Argument</h2>
<p>When we want to mock <code>FetchDefaultMessage()</code> which is method without argument we have to use <code>On(&lt;methodName&gt;, args...)</code> method. The args is variadic therefore we can pass no argument or multiple arguments.</p>
<pre><code>func TestMockMethodWithoutArgs(t *testing.T) {
	theDBMock := dbMock{} // create the mock
	theDBMock.On(&quot;FetchDefaultMessage&quot;).Return(&quot;foofofofof&quot;, nil) // mock the expectation
	g := greeter{&amp;theDBMock, &quot;en&quot;} // create greeter object using mocked db
	assert.Equal(t, &quot;Message is: foofofofof&quot;, g.GreetInDefaultMsg()) // assert what actual value that will come
	theDBMock.AssertNumberOfCalls(t, &quot;FetchDefaultMessage&quot;, 1) // we can assert how many times the mocked method will be called
	theDBMock.AssertExpectations(t) // this method will ensure everything specified with On and Return was in fact called as expected
}
</code></pre>
<h2 id="mockingmethodwithargument">Mocking Method With Argument</h2>
<p>Previously we mock <code>FetchDefaultMessage()</code> method which doesn&apos;t have any argument. Now let see example if we want to mock a method with an argument.</p>
<pre><code>func TestMockMethodWithArgs(t *testing.T) {
	theDBMock := dbMock{}
	theDBMock.On(&quot;FetchMessage&quot;, &quot;sg&quot;).Return(&quot;lah&quot;, nil) // if FetchMessage(&quot;sg&quot;) is called, then return &quot;lah&quot;
	g := greeter{&amp;theDBMock, &quot;sg&quot;}
	assert.Equal(t, &quot;Message is: lah&quot;, g.Greet())
	theDBMock.AssertExpectations(t)
}
</code></pre>
<h2 id="mockingmethodwithargumentthatwedontcare">Mocking Method With Argument That We Don&apos;t Care</h2>
<p>Sometime we want to mock a method but we don&apos;t care the actual argument that is passed. For that purpose we can use <code>mock.Anything</code> in the second parameter onward of <code>On()</code> method argument.</p>
<pre><code>func TestMockMethodWithArgsIgnoreArgs(t *testing.T) {
	theDBMock := dbMock{}
	theDBMock.On(&quot;FetchMessage&quot;, mock.Anything).Return(&quot;lah&quot;, nil) // if FetchMessage(...) is called with any argument, please also return lah
	g := greeter{&amp;theDBMock, &quot;in&quot;}
	assert.Equal(t, &quot;Message is: lah&quot;, g.Greet())
	theDBMock.AssertCalled(t, &quot;FetchMessage&quot;, &quot;in&quot;)
	theDBMock.AssertNotCalled(t, &quot;FetchMessage&quot;, &quot;ch&quot;)
	theDBMock.AssertExpectations(t)
	mock.AssertExpectationsForObjects(t, &amp;theDBMock)
}
</code></pre>
<h2 id="mockingmethodwithargumentusingmatchedby">Mocking Method With Argument Using MatchedBy</h2>
<p>There also will be a time we want to mock a method with a complex argument but want to match the mock based on certain property of the argument or calculation from it. For example, we want to mock <code>FetchMessage</code> method but only if the lang argument is started by letter <code>i</code>.</p>
<pre><code>func TestMatchedBy(t *testing.T) {
	theDBMock := dbMock{}
	theDBMock.On(&quot;FetchMessage&quot;, mock.MatchedBy(func(lang string) bool { return lang[0] == &apos;i&apos; })).Return(&quot;bzzzz&quot;, nil) // all of these call FetchMessage(&quot;iii&quot;), FetchMessage(&quot;i&quot;), FetchMessage(&quot;in&quot;) will match 
	g := greeter{&amp;theDBMock, &quot;izz&quot;}
	msg := g.Greet()
	assert.Equal(t, &quot;Message is: bzzzz&quot;, msg)
	theDBMock.AssertExpectations(t)
}
</code></pre>
<h1 id="mockery">Mockery</h1>
<p>As we can see in the previous section, before touching actual test and mocking the behaviour, we need to manually create the mock struct. <a href="https://github.com/vektra/mockery">Mockery</a> can help us from the need to do the manual work.</p>
<p>First we just need to install mockery:</p>
<pre><code>go get github.com/vektra/mockery/.../
</code></pre>
<p>Then generate the mock.</p>
<pre><code>$ mockery -name &lt;interfaceToMock&gt;
</code></pre>
<p>A file contains ready to use mock will be generated and we can add it to our test.</p>
<p>Full source of example code in this post is available in <a href="https://github.com/lamida/testify-mock">this repo</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Vagrant in 5 Minutes]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I have used vagrant since quite long time. With the recent devops movement, I want to revisit my understanding of the tool because it is very useful to use vagrant when you are simulating distributed system in your local machine. Of course the simulation wouldn&apos;t be 100% accurate</p>]]></description><link>https://blog.lamida.org/vagrant-in-5-minutes/</link><guid isPermaLink="false">5b1e5178006a9b03a990bcce</guid><category><![CDATA[vagrant]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Mon, 11 Jun 2018 11:06:13 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I have used vagrant since quite long time. With the recent devops movement, I want to revisit my understanding of the tool because it is very useful to use vagrant when you are simulating distributed system in your local machine. Of course the simulation wouldn&apos;t be 100% accurate but it is simpler to do than if you have to spawn some new VM machines in the cloud.</p>
<h1 id="instalation">Instalation</h1>
<p>This installation guide is for Mac OS. Although vagrant is not a GUI apps, but it is only available under <code>homebrew/cask</code> formula.</p>
<pre><code>$ brew install homebrew/cask/vagrant
</code></pre>
<p>It is also possible to install using binary but I still prefer to use brew.</p>
<p>If you don&apos;t have virtualisation software then we also need to install one. The easy choice will be virtualbox.</p>
<pre><code>$ brew install homebrew/cask/virtualbox
</code></pre>
<p>Check the installation with:</p>
<pre><code>$ vagrant --version
$ VBoxManage --version
</code></pre>
<h1 id="running">Running</h1>
<p>To run a VM using vagrant we need to define the VM spec inside Vagrantfile. vagrant provides a helper to generate the file filled with documentation without the need for us to write it from scratch.</p>
<pre><code>$ vagrant init ubuntu/bionic64
</code></pre>
<p>The argument after init is the VM box that we want to use, which is for above case is Ubuntu 18.08 Bionic Beaver.</p>
<p>It will add this configuration line in the Vagrantfile:</p>
<pre><code>Vagrant.configure(&quot;2&quot;) do |config|
  config.vm.box = &quot;ubuntu/bionic64&quot;
end
</code></pre>
<pre><code>$ vagrant up
</code></pre>
<p>After running up, vagrant will try to download the box if it is not available in local machine. Then it will startup the VM operating system.</p>
<p>Run this to check the status of the VM:</p>
<pre><code>$ vagrant status
</code></pre>
<p>Run this to get in to the machine:</p>
<pre><code>$ vagrant ssh
</code></pre>
<p>Run these to stop or suspend the machine:</p>
<pre><code>$ vagrant halt # stop the machine
$ vagrant suspend 
</code></pre>
<h1 id="networking">Networking</h1>
<p>Vagrant support different kind of networking setup. To test the setup, after updating the Vagrantfile, run reload to apply the updated config.</p>
<pre><code>$ vagrant reload
</code></pre>
<h2 id="forwardportmapping">Forward Port Mapping</h2>
<p>This configuration setup will forward the call from your machine port 8080 to port 80 in our ubuntu/bionic64. Please note that with this config, the port forwarding is also accessible from other computers in your network.</p>
<pre><code>Vagrant.configure(&quot;2&quot;) do |config|
  config.vm.box = &quot;ubuntu/bionic64&quot;
  config.vm.network &quot;forwarded_port&quot;, guest: 80, host: 8080
end
</code></pre>
<h2 id="forwardportmappingdisablepublicaccess">Forward Port Mapping Disable Public Access</h2>
<p>Similar like above, but the access now is limitted only from your machine.</p>
<pre><code>Vagrant.configure(&quot;2&quot;) do |config|
  config.vm.box = &quot;ubuntu/bionic64&quot;
  config.vm.network &quot;forwarded_port&quot;, guest: 80, host: 8080, host_ip: &quot;127.0.0.1&quot;
end
</code></pre>
<h2 id="privatenetworkdisablepublicaccess">Private Network Disable Public Access</h2>
<p>Instead of forwarding port, with private network the guest OS will have its own ip address.</p>
<pre><code>Vagrant.configure(&quot;2&quot;) do |config|
  config.vm.box = &quot;ubuntu/bionic64&quot;
  config.vm.network &quot;private_network&quot;, ip: &quot;192.168.33.10&quot;
end
</code></pre>
<h2 id="publicnetwork">Public Network</h2>
<p>With this config the vagrant machine will appear like another physical machine in your network.</p>
<pre><code>Vagrant.configure(&quot;2&quot;) do |config|
  config.vm.box = &quot;ubuntu/bionic64&quot;
  config.vm.network &quot;public_network&quot;
end
</code></pre>
<h1 id="foldersharing">Folder Sharing</h1>
<p>We can share files between host machine and vagrant guest OS using this config.</p>
<pre><code>Vagrant.configure(&quot;2&quot;) do |config|
  config.vm.box = &quot;ubuntu/bionic64&quot;
  config.vm.synced_folder &quot;data_from_my_laptop&quot;, &quot;/vagrant_data&quot;
end
</code></pre>
<p>To test it just create some files in your machine.</p>
<pre><code>$ mkdir data_from_my_laptop
$ touch data_from_my_laptop/foo
$ echo &quot;hello world&quot; &gt; data_from_my_laptop/bar
$ vagrant reload
$ vagrant ssh
vagrant@ubuntu-bionic $ ls /vagrant_data
</code></pre>
<p>Network and folder sharing setup should cover most common use case of using vagrant. For more details please refer to vagrant official documentation.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Late Resolution Note 2017]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I totally forgot that I haven&apos;t released this post because my recent busy life. I am blessed with a baby early this year and I also move to a new company. But those two will be stories for another day.</p>
<p>To ensure I am not breaking this couple</p>]]></description><link>https://blog.lamida.org/late-resolution-note-2017/</link><guid isPermaLink="false">5a82372dff1c7c72b8b8d4e2</guid><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Sat, 09 Jun 2018 17:10:13 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I totally forgot that I haven&apos;t released this post because my recent busy life. I am blessed with a baby early this year and I also move to a new company. But those two will be stories for another day.</p>
<p>To ensure I am not breaking this couple of years tradition where I have been consistently writing my annual resolution, I am releasing this resolution note albeit it has been almost half year late.</p>
<p>Last December I am getting one more year older again. Time to write evaluate last year resolution and making the new year resolution. No, I don&apos;t have go to gym resolution.</p>
<h2 id="resolutionnotesfrompreviousyears">Resolution Notes from Previous Years</h2>
<ol>
<li><a href="https://blog.lamida.org/resolution-note-of-2016/">2016 resolution note</a></li>
<li><a href="https://blog.lamida.org/a_late_resolution_note_of_2015/">2015 personal note</a></li>
<li><a href="http://www.lamida.net/2014/12/end-of-twenties-note-evaluate-backward.html">2014 personal note</a></li>
<li><a href="http://www.lamida.net/2013/12/another-self-reflection-of-age-increment.html">2013 personal note</a></li>
<li><a href="http://www.lamida.net/2012/12/a-short-reflection-of-age-increment.html">2012 personal note</a></li>
<li><a href="http://lamida.wordpress.com/2011/12/12/age26/">2011 personal note</a></li>
<li><a href="http://www.lamida.net/2010/12/age.html">2010 personal note</a></li>
</ol>
<h2 id="evaluationoflastyeargoals">Evaluation of last year goals</h2>
<p>Same like last year post, here are some of goals I setup last year and I will comment of how its status. The goal ended with <code>(Checked)</code> means the goal is achieved, if it ended <code>(Nay!)</code> means the goal is not achieved and if it ended with <code>(?)</code> means the goal is too vague in the first place.</p>
<ul>
<li>Completing at least 6 MOOC courses (Nay!)</li>
<li>Take a GRE test (Nay!)</li>
<li>Apply a postgraduate course (maybe in machine learning or applied math?) (Nay!)</li>
<li>Launch and work consistently on Travelogee project (Checked partially)</li>
<li>Have kids. I know this is God decision but I want to try better this year (Checked)</li>
<li>Buy a house (Nay!)</li>
<li>Reach Tech Lead position in work place (Almost, I got promoted although not to tech lead)</li>
<li>Weight no more than 65 Kg (Almost, now I am about 67 Kg)</li>
<li>Read minimum a book per 2 months and make a review on it (I read a lot but abruptly)</li>
<li>Learn Tennis (Nay!)</li>
<li>Use Scala to build something (Nay!)</li>
<li>Write a book (Nay!)</li>
<li>Speak in a country level technical conference (Nay!)</li>
<li>Learn and start investing and get 10% profit in one year (Nay!)</li>
<li>Visit at least one Africa, America and Oceania country (Checked)</li>
<li>Get Singapore Class 2 Motorbike license (Nay! but I have started the class 2 class last month)</li>
<li>Touring using big motorbike for at least to distance like from Sydney to Melbourne (Nay!)</li>
<li>Able to make a good photography (Nay!)</li>
<li>Speak English fluently to the level of IELTS 8 band score. I will not do another IELTS test again in one year, though will just try to self assessment. (Nay! I took TOEFL iBT but the score still below my expectation)</li>
<li>Speak German to basic communication level or more (Nay! The best sentence I can speak the best so far is <code>Das wetter heute is sch&#xF6;n</code>)</li>
<li>Speak Arabic to basic communication level or more (Nay! We drop out from our Arabic class because of timing)</li>
<li>Contribute something to your surround and be impactful person in a positive way (? vague goal)</li>
</ul>
<p>I have to admit that I am totally failed last year. No much major achievement.</p>
<p>Following are more detail status of the goal.</p>
<h3 id="completingatleast6mooccoursesnay">Completing at least 6 MOOC courses (Nay!)</h3>
<p>The goal seems too unrealistic. I will redo this year with more realistic target.</p>
<h3 id="takeagretestnay">Take a GRE test (Nay!)</h3>
<p>Didn&apos;t happen.</p>
<h3 id="applyapostgraduatecoursenay">Apply a postgraduate course (Nay!)</h3>
<p>Too busy.</p>
<h3 id="launchandworkconsistentlyontravelogeeprojectcheckedpartially">Launch and work consistently on Travelogee project (Checked partially)</h3>
<p>We unoffically launched <a href="https://www.travelogee.com">Travelogee</a> last year but still not work consistent enough to write good contents.</p>
<h3 id="havekidschecked">Have kids (Checked)</h3>
<p>This is a weird goal because to achieve it depends a lot with external factor and mostly the God grace. After <a href="https://blog.lamida.org/i-lost-my-kid-earlier-this-year/">a short desperate life episode</a>, we blessed with a beautiful baby girl on 17 January 2018. Life is very different since then with combination of joy and also tiredness. I will write in separate post for the detail.</p>
<h3 id="buyahousenay">Buy a house (Nay!)</h3>
<p>No. I bought a Nintendo Switch which is nothing remotely related to house at all.</p>
<h3 id="reachtechleadpositioninworkplacecheckedpartially">Reach Tech Lead position in work place (Checked partially)</h3>
<p>I didn&apos;t become tech lead but at least promoted to something else.</p>
<h3 id="weightnomorethan65kgcheckedpartially">Weight no more than 65 Kg (Checked partially)</h3>
<p>Although not reaching my goal, my current weight is around 67Kg dropping from about 74Kg last year. Still not healthy weight considering my short body of 165cm but I still quite feel good about it.</p>
<h3 id="readminimumabookper2monthsandmakeareviewonitnay">Read minimum a book per 2 months and make a review on it (Nay!)</h3>
<p>I read abruptly and managed to read and <a href="https://blog.lamida.org/tag/book/">review very few books</a> this year. But it is still under what I aimed.</p>
<h3 id="learntennisnay">Learn Tennis (Nay!)</h3>
<p>Nope.</p>
<h3 id="usescalatobuildsomethingnay">Use Scala to build something (Nay!)</h3>
<p>No.</p>
<h3 id="writeabooknay">Write a book (Nay!)</h3>
<p>Still not happening.</p>
<h3 id="speakinacountryleveltechnicalconferencenay">Speak in a country level technical conference (Nay!)</h3>
<p>Even I am not speaking or doing any presentation at all. I also finally dropped out from Toastmaster after become passive member for so long.</p>
<h3 id="learnandstartinvestingandget10profitinoneyearnay">Learn and start investing and get 10% profit in one year (Nay!)</h3>
<p>We have very few investment portfolios but we should have done better.</p>
<h3 id="visitatleastoneafricaamericaoroceaniacountrychecked">Visit at least one Africa, America or Oceania country (Checked)</h3>
<p><a href="https://www.travelogee.com/new-zealand/">We went to New Zealand</a> last year.</p>
<h3 id="getsingaporeclass2motorbikelicensenay">Get Singapore Class 2 Motorbike license (Nay!)</h3>
<p>But at least I have started the course again.</p>
<h3 id="touringusingbigmotorbikeforatleasttodistancelikefromsydneytomelbournenay">Touring using big motorbike for at least to distance like from Sydney to Melbourne (Nay!)</h3>
<p>Maybe this year.</p>
<h3 id="abletomakeagoodphotographynay">Able to make a good photography (Nay!)</h3>
<p>Didn&apos;t manage to learn photography at all. I started a course in Coursera but stopped following long time ago.</p>
<h3 id="speakenglishfluentlytothelevelofielts8bandscorenay">Speak English fluently to the level of IELTS 8 band score (Nay!)</h3>
<p>I did TOEFL iBT in 2017 but the score is still not good enough.</p>
<h3 id="speakgermantobasiccommunicationlevelormorenay">Speak German to basic communication level or more (Nay!)</h3>
<p>Fail.</p>
<h3 id="speakarabictobasiccommunicationlevelormorenay">Speak Arabic to basic communication level or more (Nay!)</h3>
<p>Fail.</p>
<h3 id="contributesomethingtoyoursurroundandbeimpactfulpersoninapositiveway">Contribute something to your surround and be impactful person in a positive way (?)</h3>
<p>Super vague goal.</p>
<h2 id="resolutionnoteof2018">Resolution Note of 2018</h2>
<ul>
<li>Completing at least <s>6</s> 2 MOOC courses</li>
<li>Take a <s>GRE</s> PTE test</li>
<li><s>Launch</s> Work consistently on Travelogee project</li>
<li>Raise a happy, healthy and smart kid. At least focus play with the kid minimum 30 minutes a day on weekday and 1 hour on weekend.</li>
<li>Reach Tech Lead position in the new work place</li>
<li>Weight no more than <s>65</s> 60 Kg</li>
<li>Read minimum a book per 2 months and make a review on it</li>
<li>Write a book about golang</li>
<li>Speak in a country level technical conference</li>
<li>Long duration travel to uncommon destination country such as Central Asia</li>
<li>Get Singapore Class 2 Motorbike license</li>
<li>Touring using big motorbike for at least to distance like from Sydney to Melbourne</li>
<li>Speak English fluently to the level of IELTS 8 band score</li>
<li><s>Speak</s> Resume to study German to basic communication level or more</li>
<li>Finish marathon sub 4 hours</li>
<li>Exercise every day</li>
<li>Do <a href="https://blog.lamida.org/todo-savers-2/">SAVERS</a> every day</li>
</ul>
<p>So that&apos;s it for this year.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Go Development in Ubuntu 16.04 Using Atom]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>To install go, refer to <a href="https://blog.lamida.org/go-development-in-ubuntu-using-vim/">this post</a>.</p>
<h1 id="installingatom">Installing Atom</h1>
<p>Add PPA and install atom.</p>
<pre><code>curl -L https://packagecloud.io/AtomEditor/atom/gpgkey | sudo apt-key add -
sudo sh -c &apos;echo &quot;deb [arch=amd64] https://packagecloud.io/AtomEditor/atom/any/ any main&quot; &gt; /etc/apt/sources.list.d/</code></pre>]]></description><link>https://blog.lamida.org/go-development-in-ubuntu-16-04-using-atom/</link><guid isPermaLink="false">5a877968ff1c7c72b8b8d4ea</guid><category><![CDATA[go]]></category><dc:creator><![CDATA[Jon Kartago Lamida]]></dc:creator><pubDate>Sat, 17 Feb 2018 01:00:49 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>To install go, refer to <a href="https://blog.lamida.org/go-development-in-ubuntu-using-vim/">this post</a>.</p>
<h1 id="installingatom">Installing Atom</h1>
<p>Add PPA and install atom.</p>
<pre><code>curl -L https://packagecloud.io/AtomEditor/atom/gpgkey | sudo apt-key add -
sudo sh -c &apos;echo &quot;deb [arch=amd64] https://packagecloud.io/AtomEditor/atom/any/ any main&quot; &gt; /etc/apt/sources.list.d/atom.list&apos;
sudo apt update
sudo apt install atom
</code></pre>
<h1 id="installingatomgoplus">Installing Atom Go Plus</h1>
<p><a href="https://atom.io/packages/go-plus">Go-Plus</a> helps to make go development easier in atom. To install, just to Edit -&gt; Preferences  -&gt; Install. Search <code>go-plus</code> in Install Packages search bar then click install.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>