f

2016-05-24

How to match grep command for all files including hidden files

grepコマンドでドット(.)で始まる隠しファイルを含む全ファイルを検索対象にするには,以下のどれかの書式を使う。

grep -r "pattern" .[!.]* *
grep -r "pattern" .* * --exlucde-dir=..
## for bash dotglob and zsh glob_dots option enabled
grep -r "pattern" .[!.]* [!.]*
grep -r "pattern" * --exclude-dir=..

Introduction

ファイル内の文字列を検索するgrepコマンドをよく使う。ファイル名のパターンマッチであるglobを活用し,ワイルドカードの*と組み合わせて大量のファイルから文字列を検索できる。

しかし,globの*では.から始まる隠しファイルは検索対象にならない。つまり,以下ではドット(.)から始まる.foo.baz/baz.baz/.bazは検索にヒットしない。

mkdir -p bar .baz
echo "1. file dot" > foo
echo "2. file dot foo" > .foo
echo "3. file bar/dot bar" > bar/bar
echo "4. file bar/dot bar" > bar/.bar
echo "5. file dot baz/baz" > .baz/baz
echo "6. file dot baz/dot baz" > .baz/.baz
grep -r "file" *
bar/bar:3. file bar/dot bar
bar/.bar:4. file bar/dot bar
foo:1. file dot

globの*でこれらの隠しファイルにマッチさせる方法は2通りある。

  1. bashのdotglobやzshのglob_dotsなどシェル機能を活用。
  2. ワイルドカードを駆使。

grepの隠しファイルへのマッチ方法

シェル機能を活用

bashとzshでは,ドット(.)から始まる隠しファイルにもglobの*がマッチできるようにするオプションがある。

以下のコマンドで機能をオンにできる。

## bash (~/.bashrc)
shopt -s dotglob

## zsh (~/.zshrc)
setopt glob_dots
grep -r "file" *
.baz/baz:5. file dot baz/baz
.baz/.baz:6. file dot baz/dot baz
.foo:2. file dot foo
bar/bar:3. file bar/dot bar
bar/.bar:4. file bar/dot bar
foo:1. file dot

ただ,これらの機能を設定ファイルで有効にしておくと,ターミナルからコマンドを入力したり,シェルスクリプトにも影響を与えるリスクがある。そのため,あまりこれらの機能を前提にしないほうがよいだろう。

ワイルドカードを駆使

シェルの設定に頼らずともワイルドカードを駆使すれば隠しファイルも検索対象に含めることはできる。例えば,.から始まるファイルは以下でマッチする。

grep -r "file" .*

しかし,上記コマンドは以下2点の理由から実行しないほうがいい。

  1. .*は1階層上のディレクトリを意味する..にもマッチし,ファイルシステム全体を再帰的に検索してしまう。
  2. 隠しファイル以外のファイルにマッチしない。

この2点をカバーするには,以下のように入力する。

grep -r "file" .[!.]* *

仕組みは以下のとおりだ。

  1. 最初の.[!.]*..を除く,.で始まる隠しファイルを検索対象とする。
  2. 最後の*.で始まらないファイル(通常のglobの*の動作)を検索対象とする。

なお,前述の..にマッチしてしまい,ファイルシステム全体を再帰的に検索することを回避するためにはgrepの--exclude-dirオプションで..を指定してもよい。

grep -r "file" .* * --exclude-dir=..

トラブルシューティング

bashのdotglobとzshのglob_dots有効時の不具合

grepでは検索対象を何回も指定できるが,間違えるとその分重複も発生するので注意する。つまり,ここでbashのdotglobのやzshのglob_dotsを有効にしていると不都合が起きる。これらの機能を有効にすると,*が隠しファイルにもマッチするので,.で始まる隠しファイルが2回マッチしてしまう。

例えば,以下の.a.datファイルには2回ヒットする。

bash
shopt -s dotglob

echo "return" > .a.dat
grep -r "return" .[!.]* *
.a.dat:return
.a.dat:return

これを避けるには,grepの最後の*で隠しファイルを明示的に除外する。

grep -r "return" .[!.]* [!.]*
.a.dat:return

補足だが,grepでは-eオプションで一度に複数のキーワードを検索(OR検索)できる。

grep -r -e "pattern1" .[!.]* * -e "pattern2"
POSIXでの[^...]は未定義

当初,以下の様にglobでのパターンマッチングに!ではなく^を使っていた。bashとzshでは動作したが,shでうまく動作しなかった。

grep -r "file" .[^.]* [^.]*

