2016/03/17


MySQLでカジュアルにズンドコキヨシ | GMOメディア エンジニアブログ

ズンドコキヨシ大流行ですね。 ズンドコキヨシまとめ - Qiita を見ていたんですが、MySQLでやってる人はいなさそうなので...

http://tech.gmo-media.jp/post/141178318699/zundoko-kiyoshi-with-mysql

SQLite3 でもやりたい!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sqlite3.h>
#include <sqlite3ext.h>

#ifdef _WIN32
# define EXPORT __declspec(dllexport)
#else
# define EXPORT
#endif

SQLITE_EXTENSION_INIT1;

static int
zundoko_connect(sqlite3 *db, void *pAux, int argc, const char * const *argv, sqlite3_vtab **ppVTab, char **c) {
  char buf[256];
  snprintf(buf, sizeof(buf)-1"CREATE TABLE %s(val text)", argv[0]);
  int rc = sqlite3_declare_vtab(db, buf);
  *ppVTab = (sqlite3_vtab *) sqlite3_malloc(sizeof(sqlite3_vtab));
  memset(*ppVTab, 0sizeof(sqlite3_vtab));
  return rc;
}

static int
zundoko_create(sqlite3 *db, void *pAux, int argc, const char * const * argv, sqlite3_vtab **ppVTab, char **c) {
  return zundoko_connect(db, pAux, argc, argv, ppVTab, c);
}

static int zundoko_disconnect(sqlite3_vtab *pVTab) {
  sqlite3_free(pVTab);
  return SQLITE_OK;
}

static int
zundoko_destroy(sqlite3_vtab *pVTab) {
  sqlite3_free(pVTab);
  return SQLITE_OK;
}

typedef struct {
  sqlite3_vtab_cursor base;
  int rowid;
  int kiyoshi;
  char zundoko[6];
} cursor;

static int
zundoko_open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {
  cursor *c = (cursor *)sqlite3_malloc(sizeof(cursor));
  *ppCursor = &c->base;
  return SQLITE_OK;
}

static int
zundoko_close(cursor *c) {
  sqlite3_free(c);
  return SQLITE_OK;
}

static int
zundoko_next(cursor *c) {
  int i, l = sizeof(c->zundoko)/sizeof(c->zundoko[0]);
  for (i = 0; i < l-1; i++)
    c->zundoko[i] = c->zundoko[i+1];
  c->zundoko[5] = c->kiyoshi ? 'K' : (rand() % 2 == 0 ? 'Z' : 'D');
  c->rowid++;
  return SQLITE_OK;
}

static int
zundoko_filter(cursor *c, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) {
  srand((unsigned)time(NULL));
  c->rowid = 0;
  c->kiyoshi = 0;
  memset(c->zundoko, 0sizeof(c->zundoko));
  zundoko_next(c);
  return SQLITE_OK;
}

static int
zundoko_eof(cursor *c) {
  c->kiyoshi = memcmp(c->zundoko+1"ZZZZD"5) == 0;
  return c->zundoko[4] == 'K';
}

static int
zundoko_column(cursor *c, sqlite3_context *ctxt, int i) {
  char *p = "?";
  switch (c->zundoko[5]) {
    case 'Z': p = "ズン"break;
    case 'D': p = "ドコ"break;
    case 'K': p = "キ・ヨ・シ!"break;
  }
  sqlite3_result_text(ctxt, strdup(p), strlen(p), NULL);
  return SQLITE_OK;
}

static int
zundoko_rowid(cursor *c, sqlite3_int64 *pRowid) {
  *pRowid = c->rowid;
  return SQLITE_OK;
}

static int
zundoko_bestindex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) {
  return SQLITE_OK;
}

