2017年12月26日火曜日

Batch Normalizationとスケーリングの影響を可視化して遊んでみた

Batch Normalizationとスケーリングが性能に与える影響を可視化してみました。 たぶん大多数の人にとっては誰得感のある情報ですが、 世の中のデータはスケーリングが簡単なデータばかりではないので、私は一度で良いから可視化してみたかった。

全体のコードは出すまでもないかなと思ったので省略しますが、Kerasの一番わかりやすいサンプルであるmnist_mlp.pyをベースにして調査してみました。 まずはBatch Normalizationを付けない状態で、スケーリングを行っている部分を以下のように変化させてみました。
# x_train /= 255  # 1e1 (baseline)
# x_test /= 255  # 1e1 (baseline)
# x_train = x_train / 255 / 100   # 1e-2
# x_test = x_test / 255 / 100  # 1e-2
x_train = x_train / 255 * 10000   # 1e4
x_test = x_test / 255 * 10000  # 1e4
結果は以下。mnistのコードをそのまま利用した場合、適切なスケーリングである1e1から離れると顕著に性能が下がる事がわかります。 特に特徴量の平均が大きくなるとまったく学習できていません。 いかにスケーリングが重要かよくわかる結果と思います。




次にBatch Normalization (BN)を付けた場合も検証してみます。 モデルに以下のようにBNを追加し、同じようにスケーリングを変化させてみました。
model = Sequential()
model.add(Dense(512, input_shape=(784,)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Dense(512))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Dense(num_classes, activation='softmax'))
特徴量の平均を小さくすると性能低下しています。 [0,1e-2]のスケーリングでも若干の収束遅れが見られ、[0,1e-4]では悲惨な事になる事がわかりました。 逆に平均を大きくしても性能にはまったく影響なし。BNも割とあっさり死ぬんだなあ。



特徴量の平均を小さくした時にBNが死ぬのはなぜでしょう。 BNの標準化式に含まれるepsilonの影響かと考え、epsilonをより小さな値(1e-8)にしてみました。 しかしこれは失敗で、先ほどと大差ないグラフになりました。 epochを増やしたり、epsilonをさらに小さくしたり、最適化関数を変えたりしてみましたが駄目駄目。 となると更新幅の係数の影響のほうが大きいのかも。 まあよくわからないので、BNを使う時は特徴量は小さくするよりを大きくしたほうが良さそうと、お茶を濁しておきます。 ちなみに[0,1e-4]などの分布のデータを事前に標準化すれば問題は起きません。 この特性は多層で大丈夫なのかなあとちょっと心配になる結果。



まとめ

  • 特徴量はスケーリングしないと駄目、絶対
  • スケーリングが面倒臭いならBatch Normalizationしよう
  • ただし特徴量の平均が小さ過ぎるとBatch Normalizationは死ぬ
  • Batch Normalizationが死んだ時は特徴量の平均を大きく
  • 緩募: 特徴量の平均が小さい時でもBatch Normalizationを動かす方法

誰得感のある情報ですが、Batch Normalizationは凄いものの特徴量の平均が小さい時に起きる突然の死に注意という事がわかりました。

2017年12月6日水曜日

フリゲ紹介: ひよこ侍

ひよこ侍は結構昔の有名な作品なのですが、 名前が適当な感じ(失礼)に感じてスルーしていたゲームでした。 ただ実際にプレイしてみると、評判通り面白かった。 もっと早くプレイすれば良かったなあ。やはり食わず嫌いは良くないですね。



最初はかわいいひよこが主人公のほのぼのRPGなのかと思っていましたが、 ひよこのぬいぐるみを被った目つきの悪い主人公(左下)の、割とシリアスなRPGでした。 なぜ主人公はひよこのぬいぐるみを被るのか…それはプレイして確かめてみてください。



ひよこ侍は1vs1のシンプルな剣術アクションRPGなのですが、これがなかなかどうして面白い(右上)。 必殺技などももちろんあります。 気を抜くとあっさり負けますが、難し過ぎる訳でもなく、手頃な難易度で爽快感もある。 絶賛も頷ける作品でした。

フリゲ紹介: Trustia 〜トラスティア〜 Last Reincarnation

Trustia 〜トラスティア〜 Last Reincarnationウディコン2016で5位だった作品。 なぜかプレイしていなかったのですが、凄い作品でした。



ストーリーは王道的なRPGなのですが、とにかくバトルシステムが凄い。 まさに「俺の考えた最強のバトルシステム」を地で行くゲームで、ただただ凄いとしか言いようがない。

戦闘はリアルタイムに進行し、ド派手に攻撃が駆け巡ります(左下)。 4人の仲間のポジションは戦闘中に変更して攻守を調整でき(右下)、 敵の攻撃をアクションでブロックする事もでき、 連携ゲージを溜める事で連携必殺技を使う事ができ、 操作キャラ以外は自動で戦ってくれる。 ………凄過ぎる。



一応イメージは上記の通りなのですが、この凄さは画像だとまったくわからないかも (私も上の紹介画像を見てもスルーしていました)。 そこで作者様の動画も合わせて貼ってみます(下)。 これを見ると凄さがよくわかると思う。



今までプレイしたRPGの中で一番凄いバトルシステムだったと思います。 是非一度は体験してみて欲しい作品でした。

フリゲ紹介: ニルダ物語

ニルダ物語はVIPRPG 2007紅白で1位だった作品。 VIPRPG 2007紅白はリンク切れでプレイした事がない作品ばかりなのですが、評判が良かったのでプレイしてみました。 どことなく○ルダの伝説に名前が似ている作品ですが、そっくりという訳でもない。



ニルダ物語は左下の主人公を操り、剣と魔法を駆使して世界を探索するシンプルなアクション2Dローグライクです(右下)。 ローグライクらしく物語の意味はあまり語られませんが、徐々に目的が見えてくるようになっています。



武器や防具はすべて敵がドロップするので、とにかく敵を倒すのみです。 敵を攻撃する場合は隣接してひたすらキーを連打するという方式になっています。 魔法も色々あるのですが、基本はキー連打でタコ殴りにしていく事になると思います。

長編RPGではないのでサクッとクリアできました。 さほどレベル上げも必要とせず、難易度も手頃で爽快感があり、シンプルに面白かった作品でした。 後継作品にニルダ戦記というものもあるようなので、いつかプレイしてみたいです。

2017年11月28日火曜日

imbalanced-learnでお手軽サンプリング

アンダーサンプリングやオーバーサンプリングは今まで手動で書いていたのですが、imbalanced-learnという素晴らしいライブラリがある事に気付きました。

以下はKerasと組み合わせた時のアンダーサンプリングの実装例。
from keras.utils import np_utils
from imblearn.under_sampling import RandomUnderSampler

negative = y_train.count(0)
positive = y_train.count(1)
count = min([positive, negative])
rus = RandomUnderSampler(ratio={0:count, 1:count})
x_train, y_train = rus.fit_sample(x_train, y_train)

y_train = np_utils.to_categorical(y_train, class_num)
y_test = np_utils.to_categorical(y_test, class_num)

model.fit(x_train, y_train, batch_size=128, epochs=1000)

上記は一番簡単なアルゴリズムを採用していますが、他にも様々なアルゴリズムを利用できるのはポイント高い。 これでもう面倒なコードを書かないでOKですね。

2017年11月24日金曜日

Vim/Neovimの設定で注意したい事まとめ

Vim/Neovimの設定を見直していて、結構地雷を踏んでいた事に気が付きました。 踏む地雷は人それぞれとも思うのですが、自分自身が再び地雷を踏まないように、 ハマった事のある~/.vimrcや~/.config/nvim/init.vimの設定の地雷をまとめてみました。

set paste
コピペが大好きな私は常にset pasteモードになっていればさぞ便利だろうと考えていた時期もありました。 しかしこの設定を行うと、deoplete.nvimのような補完プラグインの動作が変わる他、 tcommentのような自動入力系のプラグイン、それらに関連するような設定が機能しなくなります。 これに気付かずにかなり長い時間を無駄にした事があるので、要注意設定の1つ。

set t_Co=256
vimの色調を256色に設定するオプションです。 vimをターミナルで実行する場合、ターミナルのTERM変数からterm変数→t_Co変数を決定する仕組みになっているようです。 本来であれば ~/.bashrc などで export TERM='xterm-256color' を設定すればこの設定は必要ないはずだけど、 わざとターミナルの色調を落としているような場合は設定する必要がある。


set mouse=a
2019-12-22: 昔バグることが多かった設定でしたが、最近は問題がなくなったので、記述を削除しました。 最近はハマるポイントも減ってきて、完成度が高まってます。


set foldmethod=syntax
プログラミング言語のsyntaxを利用してコードを折り畳んでくれる便利機能ですが、これを設定すると全体の動作が非常に重く、もっさりになります。 様々なページで解決策を紹介されていますが、以下のような設定が私のおすすめです。
" ---------- もっさり対策
" ----- 共通
call dein#add('Konfekt/FastFold')
let g:fastfold_savehook = 1
let g:fastfold_fold_command_suffixes =  ['x','X','a','A','o','O','c','C']
let g:fastfold_fold_movement_commands = [']z', '[z', 'zj', 'zk']

" 再描画の方法を変更して高速化
set ttyfast  " これは要確認かも
set lazyredraw

" 挿入モード時にsyntaxを解除して高速化
augroup foldmethod-syntax
  autocmd! 
  autocmd InsertEnter * if &l:foldmethod ==# 'syntax'
  \                   |   setlocal foldmethod=manual
  \                   | endif
  autocmd InsertLeave * if &l:foldmethod ==# 'manual'
  \                   |   setlocal foldmethod=syntax
  \                   | endif
augroup END

" syntaxを探索する行数/列数を限定する事で高速化
set synmaxcol=256
syntax sync minlines=256

