<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: George Calianu</title>
    <description>The latest articles on DEV Community by George Calianu (@geosoft1).</description>
    <link>https://dev.to/geosoft1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F73259%2F08254425-9933-46dd-8cb9-2f045d5efa86.jpeg</url>
      <title>DEV Community: George Calianu</title>
      <link>https://dev.to/geosoft1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geosoft1"/>
    <language>en</language>
    <item>
      <title>Server side application skeleton for Go language</title>
      <dc:creator>George Calianu</dc:creator>
      <pubDate>Tue, 23 Apr 2019 08:54:30 +0000</pubDate>
      <link>https://dev.to/geosoft1/server-side-application-skeleton-for-go-language-did</link>
      <guid>https://dev.to/geosoft1/server-side-application-skeleton-for-go-language-did</guid>
      <description>&lt;p&gt;Writing web application in Go can be pretty hard if you take care about login process wich include signing in, singing out, password recovery and minimal user management (like changing name, password and deleting account).&lt;/p&gt;

&lt;p&gt;The solution can be a high level skeleton to help all those developers to focus on the application content.&lt;/p&gt;

&lt;p&gt;Project is a work in progress, hosted on Github and is documented with code examples and some pictures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/geosoft1/ssas"&gt;https://github.com/geosoft1/ssas&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How the things works? Supposing you have some experience with Go language and Mysql database, download the project from repository and compile.&lt;/p&gt;

&lt;p&gt;You must create a database on your server and import &lt;code&gt;database.sql&lt;/code&gt; file into (adjust before the file with your database name). In &lt;code&gt;model&lt;/code&gt; folder you will find a model for Mysql Workbench application. You can use this model to sincronize with an existing database.&lt;/p&gt;

&lt;p&gt;Next, you must complete the configuration file &lt;code&gt;conf.json&lt;/code&gt;. Basically you must set the database connection informations like ip/domain, user, password and schema name.&lt;/p&gt;

&lt;p&gt;Also, you may need to set the mailer for password recovery procedure. No big deal here, use a mailbox created for this purpose.&lt;/p&gt;

&lt;p&gt;If you run the skeleton for the first time you will be asked to add a new user (or signup).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--daUVSek5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/signup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--daUVSek5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/signup.png" alt="signup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feel free to do this and then login&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0Gwzskd5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/signin.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Gwzskd5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/signin.png" alt="signin"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that you must see the home page&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---Z9hJyAv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/home.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---Z9hJyAv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/home.png" alt="home"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can manage local user account, logout and recovery forgotten password by clicking on the options from the top right bar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---UiwYh-p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/user.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---UiwYh-p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/user.png" alt="user"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A nice part is that you have a fallback offline page for network fails.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qnxGIIy1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/cache.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qnxGIIy1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/geosoft1/ssas/raw/master/static/images/cache.png" alt="home"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you are ready to write your applications, take a look over &lt;a href="https://github.com/geosoft1/ssas#adding-a-simple-application"&gt;how to add simple application&lt;/a&gt; section from documentation to see how to extend the skeleton with new functionalities. A dummy example explain this.&lt;/p&gt;

&lt;p&gt;Note that you will need a HTML5 browser to see the application but you shouldn't have problems with modern browsers. You can also use Chrome &lt;a href="https://developers.google.com/web/fundamentals/app-install-banners/"&gt;application&lt;/a&gt; mode for an experience more closest to native applications.&lt;/p&gt;

&lt;p&gt;Enjoy.&lt;/p&gt;

</description>
      <category>go</category>
      <category>web</category>
    </item>
    <item>
      <title>Versioning your API in Go</title>
      <dc:creator>George Calianu</dc:creator>
      <pubDate>Mon, 24 Dec 2018 08:33:26 +0000</pubDate>
      <link>https://dev.to/geosoft1/versioning-your-api-in-go-1g4h</link>
      <guid>https://dev.to/geosoft1/versioning-your-api-in-go-1g4h</guid>
      <description>&lt;p&gt;At some point in time your API need to have versions like &lt;code&gt;/v1&lt;/code&gt; or &lt;code&gt;/v2&lt;/code&gt; (like &lt;a href="https://developer.github.com/v3/"&gt;github&lt;/a&gt; API).&lt;br&gt;
To implement this in Go I will use &lt;a href="https://github.com/gorilla/mux"&gt;gorilla/mux&lt;/a&gt; router and I will assume you have a functional &lt;a href="https://golang.org/doc/install"&gt;Go&lt;/a&gt; environment.&lt;/p&gt;