気になって確認したところ,POSIXではワイルドカードにおける開き角括弧[の開始のサーカムフレックス^の動作([^...])は未定義のようなので,使用を控えたほうがよいだろう。

A bracket expression starting with an unquoted <circumflex> character produces unspecified results.

Shell Command Language

まとめ

元々はVimでのgrep検索について調べていたのだが,気づいたらgrep検索についてはまってしまっていた。時間を余計に使ってしまったが,POSIXの仕様も確認できて勉強になった。

冒頭でも記載した通り,現在ディレクトリ以下の隠しファイルを含む全ファイルを対象に検索したければ,以下のどちらかの書式を使う。

grep -r "pattern" .[!.]* *
## for bash dotglob and zsh glob_dots option enabled
grep -r "pattern" .[!.]* [!.]*

2番目の書式の方がbashのdotglobとzshのglob_dotsオプションに依存しないので,より確実だが,これらのオプションを考慮するのはやりすぎなような気もする。お好みで選べばよいだろう。

参考:

2016-05-22

今までの発表資料・イベント参加履歴の一覧ページの作成・公開

今までの発表資料とイベント参加履歴の一覧ページを作成してみた。

勉強会に参加し始めたのが,2013年の夏頃で,発表を始めたのが2014年03月からだ。活動を初めてもう2年ほど経過して,イベント参加累計回数も50回を越え,発表資料も10個となり蓄積してきた。

そろそろ活動履歴一覧を作ったほうがよいかなと思ったので作ってみた。狙いは以下2点だ。

  • 僕がこれまでの活動履歴を把握。
  • 他人に僕の活動履歴をアピール。

この先,ますますいろんな人と出会うことがあるだろう。そういうときに,自分が何に興味関心をもってどういう活動をしてきたかをわかりやすく伝えて,仲良くなれたらいいなと思う。そのためにも,こういう一覧ページを作るのが中長期的にとても効果的じゃないかなと思った。ブログの断片的な情報はすぐに埋もれて見えなくなってしまう。ある程度まとまった情報はWebサイトにするなど,一覧ページを作ったほうがよいだろう。

一覧ページは,このブログのヘッダー部分の[Activity]からアクセスできる。

また,以下のURLでもアクセスできる。

My Future Sight for Past: Activity http://myfuturesightforpast.blogspot.jp/p/activity.html

一覧ページ作成にあたって,大学での研究発表資料も一覧化した。

今まで発表時にはボイスレコーダーで自分の発表音声を録音していた。この音声と当時の発表資料を使って,動画も作ってみた。一覧ページの表にも掲載しているが,以下でもアクセスできる。

presentation - YouTube

当時の発表の様子などがなんとなくわかって,懐かしめたりしてよいかなと思った。

イベントに参加したり,特に発表するのはけっこうたいへんなときもあるので,自分の活動の成果としてしっかり記録していきたい。

2016-05-21

Twitterの埋め込みツイートのXHTMLへの変換ページTweet2XHTML

Twitterの埋め込みTweetをXHTMLに変換するページTweet2XHTMLを作ったので紹介する。

Twitterのツイートは,右下の[…(その他)]>[ツイートをサイトに埋め込む]でブログなどで埋め込めるHTMLを取得できる。

例えば,以下のようなHTMLコードを取得できる。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">toolとutilityをどう使い分けるか悩む。WikipediaとLongmanの英英辞書を参照した。<br>toolは物理的なもの。仕事道具とかそういう感じ。<br>utilityはコンピューター向けの用語。POSIX:2008もこちらを使っている。<br>基本はutilityにするか。</p>&mdash; せのぺん (@senopen) <a href="https://twitter.com/senopen/status/733901332176736257">2016年5月21日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

これをブログに貼り付けると以下のように表示される。

このHTMLコードには以下の不満があった。

  • HTMLの形式になっており,XHTML文書に貼り付けるとエラーになる。具体的には以下の項目がエラーとなる。
    • br要素に終端スラッシュがない。×:<br>,○:<br />
    • 文字実体参照&mdash;が使えない。×:&mdash;,○:
  • 外部JavaScriptを使いたくないので,script要素は削除したい。

文字実体参照については,以下のように文書宣言時に定義してやれば使うことはできる。

<!DOCTYPE html [
  <!ENTITY mdash "&#x02014;">
]>

しかし,使用しているエディターのBlueGriffonで対応しておらず,HTML文書が汚くなるのでこの方法は避けたかった。

今まで手作業でその都度修正していたが,煩雑だったので,簡単に処理したかった。

そこで,自分で埋め込みツイートのHTMLをXHTMLに変換するページTweet2XHTMLを作った。

Tweet2XHTML

[変換元HTML]のフォームに埋め込み用ツイートのHTMLコードを貼り付けて,[変換]ボタンを押下すれば,[変換後HTML]のフォームに整形されて表示される。

やっていることは非常に初歩的なことで,単にtextareaの文字列を正規表現で処理しているだけだ。メインの処理部分は以下となる。

<script>
  function convert() {
    var value = document.getElementById("input").value;
    value = value.replace(/<br>/g, "<br />");
    value = value.replace(/&mdash;/g, "—");
    value = value.replace(/<script.*<\/script>/g, "");
      var target = document.getElementById("output");
      target.value = value;
  }
</script>

<form>
  <fieldset>
    <legend>変換元HTML </legend>
    <textarea id="input" placeholder="ここに記入してね。" style="width: 100%; height: 10em;"></textarea>
    <button type="button" onclick="convert();">変換</button>
  </fieldset>
</form>
<form>
  <fieldset>
    <legend>変換後HTML</legend>
    <textarea id="output" placeholder="ここに表示される。" style="font-family: monospace; width: 100%; height: 10em;"></textarea>
  </fieldset>
</form>

これでTweetを備忘録にまとめるのが楽になった。もう少しJavaScriptやフォーム関連の操作方法を勉強してこういった簡単なユーティリティーを作れるようになりたい。

2016-05-15

WebベースGUIライブラリElectronのチュートリアルの実行

2016-05-11にElectron 1.0のリリースがアナウンスされた(実際のリリースは2016-05-09)。気になったので試しにチュートリアルのサンプルアプリの作成からパッケージ化までやってみた。

ElectronはGitHub社により作られた,クロスプラットフォームなデスクトップアプリを開発するためのライブラリとなっている。JavaScriptのライブラリであるNode.jsとブラウザであるChromiumをベースにHTML,CSS,JavaScriptなどのWeb技術で開発できるのが特徴となっている。最初のリリースは2013-07-15となっており,リリースが始まって約3年経過したことになる。時間が立って安定してきたので,1.0がリリースされたのだと思われる。

ネットで見ていてもElectronでのアプリ開発例をちらほらみかけるようになり,いいタイミングなのでちょっとだけ試してみることにした。

動作環境はUbuntu 14.04 64bitであり,チュートリアルとしてQuick Startを参照した。

少し長いので目次も書いておく。

  1. Electronのインストール
    1. npmのモジュールelectron-prebuiltをインストール
    2. 公式で配布されているバイナリをインストール
  2. サンプルアプリの作成・実行
    1. package.json
    2. main.js
    3. index.html
    4. サンプルアプリの実行
  3. パッケージング
    1. アプリディレクトリ丸ごとの配布
    2. asarコマンドでアプリディレクトリ.asarファイルに固めて配布
    3. Electronごと配布
  4. まとめ

Electronのインストール

Electronのインストール方法は2種類ある。

  1. npmのモジュールelectron-prebuiltをインストール。
  2. 公式で配布されているバイナリをインストール。

開発中であれば,どちらの方法でインストールしてもよい。しかし,最終的にパッケージングして配布するときは2.のバイナリを使うことになる。

npmのモジュールelectron-prebuiltをインストール

npmのモジュールであるelectron-prebuiltはビルド済みのElectronを含んでいる。以下のコマンドでインストールできる。

mkdir -p ~/local/
npm install -g --prefix=$HOME/local/ electron-prebuilt

npm install -gでインストールすると,既定では以下のディレクトリにインストールしようとする。

  • /usr/bin
  • /usr/lib/node_modules/

これらのディレクトリにインストールするには管理者権限が必要なので,--prefixオプションで以下のディレクトリにインストールされるように変更した。

  • $HOME/local/bin
  • $HOME/local/lib/node_modules/

.bashrcなどでexport PATH=$HOME/local/bin:$PATHなどと記述してPATH変数を設定しておく。これで,electronコマンドをインストールできた。以下のコマンドでelectronが起動する。

electron

npmでのインストール方法は以下を参照した。

npm のローカルモードでインストールした実行モジュールにパスを通す設定 - Qiita

公式で配布されているバイナリをインストール

Electronの各OS向けの最新のバイナリは以下のGitHubのページで公開されている。

Releases · electron/electron

ここから各OS,アーキテクチャ向けのelectronをダウンロードする。今回はUbuntu 14.04 64bitなので,electron-v1.1.0-linux-x64.zipをダウンロードして,展開し,~/local/opt/に配置した。

コマンドでやると以下のようになる。

mkdir -p ~/local/opt/; cd ~/local/opt/
VER=1.1.0
wget -nc https://github.com/electron/electron/releases/download/v$VER/electron-v$VER-linux-x64.zip
unzip -d electron-v$VER-linux-x64{,.zip}

electronを起動するときは以下のコマンドを入力する。

~/local/opt/electron-v1.1.0-linux-x64/electron

これでElectron自体のインストールは完了となる

サンプルアプリの作成・実行

まず,今回作るアプリの名前をyour-appとして作業ディレクトリを作る。

mkdir -p ~/tmp/your-app
cd ~/tmp/your-app

一般的に,Electronアプリは以下のディレクトリ構成となる。

your-app/
├── package.json
├── main.js
└── index.html

以下で各ファイルの簡単な説明とサンプルを示す。

なお,ファイル作成を簡単にするためにファイルサンプルの前後に以下のシェルコマンドを入れている。

cat << EOF > ファイル名
...
EOF

これにより,catからEOFまでをターミナルにコピーペーストするだけでファイルが作成できる。

package.json

package.jsonの形式はNodeのモジュールと同じで,mainフィールドでアプリのメインプロセスとして実行するスクリプトを指定する。例えば,以下のようになる。

cat << EOF > package.json
{
  "name"    : "your-app",
  "version" : "0.1.0",
  "main"    : "main.js"
}
EOF

package.jsonmainフィールドがなければ,Electronはindex.jsを読み込もうとする。

main.js

main.jsはウィンドウを作り,システムイベントを操作する。サンプルは以下となる。

cat << EOF > main.js
const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600})

  // and load the index.html of the app.
  mainWindow.loadURL('file://' + __dirname + '/index.html')

  // Open the DevTools.
  mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
