20200807のGoに関する記事は4件です。

あなたのファイル、ソーシャルディスタンス保てていますか?

注意

この記事は今の御時世に関係ありますが、まじめな記事ではございません。

はじめに

最近コロナのせいで、いつも以上に電車やバスなどで他の乗客との距離感が気になったり、
ドラマや映画で密になっていたりすると「これめっちゃ密やん」って思ったりしますよね。

それと同じで、ファイルの中身を見ているとなにかムズムズしませんか?

しますよね?

それって行間のソーシャルディスタンスが保てていないからじゃないですか?

そんなムズムズを解消してくれるプログラムを GO で作ってみました!

ファイルがソーシャルディスタンスを保つ方法

ウェブサイトで推奨されているフォントサイズが約 3 ~ 4 mm
日本の社会的距離の推奨距離である 2.0 m から、
571 行の行間を開けることで、ファイルに社会的距離を保たせることにしました。

環境

  • OS : Windows10
  • Go : 1.14.6
  • エディタ : Visual Studio Code

プログラム

プログラムのソースコードはこんな感じ。
Goは触って1ヶ月もたってないので、多分ひどいコードだと思います(笑)。

package main

import (
    "bufio"
    "flag"
    "fmt"
    "io"
    "log"
    "os"
    "path"
)

func main() {

    flag.Parse()

    if flag.NArg() != 1 {
        fmt.Println("ファイルを1つだけ指定してください(Please specify only one file)")
        return
    }

    filepath := flag.Arg(0)

    _, fname := path.Split(filepath)

    rfp, err := os.Open(fname)
    defer rfp.Close()
    if os.IsNotExist(err) {
        fmt.Println("ファイルが存在しません。(file does not exist.)")
        return
    }

    wfp, err := os.Create("sdt-" + fname)
    defer wfp.Close()
    if os.IsNotExist(err) {
        log.Fatal(err)
    }

    lines := bufio.NewScanner(rfp)

    for lines.Scan() {
        line := lines.Text()

        io.WriteString(wfp, (line + "\n"))

        for j := 0; j < 571; j++ {
            io.WriteString(wfp, ("\n"))
        }
    }

    if err != nil {
        log.Fatal(err)
        return
    }

}

1. ソーシャルディスタンスを保ちたいファイルを読み込む。
2. 書き込み用のファイルをファイル名「sdf-{読み込んだファイル名}」で用意する。
3. 1 行書き込んでは、571 行改行するを繰り返す。

という感じの流れで実装しました。

実行方法

Go を実行できるターミナルなら動くはず

$ go run main.go ファイル名

もしくは

$ go build main.go
$ ./main.exe ファイル名

実際どうなる?

今回は例として「じゅげむ」を用意してみました。
見ているだけで密になっていてムズムズしますね。

じゅげむ じゅげむ ごこうのすりきれ
かいじゃりすいぎょの すいぎょうまつ
うんらいまつ ふうらいまつ
くうねるところに すむところ
やぶらこうじの ぶらこうじ
パイポパイポ パイポのシューリンガン
シューリンガンのグーリンダイ
グーリンダイのポンポコピーのポンポコナーの
ちょうきゅうめいのちょうすけ

変換前のファイルは、9 行でサイズが 445 バイトでしたが、

ソーシャルディスタンスを保たせると、、、

変換後のファイルは、5149 行でサイズが 5577 バイトになりました!
(ファイルの行数が多すぎてここに掲載できません。)

ファイルサイズは大きくなりましたが、ソーシャルディスタンスを保てていない方が問題ですよね?

まとめ

社会的距離や密を避けるために多大なコストが必要というのは、
リアルの世界もデータの世界も変わらないということがわかりました。

しかしこれで、ファイルのソーシャルディスタンスを保つことができたので快適な生活を送れますね!

GitHubにソースコード上げているので、ここが気に入らないなどがあればプルリク等くださいね!
GitHub:SocialDistanceFile

