2017年8月20日日曜日

GIFアニメにLGTMロゴを合成する

フレームレート(Delay)を調べる

$ identify -verbose animation.gif | grep "Delay"
 Delay: 20x100

ここで調べたDelay値を再合成時のdelayパラメータに指定する
(この場合は、100分の20秒毎にアニメーション、フレームレート換算すると5fps相当)

GIFファイルをフレーム単位に分割する

$ convert -coalesce animation.gif part%d.png
or 
$ convert +adjoin -coalesce animation.gif conv/%02d.gif
  • +adjoin: 画像分割するためのオプション(無くても分割できるかもしれない)
  • -coalesce: フレーム差分のみの画像が出力されるのを抑制するために指定

LGTMを合成する

LGTMの透過画像を準備しておくこと
$ for i in `seq -w 0 10`; do 
  composite -gravity center -compose over lgtm_320.png  conv/${i}.png tmp/${i}.png ; 
done
  • -gravity center: 位置を指定
  • -compose over image1.png image2.png : image2.pngの上にimage1.pngを重ね合せる

画像からGIFアニメを作成

$ convert -delay 10 -layers optimize tmp/*.png lgtm.gif
  • -delay: 1枚の画像を100分のx秒間表示する. ffmpegコマンド実行時に指定したフレームレートから計算して指定
  • -layers optimize: 最適化オプション.

おまけ: トリミングしたい

convert -crop 285x285+5+15! -resize 300 pngs/*.png  tmp/%d.png
基準座標から5x15pxの位置から285x285pxで画像を切り出し、300x300pxに拡大する

mp4からLGTMを作成する

動画の前処理をしてサイズを落とす

$ ffmpeg -ss 3200 -t 100 -i input.mp4 -an output.mp4
  • ss: 開始位置(sec)
  • t: トリミング期間(sec)
  • an: 音声を出力しない
  • -i: 入力ファイル

動画ファイルからpng画像に変換する

$ ffmpeg -i output.mp4 -an -r 10 -vf crop=406:406:0:157 pngs/%04d.png
 or 
$ ffmpeg -i output.mp4 -an -r 10 -s 320x240 pngs/%04d.png
  • -r : フレームレート(1秒間に何フレーム抽出するか)
  • -vf crop : 動画のフィルタリング
  • -vf crop : 出力結果のトリミング(出力サイズx:y:トリミング開始位置x:y)
  • -s : リサイズ(出力サイズ) : 640x480 等

LGTMを合成する

LGTMの透過画像を準備しておくこと
$ for i in {101..200}; do 
  composite -gravity center -compose over lgtm_320.png  pngs/${i}.png tmp/${i}.png ; 
done
  • -gravity center: 位置を指定
  • -compose over image1.png image2.png : image2.pngの上にimage1.pngを重ね合せる

画像からGIFアニメを作成

$ convert -delay 10 -layers optimize tmp/*.png lgtm.gif
  • -delay: 1枚の画像を100分のx秒間表示する. ffmpegコマンド実行時に指定したフレームレートから計算して指定
  • -layers optimize: 最適化オプション.

(オプション)サイズを調整する

$ convert lgtm.gif -coalesce -colors 64 -geometry 320 opt.gif 
  • -coalesce -colors: 減色処理
  • -geometry: 画像の縦横サイズを変更する. 縦横比は維持されるため長辺のサイズを指定してやる

2017年1月1日日曜日

bitbucketのprivateレポジトリにCIツールからアクセスできない場合

トラブルシューティング

status code:128でエラーが出る場合(jenkins)

ソースコード管理システムでGitを選択して、正しいURIを設定しても以下のようなエラーが表示される場合がある
Failed to connect to repository : Command "git ls-remote -h git@bitbucket.org:accountname/reponame.git HEAD" returned status code 128:
stdout: 
stderr: fatal: The remote end hung up unexpectedly
このエラーが出る場合、known_hostsに登録されていないためにエラーになるケースがある。
その場合は、CIツールの実行ユーザで一度適当なgitコマンドを実行してみる。 (cloneしてきたリポジトリはすぐに消して問題ない
sudo -u jenkins git clone git@bitbucket.org:accountname/reponame.git
Cloning into reponame...
The authenticity of host 'bitbucket.org (131.103.20.168)' can't be established.
RSA key fingerprint is 72:6e:1a:f2:9f:14:10:5c:b4:ec:a8:46:61:74:32:42.
Are you sure you want to continue connecting (yes/no)? *yes*

ポート22が使えない場合

インフラの都合上FW外へのポート22がブロックされている場合、 bitbucketはssh over httpsをサポートしているため、以下のURIを設定することでhttps(ポート443)で接続可能。
ssh://git@altssh.bitbucket.org:443/accountname/reponame/

2016年12月23日金曜日

GAEのOutbound IP address確認方法

概要

GoogleAppEngine(GAE)上に構築したアプリケーションからのアクセスをwhitelist形式で許可したい場合など、接続元IPでアクセス制限を行う際のIPアドレス(の範囲)を調べる方法
ちなみに、公式ドキュメントにも明記されていますが、今のところGAEからの外部へのアクセス時のIPアドレス(Outboud IP addres)を固定化は出来ない(らしい)ため、GAE全体のIPアドレスのレンジとしてしか調べられません。
※ 第三者の悪質なGAEアプリケーションも同じIPアドレス範囲を共有するため、根本的にはIPアドレス以外の方法でアクセス制限が推奨されています。

https://cloud.google.com/appengine/kb/#static-ip


確認方法

公式ドキュメントの内容を雑にスクリトに落としただけですが、 以下のスクリプトを実行してもらえればIP Addressのレンジを取得できます。
#!/bin/bash
includes=`nslookup -q=TXT _cloud-netblocks.googleusercontent.com 8.8.8.8 \
| tr ' ' '\n' | grep include | sed "s/include:\(.*\)/\1/g"`
for include in $includes; do
  nslookup -q=TXT $include 8.8.8.8 | tr ' ' '\n' | grep ip | sed "s/ip[4,6]:\(.*\)/\1/g"
done

2016年12月22日木曜日

ElasticSearchで禁止ワードチェックしてみた

Elasticsearchを使っていてpercolator機能で何か面白い使い方できないかなぁということで遊んでみたのでメモを。

0. 環境

  • ElasticSearch 1.0.1
  • elasticsearch-analysis-kuromoji 2.0.0

1. 下準備

index,mappingを作成します. messageのindex_analyzerは調べたいテキストを解析するanalyzeするanalyzer、 search_analyzerはNGワードの検索クエリを解析するanalyzerになる点に注意して下さい。
$ curl -XPUT  http://localhost:9200/filter/ -d '
{
    "index":{
        "analysis":{
            "analyzer" : {
                "kuromoji" : {
                    "tokenizer" : "kuromoji_tokenizer"
                }
            }
        }
    }
}
'
{"acknowledged":true}
$ curl -XPUT localhost:9200/filter/message/_mapping -d '
{
    "message": {
        "_id": {},
        "properties": {
            "message": {
                "type": "string",
                "index_analyzer": "kuromoji",
                "search_analyzer": "whitespace"
            },
            "filter_id": {
                "type": "long",
                "include_in_all": false
            }
        }
    }
}
'
{"acknowledged":true}
$ curl -XPUT localhost:9200/filter/.percolator/_mapping -d '
{
  ".percolator": {
    "_id": {
        "index": "not_analyzed",
        "path" : "filter_id"
    },
    "properties": {
        "query": {
            "enabled": false,
            "type": "object"
        },
        "filter_id": {
            "type": "long"
        }
    }
  }
}
'
{"acknowledged":true}

2. 禁止ワード登録

$ curl -XPOST localhost:9200/filter/.percolator/ -d '
{
    "query": {
        "match": {
            "message": "売春 殺す 死ね"
        }
    },
    "filter_id" : 1
}
'
{"_index":"filter","_type":".percolator","_id":"1","_version":1,"created":true}
$  curl -XPOST localhost:9200/filter/.percolator/ -d '
{
    "query": {
        "match": {
            "message": "ブタ"
        }
    },
    "filter_id" : 2
}
'
{"_index":"filter","_type":".percolator","_id":"2","_version":1,"created":true}

3. NGチェック

禁止ワードが含まれているかどうかの判定だけではなく、 highlight指定してやると該当箇所を伏字(ニ○ニ○動画風)にし易い形式でも取得することが可能です。
禁止ワードの有無を判定
$ curl -XGET localhost:9200/filter/message/_percolate?pretty -d '
{
    "doc": {
        "message": "nobuta@github死ね"
    }
}
'
{
  "took" : 1,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "total" : 1,
  "matches" : [ {
    "_index" : "filter",
    "_id" : "1"
  } ]
}
禁止ワード部分の抽出
$ curl -XGET localhost:9200/filter/message/_percolate?pretty -d '
{
    "highlight": {
        "fields": {
            "message": {
                "pre_tags": [ "(" ],
                "post_tags": [ ")" ]
            }
        }
    },
    "size": 10,
    "doc": {
        "message": "nobuta@github死ね"
    }
}
'
{
  "took" : 30,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "total" : 1,
  "matches" : [ {
    "_index" : "filter",
    "_id" : "1",
    "highlight" : {
      "message" : [ "nobuta@github(死ね)" ]
    }
  } ]
禁止ワード部分の抽出(複数のパターン)
$ curl -XGET localhost:9200/filter/message/_percolate?pretty -d '
{
    "highlight": {
        "fields": {
            "message": {
                "pre_tags": [ "(" ],
                "post_tags": [ ")" ]
            }
        }
    },
    "size": 10,
    "doc": {
        "message": "ノブタ@github殺す"
    }
}
'
{
  "took" : 3,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "total" : 2,
  "matches" : [ {
    "_index" : "filter",
    "_id" : "1",
    "highlight" : {
      "message" : [ "ノブタ@github(殺す)" ]
    }
  }, {
    "_index" : "filter",
    "_id" : "2",
    "highlight" : {
      "message" : [ "ノ(ブタ)@github殺す" ]
    }
  } ]
}
ElasticSearchといえば全文検索であったりKibanaが主流ですが、こんな使い方もできるんじゃないだろうかってことで紹介をしてみました。
他にもこんな使い方してるよって方いましたら是非教えてください。