EOF
index.html

最後に,index.htmlは表示したいWebページだ。

cat << EOF > index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using node <script>document.write(process.versions.node)</script>,
    Chrome <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
  </body>
</html>
EOF
サンプルアプリの実行

main.jsindex.htmlpackage.jsonを作ったら,アプリを実行してみよう。

npmelectron-prebuiltをインストールしていれば,以下のコマンドでアプリを実行できる。

electron .

バイナリをインストールしていれば,以下のコマンドでアプリを実行できる。

~/local/opt/electron-v1.1.0-linux-x64/electron .

electronコマンドにindex.htmlmain.jspackage.jsonが格納されているディレクトリを指定するとよい。

実行すると,以下のように開発者ツールの画面が開いた状態のウィンドウが表示される。

パッケージング

公式で紹介されているアプリの配布方法には以下の3通りがある。

  1. アプリディレクトリ丸ごとの配布。
  2. asarコマンドでアプリディレクトリを.asarファイルに固めて配布。
  3. Electronごと配布。

1と2は,配布するファイルサイズは小さいが利用者の環境にElectronがインストールされていないと動作しない。3は配布するファイルサイズは40 MB以上と大きくなるが,Electronごと配布するので,利用者の環境にElectronがインストールされていなくても動作する。利用者がElectronをインストールしていることは想定しにくいので,実際には3の方法を採用することになるだろう。しかし,2の方法は,.asarファイルにElectronを関連付けさせておけばダブルクリックで実行できるので悪くない方法だ。

なお,この他にサードーパーティーのパッケージ化コマンドとしてelectron-packagerelectron-builderなども存在するが,調査に時間がかかるので省略した。実際にアプリをリリースするときに検討すればよいだろう。

アプリディレクトリ丸ごとの配布

1の方法は,単に作成したアプリディレクトリ(今回は~/tmp/your-app)を配布するだけだ。利用者側ではelectronコマンドでこのディレクトリを指定すれば起動できる。

この方法だと,ユーザーにソースコードが丸見えなので,ソースコードをユーザーに隠したいときは使えない。

asarコマンドでアプリディレクトリ.asarファイルに固めて配布

事前にアプリ一式をasarコマンドで.asarファイルに固めて配布する。ユーザー側ではelectronコマンドで.asarファイルを指定することで実行できる。

ソースコードを利用者から隠したいときにこの方法が使える。

