まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

2017/02

ウェブブラウザの検索履歴機能が有効になっていると、アドレスバーに一文字入力しただけで過去の履歴から参照ページの候補を出してくれます:
2017022101
 ↑ アドレスバーに "b" とだけ入力した時の画面。僕の第一候補は IBM Bluemix です!


これ、当然アルファベット毎に候補が変わります。また人によっても(細かなことを言うとブラウザによっても)結果は異なってくるわけです。

で、自分の場合の各アルファベット文字ごとに出てくる第一候補のサイトはどんな感じになるのかを面白そうなので調べてみました。なお 'L' の第一候補は localhost だったのですが、結果としてつまらなかったので排除しています。また http と https の混在は http で統一しています。その結果は以下の通りでした:

#URL説明
ahttp://analytics.google.com/Google Analytics
bhttp://bluemix.net/IBM Bluemix トップページ
chttp://console.ng.bluemix.net/IBM Bluemix コンソールページ
dhttp://dotnsf.blog.jp/まだプログラマーですが何か(個人ブログ)
ehttp://eclipse.org/Eclipse
fhttp://facebook.com/facebook
ghttp://github.com/dotnsf/GitHub
hhttp://h********.mybluemix.net/IBM Bluemix 上に作りかけのサービスサイト
ihttp://info.mybluemix.net/業務用ブログ
jhttp://juge.me/所有ドメインである juge.me の Tumblr サイト
khttp://kuku.lu/PGO サーチ(ポケモンGo)
lhttp://livedoor.blogcms.jp/livedoor Blog
mhttp://manholemap.juge.me/マンホールマップ
nhttp://nikkansports.com/日刊スポーツ
ohttp://openntf.org/OpenNTF.org
phttp://product.rakuten.co.jp/楽天商品価格ナビ
qhttp://qiita.com/キータ
rhttp://rakuten.co.jp/楽天市場
shttp://status.ng.bluemix.net/IBM Bluemix の稼働ステータス確認ページ
thttp://tweetdeck.twitter.com/TweetDeck(Twitter クライアント)
uhttp://uken.or.jp/IBM ユーザー研究会
vhttp://vm-171qzx1tim.sova.bz/wp.sova.jp 内に個人的実験目的で作った WordPress サイト
whttp://watson-api-explorer.mybluemix.net/IBM Watson の API Explorer
xhttp://www.play-asia.com/ゲームやゲーム機の情報サイト PLAY-ASIA.com(XBox などのキーワードでアクセスが多かったと思われる)
yhttp://youtube.com/YouTube
zhttp://japan.zdnet.com/article/35094997/ZDNet 内の IBM Bluemix 記事


2点ほど補足すると、"H" のサイトはいま開発途中のもので、まだ URL をお見せしたくないので伏せ字にさせていただきました。また "X" と "Z" は厳密には頭文字がこれらで始まるサイトではないのですが、他に候補がなかったのか、これらのページが第一候補になっていたので、そのまま記載しています。


結果を見た感想としては「マジメだなあ(笑)」という感じ。業務や自分の運営サービス、およびその関連サイトが多くなっています。あと O とか U とか V とか Z あたりはそんなに頻繁に使っている印象もないサイトなのですが、おそらく他の候補が弱すぎるのと、一時期何回もアクセスしていた時期が昔あったのでその影響もあるんだと思います。

1つ気になったのは T 。ここは自分が開発&運用しているツイートマッパー http://tweetsmapper.juge.me/ になってほしいところだったけど、実際によく使っているのは TweetDeck でした。ツイッター関連という意味では同様のサービスですが、やっぱり自分でも使わないとね。。



 

EclipseNode.js アプリケーションの開発(というかデバッグ)を行うことができるような環境を作ります。そのために Nodeclipse というプラグインを導入します:
2017022001


導入手順は Eclipse のメニューから Help - Install New Software を選択し、インストール元の URL には "http://nodeclipse.org/updates/" を指定します。しばらく待つと導入可能なプラグインの一覧が表示されるので、"1st Nodeclipse Core" と "Enide Tools Collection" の2つにチェックを入れてインストール作業を続行します。最後に Eclipse を再起動するよう指示されるので再起動します:
2017022002