&lt;p&gt;We will make a new project with the following &lt;code&gt;main.go&lt;/code&gt; file:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "flag"
    "net/http"

    "github.com/gorilla/mux"
)

var (
    port = flag.String("port", "8080", "port")
)

func main() {
    flag.Parse()
    var router = mux.NewRouter()
    var api = router.PathPrefix("/api").Subrouter()
    api.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusNotFound)
    })
    http.ListenAndServe(":"+*port, router)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On short we have created a new router with a nice soubrouter for handling &lt;code&gt;/api&lt;/code&gt; which represent the base of our versioned routes.&lt;br&gt;
The routes will show like &lt;code&gt;/api/v1/endpoint&lt;/code&gt;,&lt;code&gt;/api/v2/endpoint&lt;/code&gt; and so on. &lt;/p&gt;

&lt;p&gt;Also we have defined a not found handler attached to the subrouter who just returns a status code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that we will use in the following various return codes to understand what routine is executed at each moment of time. &lt;/p&gt;

&lt;p&gt;In this step we can attach a &lt;a href="https://github.com/gorilla/mux#middleware"&gt;middleware&lt;/a&gt; to our subrouter to print what route is currently requested.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api.Use(func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println(r.RequestURI)
        next.ServeHTTP(w, r)
    })
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we are ready to add our first version of API&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var api1 = api.PathPrefix("/v1").Subrouter()
api1.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
})
api1.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusForbidden)
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the same manner like &lt;code&gt;/api&lt;/code&gt; creation, add &lt;code&gt;/v1&lt;/code&gt; subrouter and coresponding not found handler. Note that the base of this subrouter is &lt;code&gt;api&lt;/code&gt; subrouter not main &lt;code&gt;router&lt;/code&gt;. Also we have defined the handler function for an endpoint named &lt;code&gt;/status&lt;/code&gt;. Similarly we can create the &lt;code&gt;/v2&lt;/code&gt;. Just paste this code and replace 1 with 2 and our code become&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func main() {
    flag.Parse()
    var router = mux.NewRouter()
    var api = router.PathPrefix("/api").Subrouter()
    api.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusNotFound)
    })
    api.Use(func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            log.Println(r.RequestURI)
            next.ServeHTTP(w, r)
        })
    })
    var api1 = api.PathPrefix("/v1").Subrouter()
    api1.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
    })
    api1.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusForbidden)
    })
    var api2 = api.PathPrefix("/v2").Subrouter()
    api2.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusAccepted)
    })
    api2.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusNoContent)
    })
    http.ListenAndServe(":"+*port, router)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We are ready to test our API. For this run the project and use &lt;code&gt;curl&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -I 'localhost:8080/api/'
HTTP/1.1 403 Not Found

curl -I 'localhost:8080/api/v1/'
HTTP/1.1 404 Forbidden

curl -I 'localhost:8080/api/v1/status'
HTTP/1.1 200 OK

curl -I 'localhost:8080/api/v2/'
HTTP/1.1 204 No Content

curl -I 'localhost:8080/api/v2/status'
HTTP/1.1 200 Accepted
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tests looks ok but we miss the authentications for our API. First idea is to simply use a &lt;a href="https://github.com/gorilla/mux#matching-routes"&gt;MatcherFunc&lt;/a&gt; with a token and the following line&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var api = router.PathPrefix("/api").Subrouter()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;become&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var api = router.MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
    return r.Header.Get("x-auth-token") == "admin"
}).PathPrefix("/api").Subrouter()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Test again&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -I 'localhost:8080/api/v1/status' -H "x-auth-token: admin"
HTTP/1.1 202 OK

curl -I 'localhost:8080/api/v1/status' -H "x-auth-token: notadmin"
HTTP/1.1 404 Not Found
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Not good, if i enter a wrong password i will receive &lt;code&gt;not found&lt;/code&gt; error code. Basically is nothing wrong with this but i want to see that i'm not authorised. So, we will move the authentication code on the middleware and our finally code looks like that:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "flag"
    "net/http"
    "log"

    "github.com/gorilla/mux"
)

var (
    port = flag.String("port", "8080", "port")
)