まず,npmからアプリを固めることができるasarコマンドをインストールする。

npm install -g --prefix=$HOME/lobal asar

そしてasarコマンドでアプリディレクトリを.asarファイルに固める。イメージとしてはtar.gzなどに圧縮するような感じだ。

asar pack your-app your-app.asar
# asar pack your-app{,.asar} ## シェルのブレース展開でこうしてもよい。

これで,以下のコマンドでElectronのアプリケーションを実行できる。

electron your-app.asar

.asarファイルをelectronコマンドで開くように関連付けさせればダブルクリックでも実行できるだろう。

Electronごと配布

利用者がElectronをインストールしていることは想定しにくいので,Electronごと配布する。

  1. 配布先OS用Electronのダウンロード

    まず,以下にOSごとのElectronが配布されているので配布先のOSのものをダウンロードする。

    Releases · electron/electron

    例えば,冒頭でも行ったがLinux版だと以下のコマンドでElectron本体をダウンロードして,解凍する。

    VER=1.1.0
    wget -nc https://github.com/electron/electron/releases/download/v$VER/electron-v$VER-linux-x64.zip
    unzip -d electron-v$VER-linux-x64{,.zip}

    なお,解凍後のディレクトリはelectron-v1.1.0-linux-x64というようなOSごとのディレクトリ名になっている。説明を簡単にするために,このディレクトリを単にelectronと表記する。

  2. アプリ一式をasarコマンドでapp.asarに固める。

    ファイル名をapp.asarにしてasarコマンドでアプリ一式を固める。後からファイル名をapp.asarに変えるだけでもよい。

    例:

    asar pack your-app app.asar
    ## または以下のように既に固めたasarファイルのファイル名を変えるだけもよい。
    # asar pack your-app your-app.asar
    # mv your-app.asar app.asar
  3. 固めたapp.asarをElectronに配置。

    配布先OSに応じて以下の場所にapp.asarを配置する。

    app.asarの配置場所
    OS 配置場所

    electronは展開したElectronのディレクトリのこと。例:electron-v1.1.0-linux-x64。
    OS X electron/Electron.app/Contents/Resources/
    Windows, Linux electron/resources/

これでパッケージングは完了だ。後はelectronディレクトリに存在する,OSごとのelectronファイルをダブルクリックなどで起動するとアプリが実行される。

OS毎のelectronの実行ファイル名
OS ファイル名
Linux electron
Windows electron.exe
OS X electron.app

必要に応じて,上記の実行ファイル名electronをアプリケーションの名前に変更したり(例:your-app),アイコンを設定すればパッケージングは完了となる。

まとめ

Electronの導入として,公式サイトのチュートリアルをやってみて,パッケージングの方法までまとめた。

チュートリアルをやっていて躓いたのは,Electronごとパッケージ化の際のファイル名だった。app.asarというファイル名はただのサンプルかと思っていたらそうではなくて,このファイル名でなければならなかった。これに気づくのに時間がかかってしまった。

実際にアプリを作成するにはmain.jsの書き方や使えるモジュールなど細かく見ていかなければならない。この記事を,今後Electronでアプリを作成する際の足がかりしていきたい。

2016-05-10

Install GLFW 3.1.2 from source on Ubuntu 14.04

GLFWというOpenGLでGUIを簡単に作るためのC言語のライブラリが公開されており,興味を持ったのでUbuntu 14.04にソースからインストールしてみた。

公式サイトからファイルをダウンロードしてインストールする。インストール方法は以下の公式サイトを参照する。

GLFW: Compiling GLFW

基本的にはファイルを展開してcmakeを実行するだけだ。標準では/usr/local/にインストールされてしまう。管理者権限は使わずに,stowで管理したいので,cmakeの実行時にインストール先を指定した。

VER=3.1.2
cd ~/local/src
wget -nc https://github.com/glfw/glfw/releases/download/$VER/glfw-$VER.zip
unzip glfw-$VER.zip
cd glfw-$VER
mkdir glfw-build
cd glfw-build
cmake ../ -DCMAKE_INSTALL_PREFIX:PATH=$HOME/local/stow/glfw-$VER
make install
cd ~/local/stow/
stow glfw-$VER

思っていた以上に簡単にインストールできた。

なお,stowでインストールするにあたって,~/.bashrcなどで以下のように各種PATHを設定している。GLFWではpkg-configを使うので,忘れずにPKG_CONFIG_PATHを設定しておく。

  ### local install path
  LOCAL="${HOME}/local"
  export PATH="${LOCAL}/bin:$PATH"
  export LD_LIBRARY_PATH="${LOCAL}/lib:$LD_LIBRARY_PATH"
  export CPATH="${LOCAL}/include:$CPATH"
  export MANPATH="${LOCAL}/man:${LOCAL}/share/man:$MANPATH"
  export INFOPATH="${LOCAL}/info:${LOCAL}/share/info:$INFOPATH"

  export PKG_CONFIG_PATH="${LOCAL}/lib/pkgconfig:${PKG_CONFIG_PATH}"

早速サンプルプログラムをビルドしてみる。

サンプルは以下に示す公式サイトのものを使用する。

// \file example.c

#include <GLFW/glfw3.h> int main(void) { GLFWwindow* window; /* Initialize the library */ if (!glfwInit()) return -1; /* Create a windowed mode window and its OpenGL context */ window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL); if (!window) { glfwTerminate(); return -1; } /* Make the window's context current */ glfwMakeContextCurrent(window); /* Loop until the user closes the window */ while (!glfwWindowShouldClose(window)) { /* Render here */ /* Swap front and back buffers */ glfwSwapBuffers(window); /* Poll for and process events */ glfwPollEvents(); } glfwTerminate(); return 0; }

GLFWのプログラムのビルド手順は以下を参考にする。

GLFW: Building applications

GLFWではpkg-configを使って必要なライブラリをリンクする。以下のようにpkg-configの実行結果をコンパイル時の引数に渡してやる。

