<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Dhanush Gopinath on Medium]]></title>
        <description><![CDATA[Stories by Dhanush Gopinath on Medium]]></description>
        <link>https://medium.com/@dhanushgopinath?source=rss-a1c6fefc4f2b------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*mZ7SWcXa5wpRvI8C.jpeg</url>
            <title>Stories by Dhanush Gopinath on Medium</title>
            <link>https://medium.com/@dhanushgopinath?source=rss-a1c6fefc4f2b------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 01:54:19 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@dhanushgopinath/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Half a decade of Geektrust.]]></title>
            <link>https://medium.com/@dhanushgopinath/half-a-decade-of-geektrust-514873292ad4?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/514873292ad4</guid>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[5-years]]></category>
            <category><![CDATA[startup]]></category>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Sat, 01 Aug 2020 12:59:49 GMT</pubDate>
            <atom:updated>2020-08-01T13:02:27.912Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/687/1*KhhG6jZvHxG-6eG8Dnj5pQ.png" /><figcaption>One of our earlier home pages</figcaption></figure><p>Today it has been 5 years since I &amp; Sneha Jain joined <a href="https://medium.com/u/f6b85bf96af1">Krishnan Nair</a> in building Geektrust.</p><p>Well of course, it had been one of the hardest decisions in my life to start up, but 5 years down the lane there are absolutely no regrets. It has been incredible working with Krishnan and Sneha.</p><p>From the days of roaming around and working from the cafes of Koramangala and Indiranagar, we have slowly graduated to 1 BHK &amp; 2 BHK offices and slowly and steadily built a team of 12 which include tech, ops &amp; sales. We could remain lean because of the hell lot of automation that went into Geektrust. And most importantly we do exist without getting a penny of VC money. Yes! We exist :D</p><p>These 5 years were not just of learning technically, but also about learning how a company is built and a product is sold. I had always thought that building a product is the hardest part, and always said it with pride. Today, with the 2 products we built in 5 years, I would say building/developing is easy-peasy. The hardest thing is selling the product. And mind you, this is coming from a person who codes 5 days a week for the last 17+ years.</p><p>Personally, the biggest challenge I faced in these 5 years is building the code evaluation automation engine, which we have aptly named Codu (codu.ai), as a tribute to code and Bengaluru. Codu today can predict Readability &amp; Object Orientedness of your program, based on the code evaluation we have done in the past.</p><p>Thanks to a lot of people who helped us in all parts of our life with Geektrust. And to those amongst us.Without the team of Clair, Midhu, Luka, Meenu, Shiby, Akshay, Adarsh, Gaurav &amp; Purnima we couldn’t have built Geektrust as it is today. Thanks to Madhav for being a guardian angel.Thanks to all our clients who trusted us and hired through us, and released the cheques faster to stay afloat.</p><p>Last, but not the least, thanks to the community of software developers who took our coding challenges and trusted us with the opportunities they got through us. Without your help and word of mouth marketing, we couldn’t have survived 5 years.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0C_YUtBR_MyZUBMiSlM5aQ.png" /><figcaption>Our home page now</figcaption></figure><p>Thank you all for making my last 5 years beautiful.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=514873292ad4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Automatically recovering RabbitMQ connections in Go applications]]></title>
            <link>https://medium.com/@dhanushgopinath/automatically-recovering-rabbitmq-connections-in-go-applications-7795a605ca59?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/7795a605ca59</guid>
            <category><![CDATA[recovery]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[distributed-systems]]></category>
            <category><![CDATA[messaging]]></category>
            <category><![CDATA[rabbitmq]]></category>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Mon, 01 Jun 2020 14:11:16 GMT</pubDate>
            <atom:updated>2020-06-01T14:11:16.358Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/560/1*cfXTB_qThe9nk3FlGq6mwg.png" /></figure><blockquote>Codu is an ML product, built by us, that reviews code how a developer would, for parameters that we’ve seen mostly matter in the real world, which is the ability to <strong>write clean code</strong> — code that others can read and understand.</blockquote><blockquote>You can read about <a href="https://medium.com/@krishnannair/automated-code-reviews-for-clean-code-b9d3c5e20b22">why</a> and <a href="https://medium.com/@krishnannair/how-we-automated-code-evaluation-for-clean-code-a601806b0245">how</a> we built it.</blockquote><p>At <a href="https://geektrust.in/">Geektrust</a>, we use <a href="https://www.rabbitmq.com/">RabbitMQ</a> as our message broker for communicating between distributed applications.</p><p>Recently when we introduced RabbitMQ in <a href="https://codu.ai/">Codu.ai</a>, we started seeing this issue of the connection getting dropped when the publisher/consumer is inactive for a long period of time.</p><p>Codu is built using <a href="http://golang.org/">Go</a>, and uses the <a href="https://godoc.org/github.com/streadway/amqp">Go client</a> supported by <a href="https://www.rabbitmq.com/tutorials/tutorial-one-go.html">RabbitMQ</a>. It is currently in <a href="https://medium.com/@krishnannair/automated-reviews-for-clean-code-private-beta-launch-a4952c4cb4d1">private beta</a>, and there are only a few regular users. Once in a while, when someone sends a request, they don’t get any response because the <a href="https://github.com/streadway/amqp/issues/91">Go client has lost its connection</a> with RabbitMQ server. As the <a href="https://github.com/streadway/amqp/issues/91#issuecomment-262338154">client library doesn’t give</a> an option for automatic connection recovery, we had to implement it ourselves.</p><p>We have only one publisher process and one consumer process that will publish and consume the messages to and from multiple queues in the same exchange. The consumer listens to messages from multiple queues and handles these messages differently based on the message type. Most of the sample code we saw, showed the example of one consumer for one queue, which was slightly different from our implementation. In this post, we show how we handled the auto-reconnect of a consumer and publisher even when connected to multiple queues.</p><h3>Setting things up</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/019d650f28a30e6defaaf708a414f3df/href">https://medium.com/media/019d650f28a30e6defaaf708a414f3df/href</a></iframe><p>The above gist shows how a RabbitMQ connection is established. I use a custom Connection struct to encapsulate all the necessary information. An object of this struct is returned by using the function NewConnection on the comms package. All the connections can be managed in the pool against a name, if you have multiple consumers and publishers. After creating a Connection object we need to call the Connect and BindQueue methods, so that the connection is established and queues are bound to the exchange. There is also a Reconnect method which is called when the connection is lost.</p><p>Now coming to the most important part. In the Connect method, a Goroutine is called, which will wait on after registering a listener on the NotifyClose method on the amqp.Connection object.</p><blockquote>From the AMQP library docs:</blockquote><blockquote>NotifyClose method on the amqp.Channel object registers a listener for when the server sends a channel or connection exception in the form of a Connection.Close or Channel.Close method</blockquote><p>When the ‘connection close’ event is received, we push a custom error to the err channel of the Connection object.</p><pre>go func() {<br>     //Listen to NotifyClose  <br>     &lt;-c.conn.NotifyClose(make(chan *amqp.Error)) <br>     c.err &lt;- errors.New(&quot;Connection Closed&quot;) <br>}()</pre><p>You need to be waiting on this channel and if there is an error, we call the Reconnect method, where we reestablish the connection. We will see how this is used in the consumer and publisher.</p><h3><strong>The Consumer side of things</strong></h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b00dc4e0f040f7b75b1833ffbcd90fdc/href">https://medium.com/media/b00dc4e0f040f7b75b1833ffbcd90fdc/href</a></iframe><p>In this gist you can see theConsume method which will loop through the queues and consume the messages from the amqp.Delivery channel. Once consumed, it is stored in map (this is not thread safe) and returned.</p><p>The HandleConsumedDeliveries method will handle these messages that are consumed from the channel for each queue in an infinite loop. It also takes in a function of definition func(Connection, string, &lt;-chan amqp.Delivery) which is the actual function that handles your message. This will be called in a separate go routine so that the messages are handled without any blocking. In this function we also wait for the err channel on the Connection object.</p><pre>if err := &lt;-c.err; err != nil {   <br>     c.Reconnect()   <br>     deliveries, err := c.Consume()   <br>     if err != nil {    <br>        panic(err)<br>     }<br>     delivery = deliveries[q]  <br>}</pre><p>On the NotifyClose listener defined while initialising the connection an error object is pushed to this channel, whenever the RabbitMQ channel/connection is closed. Here, when the error obtained is not nil, we reconnect the connection, and start consuming the deliveries again. The delivery channel for the specific object is set again so that the messages are picked up again and the fn object is called again. The consumer section below shows how all this is wired together.</p><h3>The Publisher side of things</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/634151600b54ba954c869e6dcdd85f5b/href">https://medium.com/media/634151600b54ba954c869e6dcdd85f5b/href</a></iframe><p>The publisher side of things is relatively easy.</p><p>Here, we use a non-blocking channel setup with the select keyword, as there are no Goroutines calling this method. So, if there is no error on the err channel, it just goes and publishes the message. Else if the connection is lost, it will reconnect and then publish the message.</p><h3>The Consumer application</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5d698f0fb4775e2a32b951aa7585493d/href">https://medium.com/media/5d698f0fb4775e2a32b951aa7585493d/href</a></iframe><p>The consumer main program is waiting forever as it has to wait for the messages arriving in the queues. We create a new Connection object, and call the methods Connect and BindQueue on it. Then, we consume the queued messages using the Consume method. Once this is done, we loop through all the queues, and call the HandleConsumedDeliveries method on each of them in a separate Goroutine. Notice that we pass a function messageHandler of type func(Connection, string, &lt;-chan amqp.Delivery), which actually deals with the raw message obtained from the queue. Here I am only printing a message using it.</p><h3>The Publisher</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7c35bdcbabb81e235a592f789fdf2107/href">https://medium.com/media/7c35bdcbabb81e235a592f789fdf2107/href</a></iframe><p>In this application, we create a new Connection object and then call the methods Connect and BindQueue on it. We loop through the queues and publish the message into each of this.</p><p>This program will be executed one time, so it won’t have the ‘connection close’ issue. But if you are running a web application and pushing messages to RabbitMQ, there is a chance that the connection will be closed on too much idling. At that time, the auto reconnect feature will come in handy.</p><p>Hope this was useful for some of you folks, and let me know if you got any questions in the comments section.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7795a605ca59" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to build Docker images on the Go]]></title>
            <link>https://faun.pub/how-to-build-docker-images-on-the-fly-2a1fd696c3fd?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/2a1fd696c3fd</guid>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[containers]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Fri, 18 Jan 2019 12:42:53 GMT</pubDate>
            <atom:updated>2019-07-18T15:34:59.472Z</atom:updated>
            <content:encoded><![CDATA[<p>Recently we started on an interesting task which will take <a href="http://geektrust.in/">Geektrust</a> to the next level. In our effort to give faster feedback to developers on their code submission, we wanted to automate the checking of input/output on an entire problem set. So far we have had only one problem — that too a smaller one — that could be <a href="https://medium.com/@dhanushgopinath/reading-docker-container-logs-with-golang-docker-engine-api-702233fac044">automatically evaluated</a>.</p><p>The high level idea is to get the candidate’s code inside a docker container and execute it. This docker container is created for the programming language she has solved the problem in. When the container is created an executable will be run to test the input and output of the candidate’s code. The executable will run the candidate’s code using the language specific execution command. For e.g. for Python it can be python main.py</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*SBepmXPvwiTbXAa9TN-h9Q.png" /></figure><p>For this we have to build Docker Images. These images will have the execution environment for each language, that a candidate will submit the code in. So there will be a Docker image for Java 1.8, another for Java 1.11, one for Ruby 2 etc. These docker files are pre-defined. But the code that executes the candidates code, inside the container, is not available as part of it. This is because it is bundled as a Go executable file. We do not want to build that every time and check it in along with the Dockerfile into the git repo.</p><p>So instead of doing a docker build -t build_name . we build the image programmatically using the <a href="https://github.com/moby/moby/tree/master/client">Go client</a> for <a href="https://docs.docker.com/develop/sdk/">Docker’s Engine API</a>.</p><p><strong>Docker Build Context</strong></p><p>Before we get into building the image programmatically it is important to understand what a Docker build context is.</p><p>Docker build context is essentially the source directory from where you execute your Docker builds. For the given Dockerfile</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ae0ce541a74348d87acbe6f8788d0169/href">https://medium.com/media/ae0ce541a74348d87acbe6f8788d0169/href</a></iframe><p>the source directory will look like this</p><blockquote>.<br>├── Dockerfile<br>├── test.env<br>└── test.exe</blockquote><p>This Dockerfile will build an image from Alpine Linux base image. When run, a program test.exe will be executed inside the container.</p><p>The step COPY ./test.exe ./ copies the executable file test.exe from the host machine to the work directory of the Docker image that is built. All the files you need have inside the container should be in the Docker build context before you build the image.</p><p><strong>Building the Image</strong></p><p>There are different ways to build a Docker image. The traditional way is to build from the source directory (docker build -t tag.) We can also build an image from a TAR file. In this case we pass the TAR file which contains the Docker build context to the docker build command. We build the Docker image programmatically this way.</p><p>The steps to build the image in our case are the following.</p><ol><li>Clone the repo which has the Dockerfile to a temporary folder.</li><li>Download &amp; copy the pre-built exe to the temporary folder created from the above step.</li><li>Create the tar file of the Docker build context from the temporary folder.</li><li>Build the image using Docker Engine API using the tar file we created.</li></ol><p>The code for step 4 is given below</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f0eb5944240977632e4872fc753b2771/href">https://medium.com/media/f0eb5944240977632e4872fc753b2771/href</a></iframe><p>In the above code BuildImage takes in the Docker source directory location and a tagName. A context instance is created with 5 minutes timeout. dockerFileTarReader, err := tarDirectory(dockerBuildCtxDir) will convert the directory into a Tar file of type io.Reader . You can use <a href="https://twitter.com/mholt6">Matt Holt’s</a> <a href="https://github.com/mholt/archiver">archiver</a> in Go for creating a tar. Once the tar file is created we pass it onto the ImageBuild api of the Docker client instance. This client instance can be created from the <a href="https://github.com/moby/moby/tree/master/client">Go client library</a> for the Docker Engine API</p><pre>resp, err := cli.ImageBuild(<br>  ctx,<br>  dockerFileTarReader,<br>  types.ImageBuildOptions{<br>   Dockerfile: &quot;Dockerfile&quot;,<br>   Tags:       []string{tagName},<br>   NoCache:    true,<br>   Remove:     true,<br>   BuildArgs:  buildArgs,<br>  })//cli is the docker client instance created from the engine-api</pre><p>The ImageBuildOptions take the options required for the Docker build. It is the Go struct for the <a href="https://docs.docker.com/engine/reference/commandline/build/#options">build options</a> in the docker build command. NoCache ensures that cache is ignored when we run the Docker build every time. Tags adds the tags you want to give to the build. Remove ensures that the intermediate containers created are removed after a successful build.</p><p>The response returned has a Body of type io.ReadCloser which can then be read for the logs. These logs are exactly the same when you run a docker build from the command line.</p><p>Once the call to BuildImage successfully returns, we have built a docker image programmatically.</p><p>You can plug this code where ever you want to build such docker images on the fly. You can verify the availability of the image using the docker images command on the host machine. You can also do a docker run &lt;image_name&gt; to create and execute the container.</p><p><em>[About the author — Dhanush is co-founder &amp; CTO at </em><a href="http://www.geektrust.in/"><em>Geektrust</em></a><em>.</em></p><p><a href="http://www.geektrust.in/"><em>Geektrust</em></a><em> is built for technologists to connect with remarkable job opportunities.]</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/727/0*Piks8Tu6xUYpF4DU" /></figure><p><strong>Join our community Slack and read our weekly Faun topics ⬇</strong></p><figure><a href="https://www.faun.dev/join/?utm_source=medium.com%2Ffaun&amp;utm_medium=medium&amp;utm_campaign=faunmediumbanner"><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*oSdFkACJxs5iy1oR" /></a></figure><h4>If this post was helpful, please click the clap 👏 button below a few times to show your support for the author! ⬇</h4><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2a1fd696c3fd" width="1" height="1" alt=""><hr><p><a href="https://faun.pub/how-to-build-docker-images-on-the-fly-2a1fd696c3fd">How to build Docker images on the Go</a> was originally published in <a href="https://faun.pub/">FAUN.dev() 🐾</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[When the Kerala Chief Minister extends his hand for request.]]></title>
            <link>https://medium.com/@dhanushgopinath/when-the-kerala-chief-minister-extends-his-hand-for-request-d5ea5f3a7799?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/d5ea5f3a7799</guid>
            <category><![CDATA[kerala-flood-relief]]></category>
            <category><![CDATA[kerala-flood]]></category>
            <category><![CDATA[doitforkerala]]></category>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Fri, 17 Aug 2018 03:59:11 GMT</pubDate>
            <atom:updated>2018-08-17T04:00:42.168Z</atom:updated>
            <content:encoded><![CDATA[<blockquote>Note: This is my translation of the <a href="https://www.facebook.com/abdul.rasheed.73932/posts/10215208963072732">original pos</a>t published by <a href="https://www.facebook.com/abdul.rasheed.73932?hc_ref=ARQpo3e6jXZS5LP4XDjgSVJ3vhocpWb_jCJuphHhpVsov24TI1L3-C6-3mlaiFNk02A&amp;fref=nf">Mr. Abdul Rasheed</a>. I took the liberty to translate this, without his permission, from Malayalam to English so that the essence of his story can be spread to a wider audience. The ‘I’ in this article is Mr. Abdul Rasheed.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/1*4aC39B2Ac1H4Oy9qemlwIg.jpeg" /></figure><p>I had the opportunity to interview Minister G Sudharakaran at his office. While talking with him in detail, Kondotty MLA and Muslim League leader Muhamadunni Haji came in with an old lady. She came with the MLA to see the Minister for requesting something.</p><p>Some years back, her son had taken a loan from a nearby co-operative bank, by pledging their house, and left the town without paying it back. Now the interest and the principal amount has gone up and the bank decided to attach the property. The poor old lady has no where to go.</p><p>Her life, explained in tears, moved the minister. He forgot the interview and involved in fixing her issue. We all know how difficult are the bank formalities. But that day, I realised a minister can remove any red-tapes in governance, if he/she takes it up.</p><p>10 phone calls. Strict instructions in his usual style .. that was enough. In 30 min he included the old lady in some scheme and relieved her of all the issues.</p><p>With teary eyes when she thanked the minister and left, he said to me. “Poor. The MLA is a good soul, so he brought her. Otherwise her property would have gone”.</p><p>How much ever we criticise the Kerala politicians, in between all the politics they play, they do a lot of good for the common people. When bureaucracy, citing laws, fails to provide support to the poor and needy they can go to only place and knock. That is their representative in the state assembly. Whichever Kerala politician’s house you go, you can see people standing there with their painful stories. There still remains some goodness in the name of humanity amongst our politicians, irrespective of the party and flag they represent. That is why a Ramesh Chennithala and Pinarayi Vijayan can travel together in the same helicopter and reach the places where calamity has struck.</p><p>The point I am coming to is that, whoever is ruling, one of the good thing about Kerala is its Chief Minister’s Distress Relief Fund. Irrespective of the party lines deserving people get it. Kerala is one of the states of India, which distributes the CMDRF in an efficient way.</p><p>Last UDF government disbursed 800 Crore Rupees to the needy in the its 5 years. This Pinarayi government have disbursed 423 crores in the last 2 years. It has helped 234899 people stay afloat. (Donations to CMDRF is less. Most of it comes from the Lottery sale)</p><p>This government made the process easier. The disbursement is via DMR software these days. Now you need not go looking for the MLA, need not go to Thiruvananthapuram. Everything can be done online. You can even get the status of it online. Once applied the money will be in the account within 100 hours. When this government took charge there was 30000 requests waiting for them. That was all settled very fast. The government gave permissions to Thahasildars to disburse the money, after opening an account in the state treasury.</p><p>If you want to know the goodness of Kerala in this, you need to look at other states. In Maharashtra brokers made fake documents to get the amount. In Karnataka, the fund itself was converted into an FD by the officials, in 2010. Goa spent it in extravaganza and Punjab brokers took it.</p><p>In Kerala there had not been a single instance of complaint against the CMRDF. The fund is distributed to people who have serious illness, people who have met with accidents and to people who have met with natural calamities. The District Collector, Revenue special secretary and Revenue minister can disburse upto 10000, 15000 &amp; 25000 Rs respectively from this fund. Chief Minister can disburse upto 3 Lakhs rupees. Above that you need the permission of the senate/assembly.</p><p>In this times of distress and calamity our CM, Shri Pinarayi Vijayan has been requesting time and again to individuals and companies to donate to this fund. In reality the chief minister is extending his hand of request for our state. We can be proud that every rupee that reaches the CMDRF is distributed to the people who deserve it. From July 26th to August 9th 2018, 1.75 Crore rupees has been reached this fund . You can send your donations to this account</p><p><strong>Bank : State Bank of India (SBI)<br>Account Number : 67319948232<br>Branch : City Branch, Thiruvananthapuram<br>IFSC : SBIN0070028<br>PAN: AAAGD0584M<br>Account Type: Savings<br>SWIFT CODE : SBININBBT08</strong></p><p>UPI: <strong>keralacmdrf@sbi</strong><br>Website: <a href="https://l.facebook.com/l.php?u=https%3A%2F%2Fdonation.cmdrf.kerala.gov.in%2F&amp;h=AT16u6-87Y1oXk1j60PFdGzAmWwWEhaUndyVl3SCPHsUX_EwWG0hPljFsjrM3VRvVjHB2_SHwm9MiR9pV3BfgtWFrtFJ0_YKEcI93O1TAzxli_2JFUA3W3kE5quE4nIOatDFfkJ-LFSebrEwEQQLgHnN">https://donation.cmdrf.kerala.gov.in/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d5ea5f3a7799" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kerala is flooding. We need your help]]></title>
            <link>https://medium.com/@dhanushgopinath/kerala-is-flooding-we-need-your-help-99216ca8c342?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/99216ca8c342</guid>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Fri, 17 Aug 2018 02:04:48 GMT</pubDate>
            <atom:updated>2018-08-17T02:04:48.212Z</atom:updated>
            <content:encoded><![CDATA[<p>Hello,</p><p>My state, Kerala, has been reeling under heavy monsoon and floods. A lot of people have lost their lives and belongings. According to reports, so far 94 people have lost lives and more than a lakh of people are staying in relief camps and other places. The state government is in full action and helping everyone to evacuate and rescue. Central government is providing the necessary support. But we need your help. We are in need of funds and supplies.</p><p>An organisation Anbodu Kochi has setup different collection centers in Bangalore to collect supplies. You can donate to the Kerala CM’s Distress Relief Fund through <a href="https://donation.cmdrf.kerala.gov.in/">here</a>. You can be sure that it will reach the poor &amp; needy as Kerala is one of the best states that manages its <a href="https://www.facebook.com/dhanush.gopinath/posts/10216223871845396">CMDRF fund well</a>.</p><p>You can do NEFT transfer to this account.</p><p>Bank :<strong> State Bank of India (SBI)</strong></p><p>Account Number : <strong>67319948232</strong></p><p>Branch : <strong>City Branch, Thiruvananthapuram</strong></p><p>IFSC : <strong>SBIN0070028</strong></p><p>PAN: AAAGD0584M</p><p>Account Type: Savings</p><p>SWIFT CODE : SBININBBT08</p><p>Or do an UPI transfer to <strong>keralacmdrf@sbi</strong></p><p>Following are the places in Bangalore, where Anbodu Kochi has setup collection centers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bdVsDLJbu5t1s6eR0udzQw.jpeg" /></figure><p>And they are in need of these items</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/904/1*QHL1icqcWGQt1U_Om0g4Bg.jpeg" /></figure><p>Please do share this message with your other groups.</p><p>I am sure our God’s own country will be back to its glory days soon with all your help.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=99216ca8c342" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Concurrent HTTP downloads using Go]]></title>
            <link>https://medium.com/@dhanushgopinath/concurrent-http-downloads-using-go-32fecfa1ed27?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/32fecfa1ed27</guid>
            <category><![CDATA[https]]></category>
            <category><![CDATA[concurrency]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[channel]]></category>
            <category><![CDATA[goroutines]]></category>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Thu, 01 Feb 2018 08:19:59 GMT</pubDate>
            <atom:updated>2018-02-05T13:35:04.482Z</atom:updated>
            <content:encoded><![CDATA[<p>Recently for an implementation of feature in <a href="http://geektrust.in/">Geektrust</a>, we had to download multiple images from the internet and use it. This had to be an efficient implementation. This post is a brief explanation of the simple implementation done using goroutines and channels.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*qBiZD7mvwkNcIGDrkyZeCQ.jpeg" /><figcaption>Image courtesy — <a href="https://hackernoon.com/why-we-love-concurrency-and-you-should-too-c64c2d08a059">https://hackernoon.com/why-we-love-concurrency-and-you-should-too-c64c2d08a059</a></figcaption></figure><p><a href="http://golang.org/">Go</a> has an <a href="https://golang.org/pkg/net/http/">http</a> package which has simple APIs to do HTTP operations. For e.g. if you want to download a page all you need to do is this.</p><pre>resp, err := http.Get(&quot;<a href="http://example.com/">http://example.com/</a>&quot;)<br>if err != nil {<br>	// handle error<br>}<br>defer resp.Body.Close()<br>body, err := ioutil.ReadAll(resp.Body)</pre><p>Given below is the implementation of downloading a file from a public URL and using it as bytes.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bc21aeb52b9cd4b390991b741993c3b3/href">https://medium.com/media/bc21aeb52b9cd4b390991b741993c3b3/href</a></iframe><p>For downloading multiple files concurrently you can use the help of goroutines and channels.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a2f8f98a2daae382e81918a16ab8ae9f/href">https://medium.com/media/a2f8f98a2daae382e81918a16ab8ae9f/href</a></iframe><p>In the above code snippet, we initialise two channels, one for sending the file downloaded as <strong><em>[]byte</em></strong> type and another for sending any errors that happened while downloading.</p><p>We then loop though all the urls and call the <strong><em>downloadFile</em></strong> method for each of them in a goroutine. These goroutines are executed concurrently and so the for loop is finished processing in no time. Inside the goroutine each file is downloaded and we get back bytes and error.</p><p>If there is an error in the download, then the error is pushed to the error channel and nil value is pushed to the done channel. If there is no error then the bytes are pushed to the done channel and a nil entry is pushed to the error channel.</p><p>An array of byte arrays is declared to collect the downloaded files back. We again loop through as many times as there are URLs to collect the byte array back from the done channel.</p><pre>bytesArray = append(bytesArray, &lt;-done)  <br>if err := &lt;-errch; err != nil {   <br>   errStr = errStr + &quot; &quot; + err.Error()  <br>}</pre><p>These two lines inside the for loop wait for the done and the error channel to receive data. Once the data has arrived, it increments the loop count. Bytes are appended to the array of bytes while error string is appended, if there are any errors.</p><p>You have now downloaded the files concurrently and they are available as an array of bytes. All just using simple Go code.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=32fecfa1ed27" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How we used Machine Learning to identify what sort of technologists register on Geektrust]]></title>
            <link>https://medium.com/@dhanushgopinath/how-we-used-machine-learning-to-identify-what-sort-of-technologists-register-on-geektrust-bdcbc59332db?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/bdcbc59332db</guid>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[recruitment]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[python]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Mon, 16 Oct 2017 05:31:13 GMT</pubDate>
            <atom:updated>2017-10-16T06:20:59.732Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HOCmTXv4pZJmxKLMljl3fg.png" /></figure><p>Sometime back at <a href="https://geektrust.in/">Geektrust</a>, we were up with our recommendation engine, recommending kick-ass developers to our clients based on their profile, years of experience and technology. It was built on <a href="http://golang.org/">Go</a> &amp; <a href="https://www.elastic.co/products/elasticsearch">Elasticsearch</a>. What we did was match the user profiles for the requirements of the companies. In addition we matched the best developers who had a close similarity to what the company was looking for. We took small steps into the world of Machine Learning at that time by doing similarity matches.</p><p>But, we had a problem. We were relying on the technologies that our users entered, and people always entered Java. Not everyone, but at least 60–70% of them did that. This resulted in QA Engineers with some Java expertise getting recommended to a company that was looking for a hardcore Java Backend developer. This didn’t look good in front of the customer and we decided to tighten up our recommendations. What we needed to do was identify what kind of developers were registering on our site. And that’s where Machine Learning came to our help.</p><h4>Training Data</h4><p>We went with supervised learning, which means classifying data based on previously labelled training data.</p><p>As part of this, the first thing we did was to list down the features we wanted to identify in a developer to classify him/her as a Backend or Frontend or Fullstack developer. Keeping that in mind we came up with a set of features like count of backend technologies in a user and scan their resumes to understand what kind of technologies have they worked on.</p><p>Once these were identified, we churned out a file that marked these features against each developer in our database. This was the first step in creating our training data.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/96802317bc7dc89088e11ca70d97eb3d/href">https://medium.com/media/96802317bc7dc89088e11ca70d97eb3d/href</a></iframe><p>In the above file, the columns indicate the features and the last column indicates the item we want to predict. In the training data the existing data was cleaned and marked with a specific role. This can be generated with scripts, but without 100% accuracy. We had to modify our training data to label the column that needs to be predicted, which is <strong>role</strong>. 6 of us worked through around 7000 rows of data and verified, validated and modified the data, if required.</p><h4>Training &amp; Testing</h4><p>Once the training data was ready we had to test the accuracy of this model. We tried different classifiers like K Nearest Neighbours (KNN), Decision Trees and Support Vector Machines(SVM). We also had to go back and fine tune the training data, adding more features, removing some of them. All these decisions were based on the accuracy we got on these different classifiers. SVM gave us the best accuracy and we went ahead with it using a linear Kernel. The implementation was in Python. With well established libraries like <a href="http://scikit-learn.org/">scikit-learn</a> , <a href="http://www.numpy.org/">NumPy</a>, <a href="https://www.scipy.org/">SciPy</a> and <a href="http://pandas.pydata.org/">pandas</a> available, we had little doubt in selecting Python as our go-to language for ML.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bf8279fc50d1b13c0fbd47921656ee3a/href">https://medium.com/media/bf8279fc50d1b13c0fbd47921656ee3a/href</a></iframe><p>The above code shows how you can train &amp; test your model. The trained data in csv file is split into test &amp; train data and then the test data is used to check if the prediction is correct or not. It also gives you the probability percentage of the prediction. The predictions made by the SVM were verified against the already trained data and it was pretty accurate.</p><p>And that’s it. Now for every profile update the developer does on Geektrust, we build the feature data and predict the role from it. Once we predict what kind of a developer he/she is, we use that information to recommend them accurately to a specific requirement of a company. Now our recommendations to companies are better than earlier.</p><p>However, this doesn’t guarantee that the predicted role is correct all the time. Sometimes, we get predicted role with probabilities as low as 20–30%. In such cases we manually override the prediction, to what we think is the role of the user. We also update the existing training data at periodic intervals, which helps in improving future predictions.</p><p>At <a href="https://geektrust.in/">Geektrust</a>, we continue to work on ML &amp; AI related stuff and this is an ongoing activity. We have started working on our own resume parser and look forward to building an advanced code evaluation engine that checks for clean code.</p><p><em>[About the author — Dhanush is co-founder at </em><a href="http://www.geektrust.in/"><em>Geektrust</em></a><em> and takes care of all things tech.</em></p><p><a href="http://www.geektrust.in/"><em>Geektrust</em></a><em> is built for technologists to connect with remarkable job opportunities.]</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bdcbc59332db" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Reading docker container logs with Golang docker-engine API]]></title>
            <link>https://medium.com/@dhanushgopinath/reading-docker-container-logs-with-golang-docker-engine-api-702233fac044?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/702233fac044</guid>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[containers]]></category>
            <category><![CDATA[remote-engine-api]]></category>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Sat, 27 Aug 2016 06:46:43 GMT</pubDate>
            <atom:updated>2016-08-27T06:46:43.423Z</atom:updated>
            <content:encoded><![CDATA[<p>We released a new feature on <a href="http://geektrust.in/">Geektrust</a> yesterday, where developers can submit solution to one of our coding problems online. There is an IDE like editor and they can write code on our site. To execute this code, we create an instance of a docker container each time.</p><p>The idea was to execute the code in the isolated container and log the output/error in JSON format, and then read this log to send the response back to the developer who is executing his/her code. A REST service will receive the developers code and language in which he/she has written. This service is written in <a href="http://golang.org/">Go</a> and I used <a href="http://docker.io/">Docker’s</a> <a href="https://github.com/docker/engine-api">docker-engine</a> API for creating &amp; running the container. We read the logs using the same API.</p><p>However there is a catch while reading the logs from <strong>stdout</strong> stream of container. The data written by the container is in a format which has a HEADER &amp; PAYLOAD. The header contains the information about the stream and payload and is encoded on the first 8 bytes like this.</p><blockquote>header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}</blockquote><p>If you read the container logs like this</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a3f48aa6515da283d194416e23a5116f/href">https://medium.com/media/a3f48aa6515da283d194416e23a5116f/href</a></iframe><p>then you will see unicode characters printed on the console and then the actual payload. If you expect a JSON from the console and is ready to decode the JSON to a struct like this</p><blockquote>json.NewDecoder(strings.NewReader(string(content))).Decode(&amp;myStruct);</blockquote><p>then this will fail, because it is reading data which contains unicode characters and JSON.</p><p>So we have to skip the first eight bytes of the stream and read from the reader like this.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8d8de0352e019deec6fbdb787e862060/href">https://medium.com/media/8d8de0352e019deec6fbdb787e862060/href</a></iframe><p>When I wrote the code first (like in the first gist), I was not aware of this issue and I couldn’t get what these unicode characters were. The documentation on the <a href="https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/get-container-logs">remote api for getting the container logs</a> doesn’t have a mention about it. It was this <a href="https://github.com/docker/docker/issues/7375#issuecomment-51462963">issue</a> raised on Github that <a href="https://github.com/docker/docker/issues/7375#issuecomment-51462963">pointed me</a> to docker remote-api’s <a href="https://docs.docker.com/engine/reference/api/docker_remote_api_v1.24/#/attach-to-a-container">Attach Container documentation</a> which explains about HEADER &amp; PAYLOAD. Hopefully some body will update the remote API’s documentation.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=702233fac044" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Sending HTML emails using templates in Golang]]></title>
            <link>https://medium.com/@dhanushgopinath/sending-html-emails-using-templates-in-golang-9e953ca32f3d?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/9e953ca32f3d</guid>
            <category><![CDATA[smtp]]></category>
            <category><![CDATA[golang]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Mon, 25 Apr 2016 09:01:52 GMT</pubDate>
            <atom:updated>2016-04-25T09:41:45.356Z</atom:updated>
            <content:encoded><![CDATA[<p>In the <a href="http://geektrust.in/">GeekTrust</a> application we send a lot of emails that are auto-generated at runtime using HTML Templates. In the new application, which we are currently developing in <a href="http://golang.org/">Go</a>, we need the same feature. So this post is a short read about reading a HTML template file and sending email using Go’s <a href="https://golang.org/pkg/html/template/"><strong>html/template</strong></a><strong> </strong>and <a href="https://golang.org/pkg/net/smtp/"><strong>net/smtp</strong></a><strong> </strong>packages.</p><p>The code is as given below.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ec72781455470d61fe20092b81d46dc6/href">https://medium.com/media/ec72781455470d61fe20092b81d46dc6/href</a></iframe><p>In this I encapsulate the smtp request in a struct <strong>Request</strong>. It contains basic things like To, Subject, Body. This template file has the data placeholders which will be replaced with actual data values by Golang’s <strong>html/template</strong> package <a href="https://golang.org/pkg/html/template/#Template.Execute"><strong>Execute</strong></a> method.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e47c3b9b292ac5c1d19e8641c2efe2e0/href">https://medium.com/media/e47c3b9b292ac5c1d19e8641c2efe2e0/href</a></iframe><p>The template data is a struct which has <strong>Name</strong> &amp; <strong>Url</strong> as the field values. It is initialised with values and passed to the <strong>NewRequest</strong> method to create an object of Request.</p><pre>templateData := struct {<br>    Name string<br>    URL string<br> }{<br>    Name: “Dhanush”,<br>    URL: “<a href="http://geektrust.in/">http://geektrust.in</a>&quot;,<br> }</pre><p>Once the instance of <strong>Request</strong> is created, then <strong>ParseTemplate</strong> method is called on it. This method receives a template filename and template data. It parses the template file and executes it with the template data supplied. A <strong>bytes.Buffer</strong> is passed to the <strong>Execute</strong> method as<strong> io.Writer </strong>so that we get back the HTML string with the data replaced. This HTML string is then set as the Email Body.</p><p>The <strong>SendEmail</strong> method sets the MIME encoding as <strong>text/html</strong> and calls <strong>smtp</strong> package’s <strong>SendMail</strong> method to send the email. When the email is sent successfully the SendEmail method returns a true value.</p><p><em>Note:</em></p><ol><li><em>If you return the Request in ParseTemplate method, instead of the error, then we make the call in one line.</em></li></ol><pre><em>ok,err := NewRequest([]string{“junk@junk.com”}, “Hello Junk!”, “Hello, World!”, “template.html”, templateData).ParseTemplate().SendEmail()</em></pre><p><em>But then any error coming out of ParseTemplate may have to be tracked inside the method.</em></p><p>2. <em>Read the package documentation of </em><strong><em>html/template</em></strong><em> to understand how Golang replaces the HTML with actual data.</em></p><p>3. <em>Thanks to </em><a href="https://github.com/jijeshmohan/"><em>Jijesh Mohan</em></a><em> and </em><a href="https://github.com/navaneeth"><em>Navaneeth</em></a><em> K. N in making the Go code more idiomatic, than it was before :)</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9e953ca32f3d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building our first app in Go — A recommendation engine]]></title>
            <link>https://medium.com/@dhanushgopinath/building-our-first-app-in-go-a-recommendation-engine-5f24aa81d957?source=rss-a1c6fefc4f2b------2</link>
            <guid isPermaLink="false">https://medium.com/p/5f24aa81d957</guid>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[recommendation-system]]></category>
            <category><![CDATA[golang]]></category>
            <dc:creator><![CDATA[Dhanush Gopinath]]></dc:creator>
            <pubDate>Tue, 12 Apr 2016 09:21:43 GMT</pubDate>
            <atom:updated>2016-04-12T11:15:01.750Z</atom:updated>
            <content:encoded><![CDATA[<p>So, on Friday, <a href="http://geektrust.in/">we</a> deployed our first <a href="http://golang.org/">Go</a> application in production. Right now it is powering our <a href="https://www.geektrust.in/startup">mini recommendation engine</a> built on top of Elasticsearch. Until now we were using Go for some minimal reporting, which I would say didn’t even account for 1% of our code base.</p><p>GeekTrust, from its start last year, has always been a Javascript shop. I selected Javascript as at that point of time, because we wanted to go to production quickly. We had to try out our business idea super fast. And Javascript helped us do that.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_cWvRISRbqrAjahstqTg8g.png" /></figure><p>I have been coding Java since 2003 and always been a fan of it. I would also admit that it solved a lot of complex problems for me. In August 2015 I just waved goodbye to Java. And I picked up Javascript actively (I have done some JS coding before on the job).</p><p>Around 3 years back, I decided that I wanted to be a Polyglot programmer. I wanted to learn something new in programming. I had shortlisted Python, Go, Haskell and Javascript as the languages I wanted to be an expert on. I went and did an Udacity course in Python. Learned Go at the free time and kept reading about Haskell. But I didn’t become a good programmer in any of those except Python.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/180/1*pv0_9hGmQcSZErKaylZCRw.png" /><figcaption>The Go Gopher designed by Renee French</figcaption></figure><p>Last year I attended <a href="http://gophercon.in/">GopherCon India</a> and was mesmerised by the talks various people gave. I had to learn and write code. I kept doing simple things on my <a href="http://github.com/dhanush">github</a>. I even extended <a href="https://twitter.com/goinggodotnet">William Kennedy</a>’s Ping pong problem to Cricket, my favourite sport.</p><p>When we started GeekTrust I wanted to write everything in Go. But I was still not fluent in Go, and I knew it will take time to learn, so I chose JS. This year too I attended GopherCon India. After that keynote from <a href="https://twitter.com/markbates">Mark Bates</a>, I realised I am also fighting the <a href="https://www.youtube.com/watch?v=TQ0gn6ihN-g&amp;index=14&amp;list=PLxFC1MYuNgJT_ynbXGuYAZbSnUnq-6VQA">Go FUD</a>. If you have fear, uncertainty and doubt about Go, you should watch that talk. And around that time, we had made some decisions about our product roadmap. I saw an opportunity to build an independent service and I decided to develop it in Go. As I started developing, I realised that I can do things fast and it was quite simple to do it. I was eliminating FUD.</p><p>Matthew Campbell’s <a href="https://www.youtube.com/watch?v=4bCaSSQsKvQ&amp;list=PLxFC1MYuNgJT_ynbXGuYAZbSnUnq-6VQA&amp;index=19&amp;nohtml5=False">talk</a> and Bryan Liles’ <a href="https://www.digitalocean.com/company/blog/taming-your-go-dependencies/">article</a> helped me understand about monorepo. The recommendation engine wouldn’t have seen daylight without <a href="https://github.com/olivere">Oliver Eilhard</a>’s beautiful <a href="https://github.com/olivere/elastic">Golang client for Elastic</a>. Many thanks for that Oliver. I could easily convert the Elastic JSON requests to code and would highly recommend it. <a href="https://twitter.com/jijeshmohan">Jijesh Mohan</a> helped a lot with insights into code organisation, monorepos, middleware &amp; what not. And so has the Golang communities.</p><p>At this moment, we are on the path to do new things in Go. Soon, I hope, the entire GeekTrust platform would be Powered by Go.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5f24aa81d957" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>