" ----- vim-ruby/vim-ruby
autocmd FileType ruby setlocal foldmethod=syntax
autocmd FileType ruby setlocal foldlevel=0
autocmd FileType ruby setlocal foldnestmax=1
" foldmethod=syntaxの後に記述する必要あり
let g:ruby_fold = 1
let g:ruby_foldable_groups = 'def'  " 処理を減らして軽く
プログラミング言語毎にも色々設定しないといけないので面倒ですが、このような設定をするとかなりストレスが軽減されるはずです。 これでも耐えられない場合は、foldmethodを他の方式に変えたほうが良いと思います。

call dein#add('lambdalisue/vim-pyenv')
Vim/NeovimでのPython利用が一般的になってきてから、Pythonの指定が結構重要になってきています。 Pythonはpyenvで管理している人が多いと思いますが、pyenvに頼りきった環境ではPythonのパスをプラグインが見つけられない事があります。 私がこの問題に直面したのはValloric/YouCompleteMeで、インストールは正しいのに以下のエラーが止まりませんでした。
The ycmd server SHUT DOWN (restart with ':YcmRestartServer'). YCM core library not detected; you need to compile YCM before using it. Follow the instructions in the documentation.
ようはインストールしたはずのものがpyenv上にあるため見つからないという状況になっていました。 これはlambdalisue/vim-pyenvを入れる事で解決できましたが、プラグインのバグではないので気付くのに結構時間が掛かりました。 anyanvの利用時にはこのような問題が発生し得る事を覚えておくとトラブルシューティングが楽になるかも。


Neovimはバージョンにも注意 (2018/06)

設定とは関係ありませんが、0.2.1〜0.2.2をインストールすると文字化けで編集が困難になりました。 エディタが死ぬと辛いので、このバグが起きない0.2.0を野良ビルドして入れたほうが良いかも。 ちなみに0.3.0ではこのバグは直っていました。

他にも何かハマりそうなポイントが見つかったら追加していこうと思います。

Googleブックマークを見やすくするChrome拡張を作った

Googleブックマークは動作が軽く気軽に利用できるので、 今でもとりあえずメモっておくような用途では使っています。ただ表示がほんの少し不満で、もっとコンパクトに表示してほしい。

これを改善してみます。まず以下のファイル構成を作ります。
googlebookmarks/
  manifest.json
  user.css
  user.js
manifest.jsonを以下のように編集します。
{
  "name": "Google Bookmarks+",
  "version": "0.0.1",
  "manifest_version": 2,
  "description": "Google Bookmarks+",
  "homepage_url": "https://www.google.com/bookmarks",
  "content_scripts": [
    {
      "matches": ["*://www.google.com/bookmarks/*",
                  "*://www.google.co.jp/bookmarks/*"],
      "css": ["user.css"],
      "js": ["user.js"]
    }
  ]
}
user.css、user.jsにはすべてのページに設定したい内容を記述します。
私はuser.cssを以下のように設定してみました。これだけでもかなり使いやすくなります。
br { display:none !important; }

#search table {
  line-height:21px !important;
  padding-top:0px !important;
  padding-bottom:0px !important;
}

あとはこの拡張を読み込むだけです。chrome://extensions にアクセスし、上部に表示されている「デベロッパーモード」をONにします。 そして「パッケージ化されていない拡張機能を読み込む...」を押して、googlebookmarksディレクトリを選択すれば完了です。 普通の拡張のようにパッケージ化していないので、user.css, user.jsを編集後に設定をリロードする事ができます。

拡張を作っていて気付いたのですが、Googleのドメインをすべて指定するには、ひたすら列挙するしかないみたいです。これはひどい(笑)。 面倒なので.com, .co.jpだけに限定しましたが、他のドメインで利用したい場合はコードに手を加えてください。

2017年11月3日金曜日

フリゲ紹介: アレックスと最終戦争と9人の少女

アレックスと最終戦争と9人の少女VIPRPG 2014紅白で4位だった作品。 VIPRPG 2014紅白はエンチャントファームのインパクトが大きくプレイしていなかった作品が多かったのですが、改めて他の作品も色々プレイしてみたところ、この作品は非常に面白かった。



9人の少女ごとにストーリーが展開されていくので、かなりボリューム感がある作品でした。15時間くらいかなあ。 過去の関連作品も一緒に同封されており、それらをすべてプレイするともっとボリュームがあります。 過去の関連作品はプレイせずとも十分楽しめる内容でしたが、プレイしたほうが背景を理解しやすいかも。

見るゲ+戦闘ゲに絞った作品で、レベル上げや探索要素を完全に排除したRPGになっているのは珍しく、また面白い。 戦闘の作り込みが凄く、キャラクターが非常に多いのにサイドビューでどのキャラもヌルヌル動く (画像右上)。 作るのにどれくらい時間が掛かったんだろう…。

戦闘システムも練られているいるなあと感じました。 VIPRPGはキャラクターが多いので全キャラを登場させると人数が多過ぎて、 戦闘に登場させる事が難しくなったり、メンバーを選ぶのも面倒になる事が多いように感じます。 この問題を戦闘中のキャラクター入れ替えで解決したのは面白いなあと思いました。 また戦闘には登場しないサポートキャラが戦闘支援をしてくれるのも良くできていて、 まさにこれが欲しかったんだ!という仕組みでした。 (戦闘中にもっと支援してくれて、もっと戦闘キャラが多いようなシステムも面白そう)

戦闘は、序盤は楽々でしたが、終盤に近付くと色々考える必要があり楽しめました。 やや暗めのストーリーでしたが、終盤では様々などんでん返しがあり面白かった作品でした。

フリゲ紹介: マリィと賢者の森

マリィと賢者の森は、ふりーむ!のランキングに一瞬だけ載っていたのですが、絵が綺麗だったので目に留まった作品。シンプルな短編SRPGですが、面白いと思った作品。



タイトル通り、主人公のマリィと賢者の森を巡る物語です。 全4ステージと非常に短い作品ですが、適度な難易度でサクサクプレイできるのが良いと思いました。 難易度は「ふつう」と「やさしい」を選択できますが、ふつうでも気軽にプレイできるくらいの難易度と思います。 難易度だけでなく、ターン毎にセーブでき、消耗する装備品が少なく、キャラクターも膨張しないなど、 深くのめり込まず気軽にプレイできる設定になっていたのも良かったです。



長編SRPGも昔はかなりプレイしていましたが、上記のような要素が強過ぎると正直面倒に感じてきています。 ヴァーレントゥーガTactical Chronicleアストゥール戦記のような名作リアルタイムSRPGが登場した影響も大きいかも知れません。 マリィと賢者の森くらいのサクサク感でプレイできると、細かい事をほとんど考える必要がないため、大いに楽しめた作品でした。

他にも仲間にできるキャラクターに自由度があり、またすべて精霊というのも風変わりで新鮮でした。 シンプルながら良作だったと思います。

フリゲ紹介: 炎帝セイバー

炎帝セイバーは、最近Twitter経由で知った2002年のRPG。 評価が非常に高かったのでプレイして見ようかと思いました。 しかし今時2002年の作品を掘り起こす人は滅多に居ないだろうなあ…などと考えつつ検索してみると、なんと作者様が炎帝セイバーをAndroidに移植中。 そして炎帝セイバーの後継作品もAndroidでプレイできる。むしろ最前線だった!



そんな訳でAndroid版炎帝セイバーが出る前に、Internet Archiveからさっそく過去の配布ファイルを掘り起こして原作をプレイしてみました。 ロボットヒーローRPGで、このRPGの面白さはHPの一言に凝縮されているように思います。

「熱さとカッコよさ、その二つを追求して誕生したRPG、それが炎帝セイバーだ!」

…この言葉で説明する事がなくなってしまった気がしますが、まさに昔ながらのフリゲという感じで、疾走感は素晴らしい。 最近のRPGもシステムは進化しているので現在視点から見るとシンプルなRPGという印象ですが、 早く続きを見たいと思わせる感じはメイジの転生録に通じるところがあるかも。 うまく言葉にできませんが、爽快感があり(下画像)、シンプルに面白いという事なのだと思います。



気付けば一気にプレイし終わっていました。 この作品がAndroidでどのように生まれ変わるかも是非見てみたいです。 (それ以前に後継作品プレイしなくちゃ)

2017年10月23日月曜日

コードに大きな変更を加えずに実行時間を計測するRubyスクリプトの例

SQLを使ったコードを書いていると、PreparedStatementがガンガン増えるので、 実行時間を計測するコードを書くのが結構面倒になります。

コードに散らばったPreparedStatementにBenchmarkやTime.nowを仕込むのは苦行です。 そんな時は以下のようにPreparedStatementにフックするクラスを用意すると計測が楽になるのかな。
require 'sqlite3'

class Statement
  @@total_time ||= 0.0
  @@list ||= {}
  attr_accessor :stmt, :name
  def initialize(stmt, name)
    @stmt = stmt
    @name = name
    @@list[name] = [0.0, 0]  # time, count
  end

  # def method_missing(name, *args)
  def execute!(*args)
    t = Time.now
    # @stmt.send(name, *args)
    result = @stmt.execute!(*args)
    t = Time.now - t

    @@total_time += t
    prev_t, prev_count = @@list[@name]
    @@list[@name] = [prev_t + t, prev_count + 1]
    return result
  end

  def self.total_time; @@total_time; end
  def self.list; @@list; end
end


db = SQLite3::Database.new('test.sqlite')
stmt1 = db.prepare('SELECT * FROM tables')
stmt2 = db.prepare('SELECT foo,bar FROM tables WHERE id=? LIMIT 1')
stmt3 = db.prepare('SELECT * FROM tables WHERE id=?')

#----- 変更はここだけ
script_time = Time.now
stmt1 = Statement.new(stmt1, :stmt1)
stmt2 = Statement.new(stmt2, :stmt2)
stmt3 = Statement.new(stmt3, :stmt3)

# スクリプト全体の実行時間を計測&表示
at_exit {
  puts "name, total, count, avg"
  puts "script, #{(Time.now - script_time).round(6)},,"
  puts "sqlite, #{(Statement.total_time).round(6)},,"
  Statement.list.each {|name, (time, count)|
    puts "#{name}, #{time.round(6)}, #{count}, #{(time/count).round(6)}"
  }
}
#-----