static const sqlite3_module module = {
  0,
  zundoko_create,
  zundoko_connect,
  zundoko_bestindex,
  zundoko_disconnect,
  zundoko_destroy,
  zundoko_open,
  (int (*)(sqlite3_vtab_cursor *)) zundoko_close,
  (int (*)(sqlite3_vtab_cursor *, intchar const *, int, sqlite3_value **)) zundoko_filter,
  (int (*)(sqlite3_vtab_cursor *)) zundoko_next,
  (int (*)(sqlite3_vtab_cursor *)) zundoko_eof,
  (int (*)(sqlite3_vtab_cursor *, sqlite3_context *, int)) zundoko_column,
  (int (*)(sqlite3_vtab_cursor *, sqlite3_int64 *)) zundoko_rowid,
  NULL// zundoko_update
  NULL// zundoko_begin
  NULL// zundoko_sync
  NULL// zundoko_commit
  NULL// zundoko_rollback
  NULL// zundoko_findfunction
  NULL// zundoko_rename
};

static void
destructor(void *arg) {
  return;
}


EXPORT int
sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) {
  SQLITE_EXTENSION_INIT2(api);
  sqlite3_create_module_v2(db, "zundoko", &module, NULL, destructor);
  return 0;
}

こんなソースファイルを用意し Windows であれば以下の様にコンパイルします。

gcc -I. -g -o zundoko.dll -shared zundoko.c

sqlite3 を起動して dll を読み込みます。

SQLite version 3.7.14 2012-09-03 15:42:36
Enter ".help" for instructions
Enter SQL statements terminated with a ";"

sqlite> select load_extension("zundoko.dll");
load_extension("zundoko.dll")

読み込めたら仮想テーブルを作ります。

sqlite> create virtual table zundoko using zundoko(val);

あとは SELECT

sqlite> SELECT * FROM ZUNDOKO;
ドコ
ドコ
ズン
ズン
ズン
ズン
ドコ
キ・ヨ・シ!

ソースコードはここに置いておきます。


2016/03/09


コマンドラインから JSON を扱うツールとしては jq が一般的ですが、例えば ls を実行した結果を JSON の Array にしたいであったり、コマンドライン引数から簡単に Object を作りたいといった場合には一旦考え込まないといけないくらい使い方が難しかったりします。そんな中でひょいと現れたのが jo です。

GitHub - jpmens/jo: JSON output from a shell

JSON output from a shell

https://github.com/jpmens/jo

作者である jpmens さんがなぜ jo を作るに至ったかをブログに書いています。

Jan-Piet Mens :: A shell command to create JSON: jo

A shell command to create JSON: jo

http://jpmens.net/2016/03/05/a-shell-command-to-create-json-jo/

JSON を書くという行為は、プレースホルダ的に考えないといけなかったり、エスケープを気にしないといけなかったりと実は色々と思考停止要素を含んでいます。しかし jo であればとても直観的に JSON を生成する事が出来ます。

まずは引数から簡単に Object を作ります。

$ jo name=Jane
{"name":"Jane"}

シェルの引数で変数やコマンド展開を使うとエスケープを気にせず JSON を出力出来ます。

$ jo time=$(date +%s) dir=$HOME
{"time":1457195712,"dir":"/Users/jpm"}

配列も簡単

$ jo -p -a spring summer winter
[
 "spring",
 "summer",
 "winter"
]

-p オプションを付与すると pretty print になります。shell に慣れている人であれば複雑な JSON でも割と簡単に出力出来ます。

$ jo -p name=JP object=$(jo fruit=Orange hungry@0 point=$(jo x=10 y=20) number=17) sunday@0
{
 "name": "JP",
 "object": {
  "fruit": "Orange",
  "hungry": false,
  "point": {
   "x": 10,
   "y": 20
  },
  "number": 17
 },
 "sunday": false
}

引数を与えない場合、標準入力を読み込むのでコマンドの出力結果から配列を作るのも簡単。

$ seq 1 10 | jo -a
[1,2,3,4,5,6,7,8,9,10]

使い方はマニュアルに書かれています。