cc -o example.{exe,c} $(pkg-config --cflags --static --libs glfw3)

不要かなと思っていたのだけど,なぜか--staticがないとビルドできなかった。ビルドできたら以下のコマンドで起動してみる。

./example.exe

これで以下の真っ黒なウィンドウが表示される。なお,ファイラーからダブルクリックでexample.exeは起動できないようだ。PATHを通したりアプリと同じ場所にlibglfw3.aを配置してもダメだった。cmakeでビルドしないとダメなのかもしれない。cmakeは使い方をよく知らないのでまた勉強しよう。

Windows 10では,MSYS2のpacmanからインストールしたらうまくいったのを確認できた。MSYS2でGLFWをソースからインストールしようとcmakeを実行するとWindowsのビルド環境を認識してしまいうまくいかなかった。

pacman -S --noconfirm mingw-w64-x86_64-glfw

ビルドコマンドは先ほど掲載したUbuntu 14.04でのものと同じでうまくいった。

Windowsでは/mingw64/bin/glfw3.dllをアプリと同じディレクトリに入れておけばExplorerからも起動できた。ただし,起動したら一瞬で閉じられてしまった。

ひとまずこれでGLFWでアプリを作る準備はできただろう。

2016-05-08

Vimで特定ファイルタイプでだけキーマップを無効化

Vimのノーマルモードの改行(<CR>)には,挿入モードと同じようにその場で改行できるように~/.vimrcに以下のキーマップを割り当てている。

nnoremap <CR> i<CR><ESC>

しかし,quickfix-windowやロケーションウィンドウ(ファイルタイプ:qf)やでは改行で対象箇所にジャンプする機能がある。上記キーマップがあるため,<CR>を入力すると以下のエラーが出てうまくジャンプできない。

E21: Cannot make changes, 'modifiable' is off

オプションmodifiableがoffになっているのにファイルを修正しようとしてエラーになってしまっている。

このジャンプの機能は残しておきたいので,quickfix-windowでは自分で定義した上記のキーマップを無効化したい。

以下のサイトで特定ファイルタイプでキーマップを無効化する方法が記されている。

参考:特定のファイル種別の時だけキーマップを無効化する方法 - かせいさんとこ

これによると,特定ファイルタイプでだけバッファーローカルの設定でグローバルな設定を上書きすればよいとのことだ。つまり,以下の内容のファイルタイプごとの設定ファイル~/.vim/after/ftplugin/qf.vimを作ればよい。

" \file qf.vim

if exists("b:did_ftplugin_qf") | finish | endif let b:did_ftplugin_qf = 1 "" Disable line break nnoremap <buffer> <CR> <CR>

ここでは,自分で定義した<CR>をもともとの<CR>に割り当て直している。

これで特定ファイルでだけキーマップを無効化できた。

2016-09-24追記:実際のところ,今回実現したいことは上記のように個別のファイルでの設定は不要で簡単にできた。以下の内容を~/.vimrcに記入すればいい。

"" Insert line break by Enter
autocmd BufEnter * if &modifiable | nnoremap <buffer> <CR> i<CR><ESC> | endif

autocmdでバッファーを開くたびに,modifiableが有効かどうか判定し,有効であるときだけそのバッファーでキーマップを有効にしている。これにより,QuickFixだけでなく,VimのHelpなどでもキーマップを無効(厳密には未設定なだけ)にでき,Enterでタグジャンプできる。

2016-05-04

VimのQuickFix-windowを自動で開く設定

quickfix-window(QuickFixウィンドウ)は自動で開かれないので,自分で:cwで開かないといけない。

以下の設定を記述すると,該当するQucikFixコマンドを実行して,対象があるときだけ自動的にquickfix-windowを開いてくれる。

autocmd QuickfixCmdPost make,grep,grepadd,vimgrep cwindow

vimでquickfixを自動で開く - Webtech Walker

作業中のファイルとquickfixで確認・修正するウィンドウは別にしたほうが作業しやすいと思う。quickfix-windowを新しいタブで開くには以下のようにする。

autocmd QuickfixCmdPost make,grep,grepadd,vimgrep tab cwindow

Vim quickfix list launch files in new tab - Stack Overflow