func main() {
    flag.Parse()
    var router = mux.NewRouter()
    var api = router.PathPrefix("/api").Subrouter()
    api.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusNotFound)
    })
    api.Use(func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            if r.Header.Get("x-auth-token") != "admin" {
                w.WriteHeader(http.StatusUnauthorized)
                return
            }
            log.Println(r.RequestURI)
            next.ServeHTTP(w, r)
        })
    })
    var api1 = api.PathPrefix("/v1").Subrouter()
    api1.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
    })
    api1.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusForbidden)
    })
    var api2 = api.PathPrefix("/v2").Subrouter()
    api2.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusAccepted)
    })
    api2.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusNoContent)
    })
    http.ListenAndServe(":"+*port, router)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Final test&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -I 'localhost:8080/api/v1/status' -H "x-auth-token: admin"
HTTP/1.1 200 OK

curl -I 'localhost:8080/api/v1/status' -H "x-auth-token: notadmin"
HTTP/1.1 401 Unauthorized
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yay, we did it. We have versioned API with some authentication. See the &lt;a href="https://github.com/geosoft1/api1"&gt;project&lt;/a&gt; on github.&lt;/p&gt;

&lt;p&gt;Enjoy.&lt;/p&gt;

</description>
      <category>go</category>
      <category>api</category>
    </item>
    <item>
      <title>Conditional compilation and runtime module names in Go</title>
      <dc:creator>George Calianu</dc:creator>
      <pubDate>Thu, 06 Dec 2018 10:15:26 +0000</pubDate>
      <link>https://dev.to/geosoft1/conditional-compiling-and-runtime-module-name-in-go-44fl</link>
      <guid>https://dev.to/geosoft1/conditional-compiling-and-runtime-module-name-in-go-44fl</guid>
      <description>&lt;p&gt;Conditional compilation in Go language is a very nice feature but what if we want to know at runtime what modules we just compiled (do not confuse with the new Go modules!). We can define a file as a particular module of our application. So, knowing that if the files are compiled or not can be interesting but we haven't a standard mechanism to do this at runtime.&lt;/p&gt;

&lt;p&gt;Let supose we have three dummy files &lt;code&gt;main.go&lt;/code&gt;, &lt;code&gt;module1.go&lt;/code&gt; and &lt;code&gt;module2.go&lt;/code&gt; doing nothing and part of package &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt; file&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