jo/jo.md at master · jpmens/jo · GitHub

NAME jo - JSON output from a shell SYNOPSIS jo [-p] [-a] [word ...] DESCRIPTION jo creates a JSON st...

https://github.com/jpmens/jo/blob/master/jo.md

ちなみに jo は Windows でもきちんと動作して、コマンドラインからマルチバイトを与えられても化けずに出力されます。

jq

入力元がストリームの場合は utf-8 として扱い、画面からの入力であった場合には自動的に utf-8 へ変換されます。出力も同様です。ログから必要な部分のみを grep して sed で加工して別の処理に JSON として渡したい、そんなニーズに簡単に答えられそうなツールです。


2016/02/24


golang で Web アプリを作ってると画像のアップロード処理を書くことって意外と多くて、その度にググったり過去の自分の実装を調べたりして、みたいな事を繰り返してましたが go-imageupload を使うとかなり端折れる事になりそうです。

GitHub - olahol/go-imageupload: Gracefully handle image uploading and thumbnail creation.
https://github.com/olahol/go-imageupload

実装は簡素ですが、毎回自分でこれを書いてたと思うと時間が勿体ないですね。使い方も簡単で README.md から転用すると 300x300 のサムネイル画像を生成するのはこれだけになります。

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/olahol/go-imageupload"
)

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

    r.GET("/"func(c *gin.Context) {
        c.File("index.html")
    })

    r.POST("/upload"func(c *gin.Context) {
        img, err := imageupload.Process(c.Request, "file")

        if err != nil {
            panic(err)
        }

        thumb, err := imageupload.ThumbnailPNG(img, 300300)

        if err != nil {
            panic(err)
        }

        thumb.Write(c.Writer)
    })

    r.Run(":5000")
}

サムネイルとは書いてますが、サイズが指定出来るので例えばアップロード画像のサイズを均一にしたい場合にも使えます。ブラウザ側の処理も dropzone.js を使えば簡単にアップロード画面が出来上がります。

まずはサーバ側のコード。

package main

import (
    "crypto/sha1"
    "fmt"
    "time"

    "github.com/gin-gonic/contrib/static"
    "github.com/gin-gonic/gin"
    "github.com/mattn/go-colorable"
    "github.com/olahol/go-imageupload"
)

func main() {
    gin.DefaultWriter = colorable.NewColorableStdout()
    r := gin.Default()

    r.Use(static.Serve("/", static.LocalFile("./assets"true)))

    r.POST("/upload"func(c *gin.Context) {
        img, err := imageupload.Process(c.Request, "file")
        if err != nil {
            panic(err)
        }
        thumb, err := imageupload.ThumbnailPNG(img, 300300)
        if err != nil {
            panic(err)
        }
        h := sha1.Sum(thumb.Data)
        thumb.Save(fmt.Sprintf("files/%s_%x.png",
            time.Now().Format("20060102150405"), h[:4]))
    })

    r.Run(":5000")
}

アップロードされた画像を 300x300 にリサイズして、日付と sha1 のファイル名付けて保存しているだけです。files というディレクトリに保存されます。クライアント側も dropzone.js 様様です。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>あぷろだ</title>
    <link rel="stylesheet" href="dropzone.css" media="all">
    <link rel="stylesheet" href="app.css" media="all">
    <script src="dropzone.js"></script>
</head>
<body>
<form action="/upload" class="dropzone" id="dropzone"></form>
</body>
</html>

一応、マウスホバーで色変えちゃうよ的な。

#dropzone {
  background-color#afa;
  bordersolid 3px #5a5;
  color#585;
  padding20px;
}

#dropzone.dropover {
  background-color#cfc;
  color#9c9;
}
upload

便利。

Go言語によるWebアプリケーション開発 Go言語によるWebアプリケーション開発
Mat Ryer
オライリージャパン / ¥ 3,456 (2016-01-22)
 
発送可能時間:在庫あり。