100.times {
  stmt1.execute!
  stmt2.execute!(123)
  stmt3.execute!(456)
}

出力は適当なのでそのままだと見にくいですが、csviewerを使うとこんな感じで表示できます。
$ ruby test.rb | csviewer
+--------+-----------+--------+-----------+
|  NAME  |   TOTAL   | COUNT  |    AVG    |
+--------+-----------+--------+-----------+
| script |  2.956297 |        |           |
| sqlite |  2.953417 |        |           |
| stmt1  |  1.148423 |    100 |  0.011484 |
| stmt2  |  0.008129 |    100 |  8.1e-05  |
| stmt3  |  1.796866 |    100 |  0.017969 |
+--------+-----------+--------+-----------+

今回はexecute!メソッドだけにフックする例を取り上げてみましたが、この登録さえ面倒な場合はコメントアウトしてあるmethod_missingのコードですべてのメソッドにフックすると良いです。このコードは汎用ライブラリとしても使えますが、不要なメソッドまで測定してしまう可能性もあり、実行速度が落ちるデメリットもあります。

Rubyでは意外と使い回せそうなコードなのでコピペ用にメモしておきます。

2017年10月4日水曜日

プロセスの終了を監視するbashスクリプト

ふと nohup command & でタスクを投げた後、別のマシンでその終了タイミングを知る方法がない事に気付きました。 マシン1でタスクを投げた後、作業場を変えたりしてマシン2でそのタスクの終了を待つ必要がある時、地味に困る。 今まではマシン2ではpsを連打したりして終了を確認したりしていたのですが、それもアホらしい作業なので、 プロセスを監視するコマンドを作ってみました。

~/binなどにコマンド登録するほどの代物ではないので、~/.bash_profileに以下を登録。
function pcheck() {
  process=`ps -p $1`
  while [ $? -ne 1 ]; do
    sleep 1
    process=`ps -p $1`
  done
  echo "$1 is finished."
}

使い方は以下。12345はプロセスIDに置換してください。 このコマンドを実行すると、プロセスが終了した時にnohupと同様に、ターミナルに通知が表示されます。
nohup bash -lc "pcheck 12345" &
# nohup pcheck 12345 &  # これでは動かない

~/.bashrcと~/.bash_profileのどちらにコマンドを登録しても、nohup pcheck 12345 & とは動かせないので注意。 また~/.bashrcに関数登録しても動きませんでした。~/.bash_profileに書く必要があるみたいです。

2017年10月2日月曜日

フリゲ紹介: ボムっと発掘!とれじゃーはんたぁ

ボムっと発掘!とれじゃーはんたぁVIPRPG 2017夏の陣で1位を取っていた作品。 私もこれは非常に面白いパズルゲームだと思いました。



ボムっと発掘!とれじゃーはんたぁは、画像左下に表示されているようなパズルを、主人公のバースティが一筆書きで解いていくゲームです。 数字が一筆書きを連続して描ける時間を示しており、 パズル内のブロックを一筆書きですべて爆破したらお宝ゲットという内容になっています。

このゲームは誰でもクリアできる難易度で、何より爽快感が非常に高いのが良いところだと思いました。 パズルはレベルが上がるごとにどんどん大きく、難しくなっていくのですが、 同時にパズルのヒントを表示する補助アイテムも手に入るようになっています。 補助アイテムを使った場合は難易度は最初から最後までほぼ一緒くらい。 大きなパズルでもあまり迷わずにクリアできるので、結構な爽快感があります。

最初のOPが長い(笑)と思いましたが、ゲームが始まってからはサクサクプレイできて、非常に印象の良かったゲームです。おすすめ。

フリゲ紹介: SWORD II マーヴの逆襲

SWORD II マーヴの逆襲はいくつかのサイトで絶賛されていたのでプレイしてみた作品。 2003年の作品ながらこれも最近存在を知りました。

王道的なRPGで10時間くらいのボリュームがある作品でした。 OP画面(左下)はそっけないですが、マップチップや敵グラやは完全自作(右下)との事で中身は気合が入っている。



それ以上にこの作品を印象付けているのはストーリーと細かな作り込み。 序盤早々で封印された邪神マーヴのご神体(左下)を拝めるのですが、このマーヴの封印を巡る物語となります。 ストーリーはなかなか重く、サクサクと味方が死んでいきます(右下)が、 そう来るかという驚きの進展も多く、また最終的には綺麗にまとまっていて、実に良くできているストーリーだと感じました。 お使い的なところも結構ありましたが、それを感じさせないのは良く練られている証拠でしょうか。 ストーリーはテンポ良く進むのでストレスもなく、サクサクとプレイできました。



長時間プレイしても飽きさせない仕組みが随所に施されている点も印象に残りました。 具体的には4番目の仲間との掛け合いや、作中で何度も登場するトトエルは面白い。 戦闘自体もシンプルながら、中盤くらいから細かな部分でスパイスが効いており、完成度の高さを感じます。 ネタバレが多くなり過ぎる気がするのであまり書けませんけど。

唯一キツめだったのはエンカウント。 完全なランダムなようで、1歩歩いて戦闘を3回くらいこなす事も。 さすがにそんな事は滅多に起きないのですが、回復を忘れて悲惨な事にならないよう注意が必要です。 昔ながらのRPGに慣れている人には見慣れた光景ですが、最近の人にはキツめかも。

昔ながらのRPGを感じるには非常に良い作品で、絶賛も頷ける作品だったと思います。

フリゲ紹介: Win' Wind' Windy

Win' Wind' WindyVIPRPG GW祭り2016の作品。敵に触れると一発でやられるウィンディをゴールまで導くシンプルなアクションパズルです。



画面内をゆっくり歩くウィンディがゴールに辿り着けるよう、方向転換やブロック設置をしていく内容。 ハードモードではウィンディがよりウィンディらしくスペランカー化します。

昔はパズルゲーはあまりやらなかったのですが、最近は面白いパズルゲーが増えてきていて、結構プレイしています。 Win' Wind' Windyは誰でもクリアできる難易度で(おまけは結構難しい)、 サクッと1-2時間くらいでプレイできて面白かった作品です。

この「誰でもクリアできて」、「爽快感や達成感がある」という2つを押さえた作品は、 私のような下手くそプレイヤーには重要で、こんなん無理でしょ…というパズルゲームより満足度が高いです。

2017年9月20日水曜日

ターミナルで動くエディタmicroに期待しつつvimと比較

ターミナルで動くエディタとしてはvimやemacsが有名ですが、 GitHubを覗いていたらmicroというエディタが人気になっていました。 結構前からあったみたいですが凄いかも。格好良いし。



特徴をざっくり列挙すると、
  • 非常に軽快な動作
  • ターミナルで動くのにマウスが使える (凄い!)
  • Windowsっぽいキーバインド
  • 画面分割やタブ操作 (Ctrl-T) は標準装備
  • プラグインシステムは標準装備
  • Go言語で作られているのでクロスプラットフォーム動作
  • Luaでプラグインが書ける (VimScriptより高速動作するはず)
  • vimっぽいコマンド操作がある程度は可能 (Ctrl-E)
  • 最近のエディタらしくシンタックスハイライトもカラースキームも豊富

コードを綺麗にしながらクロスプラットフォームを実現し、Luaで高速なプラグインを書くという目標は、 neovimでも聞いた事があるような…と思ったのは私だけでしょうか。

軽く使ってみたのですが、Windowsのキーバインドで利用しやすいvimという印象でした。 vimのようなモードが使えて日本語入力も簡単となれば、常用してみたくなります。 ただカスタマイズを重ねたvimと比較すると、まだまだmicroには以下のような課題がありそう。
  • ファイルの先頭/末尾への移動が面倒 (gg / Gに対応するものがない?)
  • Ctrl-Fの検索でヒットしたものを一括カラーリングできない
  • タブとかコマンド補完の表示がやや見辛い
  • 自動補完はまだできない
  • 矩形選択できない
  • 割当できないキーバインドがある
  • 全角スペース、半角スペース、タブの表示の区別ができない?
  • microで検索するとMicrosoftに邪魔されてかなり辛い

現状でも手軽な編集なら十分に使いやすいエディタですが、 これらが解決されれば一線級のエディタになりそう。 気付いたらどれも実装されてそうな勢いがあるので、注目したいエディタです。

Minimal User CSS & JavaScript なChrome拡張を作った

最近、マルウェア化するソフトウェアが増えてきています。 特にGoogle Chromeの拡張機能の自動アップデートは危険で、 自動アップデートの停止が難しい上、管理も面倒、マルウェア判定も難しい。

私は拡張機能自体ほとんど使ってませんが、 前の投稿で説明した拡張を使ってユーザCSS、ユーザスクリプトを管理する行為を行っていました。 しかしこれもかなり危険に思ってきました。 (1)どう頑張っても拡張がすべてのページに対してアクセス権を持ってしまう事や、 (2)ユーザスクリプトでのマルウェア報告が増加しているためです。

例を挙げると最近では以下のような被害があります。 また実際に悪意のあるChrome拡張がどのくらい危険かという事は Chrome拡張の権限でどこまで(悪いことを)できるのか?とその対策【デモあり】 - Qiita によくまとまっているので興味のある方は参照してみてください。

このような経緯もあり、最小限の機能ですべてのページに適用するユーザCSS、ユーザスクリプトを自作してみる事にしました。 自作ならセキュリティ上まったく問題ない。

まず以下のファイル構成を作ります。
usercssjs/
  manifest.json
  user.css
  user.js
manifest.jsonを以下のように編集します。
本当はどのタイミングでChrome拡張を起動するかなどの細かい話もあるのですが、話が長くなるだけなので割愛。興味のある方はこちらも参考にしてみてください。
{
  "name": "Minimal User CSS & JavaScript",
  "version": "0.0.1",
  "manifest_version": 2,
  "description": "Minimal User CSS & JavaScript",
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "css": ["user.css"],
      "js": ["user.js"]
    }
  ]
}
user.css、user.jsにはすべてのページに設定したい内容を記述します。
私は以下のように設定してみました。まずuser.css。!importantを設定しないと駄目みたいです。
a:visited {
  color:red !important;
}
次にuser.js。例として右クリック禁止を無効化してみました。
// Enable Right Click
document.addEventListener('contextmenu', event => event.stopImmediatePropagation(), true);