あれ、今度は1文字1文字の間隔がムズムズしてきたな。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Go】Windowsでginフレームワーク触ってみた

Go言語でのWEBアプリは、どうなもんか軽く触れてみようという事で、
簡単なログイン認証の機能を作ってみました。

参考

公式
goの環境構築
ginの環境構築
Go database/sql チュートリアル 01 - 概要 · golang.shop

環境

windows10
go1.14.7
エディタ:VisualStdioCode

1.goの実行環境インストール

以下のサイトの通りに実施する事で、特にはまることも無く構築できました。
goの環境構築

あと、インストーラがupdateされたのか、環境変数は手動で設定しませんでした。
インストール完了時点で自動で設定されるっぽい?
image.png
image.png

以下のファイルを用意して、動作確認。

sample.go
package main

import (
  "fmt"
)

func main(){
    fmt.Print("Hello world!");

}

コマンド「go run sample.go」実行で「Hello world!」が表示されたら、OK!

image.png

2.ginのダウンロード&配置

こちらのサイトを見て、作ってみました。
ginの環境構築

まず、以下からダウンロードです。
https://github.com/gin-gonic/gin
※自分は、「C:\lesson\gin」というフォルダを作って展開しました。
また、「gin-master」→「gin」にフォルダをリネームしてます。

3.サーバの起動

WEBサーバ起動用のファイル作成
MVCモデルでいう所のコントローラにも相当?

controller.go
package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()

    //テンプレートをロード 相対パス
    router.LoadHTMLGlob("views/*.html")

    //静的ファイルのパスを指定
    router.Static("/assets", "./assets")

    //ハンドラ
    router.GET("/", func(ctx *gin.Context) {
        ctx.HTML(http.StatusOK, "index.html", gin.H{})
    })

    router.GET("/login", func(ctx *gin.Context) {
        ctx.HTML(http.StatusOK, "login.html", gin.H{})
    })

    //ポート「8080」で
    router.Run(":8080")
}



この辺りに作ります。
image.png

HTMLも作ります。

index.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>Sample App</title>
</head>

<body>
    <h1>Hello World!!!</h1>
</body>

</html>
login.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ログイン</title>
</head>

<body>
    <h1>ログインしてください。</h1>
    <label>ログインID:</label><input type="text" size="10" /><br />
    <label>パスワード:</label><input type="password" size="10" /><br />
    <button>ログイン</button>
</body>

</html>

image.png

そしたら、起動コマンドを実行
「go run controller/controller.go」
image.png

以下のように表示されるはず。


http://localhost:8080/
image.png


http://localhost:8080/login
image.png


4.クライアント・サーバ間パラメータとDBとヘッダ・フッダ

WEBアプリでよく使いそうな、共通テンプレートやDBとかを扱ってみました。

なお、DBはMysqlを選択したのですが、リファレンス無いかと思って探していたら、以下のサイトがいい感じです。
Go database/sql チュートリアル 01 - 概要 · golang.shop

ライブラリのインストール

go get github.com/go-sql-driver/mysql

追加編集するファイルは、赤枠の以下の通り。
image.png

テストで使用したテーブルです。
「user_id」「user_pass」に適当に入力してレコード用意してください。

logintest.sql
CREATE TABLE `logintest` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT 'データID',
  `user_id` varchar(20) NOT NULL,
  `user_pass` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
)

以下から、ソースです。

common.css
body {
background-color: lightcyan;
}
controller.go
package main

import (
    "database/sql"
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
    _ "github.com/go-sql-driver/mysql"
)

//User is struct
type Login struct {
    user_id   string
    user_pass string
}