導入作業はこれで終わり。以下は使い方の説明です。Eclipse が再起動したら、Node.js のアプリケーションプロジェクトが作れるようになっています。

Eclipse のメニューから File - New - Project を選択するとプロジェクトウィザードが起動します。その選択肢の中に Nodeclipse カテゴリがあり、そこから Node.js や Node.js Express のプロジェクトが作れるようになっているはずです。今回は試しに "Node.js Express Project" を選んでみました:
2017022003


いつものようにプロジェクト名(以下の例では "MyExpress01")を入力し、属性を設定します。テンプレートエンジンが何種類かの中から選べそうだったので、今回は個人的に慣れている ejs を選んでみました。最後に "Finish" をクリックしてプロジェクトを作成します:
2017022004


Node.js Express プロジェクトが作成された直後の様子です。ejs テンプレートを使ったシンプルなアプリケーションが生成されています。興味ある方は中身を個別に確認してみてください:
2017022009


Eclipse の全体画面がこちら。右上を見ると Node.js 用のパースペクティブが追加され、同パースペクティブで開いていることが確認できます:
2017022000


特に明示的には何も手を加えていないこの状態で一度実行してみることにします。app.js を右クリックし、Run As - Node Application を選択します:
2017022006


コンソールに起動メッセージが表示されます。3000 番ポートで起動しているようです:
2017022007


というわけでウェブブラウザで localhost:3000 にアクセスしてみます。こんな画面になれば成功です。このページ自体は app.js から routes/index.js が呼ばれ、views/index.ejs をテンプレートとしたレンダリングが行われた結果が表示されています。ここまで確認できたら一旦サーバーを停止しておきましょう:
2017022008


では次に今の様子をデバッグしてみることにします。まず routes/index.js を開き、レンダリングを行っている箇所にブレークポイントを仕掛けてみます(該当行の左側をダブルクリックしてブレークポイントマークが付いたことを確認します):
2017022001


今度はデバッグモードで Node.js を起動します。app.js を右クリックして Debug As - Node Application を選択します:
2017022002


デバッグモードでの起動を明示したので、Eclipse のパークペクティブをデバッグ用に切り替えるか?という確認ダイアログが表示されることがあります。その場合は "Yes" を選択します:
2017022003


Debug パースペクティブに切り替わります。同時にアプリケーションがデバッグモードで起動し、最初の1行目で止まった状態になります(まだ起動していないのでブラウザからはアクセスできません)。F8 を押すか、メニュー下の Resume アイコン(右向きの緑の矢印)をクリックして、実行を続けます:
2017022004


コンソールに先程のようなメッセージが表示されるとサーバーが起動してことを意味します。ではあらためてこの状態でウェブブラウザから localhost:3000 にアクセスしてみます:
2017022005


先程のような画面が表示される前にブレークポイントを設定していたので、そこで停止しているはずです。Eclipse の画面を確認すると指定したブレークポイントで止まっている様子が確認できるはずです:
2017022006


この状態で各種変数の値を確認したり、ステップ実行したり、・・・といった、いわゆるデバッグ作業を行うことができるようになっています。最後にもう一度 Resume して処理を続けます:
2017022007


Resume 後にウェブブラウザを確認すると、先程と同じ画面が表示されているはずです:
2017022008



Nodeclipse の紹介はざっとこんな感じ。ところで、Node.js の開発に Eclipse を使うのって、結構マイノリティな気がしているが、実際のところどうなんでしょ??


(参考)
http://qiita.com/suesan/items/7f2c4863feb87a623517

自分は(慣れの要素が大きいのですが)CentOS は未だに 6.x をメインに使っています。「別に不便じゃないし~」程度にしか考えていなかったのですが、その姿勢を改めた方がいいかなあ、と思うことがあったので、その時の様子と対処がいかに大変だったかをまとめました。