あとはこの拡張を読み込むだけです。chrome://extensions にアクセスし、上部に表示されている「デベロッパーモード」をONにします。 そして「パッケージ化されていない拡張機能を読み込む...」を押して、usercssjsディレクトリを選択すれば完了です。 普通の拡張のようにパッケージ化していないので、user.css, user.jsを編集後に設定をリロードする事ができます。結構便利。

これにてセキュリティ向上は完了です。

2017年9月17日日曜日

Chrome拡張のUser JavaScript and CSSで訪問済みページを見やすく

長時間ネットで検索していると、一度見たページを明確にしながらブラウジングしたい事がよくあります。 なぜかというと、訪問済みページの表示はサイトによって見やすさがマチマチで、何度も同じページを見てしまう事があるからです。 どんなページでも見やすいCSSを適用したい。

こんな時はユーザCSSを編集して一度訪問したページのCSSを変えてしまえば良いです。 やはりChrome拡張を使うのが楽で、Stylish が有名な拡張なのですが、 User JavaScript and CSS というChrome拡張が登場している事に気付きました。 こちらがおすすめ。



User JavaScript and CSSが良いところは、ユーザスクリプトの設定も同時にでき、Stylishの半分くらいのメモリで動作するところです。 Stylishではユーザスクリプトの設定はできないし、ユーザスクリプト拡張として有名なTampermonkeyと併用して使うと、結構なメモリを食ってしまいます。 省メモリで動作させたい私の利用用途には、ぴったりの拡張でした。


さてすべてのサイトの訪問済みリンクの色を見やすくしてみましょう。これは画面上の適用URLを「*」にして、画像右のCSSエディタに以下を入力して保存すれば実現できます。
a:visited {
  color:red;
}

この設定をするとすべてのページが以下のような表示 (変更前→変更後) になります。 もちろん一部のページにだけ適用するような事もできますが、私はこれで満足しています。



本当はJavaScriptを使って親要素を編集したりしてみたかったのですが、:visited属性はセキュリティ上、色を変えるくらいしか変更できないようなので、これで諦めました。 まあ、たったこれだけの設定でも結構使いやすくなったので良しとします。見にくい時はすぐにOFFにできるのも良いところ。

追記:最近はセキュリティを意識してChrome拡張を自作しました

2017年9月15日金曜日

フリーゲームを探すのに便利なサイトまとめ

フリーゲーム(フリゲ)を探すためのまとめページは色々あるのですが、どれも微妙に不満があったので、私が実際に使っているページをまとめてみました。 商業的なものではなく、同人的なフリーゲームのまとめです。

王道的なサイト

とりあえずここを見ておけば王道ものは見つかる。 ただここだけを見ていると見逃しが多くなるので、他のサイトも見たほうが良いです。

レビューサイト

見逃しを探すのに参考にしているサイト。たくさん投稿してくれているところは購読したくなりますね。

その他色々

目新しいものを探す時には以下のリストなどを参考にしています。 普段は ふりーむ!の更新ゲームのページ や、VIP系などをよく見ています。

更新が止まっているものの参考になるサイト

更新が止まっているサイトも是非見て欲しいです。 特に フリーゲームで面白いページ まとめページ跡地 は必ず一度は見て欲しいサイト。忘れられた名作がたくさん見つかるはずです。 VIPRPG過去作品代理保管庫 もぜひ見て欲しいかな。
少し昔話になりますが、フリゲ界って2005年くらいまでは フリーゲームで面白いページ まとめページ跡地 が王道サイトだったと思うんですよね。 更新が徐々に止まってきた2005年くらいから、フリゲ20XX あなたが選ぶ今年のベストフリーゲームウディコン ができる2009年までの4年間は闇の時代で、この辺の時期のフリゲは探すのも大変だったし、かなり見落とされてると思います。



ここまでは個人的によく見ているサイト。以下は気分転換で見たりしているサイトです。


海外

以下は有名サイトだと思いますが、私は極稀に見る程度です。

その他のサイト


プログラミング言語ごとのゲームサイト

プログラミング言語で探す事は滅多にないですが、面白いゲームが見つかる時も。特にHSP。 子供用プログラミングの定番になった Scratch の一覧は、種類も非常に豊富なので新しくゲームを作る上での参考にもなります。

Flashのゲーム

私はそれほどプレイしていませんがFlashゲームは根強い人気があります。

HTML5/JavaScriptのゲーム

最近はHTML5/JavaScriptでプレイできるゲームも増えてきました。 企業が HTML ゲーム総合サイトを作ることも増えました。オセロとかさめがめとか。 例えば以下ですが、これだけ増えるとありきたりなゲームは埋め尽くされてお腹いっぱいな感じ。 独創性のほうが大切になりそうかな?

この他にもあまり有名でないものを紹介してくれているブログや小規模コンテストはたまに見ていますが、 以上を見ておけばフリゲはだいたい網羅できると思います。 海外ゲームは詳しくないのであまりまとめませんでしたが、ここ が詳しそう。

フリゲ紹介: メイジの転生録

メイジの転生録は、フリゲ2016で2位だったのに、見た目が尖り過ぎていてなぜかプレイしていなかった作品。 なんで当時はプレイしなかったんだろう…と思うくらいの名作でした。



一本道のシンプルなRPGながら、これほど面白いと思わされたRPGも珍しい。 まさに中二病を極めた作品で、このゲームならではの口調が目立ちます (下)。 「デリートるってなんだよwww」「CLOSS FAIT BATTLEってなんだよwww」と最初は思いました。 しかし気付くとこの作品特有の中二病に病みつきになるはずです。とにかく面白い!



プレイするほどクオリティにも驚かされます。 作品自体も面白いし、音楽も良い。BGMはいくつか保存してしまったくらい。 次回作にも非常に期待しているシリーズです。

2017年9月13日水曜日

フリゲ紹介: LEVEL 9

LEVEL 9はワンパンで敵を倒せるシミュレーションRPGっぽいRPG。

2014年の作品ながら最近までまったく知らなかったのですが、ふりーむで一瞬だけダウンロードランキング上位に入っていた(確か)ので、目に止まりました。 OP画面 (下) を見て、これは面白いはずと思ってプレイしてみたところ、やはり面白かった。



LEVEL 9は主人公をシミュレーションRPGのように操り、敵を薙ぎ倒していくゲームです (下)。 ワンパン(もしくはツーパンくらい)で敵を倒せる他、様々な必殺技も使えて爽快感があります。 サクサクプレイできて、短編ながらストーリーも綺麗に完結していたので、印象の良かったゲームです。



最近はダラダラとした長編RPGより、短編でも爽快感のあるゲームが好きになってきています。 そのニーズにまさにマッチした作品でした。

フリゲ紹介: フリーランスRPG -Vida-

フリーランスRPG -Vida-は結構昔の作品で、公式HPはあるものの長い間ダウンロードできずプレイできていなかった作品です。 気付いたらフリゲ補完スレで魔改造版がアップロードされていたので、やっとプレイできました。 ダウンロード先は貼って良いのかわからないので、検索してみてください。

ちなみにネットを彷徨っていたら無印版も見つけたのですが、戦闘速度が遅めなので、最近の人には圧倒的に魔改造版がおすすめです。


この作品は…凄く面白かった!
-Vida-のような探索RPGは、Nepheshelイストワール魔王物語物語Ruina 廃都の物語シルフェイド幻想譚イニシエダンジョン、 その他にも様々な名作があり、それらのクオリティに近付く事も相当難しいのですが、 間違いなく上位に食い込む面白さの作品だったと思います。

-Vida-はNepheshelの影響を非常に強く受けており、自由度が大きく、 隠し通路などを見つけて強い装備を整えていくスタイルの探索RPGです。 マップも綺麗 (右) でサクサク探索でき、探索RPGが好きな人はかなり楽しめると思います。



随所に面白いシステムが採用されており、戦闘もなかなか面白い。 敵と味方のターンがA-Fで表示されているのですが (右)、このタイミングを見て攻守を切り替えたり、 敵の攻撃を掻き消したり、ターンを遅らせたり、他のRPGでは味わえない戦略性があります。



このゲームの一番凄いところは、ボスは全身全霊で殺しに来る事です。 状態異常攻撃は当たり前。猛毒攻撃には慈悲がある訳もなく、すぐに回復しないと死にます。 中盤以降のボスは当たり前のようにハメ技を使ってきます。 レベルを上げようとも攻撃を防がない事には全滅必死の攻撃も多数。 こんなにえげつないボス戦は初めて見ました。 対策をしっかり立てないと何もできずに一瞬で全滅するでしょう。 まあ攻略法に気付くと意外とスムーズに倒せるんですけどね。そこが良い。

随所で尖りまくっている作品ですが、難易度が高いからこその面白さがあります。 ボス戦以外はサクサク進めるのでストレスもないんですよね。 私はかなりハマり、一気にクリアしてしまいました。 クリア後にはEXモードという、いわゆるハードモードもあり、こちらもなかなか面白い。

久々に探索RPGの面白さを堪能できた作品でした。

2017年9月12日火曜日

フリゲ紹介: 邪策の枷

第9回ウディコンのランキングが出たのでいくつかプレイしてみました。 全部プレイするのは大変なので、ランキング上位20位までプレイ。

多少苦手なものはありましたが、だいたいランキング順に面白かったです。 総合ランキング上位の 夏雲の島の宝船ひとりぼっちの竜の神話箱の中のバーディは安定して面白かった。

上記3つは万人受けしそうで実際面白いですが、私のおすすめは 邪策の枷。リズム&パズル戦闘RPGとのこと。 ランキングではやや下位に位置していますが、これはかなり面白いと思いました。 斬新さを考えると一番良かったかも知れません。


