- 投稿日:2020-08-07T17:05:25+09:00
あなたのファイル、ソーシャルディスタンス保てていますか?
注意
この記事は今の御時世に関係ありますが、まじめな記事ではございません。
はじめに
最近コロナのせいで、いつも以上に電車やバスなどで他の乗客との距離感が気になったり、
ドラマや映画で密になっていたりすると「これめっちゃ密やん」って思ったりしますよね。それと同じで、ファイルの中身を見ているとなにかムズムズしませんか?
しますよね?
それって行間のソーシャルディスタンスが保てていないからじゃないですか?
そんなムズムズを解消してくれるプログラムを 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文字の間隔がムズムズしてきたな。
- 投稿日:2020-08-07T16:56:44+09:00
【Go】Windowsでginフレームワーク触ってみた
Go言語でのWEBアプリは、どうなもんか軽く触れてみようという事で、
簡単なログイン認証の機能を作ってみました。参考
公式
goの環境構築
ginの環境構築
Go database/sql チュートリアル 01 - 概要 · golang.shop環境
windows10
go1.14.7
エディタ:VisualStdioCode1.goの実行環境インストール
以下のサイトの通りに実施する事で、特にはまることも無く構築できました。
goの環境構築あと、インストーラがupdateされたのか、環境変数は手動で設定しませんでした。
インストール完了時点で自動で設定されるっぽい?
以下のファイルを用意して、動作確認。
sample.gopackage main import ( "fmt" ) func main(){ fmt.Print("Hello world!"); }コマンド「go run sample.go」実行で「Hello world!」が表示されたら、OK!
2.ginのダウンロード&配置
こちらのサイトを見て、作ってみました。
ginの環境構築まず、以下からダウンロードです。
https://github.com/gin-gonic/gin
※自分は、「C:\lesson\gin」というフォルダを作って展開しました。
また、「gin-master」→「gin」にフォルダをリネームしてます。3.サーバの起動
WEBサーバ起動用のファイル作成
MVCモデルでいう所のコントローラにも相当?controller.gopackage 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") }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>そしたら、起動コマンドを実行
「go run controller/controller.go」
以下のように表示されるはず。
4.クライアント・サーバ間パラメータとDBとヘッダ・フッダ
WEBアプリでよく使いそうな、共通テンプレートやDBとかを扱ってみました。
なお、DBはMysqlを選択したのですが、リファレンス無いかと思って探していたら、以下のサイトがいい感じです。
Go database/sql チュートリアル 01 - 概要 · golang.shopライブラリのインストール
go get github.com/go-sql-driver/mysqlテストで使用したテーブルです。
「user_id」「user_pass」に適当に入力してレコード用意してください。logintest.sqlCREATE 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.cssbody { background-color: lightcyan; }controller.gopackage 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" }}動作
エラーメッセージがでます。
こんな感じ
本当に簡単な事しかしていないので、画面項目をModel化できるのか、とか。
json(ajax)通信とかのやり方とかも気が向いたら載せてみたいと思います。
- 投稿日:2020-08-07T11:51:29+09:00
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-go
とgithub.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) } }
- 投稿日:2020-08-07T01:03:50+09:00
@keymoon氏の【全方位木DP】のGo実装
↑の記事における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 }使用例
自分が試した問題と提出を載せておきます。適宜ご参照ください。