Linux で比較的新しめのアプリケーションを使おうとすると、たまにこんなエラーメッセージが出ることがあります:
./xxxxx: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by ./xxxxx)
./xxxxx: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by ./xxxxx)
./xxxxx: /usr/lib64/libstdc++.so.6: version `CXXABI_1.3.5' not found (required by ./xxxxx)
./xxxxx: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by /opt/Xxxxx/libnode.so)

これはシステムにインストールされている libstdc++(GLIBC) ライブラリが古く、動かそうとしているアプリケーションが要求するバージョン(上の例では 3.4.14 や 3.4.15)と合わないためのエラーが発生していることを意味しています。


※実はこのエラーはこのブログエントリの最後に「Rodeo は CentOS/RHEL 7.x 上で動かすのが無難」と書いた時の話です。CentOS 6.8 で普通に Rodeo をインストールして動かすと、ここで紹介しているようなエラーに遭遇するのでした:
CentOS に Rodeo(Python IDE)をインストールする


実際にシステムに組み込まれている libstdc++ のバージョンを確認するには以下のコマンドを実行します(青字は出力結果):
# strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX

GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_FORCE_NEW
GLIBCXX_DEBUG_MESSAGE_LENGTH

この例の場合、3.4.1 から 3.4.13 までは組み込まれているシステムであることが分かります。このシステムで上記アプリケーションを動かそうとすると 3.4.14 や 3.4.15 は組み込まれていないため、上述のようなエラーが発生してしまう、ということになるのでした。エラーの原因はこれで特定できました。


この状況を回避するには libstdc++ を必要なバージョンが組み込まれた新しいものと入れ替える必要があります。そして libstdc++ は gcc に含まれるモジュールなので、(まず gcc ビルドの前提となる glibc を更新して、)gcc をビルドして、そこから libstdc++ を取り出して既存のものと入れ替える、というちと面倒な手順を実行する必要があるのでした。要するに libstdc++ を新しくするためには gcc をビルドする必要があるのです。。

更に、ここまでは全ての Linux ディストリビューションに言える内容なのですが、実際にこの手順を行う場合、CentOS/RHEL 6.x だとものすごく面倒な手順が待ち構えているのでした。実際に行った長い道のりを以下に紹介します。



まず、gcc のビルドに必要なヘッダーファイルをインストールします。具体的には gmp-devel, mpfr-devel, libmpc-devel が必要で、かつ 64bit 環境では glibc-devel.i686 までも必要になります。このうち libmpc-devel 以外は標準の yum リポジトリからインストールできますが、libmpc-devel は EPEL から入手する必要があります。

というわけで、まずは EPEL リポジトリをダウンロード:
# yum install epel-release

続けて上記3つのヘッダファイルと 32bit 版 glibc ヘッダをダウンロードします:
# yum install gmp-devel mpfr-devel libmpc-devel
# yum install glibc-devel.i686

ヘッダファイルの準備ができた所で最初に前提となる glibc をダウンロードしてビルドします。以下の例では /usr/local/src 以下にソースコードを展開しています:
# cd /usr/local/src
# wget http://ftp.gnome.org/pub/gnome/sources/glib/2.32/glib-2.32.4.tar.xz
# tar Jxvf glib-2.32.4.tar.xz
# rm glib-2.32.4.tar.xz
# cd glib-2.32.4
# ./configure
# make
# make install

そして、ここからやっと gcc のソースコードをダウンロードしてビルドします。ちなみにここから先の手順を行うためには 5GB 弱の空きディスク容量が必要になります。また make の実行を開始してから完了するまでに数時間かかります。スペックにもよりますが、昼寝ではなく一度マジ寝して起きる頃に終わっている、というくらいの時間を見ておく必要があります (^^;:
# cd /usr/local/src
# curl -LO http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-4.8.4/gcc-4.8.4.tar.gz
# tar fxz gcc-4.8.4.tar.gz
# rm gcc-4.8.4.tar.gz
# cd gcc-4.8.4
# ./configure
# make (僕の仮想環境ではここで4~5時間かかりました・・)
# make install

・・・で、gcc のビルドが無事に完了したら libstdc++ の入れ替えを行います。まずは現在の状況を確認します:
# ls -l /usr/lib64/libstdc*

lrwxrwxrwx 1 root root     19  1月 23 12:35 2017 /usr/lib64/libstdc++.so.6 -> libstdc++.so.6.0.13
-rwxr-xr-x 1 root root 989840  5月 10 18:38 2016 /usr/lib64/libstdc++.so.6.0.13

ビルドした結果から、目的のライブラリをコピーして、シンボリックリンクを作り直します:
# cp /usr/local/src/gcc-4.8.4/x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.19 /usr/lib64
# cd /usr/lib64
# mv libstdc++.so.6 libstdc++.so.6.bak
# ln -s libstdc++.so.6.0.19 libstdc++.so.6
# ls -l /usr/lib64/libstdc*

lrwxrwxrwx 1 root root      19  2月 14 12:07 2017 /usr/lib64/libstdc++.so.6 -> libstdc++.so.6.0.19
-rwxr-xr-x 1 root root  989840  5月 10 18:38 2016 /usr/lib64/libstdc++.so.6.0.13
-rwxr-xr-x 1 root root 6468627  2月 14 12:06 2017 /usr/lib64/libstdc++.so.6.0.19
lrwxrwxrwx 1 root root      19  5月 26 11:23 2016 /usr/lib64/libstdc++.so.6.bak -> libstdc++.so.6.0.13

最後に目的のバージョン(今回であれば 3.4.14 や 3.4.15)が有効になっているかどうかを確認します:
# strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX

GLIBCXX_3.4
GLIBCXX_3.4.1
GLIBCXX_3.4.2
GLIBCXX_3.4.3
GLIBCXX_3.4.4
GLIBCXX_3.4.5
GLIBCXX_3.4.6
GLIBCXX_3.4.7
GLIBCXX_3.4.8
GLIBCXX_3.4.9
GLIBCXX_3.4.10
GLIBCXX_3.4.11
GLIBCXX_3.4.12
GLIBCXX_3.4.13
GLIBCXX_3.4.14
GLIBCXX_3.4.15
GLIBCXX_3.4.16
GLIBCXX_3.4.17
GLIBCXX_3.4.18
GLIBCXX_3.4.19
GLIBCXX_FORCE_NEW
GLIBCXX_DEBUG_MESSAGE_LENGTH

期待通りのライブラリに更新できました。これで CentOS 6.x でも Rodeo が動くようになりました。いやあ、長かった。めでたし、めでたし:
rodeo_centos6
↑今回のブログエントリは、この「CentOS 6.x 上で動く Rodeo」のスクリーンショットを撮るまでがいかに大変であったかを分かっていただきたいがために書きました。 (^^;


ここまで確認できれば glibc や gcc のソースコード一式は不要なので、消してしまっても構いません(何しろこの環境のために 5GB 前後のディスクを専有しているので・・・)
# cd /usr/local/src
# rf -rf glib-2.32.4 # rm -rf gcc-4.8.4




(参考)
http://qiita.com/dozo/items/de393588d5c267794ced

https://www.saintsouth.net/blog/update-libstdcpp-on-centos6/



 

マルチプラットフォーム対応の Python IDE である Rodeo を CentOS/RHEL にインストールする手順を紹介します:
https://www.yhat.com/products/rodeo

2017021300


といっても手順として特別なことはなく、リポジトリを追加して yum でインストールするだけです:
$ sudo wget http://rodeo-rpm.yhat.com/rodeo-rpm.repo -P /etc/yum.repos.d/
$ sudo yum install rodeo

インストール後、アプリケーションメニューの「その他」から起動できます:
2017021301


はい起動しました。簡単ですね~(※CentOS/RHEL 7 の場合)
rodeo_centos6


機械学習や数値解析に便利なライブラリが充実している Python をより便利に使うための Python IDE も充実してきてるんですね。。


なお、上でわざと(※CentOS/RHEL 7 の場合)と強調しているのには意味があります。ご覧のように上記のスクリーンショットは CentOS 6 上で動いている Rodeo の画像なのですが、この環境を作るのは一筋縄ではいかなかった、という背景があります(このスクリーンショットを撮るまでの作業が、まあ大変でした・・・)。別の機会に詳しく書くかもしれませんが、とりあえず Rodeo は CentOS/RHEL 7.x 上で動かすのが無難、と付け加えておきます。


まだ同期/非同期処理の違いに戸惑いながら Node.js を使っています。で、先日こんな実行時エラーに遭遇しました:
  :
  :
events.js:141 throw er; // Unhandled 'error' event ^ Error: EMFILE: too many open files, open '/home/kkimura/XXX/images/*****.jpg` at Error (native)