func main() {
    router := gin.Default()

    //テンプレートをロード 相対パス
    router.LoadHTMLGlob("views/*.html")

    //静的ファイルのパスを指定
    router.Static("/assets", "./assets")

    //ハンドラ
    //初期ページ(ログイン画面)
    router.GET("/", func(ctx *gin.Context) {
        //ログイン画面の表示
        ctx.HTML(http.StatusOK, "login.html", gin.H{
            "title":  "ログイン",
            "errmsg": "",
        })
    })

    //ログイン押下時(POSTにした)
    router.POST("/login", func(ctx *gin.Context) {

        userid := ctx.PostForm("userid")
        password := ctx.PostForm("password")
        println("userid: " + userid)
        println("password: " + password)

        if logincheck(userid, password) {
            //ログイン成功
            ctx.HTML(http.StatusOK, "menu.html", gin.H{
                "title":         "ログイン成功後",
                "paramuserid":   userid,
                "parampassword": password,
            })
        } else {
            //ログイン失敗
            ctx.HTML(http.StatusOK, "login.html", gin.H{
                "title":  "ログイン",
                "errmsg": "ログイン失敗",
            })
        }

    })

    //ポート「8080」で
    router.Run(":8080")
}

/**
 * ログイン認証
 */
func logincheck(id string, pass string) bool {

    //DB接続
    db, err := sql.Open("mysql", "userid:password@tcp(hostname:3306)/databasename")
    if err != nil {
        panic(err.Error())
    }
    defer db.Close() // 関数がリターンする直前に呼び出される

    //データベースへクエリを送信。引っ張ってきたデータがrowsに入る。
    rows, err := db.Query("SELECT user_id,user_pass FROM logintest where user_id = ? and user_pass = ? ", id, pass)
    defer rows.Close()
    if err != nil {
        panic(err.Error())
    }

    var find bool
    find = false

    for rows.Next() {
        var login Login //構造体Person型の変数personを定義
        err := rows.Scan(&login.user_id, &login.user_pass)

        find = true

        if err != nil {
            panic(err.Error())
        }
        fmt.Println("ログイン成功!")
    }
    err = rows.Err()
    if err != nil {
        panic(err.Error())
    }

    return find
}

DBの接続情報は、適宜書き換えてください。
「db, err := sql.Open("mysql", "userid:password@tcp(hostname:3306)/databasename")」の部分。
userid=ユーザID
password=パスワード
hostname:データベースホスト名
databasename:データベース名

フッタのテンプレート

_foot.html
{{ define "foot" }}

</html>
{{ end }}

ヘッダのテンプレート

_head.html
{{ define "head" }}
<!DOCTYPE html>
<html lang=ja>

<head>
    <meta charset="utf-8">
    <meta name="description" content="ヘッダ">
    <link rel="stylesheet" href="/assets/common.css">
    <title>〇〇システム</title>
</head>
{{ end }}

ログイン画面

login.html
{{ template "head" }}

<body>
    <h1>{{ .title}}</h1>
    <form action="/login" method="post">
        <label>ログインID:</label><input type="text" name="userid" size="10" /><br />
        <label>パスワード:</label><input type="password" name="password" size="10" /><br />
        <button type="submit">ログイン</button>
        <span style="color: red;">{{.errmsg}}</span>
    </form>
</body>

{{ template "foot" }}

ログイン成功後の画面

login.html
{{ template "head" }}

<body>
    <h1>{{ .title}}</h1>
    <form action="/menu" method="post">
        <label>ログインID:</label><label>{{ .paramuserid}}</label><br />
        <label>パスワード:</label><label>{{ .parampassword}}</label><br />

    </form>
</body>

{{ template "foot" }}

動作

http://localhost:8080/

image.png


ログイン失敗時
image.png

エラーメッセージがでます。


ログイン成功時
image.png

こんな感じ


本当に簡単な事しかしていないので、画面項目をModel化できるのか、とか。
json(ajax)通信とかのやり方とかも気が向いたら載せてみたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker SDK & Go言語 を使ってAWS ECRのimageをpull & run する

「AWS ECRにログインして docker imageを pullし、docker runする」

このような作業はあまりプロダクションで手動でやることはありませんが、やるとすれば普通に aws-cliを使ってECRにLogin, 後は dockerコマンドでの作業となるかと思います。