func main() {
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;module1.go&lt;/code&gt; file&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//+build module1

package main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;module2.go&lt;/code&gt; file&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//+build module2

package main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Build arguments are given at compile time as &lt;code&gt;tags&lt;/code&gt;, eg.:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; go build -tags="module1 module2" -o test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Unfortunately the build args are no more accesible after the compiling process, nowhere are writen what was compiled and what not. If we want for example at runtime to print the efective compiled files we simply can't.&lt;/p&gt;

&lt;p&gt;Here it come the tricky part. In Go &lt;code&gt;runtime&lt;/code&gt; package we have the &lt;a href="https://golang.org/pkg/runtime/#Caller"&gt;Caller()&lt;/a&gt; function who knows the current invocation file and can be used to identify if the file is compiled or not. So, our dummy program become like following.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt; file&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package main

import (
    "fmt"
    "path/filepath"
    "runtime"
    "strings"
)

var mods []string

// include this in every init() function to detect linked modules
func _init() {
    _, file, _, _ := runtime.Caller(1)
    mods = append(mods, strings.TrimSuffix(filepath.Base(file), ".go"))

}
func init() {
    _init()
}

func main() {
    fmt.Println(mods)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;module1.go&lt;/code&gt; file&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//+build module1

package main

func init() {
    _init()
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;module2.go&lt;/code&gt; file&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//+build module2

package main

func init() {
    _init()
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We has defined &lt;code&gt;_init()&lt;/code&gt; function which we will include in every &lt;code&gt;init()&lt;/code&gt; functions from every module. At runtime &lt;code&gt;init()&lt;/code&gt; functions will update an array of names which can be easy printed. The &lt;code&gt;Caller()&lt;/code&gt; parameter mean the nesting level.&lt;/p&gt;

&lt;p&gt;Running again.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go build -tags="module1 module2" -o test
./test
[main module1 module2]
go build -tags="module1" -o test
[main module1]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This technique suppose that you will have a consistency between the file name and build tags, so, be care to this aspect to avoid confusion.&lt;/p&gt;

&lt;p&gt;Enjoy.&lt;/p&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Gopei explained</title>
      <dc:creator>George Calianu</dc:creator>
      <pubDate>Thu, 06 Sep 2018 08:17:56 +0000</pubDate>
      <link>https://dev.to/geosoft1/gopei-explained-3p7g</link>
      <guid>https://dev.to/geosoft1/gopei-explained-3p7g</guid>
      <description>&lt;p&gt;Basically installing Go working environment means downloading the compiler from &lt;a href="//golang.org"&gt;https://golang.org&lt;/a&gt;, doing some things with PATH and GOPATH (where many people get stuck here) and installing an IDE. There are a lot of tutorials around but let see a smart tool which can make the installation easier.&lt;/p&gt;

&lt;p&gt;We talk about Unix/Linux world so make sure you have a Mac or a Linux distro with &lt;code&gt;bash&lt;/code&gt;,&lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;git&lt;/code&gt; installed. If you don't have a &lt;a href="https://github.com"&gt;github.com&lt;/a&gt; account then make yourself one. I typically use it on Ubuntu but Gopei should work on any machine which has &lt;code&gt;bash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We will use &lt;a href="https://github.com/geosoft1/tools"&gt;Gopei (Go Programming Environment Installer)&lt;/a&gt; toolbox wich is an installer and an customizer for entire Go environment to bring a better experience especially for the new users. Gopei install the Go compiler, LiteIDE (a very lite and quick IDE made for Go language) set PATH, GOPATH and link all together. Also, comes with some tools for github and deploy in the cloud.&lt;/p&gt;

&lt;p&gt;Gopei options are well documented on the project &lt;a href="https://github.com/geosoft1/tools/wiki"&gt;wiki&lt;/a&gt; page.&lt;/p&gt;

&lt;p&gt;First of all download Gopei toolbox from &lt;a href="https://github.com/geosoft1/tools/archive/master.zip"&gt;here&lt;/a&gt; in your local &lt;code&gt;Downloads&lt;/code&gt; folder, unpack it and execute:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Downloads/tools-master/gopei -h

Golang Programming Environment Installer
Usage: gopei [options]
Options:
-c        enable classroom mode (Linux only)
-g        enable git suppport
-h        show this help message and exit
-k        show key fingerprint
-s        server mode, install golang only
-u        uninstall
-U        uninstall including .gitconfig file and .ssh folder
-q [name] set theme (eg. -q webstorm)
-x [name] set color scheme (eg. -x sublime)
-v        version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Basically you will need to go in Downloads folder (but not mandatory) and run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gopei
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;or &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gopei -g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;-g&lt;/code&gt; is for github. Use it if you want to work with github repositories.&lt;/p&gt;

&lt;p&gt;After the installation on some systems you will find a launcher icon with a nice gopher for IDE. On Gnome systems you will need to search in dash for the launcher. On Mac you will find the original IDE icon on dock bar.&lt;/p&gt;

&lt;p&gt;If you want to use other IDE (like VSCode, Atom, Sublime or whatever) consider using this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gopei -sg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;-s&lt;/code&gt; is for server mode (no default IDE). Now you can install your favorite IDE and Go compiler but also Gopei toolbox (like the &lt;a href="https://github.com/geosoft1/tools/wiki/Cloud-tool"&gt;cloud&lt;/a&gt; tool) will be available from your IDE or from Terminal.&lt;/p&gt;

&lt;p&gt;Another interesting mode, useful for people who learn, is the classroom mode. Using &lt;code&gt;-c&lt;/code&gt; flag any settings you make in the IDE are lost after closing.&lt;/p&gt;

&lt;p&gt;Let say now you have many instalations and you want to locate your local key in github keys list. This is hard job because github don't allow you to give a name for each key. So, you can use the following command to see the local machine ssh key fingerprint.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gopei -k
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you already saw you have two options to uninstall. The main difference is that &lt;code&gt;-U&lt;/code&gt; also delete &lt;code&gt;.ssh&lt;/code&gt; folder. Uninstall with &lt;code&gt;-u&lt;/code&gt; if you want just to update tools.&lt;/p&gt;

&lt;p&gt;Another new nice options added in Gopei version 2 are about setting themes designed for big screens. To set the theme from installation use &lt;code&gt;-q&lt;/code&gt; and &lt;code&gt;-x&lt;/code&gt; flags.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./gopei -g -q webstorm -x sublime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Hope that you found out this tool useful. Enjoy. &lt;/p&gt;

</description>
      <category>go</category>
      <category>unix</category>
      <category>linux</category>
      <category>bash</category>
    </item>
  </channel>
</rss>