その時のコード(抜粋)がこちらです:
var fs = require( 'fs' );
fs.readdir( './images', function( err, files ){  // ./images/ フォルダを開く
  if( err ) throw err;
  
  files.forEach( function( jpgfile ){  // ./images/ フォルダの全ファイルを1つずつ取り出して、、、
          :
    (各ファイルに対する処理)
          :
  });
});

現在のディレクトリから、fs モジュールを使って images/ サブフォルダの中にある画像ファイル全てを取り出して、各ファイルに対して何らかの処理をする・・・という、よくあるとまで言えるかどうかはわかりませんが、ごく普通の内容だと思います。この処理中に上記のエラーが発生しました。エラーそのものもネイティブコードの中で発生しているので、どの画像ファイルを読み込んでいる時のエラーかはわかるのですが、何が原因のエラーなのかのヒントはほとんどありませんでした(結論としては画像ファイル側の問題ではないので、どの画像ファイルであったかは解決の上ではあまり重要な情報ではありませんでした)。

が、エラーメッセージそのものから原因はなんとなく推測できました。

まず、この処理は特定のフォルダ(./images)の中にある全てのファイルを取り出し、forEach() ループで各ファイル毎になんらかの処理をする、というものです。そしてエラーメッセージは "Too many open files(ファイルを開きすぎている)"。 実際、このフォルダ内には非常に多くのファイルが存在していたのですが、それらを同時に開きすぎて、処理の限界を超えてしまった、というエラーが発生していたようです。