ところで、Go製であるDockerには公式SDKがあります。
今回とある事情があり、 github.com/aws/aws-sdk-gogithub.com/docker/docker を使って上記の作業をGoのコードのみでやる機会がありました。

Develop with Docker Engine SDKs
Examples using the Docker Engine SDKs and Docker API

ググっても出てこないくらい触らなそうな作業ではありますが、どこかの誰かのためにサンプルコードを置いておきます。

package main

import (
    "context"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/ecr"
    "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/container"
    "github.com/docker/docker/api/types/mount"
    "github.com/docker/docker/client"
    "github.com/labstack/gommon/log"
    "io"
    "os"
    "strings"
    "time"
)

func main() {

    auth := getEcrRegistryAuth()
    pullAndRunContainer(auth)

}

func getEcrRegistryAuth() string {

    /*  ECR Login  */
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))

    ecrSdk := ecr.New(sess)
    authOutput, err := ecrSdk.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{})
    if err != nil {
        log.Panic(err)
    }

    token := authOutput.AuthorizationData[0].AuthorizationToken

    authStr := aws.StringValue(token)
    decoded, err := base64.StdEncoding.DecodeString(authStr) // Decode the Base64 encoded token
    if err != nil {
        log.Panic(err)
    }
    password := strings.ReplaceAll(string(decoded), "AWS:", "")

    jsonBytes, _ := json.Marshal(map[string]string{
        "username": "AWS",
        "password": password,
    })

    return base64.StdEncoding.EncodeToString(jsonBytes)

}