quickfix-windowでは,Enterで該当ファイルの該当箇所にジャンプできる。しかし,たくさん見比べるときはタブで開きたいときがある。新しいタブで開きたければ,以下のキーバインドを使えばいい。なお,^[はC-vを押して,Alt+Enterを押して直接制御文字を入力する。

nnoremap ^[ <C-W><CR><C-W>T

これで,quickfix-windowでAlt+Enterで該当ファイルの該当箇所を新しいタブで開ける。

ターミナルの制約で,C-CRやS-CRにキーを割り当てるのは難しいみたい。

参考:

2016-05-17追記

上記のキーバインドは,Windowsなどで使えなかったりする。可搬性が下がるのでやめておこう。

代わりに以下の内容の~/.vim/after/ftplugin/qf.vimを作成しよう。

if exists("b:did_ftplugin_qf") | finish | endif
let b:did_ftplugin_qf = 1

"" open new tab nnoremap <buffer> t <C-W><CR><C-W>T

この設定により,quickfix-windowでだけ,tで現在カーソルのファイルを新しいタブページで開ける。<C-W>Tのキーで現在のバッファーを新しいタブページに異動させる。このキーは普段使いでも便利そうなので覚えておこう。

JScriptのWScript.Echo()とJavaScriptのconsole.log()の共通化

JScriptで書いたコードがJavaScriptでも動作するように調整する。

メッセージの表示でよく使うWScript.Echo()console.log()を共通化する。try-catch文で実際に関数を実行して成功するかどうかで判定する。

function print(text){
try {
console.log(text);
} catch (e) {
WScript.Echo(text);
}
}

print("HI");

このようにprint()というWrapper関数を作ってしまえば,JScriptとJavaScriptのどちらでも使える。

以下のようにif文でconsoleオブジェクトの有無で判定すると,オブジェクトが存在しなければ,エラーが表示されてしまう。tryで実際に試してエラーを検知したほうが確実だ。

if (typeof(console)) console.log(text);
else WScript.Echo(text);

2016-08-14追記:これはif文のやりかたが悪かっただけだった。以下のようにきちんとやれば問題ない。

if (typeof(print) === "undefined"){  // for SpiderMonkey
  function print(text){
    if      (typeof(console) !== "undefined") console.log(text );
    else if (typeof(WScript) !== "undefined") WScript.Echo(text);
  }
}

SpiderMonkeyではprint関数が既にあるので,if文を関数定義の前に書いて回避している。

2016-05-03

2016-04-09第56回オープンCAE勉強会@関東での発表「OpenFOAM標準ソルバー人気ランキング」の感想

2016-04-09に 第56回オープンCAE勉強会@関東(流体など)+平林純様特別講演に参加して,「OpenFOAM標準ソルバー人気ランキング」という題で発表した。参加・発表の感想を記す。

少し長いので以下に目次を記しておく。

  1. 参加・発表の背景
  2. 発表資料
  3. 参加・発表の感想
  4. 発表後の指摘
  5. スライド作成
    1. 作成フロー
    2. HTML作成
    3. PDF生成
    4. 残る問題点
    5. 公開先
  6. 動画作成
    1. 動画を作成・公開した意図
    2. 動画作成方法
  7. まとめ

参加・発表の背景

発表時に口頭でも説明したが,今回の発表の主な目的は以下3点だ。

  1. 転職して東京に引っ越してきた挨拶。
  2. OpenFOAMの標準ソルバーの利用状況について自分が調べたことを発表するという自己満足。
  3. Reveal.jsを使った僕の初めてのCSS組版の技術的挑戦。

以下で各目的について簡単に説明する。

1点目。大阪の会社に勤務していたのだが,2016-03-31で会社を退職して,東京の会社に転職することにした。この先当分東京にいるので,ひとまず引っ越しの挨拶をしておいたほうがいいかなとおもった。

2点目。オープンCAE勉強会@関東には今まで2回参加していたが,CAEといえるような内容の発表はあまりしていなかった。発表内容としては,OpenCAE勉強会のメインテーマの一つと思っているOpenFOAMに関するものをそろそろやったほうがいいかなと思った。単純に今後OpenFOAMで何かやるときの参考にしたいなと思ったし,新しく始める人にとっては需要があるんじゃないかなと思った。

3点目。自分の関心の一つに「CSS組版」がある。2016-03-31にHTML5プロフェッショナルレベル1の試験に合格して,HTMLに関する知識の自信がついた。CSS組版の探求として,HTMLでスライドを作ってみたいと思っていた。HTMLでスライドを作るにあたって,いくつかライブラリがある。そのうち,比較的人気のReveal.jsがどんなものか試してみたかった。

主でないが以下の項目も今回の参加の目的だ。

  1. 会場提供者への挨拶・お礼。
  2. 2015-05頃にできたオープンCAE勉強会のロゴの使用。

1点目。今回でこの勉強会には3回目の参加だ。勉強会幹事には既に挨拶をしていたが,会場の提供者には挨拶をしていなかった。挨拶したほうがいいなと思ったので名刺を渡して挨拶した。

2点目。2回目に参加した2014-11-29に参加・発表した第44回オープンCAE勉強会@関東(流体など)で,勉強会のロゴがほしいなとツイートした。そこから話が発展して,2015-05頃にオープンCAE勉強会のロゴが作られた。この一連の経緯は以下でまとめている。

オープンCAE勉強会のロゴができるまでの経緯 - Togetterまとめ

言い出しっぺとして,使わないわけにはいかなかったし,かっこいいあのロゴを使いたかった(スライド表紙の右側に配置)。

以上が今回の勉強会の参加・発表の経緯だ。


たまたま今回の勉強会では平林純という雑学科学研究者を名乗る人の特別講演会があった。僕は知らなかったのだけど,一部で有名な人らしくこの人目当ての参加者もいたようで,最初は参加者が多かった。

参加前にこの人について調べていたのだけど,いくつか本を出しているようで,以下の本は購入して読んでいた。

論理的にプレゼンする技術 聴き手の記憶に残る話し方の極意 (サイエンス・アイ新書) | 平林 純 | 本 | Amazon.co.jp

大学院生のときにプレゼンテーションをうまくやる方法について片っ端から調べていた時に読んだ本だ。2013-11-02に手元に読了記録があり,「悪くはなかった。」とメモがあった。

この人は数値解析を使ってなんかいろいろ遊んでいるみたいだった。数値解析を日常で役に立てられないことを自分の中で大きな問題と思っていたので参考にできたらいいなと少し興味をもった。

発表資料

今回のスライドはReveal.jsで作ったのでHTML版とPDF版の2種類の媒体が存在する。発表にはHTML版を使った。こちらのほうがレイアウトが僕の意図通りなのでこちらで見たほうがよいだろう。PDF版はスライドシェアで公開している。

HTML版:OpenFOAM標準ソルバー人気ランキング

PDF版:

OpenFOAM標準ソルバー人気ランキング(第56回オープンCAE勉強会@関東(流体など)) from Ken SENOO

動画:

また,今回は発表時の音声と画面を自分で動画にしてYoutubeで公開することにした。オープンCAE勉強会では発表者の許可を得て,Vimeoで発表動画を公開している。僕の発表もこちらで公開されている。他の発表動画など自分のことは自分で一元管理したいなと思って自分で動画にしてみた。

なお,今回調査した検索ヒット数の一覧はここにods形式で格納しているので必要であればお持ちください。

参加・発表の感想

今回は参加者が多く,初参加の人が8人だった。その人たちの自己紹介とそれに対する質疑がそれぞれ20分くらいだった。 自分の発表は17:00頃で待ち時間が長くて退屈だった。この勉強会自体の経緯や説明があったのは参考になった。 ゲストに質問してみたが,自分が納得いくような回答は得られなかった。CAEが楽しいという人がいて珍しく思った。

勉強会の最後に,なんかCAEと全く無関係な内容の発表している人がいた。小学校の数学の教科書に江戸しぐさという言葉が間違った意味で伝えられてしまっているので,この問題への啓蒙とかそんな内容だったと思う。インターネットがつながらないとかを理由に,きちんと資料も掲示せずに,何が言いたいのか・なぜここで発表するのかの説明がなくて,何考えているのかよくわからなかった。発表するならきちんとやってほしいなと思った。


今回の発表スライドは4/3日から作成を開始した。テーマ自体はそんなに難しくないが,今回は初めてHTMLでスライドを作るということで,あまり余裕はなかった。Reveal.jsの使い方の学習や,ツールの作成で日曜日は終わり,平日夜間にスライドの大部分を作らざるを得なくなった。今回の勉強会は,引っ越してきて一発目ということでタイミング的にも何がなんでも発表したかった。数値解析と無関係な職業に就くことにしたので,もう当分は参加することがないだろうと思っていたからだ。

一年ぶりの勉強会での発表で少し緊張した。発表スライドはきっちりしたものが作れた。テーマも含めて,発表自体はまあまあうまくできたんじゃないかなと自分では思っていた。最初に掲げた3+2の自分の今回の発表の目的も果たせたのでよかった。

質問されたが,Vivliostyleを知っている人がいて,びっくりした。ランキングに対して怪しいとの声があったが,示している条件で検索すると実際になっている。会場で検索してくれた人がいたが,実際にdsmcFoamの検索数を再現できていた。なので,調査結果自体は間違っていなかった。こういうのは,社会実験とか数値実験みたいなものだと考えている。きちんと条件・手順を示してトレーサビリティーを確保しておくことは大事だと思った。

今回調べた内容は実際のところはOpenFOAMv2.3系の標準ソルバーだったようだ。参照していたマニュアルが古くて,古い情報を元にしていたようだった。別に僕はOpenFOAMのユーザーでも専門家でもないし,そんな細かい情報は知りようがない。他の人がわかるように,公式文書にはきちんと明記してほしいなと思った。

今回の標準ソルバーの検索数の調査は,手作業で行った。自分でGoogle検索でコピーペーストして一個ずつ検索して,ヒット数を控えるということをやった。全部で69ソルバーあり,途中で検索条件を間違えていたのもあり,検索数の調査自体は約2時間かかった。

手作業でやること自体は効率が悪いだろうとは思っていた。しかし,今までやったことがないので自動化するにも試行錯誤が必要だ。イベントまで時間があまりない。時間以内に検索数の取得が間に合う保証はなかったし,自動化着手から2時間以内に完了できる気はしなかった。だから今回は手作業で行った。Google検索を自動化することは今回の発表の趣旨とは無関係であり,これからも継続的に調べるつもりもなかったので,自分としては別に何も問題なかった。

懇親会でこの検索方法の話をふられて,手動でやったといったらその場にいた5人くらいの人全員に驚かれた。「てっきり自動化してるもんだと思っていた」とか,「それくらい調べればすぐにスクリプト組めるでしょ?」とかいろいろ言われた。できる自信がなかったとか,時間が足りなかったとか,手動でやった理由を説明したが理解してもらえなかったようだった。

何も悪い子としていないし,誰にも迷惑をかけていないのに,本題と関係ないところで周りの全員から集中的に批判を受けて,無能扱いされたみたいで不愉快だった。

ちょっとくらいからかわれたり,馬鹿にされたり,笑いものにされたりするのは,わかっていても平気な顔していちいち気にしない。そんな人間相手にせずに,あまり気にしないようにしていた。しかし,今回は許容限界を越えたようで残念だった。

発表後の指摘

今回の発表では,手作業でOpenFOAM標準ソルバー69個をGoogle検索で検索してヒット数を集計した。

勉強会終了後に,この検索ヒット数を自動化する方法を教えてくれた。

シェルスクリプトを意味のある単位にまとめると以下となる。なお,事前にOpenFOAMの設定.bashrcを読み込んでaliasのsol(OpenFOAMのソルバーディレクトリへの移動)を使えるようにしておく必要がある。

sol
U="https://t.co/wbgv8v8uGW"
for CS in `find . -name files | xargs grep EXE | sed "s/\.\/\([^\/]*\).*\/\(.*\)\/Make\/.*/\1,\2/"`
do S=${CS#*,}
R=`curl -s -e $U -A "Mozilla/4.0 (compatible; MSIE 5.5; Windows 95)" $U/search?q=%22$S%22+%22OpenFOAM%22 | grep " results (" | nkf -u | sed "s/.*>\([^>]*\) results (.*/\1/"`;echo $CS,\"$R\";sleep $(($RANDOM % 10))
done

スライド作成

今回は初めてHTMLでスライドを作った。いくつか発見などあったのでメモしておく。 なお,今回のスライドの元ファイル一式は以下のリポジトリに格納している。

slide/2016/20160409_OpenFOAM標準ソルバー人気ランキング at master · lamsh/slide

作成フロー

Reveal.jsを使った。Reveal.jsの公式サイトから一式をダウンロードしてきてそのひな形をベースにした。僕はWYSIWYGで資料 を作りたいので,エディターにBlueGriffonを使ってやろうとしていた。BlueGriffonとReveal.jsを組み合わせて使ったのは僕 が初めてなんじゃないだろうか…

  • ひな形のファイルにユーザーカスタム属性data-*が使われており,一箇所でもこの属性があればBlueGriffonではファイルを編集できないようだった。なので,手動でdata-*属性を除去した。
  • Reveal.jsを構成するCSSやJavaScriptを読み込むと画面が真っ暗なままで編集できない。なので,ひとまずCSSやJavaScriptの読み込み箇所は分離してsrc.htmlで作成した。
  • スライドは見た目が大事なので,最終表示結果を確認し微調整するがあった。merge.shというシェルスクリプトでhead要素の終端とbody要素の終端にそれぞれCSSとJavaScriptを追記して最終表示結果index.htmlを出力する簡単なツールを作った。

HTML作成

  • Reveal.jsでは.reveal > .slides > sectionの階層を持たないといけない。ひな形はdivを使っていたが,div要素は気持ち悪いから使いたくないので,body.reveal>main.slides>sectionという構成にした。
  • 普段使っているCSSをできるだけ使った。節番号を入れたり,表をボーダーカラーにしたり。
  • ただ,節番号をいれるとき,目次やタイトルには番号を入れたくなかったのでbody>main>section>hrというようにsection要素の一行目にhr要素を入れた。だから,表紙と目次には白い罫線が上に付いている。
  • 表紙の氏名にはruby要素でルビを振った。今まで使っていたLibreOffice Impressではルビが振れなかった。
  • 表の中に長い英単語を入れると折り返されないので,単語の途中でも折り返すように,以下のスタイルを適用した。
th, td {
  word-wrap: break-all;
}

PDF生成

PDFを出力するときは,以下のようにURLの末尾に?print-pdfとしたページにアクセスしてC-pの印刷から背景画像にチェックを付けてファイルに印刷する。

http://lamsh.github.io/slide/2016/20160409_OpenFOAM%E6%A8%99%E6%BA%96%E3%82%BD%E3%83%AB%E3%83%90%E3%83%BC%E4%BA%BA%E6%B0%97%E3%83%A9%E3%83%B3%E3%82%AD%E3%83%B3%E3%82%B0/index.html?print-pdf

PDFに出力すると余白など配置がずれることがある。例えば,p. 2のTable of Contentsの次のページに空のぺーじができたり,最終ページに白紙ページができたりする。公開時には手動でこれらの余分なページは削除している。ずれるのは,例えば3.2など鉛直方向にスライドが進むとき,親の節の部分のスペースを確保しないといけないからだろう。

残る問題点

  • HTMLだと節番号が3以降増えない。
  • PDFだと右下のページ番号が反映されない。
  • 配置のずれ。
  • 画像の色がHTML版と変わる。

公開先

作成したHTMLスライドの公開場所を少し悩んだ。SlideshareではPDFやpptx,odpといった一般的なスライドの形式しか対応していない。HTMLのスライドを公開するのによいサービスというのは思いつかなかった。

そこで,Github Pagesを利用した。これはGithubのリポジトリからWebページを生成するGithubのサービスだ。発表スライドを公開するリポジトリslideを新しく作り,ここで公開することにした。

https://github.com/lamsh/slide

今回のスライドは以下のURLでアクセスできる。

http://lamsh.github.io/slide/2016/20160409_OpenFOAM標準ソルバー人気ランキング/index.html

動画作成

動画を作成・公開した意図

動画を自分でYoutubeに公開するのは以下2点の狙いがある。

  1. 自分の活動のアーカイブ。
  2. お小遣い稼ぎ。

1点目。勉強会で発表するというのは自分にとってはかなりの労力となる。自分の発表欲をみたすためだけにやるのはジリ貧で辛いなと思っていた。どれ もそのときの全力で作っている。その場の人だけのものにするのはもったいないなと思っていた。動画として公開しておけば,他の人にもこの先もずっと見ても らえるし,自分の活動の振り返りとしても面白いかなと思っていた。

2点目。ここ何年かでYoutuberと呼ばれる人が登場してきた。Youtubeに動画を公開して広告収入を得ている人たちのことだ。Youtubeはけっこうお金が儲かるという噂をきいていた。自由で生きていくにはやはり自分でお金を稼ぐ必要がある。自分で楽しめて,お金が稼げるならそれはよいだろう。まだ,広告収入を得る設定はしていないが,今後そういう狙いもある。よくわからないが,自分の中で広告とかでお金を稼ぐことには抵抗がある。しかし,自分の声を公開するのは少し恥ずかしいのもあるので,その対価ということで納得させている。

また,どうせ既にオープンCAE勉強会の発表動画は公開されているので,別に隠しても意味がないと判断した。声は目には見えないので,特定される形で顔写真がネット上で拡散することに比べたら,そんなに恥ずかしくはないかなと思う。

動画作成方法

今回は初めて自分で発表動画を作ったので,手順をメモしておく。

  1. 以前から,質疑の確認や記録として発表時には音声レコーダーで自分の発表を録音していた。
  2. 画面キャプチャーソフトを使って,発表音声を聞きながら,画面を切り替えて無音声動画を録画。
  3. 音声と無音声動画を結合させて動画を作成。
具体的には以下のソフトを使った。
  • 画面キャプチャー:kazam
  • 音声と動画の結合:avconv

初めは画面キャプチャーにメディアプレーヤーのVLCを使おうとしたが,マウスポインターがうまく映らないので断念した。また,音声と動画の結合にはOpen Shotを使ってみたが,エンコード後の動画サイズが220 MBと元の動画(50 MB)と音声(8 MB)の4倍近く肥大化したのでavconvを使った。

avconvはffmpegからForkしたものでUbuntuではffmpegではなくavconvをインストールできる。基本的には同じもののようだ。以下のコマンドで動画と音声を結合させた。

avconv -i 動画.mp4 -i record.mp3 結合後動画.mp4

驚くことに,avconvで結合させたらファイルサイズが20 MB程度と元動画より小さくなっていた。

まとめ

今回の勉強会での発表では以下の新しいことに挑戦できた。

  • CSS組版によるスライド作成・公開。
  • 発表動画の作成・公開。

一部残念なことはあったが,次につなげていきたい。