戦闘面が面白く、相手のアクション攻撃を扇子で防ぎ(左下)、パワーを溜めて反撃というシステム。 反撃時はパズドラみたいなパズルを使います (右下)。 パズルで星座を作る事で様々な魔法が発動するようになっています。 戦闘システムを工夫するのはゲームの面白さを出すためには重要と思いますが、 アクション要素を取り込んだ作品は好きです。 パズルは苦手なので私は反撃にネックがありましたが、良くできているなあと思った作品でした。

今後もたまにプレイ日記を書いていくつもりです。 あっさりとした感想が多いと思うので、最近プレイしたゲームの中で面白かったものに留める予定です。

2017年8月20日日曜日

.inputrcでターミナルの補完を便利に

今までbashのTab補完にはどうやって色付けすれば良いのだろうと思っていました。 lsした時に色付けするのは--color=autoのaliasを ~/.bashrc に書いていればOKですが、cd [Tab] でカレントディレクトリの補完をしようとした時には色付けされません。
これはどうやら ~/.inputrc で set colored-stats on とする事で設定できるみたい。 .inputrcはreadlineの設定ファイルなので、他にも色々と設定しておくと幸せになれそうです。

設定可能な項目を見ていると、以下のように設定すると便利そう。
# 補完時に大文字小文字を無視
set completion-ignore-case on
# ファイルタイプをカラフルに
set colored-stats on
# 補完の接頭辞をカラフルに
set colored-completion-prefix on
# 実行ファイルに印を付ける
# set visible-stats on