というわけで原因はなんとなくわかりました。しかし本当の問題はここから。


Node.js(JavaScript) は非同期に処理を実行します。つまり上記のようなケースでは「ファイルを1つずつ開いて処理をして、終わったら閉じて次へ」ではなく、「同時に(非同期に)全ファイルを開いて、同時に(非同期に)全ファイルに処理を施して・・・」という形で実行されます。そしてその際に多くのファイルを開きすぎて "Too many open files" というエラーが発生していたのでした。このエラーは多くのファイルが保管されているディレクトリへの処理を非同期に実行する以上は解決しにくい問題のように思えますが、さてどうする・・・


これ、自分以外でも悩んでいる人が多かったらしく、StackOverflow などでも議論(後述)されていました。結果的には fs ライブラリそのものを改良したものを使う、という方法が紹介されていました。その改良モジュール(graceful-fs)はこちら:
https://github.com/isaacs/node-graceful-fs

この graceful-fs は fs の代わりに使うことができ、かつ "Too many open files" エラー時に発生する EMFILE イベントを検知したら、少し待ってからやり直し処理を行う(という方法でエラーを回避しながら全ファイルを処理する)、という処理が実装されたもののようです。

graceful-fs モジュールを使うには、まず npm 等でインストールを行います:
$ npm install graceful-fs

そしてコードを書き換えます。といっても require( 'fs' ) を require( 'graceful-fs' ) にするだけで、他は変更なしでそのままエラーもなく動きました:
var fs = require( 'graceful-fs' );
fs.readdir( './images', function( err, files ){
  if( err ) throw err;
  
  files.forEach( function( jpgfile ){
          :
    (jpgfile に対する処理)
          :
  });
});


それにしても同期/非同期処理の頭を素早く切り替え出来るのって、それだけで才能ではないかと思う。。。


(参考)
http://stackoverflow.com/questions/8965606/node-and-error-emfile-too-many-open-files

このページのトップヘ