func pullAndRunContainer(auth string) {

    imageUri := `xxxxxxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-ecr:latest`
    containerName := fmt.Sprintf(`test-container-%v`, time.Now().UnixNano())

    ctx := context.Background()

    cli, err := client.NewEnvClient()
    if err != nil {
        log.Fatal(err)
    }

    reader, err := cli.ImagePull(ctx, imageUri, types.ImagePullOptions{
        RegistryAuth: auth,
    })
    if err != nil {
        log.Panic(err)
    }
    io.Copy(os.Stdout, reader)

    cont, err := cli.ContainerCreate(
        ctx,
        &container.Config{
            Image: imageUri,
            Cmd: []string{
                `sh`,
                `-c`,
                `echo "Run App !!!!!"`,
            },
            Env: []string{
                "PASS=xxxxxxxxxxxxxx", // いいのか?
            },
            //Cmd:   command,
        }, &container.HostConfig{
            Mounts: []mount.Mount{
                {
                    Type:   mount.TypeBind,
                    Source: "<HostのMount Dir>",
                    Target: "/mnt", // gyao_yvpub_wrapper内のmount dir
                },
            },
        }, nil, containerName)
    if err := cli.ContainerStart(ctx, cont.ID, types.ContainerStartOptions{}); err != nil {
        log.Panic(err)
    }

    go func() {
        out, logErr := cli.ContainerLogs(ctx, cont.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
        if logErr != nil {
            log.Error(logErr)
        }
        containerLog := streamToString(out)
        fmt.Println(containerLog)
    }()

    exitCode, err := cli.ContainerWait(ctx, cont.ID)
    if err != nil {
        log.Fatal(err)
    }

    if exitCode != 0 {
        log.Error(err)

        out, logErr := cli.ContainerLogs(ctx, cont.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
        if logErr != nil {
            log.Error(err)
        }

        containerLog := streamToString(out)
        fmt.Println(containerLog)
    }

}


  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

@keymoon氏の【全方位木DP】のGo実装

【全方位木DP】明日使える便利な木構造のアルゴリズム

↑の記事におけるkeymoonさんによるC#のコードをGoで写経したものです。

コード

Goにはジェネリクスがないので型 T を動的に変更できないのが少し気になるところですが、まぁ問題に合わせて都度書き換えるということで(セグメント木とかでもそうですが、なにかもっとスマートなプラクティスがあれば教えて下さい?)。

また、Stackは単なるスライシングでやっているので、もしかしたらここが速度を損ねているかもしれません。
しかしながら、これ以上コードを増やすのもどうかと思ったので、とりあえずそのままにしています。

type T int

type ReRooting struct {
    NodeCount int

    Identity    T
    Operate     func(l, r T) T
    OperateNode func(t T, idx int) T

    Adjacents         [][]int
    IndexForAdjacents [][]int

    Res []T
    DP  [][]T
}

func NewReRooting(
    nodeCount int, edges [][]int, identity T, operate func(l, r T) T, operateNode func(t T, idx int) T,
) *ReRooting {
    s := new(ReRooting)

    s.NodeCount = nodeCount
    s.Identity = identity
    s.Operate = operate
    s.OperateNode = operateNode

    s.Adjacents = make([][]int, nodeCount)
    s.IndexForAdjacents = make([][]int, nodeCount)
    for _, e := range edges {
        s.IndexForAdjacents[e[0]] = append(s.IndexForAdjacents[e[0]], len(s.Adjacents[e[1]]))
        s.IndexForAdjacents[e[1]] = append(s.IndexForAdjacents[e[1]], len(s.Adjacents[e[0]]))
        s.Adjacents[e[0]] = append(s.Adjacents[e[0]], e[1])
        s.Adjacents[e[1]] = append(s.Adjacents[e[1]], e[0])
    }

    s.DP = make([][]T, len(s.Adjacents))
    s.Res = make([]T, len(s.Adjacents))

    for i := 0; i < len(s.Adjacents); i++ {
        s.DP[i] = make([]T, len(s.Adjacents[i]))
    }

    if s.NodeCount > 1 {
        s.Initialize()
    } else {
        s.Res[0] = s.OperateNode(s.Identity, 0)
    }

    return s
}

func (s *ReRooting) Query(node int) T {
    return s.Res[node]
}

func (s *ReRooting) Initialize() {
    parents, order := make([]int, s.NodeCount), make([]int, s.NodeCount)

    // #region InitOrderedTree
    index := 0
    stack := []int{}
    stack = append(stack, 0)
    parents[0] = -1
    for len(stack) > 0 {
        node := stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        order[index] = node
        index++
        for i := 0; i < len(s.Adjacents[node]); i++ {
            adjacent := s.Adjacents[node][i]
            if adjacent == parents[node] {
                continue
            }
            stack = append(stack, adjacent)
            parents[adjacent] = node
        }
    }
    // endregion

    // #region fromLeaf
    for i := len(order) - 1; i >= 1; i-- {
        node := order[i]
        parent := parents[node]

        accum := s.Identity
        parentIndex := -1
        for j := 0; j < len(s.Adjacents[node]); j++ {
            if s.Adjacents[node][j] == parent {
                parentIndex = j
                continue
            }
            accum = s.Operate(accum, s.DP[node][j])
        }
        s.DP[parent][s.IndexForAdjacents[node][parentIndex]] = s.OperateNode(accum, node)
    }
    // endregion

    // #region toLeaf
    for i := 0; i < len(order); i++ {
        node := order[i]
        accum := s.Identity
        accumsFromTail := make([]T, len(s.Adjacents[node]))
        accumsFromTail[len(accumsFromTail)-1] = s.Identity
        for j := len(accumsFromTail) - 1; j >= 1; j-- {
            accumsFromTail[j-1] = s.Operate(s.DP[node][j], accumsFromTail[j])
        }
        for j := 0; j < len(accumsFromTail); j++ {
            s.DP[s.Adjacents[node][j]][s.IndexForAdjacents[node][j]] = s.OperateNode(s.Operate(accum, accumsFromTail[j]), node)
            accum = s.Operate(accum, s.DP[node][j])
        }
        s.Res[node] = s.OperateNode(accum, node)
    }
    // endregion
}

使用例

自分が試した問題と提出を載せておきます。適宜ご参照ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む