キーバインドの登録もできるみたいで、以下のような設定をしている人は多かったです。
set editing-mode vi
"\e[A":history-search-backward  # arrow up
"\e[B":history-search-forward  # arrow down
特殊キーを設定するための文字列はcatコマンドを入力後に、特殊キー(例えばarrow up)を押すと、 ^[[A という文字列が出てきますが、この ^[ を \e に置換したものを使うとのこと。


.inputrcがこんなに便利だったとは。もっと早く知りたかったよ…。

2017年8月18日金曜日

プロダクト比較サービスSlantが便利

SlantというサイトのLinuxランチャー比較がとても秀逸だったので、他にも面白い比較がないか色々調べてみました。人気のページを眺めてみましたが、結構面白いものがあります。 さすがに日本製ツールまではまとまっていないですが、海外製ツールの動向を知るには便利そうなサイトですね。

今まで知らなかったアプリも結構見つかりました。以下は特に便利そう / 面白いと思ったもの。

他にもウィンドウマネージャ ( LinuxWindowsMac) なども紹介されていました。使った事ないですが、使い方次第では便利なのかも知れません。

2017年8月17日木曜日

Linuxディストリビューション比較: やっぱりLubuntuは軽い

Ubuntuが18.04からUnityを廃止してGNOMEを採用するとの事で、 久々にUbuntu 16.04にapt-getで色々なディストリビューションをインストールして比較してみました。



ディストリビューションの比較は際限がないですが、 マニアックなものは抜きにして、Ubuntuから確認できる平凡なものだけにしています。

起動→安定後のメモリ使用量をタスクマネージャで確認すると以下になりました。
  • Ubuntu: 943MB
  • Ubuntu GNOME: 882MB
  • Kubuntu: 1185MB
  • Xubuntu: 851MB
  • Lubuntu: 538MB
  • Ubuntu MATE: 820MB

やはり前評判通りUnityはやや重く、Lubuntuは軽いという結果です。 Kubuntuは気付いたら標準Ubuntuより重くなってる…。 その他も標準より多少軽い程度で大差なくなってますね。 今後標準になるであろうUbuntu GNOMEは高機能で使いやすく、慣れればUnityと大差ない操作感で使用できるので、 今後は標準Ubuntuを使っておけばまず間違いないように思いました。

軽量を求めるならLubuntu一択。 起動時間も顕著に高速なのでなかなかに爽快感があります。 一つだけ注意点を挙げると、現在のLubuntuは軽量化のために透過ウィンドウは非透過になる仕様なので、この点にはご注意を。

あとLubuntuは軽量さの根幹のLXDEをLXQtへ移行する事を予定しており、動向が不安定な状態にあります。 2015年時点ではメモリ使用量はLXDE < XFCE < LXQtと残念な結果でした2016年にはLXDE < LXQt < XFCEになり改善はされましたが、 まだまだ開発中の状態であったため、18.04ではどうなるのかという状態が続いていました。

追記: そんな不安定な動向だったLubuntuでしたが、引き続きLXDEを採用した18.04が、2018/04/27にリリースされました比較してみたところ、Lubuntu 18.04も軽量さが維持されていました。 LXQtについてはLubuntu Nextの名称で現在も開発中らしいです。

ところでLubuntuは標準設定では少々使いにくいので、最低限ランチャーは用意したほうが良いと思います。 もっともLubuntuを使うような軽量志向の方はランチャーも自前で用意したほうが良いと思います。 おすすめランチャーは3つほど。

AlbertランチャーとLubuntuの組み合わせは最強かも

久々にディストリビューションで遊んでみると、やはりLubuntuは高速でした。 ただ以前使っていた時も感じたのは、常用するにはLubuntuは少々使いにくいという事です。 特にUnityランチャーやGNOMEランチャーに慣れてしまうと、多くの人は標準のランチャーが貧弱過ぎてツライんじゃないかと思う。

そこでLinuxで使いやすいランチャーを検索してみたところ、非常に良いページが見つかりました。

ランチャーと言えばSynapseやKupferが有名と思っていましたが、色々なランチャーがあるのですね。 一番人気のAlbertを使ってみたところ、確かにシンプルで良い。


その他の紹介されていたランチャーを使ってみて感じたのは、自然なパス補完、アプリ名の表示、インストールの容易さといった機能を高水準で用意しているランチャーはそれほど多くないという事です。Albertはいずれも良い感じの出来で、高評価も頷けます。


Lubuntuではこのような外部ランチャーをLubuntu起動時に自動起動するようにしておくと良いと思います。 ~/.config/lxsession/Lubuntu/autostart に以下を記載しておくとAlbertを自動起動してくれます。 全ユーザに同じ設定を適用したい場合は /etc/xdg/lxsession/Lubuntu/autostart に以下を書いておくと良いようです。
@albert

設定してみるとなかなかの使用感。 Lubuntuはランチャーさえ用意すれば他ディストリビューションに大きく劣る点はなさそう(細かな点は色々ある)なので、 Albertを知った事で久々に使ってみようと思いました。

Lubuntuのさらに細かな機能改善方法については、こちらにまとめてみました

Lubuntuを標準Ubuntu並に使えるように設定する

Lubuntuの標準設定はそれほど使いやすくありませんが、以下の設定をすると、 Ubuntuと遜色ない機能を、より少ないメモリ使用量で利用できます。

ワークスペースを増やす

Ubuntuの標準数は4個ですがLubuntuでは2個。以下の設定で増やす事ができます (18.04ではデフォルトが4個になったので設定不要)。

「設定」→「Openbox Configuration Manager」→「デスクトップ」で以下の画面へ。


上記のように「デスクトップの数」を4にすればOK。この設定をしても現在のUbuntuのように上下左右にワークスペースを作れる訳ではないですが、そこは我慢。 将来の標準予定のUbuntu GNOMEも上下左右には配置できないので許容範囲でしょう。


IMEのトレイアイコンを表示する

ibusのバグのようですが、Lubuntuでは何も設定しないとIMEのトレイアイコンが表示されません (18.04では解決済み)。 私の環境では以下を実行し、再起動する事で解決しました。
sudo apt-get install python-appindicator
sudo apt-get install python-gconf
sudo apt-get install python-glade2
sudo apt-get install python-pexpect

ランチャーを高機能化

Alt+F2で利用できるLubuntuのランチャーは先頭一致検索しかできないので不便です。 外部ランチャーを利用すると一気に使い勝手が良くなります。

CtrlとCapsLockを入れ替える

Ubuntuだとこの設定は簡単なのですが、Lubuntuではハマりがちです。 様々な設定方法があるようですが、 ~/.profileに以下を記述するのが最も簡単なように感じます。
# CapsLockをCtrlに変更
setxkbmap -option ctrl:nocaps
# # CapsLockとCtrlを入れ替える
# setxkbmap -option ctrl:swapcaps
# # CapsLockを元に戻す
# setxkbmap -option

スクリーンショット機能を標準Ubuntuに近付ける

Ubuntuの密かに便利な機能として、PrintScreenキーでのスクリーンショット機能があります。 Lubuntuでも同じ機能をscrotを使って再現していますが、確認画面なしでホームディレクトリに画像が保存されるなど若干の違いがあります。 この動作が気に入らない場合は、Ubuntuが利用しているgnome-screenshotに変えると良いです。
~/.config/openbox/lubuntu-rc.xml でショートカットキーが設定できるので以下を削除し、
<keybind key="Print">
  <action name="Execute">
    <command>lxsession-default screenshot</command>
  </action>
</keybind>
<keybind key="A-Print">
  <action name="Execute">
    <command>lxsession-default screenshot window</command>
  </action>
</keybind>

以下に書き換えるのは便利と思います。設定は openbox --reconfigure で反映できます。
<keybind key="Print">
  <action name="Execute">
    <command>gnome-screenshot --interactive</command>
  </action>
</keybind>


ほんの少しの設定で、Ubuntuと操作感がほとんど変わらなくなりました。大満足。

2017年7月22日土曜日

Webブラウザ (特にGoogle Chrome) が重い時の必殺技

Google Chromeはとにかくメモリを使います。 これはもうどうしようもない事なので、へっぽこマシンでは以下のようなユーザ努力も必須になります。 他ブラウザにも通じる最適化ではありますけど。
  1. OneTabTab Memory Purgeなどでタブをまとめてメモリを開放する
  2. Click&Cleanなどを利用してキャッシュを定期的に削除する
  3. 拡張機能は最小限にする
  4. バックグラウンドアプリの処理を実行しない
他にも試験運用機能をONにするなどの方法もありますが、不都合が生じる場合もあるのでこの4つが一般的でしょう。 こういった努力をするとかなりマシになるのですが、 それでも調子に乗ってページをガンガン開いていると、気付けばメモリがパンクしてプチフリーズする事もあります。 さらに軽くできないかと思っている方もいるのではないでしょうか。


ここからが本題。 最近ふと気付いたのですが、頻繁に訪れるページが決まっている場合には、上記に加えてもう1つの解決策がありました。 それは…

5. サイト設定でJavaScriptや画像をブロックする


上図のデフォルトになっているものから、サイトごとに不要なものをブロック状態に変えるだけ。 様々な項目がありますが、JavaScriptと画像が最も効果的と思います。 サイトごとに設定するので重いページにだけ適用する事ができる優れものです。

JavaScriptをブロックすると当然ページを開くのが高速化しますし、 タイマーなどのスクリプトを無意味に使っているページではCPUリソースの削減になります。 画像も不要だとわかっているならブロックする事で、メモリ削減とページロード高速化にかなりの効果があります。 例として挙げたGoogleでブロックしても効果はないと思いますが、ゴテゴテしたサイトでは効果抜群。

このような画像やJavaScriptのブロックなどのサイト設定は、ChromeだけでなくFirefoxでも可能です。 万能な解決法ではないですが、一度設定すれば高速ブラウジング環境の出来上がり。 おすすめです。

2017年6月28日水曜日

AA表示用フォントはFirefoxとの相性に注意

Ubuntuで久々にFirefoxを起動してかなり驚いた事がありました。 …大手サイトさえまともに表示できない。文字が何も表示されない。 なんでだろうと思って色々確認してみるとフォント指定に影響を受けていました。

例えばYahoo!ではbodyに"MS PGothic","Hiragino Kaku Gothic Pro","ヒラギノ角ゴ Pro W3",Helvetica,Arial,sans-serif を指定しているのですが、実際の表示ではArial, IPAMonaPGothic, TakaoPGothic, Ubuntuを使っていました。

どうやらAAの表示確認に入れたIPAモナーフォントが悪さをしていたようです。 IPAモナーフォントはMS PGothicの代替として使われますが、 フォントが不足しているのでまともに表示できないという状況に陥っていたようです。 IPAモナーフォントを削除してフォントキャッシュを作成し直すと無事元通りに。

Chromeではこのような問題は起きなかったので、何らかの処理が異なるのだと思いますが、 MS PGothic互換のAA表示用フォントのインストールは注意深く行う必要がありそうです。

2017年6月27日火曜日

Linuxコマンドを補完するRubyスクリプト

Rubyによる補完スクリプトを作っていて気付きましたが、 rb-readlineはファイル補完はしてくれますが、Linuxコマンドの補完はしてくれないようです。 仕方ないので自作してみました。

まず、Linuxのコマンド一覧は以下で取得できるらしいです。これはMacでも使えます。 ただWindowsはコマンドを一覧表示できないようなので、cygwinの利用を想定するしかないかも知れません。
compgen -ac
このリストを利用したコマンド補完は以下で良さそうです。
require 'readline'  # gem install rb-readline

commands = `bash -ic "compgen -ac"`.split("\n")
Readline.completion_proc = proc {|s|
  last_command = Readline.line_buffer.split(/\s*[|&]\s*/)[-1]
  if last_command =~ /^.*\s+/
    Dir.glob('*').grep( /^#{Regexp.escape(s)}/ )
  else
    commands.grep( /^#{Regexp.escape(s)}/ )
  end
}
Readline.readline("Execute: ")
これでbashの補完とまったく同じ補完が実現できるようになりました。 以前作成したスクリプトも更新しておきました。

2017年6月19日月曜日

peco/fzfは外部コマンド実行用コマンドを作っておくと便利

前回に続きpecofzfネタです。 peco/fzfはとても便利なのですが、コマンドを実行するのは少し面倒だったりします。 具体的には、pecoでファイル一覧を表示、ファイルを選択してdirディレクトリにコピーする場合、以下のコマンドを打ちます。
cp `ls -a -p | peco` dir              # 方法1
ls -a -p | peco | xargs -J% cp % dir  # 方法2
「`」だったり細かなオプションが問題で、割と入力しにくいんですよね。 またxargsのオプション覚えるのも面倒だし、事前に何を実行するかわからない事も多い。 そこで以下のスクリプトをxコマンドとして登録してみる事にしました。
#!/usr/bin/env ruby

require 'readline'  # gem install rb-readline

# 入力を置換したいキーワードを登録
keyword = '@'


commands = `bash -ic "compgen -ac"`.split("\n")
if ARGV[0]
  dir = ARGV[0]
else
  dir = '.'
end

# list = `ls -a -p "#{dir}" | peco`
# list = `ls --color -a -p "#{dir}" | fzf --ansi -m`
list = `ls --color -a -p "#{dir}" | fzf --ansi -m --preview 'ls -C #{dir} --color=auto'`
puts list.split("\n").take(10).join(', ')

# Linuxコマンド補完をできるように
# https://marmooo.blogspot.jp/2017/06/linuxruby.html
Readline.completion_proc = proc {|s|
  last_command = Readline.line_buffer.split(/\s*[|$]\s*/)[-1]
  if last_command =~ /^.*\s+/
    Dir.glob(dir).grep( /^#{Regexp.escape(s)}/ )
  else
    commands.grep( /^#{Regexp.escape(s)}/ )
  end
}
cmd = Readline.readline("Execute: ")

exit if cmd.empty?
cmd = "#{cmd.strip} #{keyword}" if !cmd.include?(keyword)
cmd.gsub!(keyword, list.gsub("\n", ' '))
system("bash -ic '#{cmd}'")
xコマンドを実行すると、peco/fzfで何らかの処理したいファイルを選択した後、入力画面が出てきます。 そこで処理したいファイル郡@に対して任意の処理を指定する事ができます。 最初の例を実行する場合は以下のように入力すればOKです。 dir部分の入力にはシェルと同様の補完が効いています。
cp @ dir
備考ですが、置換キーワードに「@」を登録したのはファイル名に使われにくく入力しやすいからです。 また"bash -ic '#{cmd}'"という形式で実行しているのは、~/.bashrcの設定を引き継ぎながら実行するためです。 この設定がないと、例えばlsを実行した時などに--color=autoの設定が反映されません。

このxコマンドは前回紹介したcコマンドと組み合わせる事もできます。以下のようにcコマンドを実行後にxコマンドを起動するようにすれば、ディレクトリを移動した後にすかさずxコマンドでフィルタリングできます。ただ少しやり過ぎかなとも思うので、私はlsにしています。
function c { cd "`cdp $1`"; ls; }  # from
function c { cd "`cdp $1`"; x; }   # to
xコマンドを登録して、大量ファイルの処理が少し楽になりました。

peco/fzfをファイラにしたら予想以上に便利だった件

pecofzfという、コマンドライン上でインクリメンタル検索ができるツールがある事を知りました。 cdの替わりに使ってディレクトリ遷移できるファイラにすると便利そうと思っていたら、同じ事を考えている人はたくさん居たみたいです。 ただしっくり来るものがなかったのでスクリプトを書いてみました。 (最終更新: 2018-10-20)
#!/usr/bin/env ruby

pwd = ARGV[0]
pwd = Dir.pwd if !pwd
pwd = pwd[0..-2] if pwd[-1] =~ /[\\\/]/
pwd = '/' if pwd == ''

if !File.exist?(pwd) || !File.directory?(pwd)
  puts "Usage: #{__FILE__} [dir]"
  exit
end

if RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
  symbol = '\\'
else
  symbol = '/'
end

begin
  if File.directory?(pwd)
    # # プレビューなし
    # # dir = `(echo '../'; echo #{pwd}/; ls -F #{pwd}) | grep / | peco --on-cancel error --select-1`.strip
    # dir = `(echo '../'; echo #{pwd}/; ls -F #{pwd}) | grep / | fzf --ansi --select-1`.strip
    # プレビュー付
    view = "echo #{pwd}#{symbol}{}; echo; ls --color #{pwd}#{symbol}{}"
    dir = `(echo '../'; echo './'; ls -F #{pwd}) | grep / | fzf --header=#{pwd} --reverse --preview '#{view}' --select-1`.strip
    case dir
    when "", "./"
    when "../"
      pwd = File.dirname(pwd)
    else
      pwd = "#{pwd}#{symbol}#{dir.chop}"
    end
  else
    pwd = File.dirname(pwd)
  end
end while $?.exitstatus == 0
puts pwd
上記をcdpなどという名前でパスの通った場所に保存し、~/.bashrcに以下のような短縮コマンドを登録します。 私はcコマンドとして登録しました。上下どちらの形式でも大丈夫です。
alias c='cd "`cdp ${1}`"; ls'
function c { cd "`cdp $1`"; ls; }

cコマンドの使い方: cコマンドを叩くとpeco/fzfが起動します。 引数にディレクトリを指定すると、そのディレクトリから検索を開始します。何も指定しない場合はカレントディレクトリからです。 ディレクトリを選択するとpeco/fzfが起動し直すので、再帰的に辿れます。 表示中のディレクトリでシェルに戻りたくなったらESCキーでpeco/fzfを終了します(標準設定なら)。

それなりに拡張しやすく作れたと思うので、表示形式を弄ったり、ブックマークを追加したり、動作を変更したり、ご自由に。 pecoとfzfはどちらを使っても良いのですが、fzf --ansiを使うとファイルとディレクトリの色分けができて視認性が良かったり、プレビューができて便利なため、私はfzfを使っています。 Windowsではls, sedコマンドの用意が必要です。

ディレクトリ移動にcd ..を打つ必要が完全になくなったので、予想以上に便利かも。 外部コマンド実行用コマンドを作っておくとさらに便利なので、こちらもおすすめ。

2017年6月3日土曜日

便利だけど忘れやすいLinuxコマンドまとめ

毎回忘れて検索している気がするので、探しやすいようにメモしておきます。

見辛いCSVを整形してターミナルで閲覧

# 他にも色々あるけどインストールが楽 (go get github.com/Konboi/csviewer)
csviewer -p test.csv
cat test.csv | csviewer

見辛いHTMLを整形してターミナルで閲覧

# xmllintは色々面倒なのでtidyを利用 (apt-get install tidy)
tidy -i -utf8 < test.html | vim -

見辛いJSONを整形してターミナルで閲覧

# apt-get install jq
jq -C . test.json | less -R

文字列を含む箇所を前後5文字を含めて抽出

# 改行のない最小化ファイルの検索に便利
grep -o -E '.{,5}foobar.{,5}' test.txt

ディレクトリの使用量を見やすい形で表示

du -sh dir

時刻/日付をUNIX TIMEに変換

date +%s                            # 現在時刻
date +%s --date `date -Idate`       # 今日の日付
date +%s --date 2017-06-01          # 指定した日付
date +%s --date "2017-06-01 12:00"  # 指定した時刻

UNIX TIMEを時刻に変換

date --date @1496242800

プロセスの表示 (ps)

# chromeなどの表示がうざいので折り返しなしで表示
ps aux --sort -pcpu | less -S  # CPU使用量順
ps aux --sort -rss  | less -S  # メモリ使用順

プロセスの表示 (top)

top  # まずは平凡に起動
# Shift+PキーでCPU使用量順
# Shift+Mキーでメモリ使用順順
# Shift+Tキーで実行時間順

プロセスをcgroupのtreeで表示

systemd-cgls

プロセスの停止

ps aux | fzf | awk '{ print \$2 }' | xargs kill -9
ps aux | fzf --preview 'echo {}' --preview-window=bottom:wrap | awk '{ print \$2 }' | xargs kill -9  # おすすめ

OSのバージョン表示

uname -a                 # カーネルのバージョン
cat /etc/lsb-release     # Ubuntuのバージョン
cat /etc/debian_version  # Debianのバージョン

ユーザ設定を読み込んでコマンドを実行

bash -lc 'command'  # ~/.bash_profileを読み込んで実行
bash -ic 'command'  # ~/.bashrcを読み込んで実行

サーバ上のXを利用 (SSH上で画像を開く等)

# サーバ側でSSHのX11 Forwardingを有効にする事前準備は必要
ssh -XC user@host    # X11転送を有効にしてSSHクライアントを起動
# display image.png  # ログイン後はXが必要なコマンドも使える

気軽にHTTPサーバを立てる

python -m SimpleHTTPServer [port]  # python2
python -m http.server [port]       # python3
ruby -run -e httpd . -p [port]     # ruby1.9.3-

ユーティリティコマンド

bc                  # 電卓
cal                 # カレンダー
curl wttr.in/tokyo  # 天気
time hoge           # hogeの実行時間を計測

関連付けに従って開く

gnome-open https://www.google.co.jp/
xdg-open test.txt

文字化けするzipファイルを展開

unzip -O cp932 test.zip

unzipで複数ファイルを一括展開

unzip '*.zip'  # シングルコーテーションなどで囲うのが重要
unzip \*.zip  # これでも動くけど上のほうが覚えやすいかな?

最近は使われない圧縮形式の展開

# x付ければ大抵なんとかなる
# 最近はatool (apt-get install atool) を使ったほうが楽かも
lha x foo.lzh    # LZH (apt-get install lha)
unrar x foo.rar  # RAR (apt-get install unrar)

コマンド終了時にメール送信

# メールコマンドのインストールと設定が必要
# 最近はTwitterに通知するスクリプトを作ったほうが気楽かも知れない
command && echo [content] | mail -s [subject] [to@example.com]

Git関連

git config --global core.quotepath false  # 日本語ファイルの文字化け回避

エイリアスに登録

alias ps-cpu="ps aux --sort -pcpu | less -S"
alias ps-mem="ps aux --sort -rss | less -S"
alias osversion="cat /etc/lsb-release"
alias unixtime="date +%s"
alias unixdate="date +%s --date `date -Idate`"
alias weather="curl wttr.in/tokyo"
alias pskill="ps aux | fzf --preview 'echo {}' --preview-window=bottom:wrap | awk '{ print \$2 }' | xargs kill -9"
頻繁に使うものや特に忘れやすいものはエイリアスに登録しておくと楽です。 ~/.bashrcに上記を登録しても良いかも知れません。

2017年6月1日木曜日

グループで最大のレコードを取得するSQL

同一グループの中で最大のレコードを取得するSQLはたまに必要になります。 このような時はGROUP BYを使ってグループをまとめながら最大値を求めてその結果を…までは良いのですが、そこから2種類の方法があるので書いておきます。 key,value, year, month, timeを持つテーブルからkey=xに関してyearごとにmax(time)を持つvalueを求める場合は以下のようになります。

1. INNER JOINを使う

explain query plan
select distinct(s.year),value from [table] as s inner join (
  select year,max(time) as max_time from [table] where key=[x] group by year)
  as m on s.year = m.year and s.time = m.max_time and key=[x];

1|0|0|SEARCH TABLE [table] USING COVERING INDEX [table_idx] (key=?)
0|0|0|SEARCH TABLE [table] AS s USING INDEX [table_idx] (key=?)
0|1|1|SCAN SUBQUERY 1 AS m

explainで実行計画も載せてみましたが、まずsの条件で検索をしてから、mの検索結果とjoinして表示しているようです。

2. サブクエリを条件式に使う

explain query plan
select distinct(year),value from [table] as s where key=[x] and time=(
  select max(time) from [table] as m where s.year = m.year and key=[x]);

0|0|0|SEARCH TABLE [table] AS s USING INDEX [table_idx] (key=?)
0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 1
1|0|0|SEARCH TABLE [table] AS m USING COVERING INDEX [table_idx] (key=?)
0|0|0|USE TEMP B-TREE FOR DISTINCT

こちらではsの条件で検索してから、サブクエリとしてmを発行し、mの検索結果を一時的に構築したB-Treeを使いながらdistinctしてるみたいです。

explainの結果を見る限りでは1のほうが早そうです。 参考になるかはわかりませんが、実際に運用しているスクリプトの実行時間は1=25分、2=33分でした。 EXISTSを使う方法もあるみたいですね。

2017年5月18日木曜日

2chのAAをOSに依存せず綺麗に表示するJavascript/CSSの設定方法 (旧版)

(注) この記事の内容は古いです。 昔はブラウザのバグで大変だったねという歴史と、細かなテクニックを覚えておくために残していますが、歴史はどうでもいいから AA をすぐに表示したい人は、こちらをどうぞ

(以下保管用) 2chのAAをOSに依存せず表示するのは結構骨が折れます。 この事に関しては私がまとめるまでもなく以下のサイトで丁寧に説明されており、おそらく現時点で最も詳しいページと思います。


ただ表示テストをしていて気付いたのですが、フォント次第でかなり気になるレベルで印象が変わります。 特に気になったのは「しょぼん」。 フォントがインストールされていれば表示の違いを以下で確認できますが、フォント指定には一考の余地があると思いました。
(´・ω・`)  # MS Pゴシック
(´・ω・`)  # 梅Pゴシック
(´・ω・`)  # IPA モナー Pゴシック
(´・ω・`)  # Monapo
(´・ω・`)  # Mona
(´・ω・`)  # Textar
上記の表示を見ていると、私はMS Pゴシック > 梅Pゴシック > Textar > IPA モナー Pゴシック > Monapo = Monaの順で綺麗と感じます。 慣れ過ぎてしまったせいかも知れませんが、梅Pゴシックはかなり綺麗な表示だと思っています。 IPA モナー Pゴシックは綺麗ですが、少しフォントが細過ぎる気もします。 Textarも綺麗ですが、「・」が丸くなり過ぎて少し違和感があります。 Mona, Monapoは「ω」が小さ過ぎてあまり可愛くなく、違和感も出てしまっています。



(2018-10-31 色々修正): またUbuntuのFirefoxではMS Pゴシックを上書きするようなフォントを利用すると他のサイトにも影響が出てしまうようです。こういった問題がある以上は、あまりMS Pゴシック互換フォントは指定しないほうが良いと思っています。

となるとLinux/Macで使えるAAフォントがないという事態になってしまうのですが、私は代替フォントとして梅Pゴシックを愛用しています。 梅Pゴシックは完全なAAフォントではなく、大量の空白文字を使うと若干ズレる事があるフォントなのですが、大半のAAは綺麗に表示できます。 標準インストールもされていないフォントなのですが、Linuxならapt-getなどで簡単にインストールできる事から、私はこれを指定に入れています。

ただiOS/Androidは梅Pゴシックでも駄目で、これらのOSはフォントのインストール自体が苦行でしかありません。 なのでこれらのOSではWebフォントのTextarを使うのがベストだと思います。



前置きが長くなりましたが、このような事情を踏まえると以下のCSSが良いと思います。 white-spaceは改行や空白をそのまま表示するようにpreを指定し、 word-wrapはデフォルト値ですがブログのテンプレートなどで変更が加わりやすいのでnormalを明示しておくと良いと思います。
(2018-10-31 修正): ただしLinuxでの利用を想定すると、さらに一手間を加える必要があります。 長くなるので上記リンクを参照してください。私はこの仕組みは良くないと思っているのですが、palm84さんがなぜそうなるのかを詳細に説明してくださったので、その記事も参照すると、Linuxのフォント指定の仕組みが詳しくわかります。
pre.aa {
  font-size: 1em;
  line-height: 1.1;
  font-family: 'MS Pゴシック','MS PGothic','梅Pゴシック',Textar,sans-serif;
  white-space: pre;
  word-wrap: normal;
}


CSSの設定はこれで終わりですが、WebフォントのTextarを表示するためには、加えてTextarのWebフォント読込用のスクリプトをダウンロードし、自分のサイト上に展開する必要があります。 これは以下のコードをHTMLの下のほうに登録するだけで済みます。 headに登録しても良いとは思うのですが、初回起動時のレンダリングが相当遅くなるのでbodyの一番下が良いと思います。 初回起動時以外はそれなりの速度でレンダリングしてくれます。
<script type="text/javascript" charset="utf-8" src="/textar-font/webfont.js"></script>

こういった野良Webフォントはあまり良くないので、Google Web FontsにTextarが採用されると安心感も出るのですけどね。 日本語対応が始まりつつあるものの、今のところ未対応のようです。

またTextarのWebフォント読込用のスクリプトの使用法について軽くメモしておきます。 実装上は<p class='textar-aa'>...AA 1行目...<br>...AA 2行目...</p>という記述方式を想定しているようですが、 <pre class='aa'>...AA...</pre>といった記載方法のほうが楽だと思います。


ここまでの設定でAAを綺麗に表示できるようになったと思いますが、 さらにフォントを設定できるボタンを付けておけばフォントにこだわりのある方にも対応でき万全だと思います。例えばこんな感じ。

とんかつ作るよ

.  ∧_∧    ヘ⌒ヽフ ⌒γ
 (`・ω・)  (・ω・ )   )
 / оо━二二二二二フ
 しー-J

2017年5月16日火曜日

JavaScriptのGridライブラリの機能比較とまとめ

JavaScript の Grid ライブラリも最近また進化してきて、比較する必要性が出てきたので、まとめてみました。 このページでの選択基準は、私が使いたかった機能の機能性、ロード速度、スマホ対応、更新頻度です。

機能面で私が必要としているのは、最低限は外部ファイル読み込みとソート機能です。ないものは評価対象外です。 キーボード操作、カラム選択、カラム範囲選択、フィルタリング、列フィルタリングはどうしても欲しい。 カラム選択は項目毎にクリックせず複数選択可能なら◎、選択に手間が掛かるなら○、選択機能がなければ×です。 フィルタリングは全体検索ができるかどうかと使いやすさで評価を多少変えています。 列フィルタリングは数値で範囲検索ができれば◎、一致検索しかできなければ△、機能がなければ×です。APIはあってもUIやサンプルがなければ×にしています。

スマホ対応に関しては、水平スクロール対応と、UI の対応しやすさが重要だと思います。 グリッドは表示幅が広くなりやすいので、水平スクロールができると表示サイズの調整がしやすいです。 スマホ対応の評価は独断と偏見ですが、実装面や機能面で課題があると思ったら評価を下げています。 ライブラリの更新は頻繁に行われるほうがバグ遭遇時に対応しやすいので考慮に入れました。

ライブラリ数がかなり多いので、高機能で良さそうなものだけまとめてみました。


名称 読込
速度
キー
操作
選択 範囲
選択
全体
検索
列検索 水平
移動
スマホ
対応
更新
頻度
備考
Angular UI Grid◎?
ag-grid◎?一部有料
Handsontable (有料)
jQWidgets商用有料
IgniteUI Grid有料
jqGrid, Guriddo◎?商用有料
w2ui Grid (1.4.x)×
w2ui Grid (1.5rc)
Handsontable (無料)××
SlickGrid実装難解
React Data Grid◎?
DataTables××
TreeGridほぼ有料
dhtmlGrid商用有料
dgrid×
jsGrid×
FancyGrid×商用有料
gripple-react◎?×××××
FooTable△?××××商用有料

気付けば良いライブラリが凄く増えてますね。機能要件を重視した分類表なので鵜呑みにはせず、利用用途に応じて選択するのが良いと思います。

参考文献:

追記: 最近は、Tabulator というライブラリも出てきました。

2017年5月5日金曜日

Hugoのページ生成をpartialCachedで高速化

静的サイトジェネレータのHugoに最近、partialCachedという機能が付いていました。 名前の通りpartialでの呼び出しをキャッシュするみたいです。 同じレイアウトを大量のページで使い回す場合にはかなり早くなりそうだと前々から思っていました。

使い方は至ってシンプルで、以下のようにするだけです。
{{ partial "header.html" . }}  # before

# after1 ... サイト全体で内容が統一な時
{{ partialCached "header.html" . }}
# after2 ... セクション内で内容が同一な時
{{ partialCached "header.html" . .Section }}

というのがマニュアルに書かれている事なのですが、実際にはマニュアルだけでは動作がよくわからなかったので色々確認してみました。 その結果、hugo/layouts/_default/single.htmlなどのデフォルト設定が優先されるようです。 ここでのグローバル宣言は他セクションを上書きします。

バグの混入が怖い方は、まず全ページで共通のpartialコンテンツだけキャッシュすると良いと思います。 ここで留めればまずバグは入らないでしょう。 さらに高速化したい人は微妙に表示が異なるようなpartialコンテンツをセクションごとに.Section付きで編集していけば、 バグの混入確率は低く抑えられそうな気がします。

何はともあれ1万ページくらいあるサイトに早速適用してみました。何度も計測している訳ではないのでざっくり計算です。 直前のキャッシュの効き方にも影響されますし、ページ構成にもよるでしょうが、結構高速化している事は確かのようです。
total in 59349 ms  # before
total in 25563 ms  # after

Hugoは元々高速なのにさらに早くなりました。素晴らしい。

もっと早く知っておきたかったmattnさんのGo言語ユーティリティ

Go言語は気付けばmattnさんのライブラリを使ってるので、先回りして便利そうなユーティリティを調査する事にしました。知ってると「めんどいムキー!」となる事がかなり減るかも。なるべく汎用的なものに絞って、よく使ってる順に並べました。いくつか初めて使って、使い始めたものもあります。

gom

Rubyのbundleの代替。ないと生きていけない。最近はdepも出てきましたが、depはGOPATHに依存するのがちょっとなあ。

go-sqlite3

SQLite3を使うための標準。ないと生きていけない。

go-shellwords

シェルのコマンド形式をGoのexec.Command形式に。ないと生きていけない。

go-zglob

RubyのDir.globの代替。ないと生きていけない。

go-runewidth

マルチバイト文字列を分割。ないと生きていけない。

go-options

コマンドラインオプションの解析。シンプルで便利。

go-forlines

標準入力から一行ずつ読み込む。ないと困る時もありそう。

go-pipeline

exec.Commandでパイプやリダイレクトを使う。ないと困る時もありそう。

go-colorable

ログをカラフルに。便利ですが、ロギングライブラリはたくさんあるので何とも。

もっと早く知っていれば人生が楽になれたかも知れないものがチラホラ。

Go言語でスクリプトを書いてみる

Go言語をスクリプトにも利用するための練習として、以前書いたスクリプトをGo言語で書いてみました。エラー処理をかっとばして書けばGoもかなりコンパクトに書けます。Rubyでは49行でしたが、Goでも70行くらいで書けました。色々面倒なところはありますが、何とかなる範囲ではあるかも。

package main

import (
  "fmt"
  "os"
  "os/exec"
  "path/filepath"
  "time"
  "github.com/mattn/go-shellwords"
  "github.com/mattn/go-zglob"
)

func html_minifier(from string, to string) {
  cmd := fmt.Sprintf(`
  sh -c 'html-minifier %v \
    --collapse-boolean-attributes \
    --collapse-whitespace \
    --remove-attribute-quotes \
    --remove-comments \
    --remove-empty-attributes \
    --remove-redundant-attributes \
    --remove-script-type-attributes \
    --remove-style-link-type-attributes \
    --html5 \
    --use-short-doctype \
    --minify-js \
    --minify-css > %v'
  `, from, to)
  args, _ := shellwords.Parse(cmd)
  exec.Command(args[0], args[1:]...).Run()
}

func main() {
  dir := os.Args[1]
  var minifySize, html_minifierSize, originalSize int64
  var minifyTime, html_minifierTime int64

  paths := getPaths(dir, "*.html")

  for _, path := range paths {
    fileinfo, _ := os.Stat(path)
    originalSize += fileinfo.Size()
  }

  for _, path := range paths {
    cmd := fmt.Sprintf("sh -c 'minify %s > %s'", path, path+".min")
    args, _ := shellwords.Parse(cmd)
    t := time.Now().UnixNano()
    exec.Command(args[0], args[1:]...).Run()
    minifyTime += time.Now().UnixNano() - t

    fileinfo, _ := os.Stat(path+".min")
    minifySize += fileinfo.Size()
  }

  for _, path := range paths {
    t := time.Now().UnixNano()
    html_minifier(path, path+".min")
    html_minifierTime += time.Now().UnixNano() - t

    fileinfo, _ := os.Stat(path+".min")
    html_minifierSize += fileinfo.Size()
  }

  fmt.Printf("file num: %v\n", len(paths))
  fmt.Printf("original:      %v\n", originalSize)
  fmt.Printf("Minify:        %v, %v\n", minifySize, time.Duration(minifyTime))
  fmt.Printf("html_minifier: %v, %v\n", html_minifierSize, time.Duration(html_minifierTime))
}
Goで即興スクリプトを書いてみて気になった点は3つほど。(1)RubyのDir.globみたいな再帰検索はこれまで自作していましたが、最近はgithub.com/mattn/go-zglobを利用すると簡単に書けるようになりました。どんどんmattnさんのライブラリで埋まっていく…。

(2)ベンチマークにはtestingという標準ライブラリがあります。時間やメモリを計測するには非常に便利ですが、計測精度を高めるために勝手に連続実行する仕組みになっています。同時に色々な情報を処理しながら計測しようとすると少し困ります。手軽な計測であればtime.Now()で地道に計算するのが楽かなあ。

(3)外部コマンドを実行するにはexec.Command(args)を使いますが、argsには文字列の配列を渡す必要があり面倒です。github.com/mattn/go-shellwordsを利用するとシェル上での実行文字列を配列に変換してくれるのでかなり楽になります。ただしcommand > outのようなコマンド内での出力には対応していないので、sh -c 'command > out'のような形式に変更して実行する必要がありました。

Go言語はスクリプトごとにbuildしていると容量がかなり無駄になりますが、以下の方法でバイナリサイズを小さくすれば気にならない程度には小さくなります。
$ sudo apt-get install upx-ucl
$ go get github.com/pwaller/goupx
$ go build -ldflags '-s' test.go
$ goupx -9 test  # or goupx test

もう少し色々なパターンで記述の容易さを確認してみたいです。