まなぶろぎーく。

西新宿で働くWebエンジニアのブログ

iwakou の投稿をブラウズ中…

前エントリに引き続き、
ずっとローカルPCに残していたRedmineのインストールメモをこの機会にエントリにした。
導入先は同じくさくらの共有レンタルサーバ(スタンダード)

■導入の前に

いろいろ試してみたところ、さくらの共有ホスティングにインストールできるRedmineのバージョンは
0.8.7が最高で、それ以上のバージョン(1.x系)は同様の手順を踏んでも動作を確認できなかった。
Google先生に聞くと、どうやら1.x系を動作できたというツワモノがいるようだけど具体的な解決には至らず。
ちなみにいざ動作確認というところまでは、1.x系はi18nの追加インストール、
rubygemsのバージョンを1.4.2にダウングレード(ここまでは初期設定のrake実行中に引っかかる)
そしてrails2.1系までに使用されたdispatcher経由によるcgi起動(本来はrails2.2系以上はrackベース)を試み失敗に終わった。。

■導入ルール

  • Rubyはrvm経由でインストール
  • Redmineはv0.8.7を使用
  • DBはSQLite3を使用
  • dispatcherはgateway.cgiを使用
  • gateway.cgiに必要なfcgiのインストール先は「$HOME/local/fcgi」
  • fcgi導入前のソースコードは「$HOME/local/fcgi/src」にダウンロード

■rvm経由でRuby1.8.7をインストール

さくらのレンタルサーバには標準でRuby1.8.7が使用できるが、今後の別バージョン利用など
こちらでバージョンをコントロールできるよう、別途rvm経由でインストールした

bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
rvm install 1.8.7
[[ -s "/home/iwakou/.rvm/scripts/rvm" ]] && source "/home/iwakou/.rvm/scripts/rvm"
rvm --default 1.8.7

# ログイン直後にrvm経由のRubyを優先的に参照する場合は.bashrcに以下を追加
echo '[[ -s "/home/iwakou/.rvm/scripts/rvm" ]] && source "/home/iwakou/.rvm/scripts/rvm"' >> ~/.bashrc

■iconvの拝借

さくらのレンタルサーバはFreeBSD系が使われており、このプラットフォームに
Rubyをインストールした場合はiconvは付属しない(このへんはよくわかってない)
そのため、標準搭載のRubyからiconvを拝借することに。

cp /usr/local/lib/ruby/1.8/i386-freebsd7/iconv.so ~/.rvm/rubies/ruby-1.8.7-p334/lib/ruby/1.8/i386-freebsd7.1/

■fcgiのインストール

さくらのレンタルサーバは原則デーモンを立てることができないため、
railsアプリケーションはcgiモードでの起動となる。
しかしそれではレスポンスがあまりにもお粗末なため、およそ1分間プロセスを常駐させ
自動で落下させるdispatcherのgateway.cgiの使用すべく、ベースとなるfcgiをインストールした。

mkdir -p $HOME/local/fcgi/src
cd $HOME/local/fcgi/src
wget http://www.fastcgi.com/dist/fcgi-2.4.0.tar.gz
tar xzvf fcgi-2.4.0.tar.gz
cd fcgi-2.4.0
./configure --prefix=$HOME/local/fcgi
make
make install

■必要なgemライブラリ一式をインストール

Redmineは基本rake freezeにより必要なrailsをあらかじめ保持しているが
念のためインストールしておく。それ以外もあわせてインストール。

gem install rails -v=2.1.2
gem install sqlite3-ruby
gem install fcgi -- --with-fcgi-include=$HOME/local/fcgi/include --with-fcgi-lib=$HOME/local/fcgi/lib

■Redmineのダウンロードと設定

前述の通りv0.8.7をダウンロードし、gateway.cgiから起動させる
また、URLは「http://xxxx.sakura.ne.jp/redmine/」を想定した設定とした

cd ~
wget http://rubyforge.org/frs/download.php/67144/redmine-0.8.7.tar.gz
tar xzvf redmine-0.8.7.tar.gz
cd redmine-0.8.7
mkdir log/drb_gateway


cp config/database.yml.example config/database.yml
vi config/database.yml
# DB設定(SQLite3を想定)、productionモードの指定先を変更する
production:
  adapter: sqlite3
  dbfile: db/redmine.db


vi config/environment.rb
# 環境設定、以下を6行目付近に追加
ENV['GEM_HOME'] ||= '/home/XXXX/.rvm/gems/ruby-1.8.7-p334'
ENV['RAILS_ENV'] ||= 'production'


vi config/environments/production.rb
# 最終行に以下を追加
ActionController::AbstractRequest.relative_url_root = '/redmine'


cp ~/.rvm/rubies/ruby-1.8.7-p334/lib/ruby/gems/1.8/gems/rails-2.1.2/lib/commands/ncgi/* script/


chmod 755 script/listener
vi script/listener
## 1行目の実行パスの変更、5行目「require 'fcgi_handler'」直前にrequire系2行を追加 
#!/usr/bin/env ruby
require 'rubygems'
gem 'fcgi'
## 17行目「super()」直前に以下2行を追加
$stdin = self.stdinput
$stdout = self.stdoutput


chmod 755 script/tracker
vi script/tracker
## 1行目の実行パスの変更
#!/usr/bin/env ruby


cp ~/.rvm/rubies/ruby-1.8.7-p334/lib/ruby/gems/1.8/gems/rails-2.1.2/dispatches/gateway.cgi public/


chmod 755 public/gateway.cgi
vi public/gateway.cgi
## 1行目の実行パスの変更、64行目のsleep値を変更
#!/usr/bin/env ruby
sleep 1


vi public/.htaccess
## 11行目をコメントアウト、46行目「dispatch.cgi」を「gateway.cgi」に変更
#Options +FollowSymLinks +ExecCGI
RewriteRule ^(.*)$ gateway.cgi [QSA,L]


rake config/initializer/session_store.rb
rake db:migrate RAILS_ENV="production"
rake redmine:load_default_data RAILS_ENV="production"


cd ~/www
ln -s ~/redmine-0.8.7/public redmine

■補足

どのようなURLで見せるかで設定を一部変える必要がある
1.「http://xxx.sakura.ne.jp/redmine/」の場合は、、、
  ・RAILS_ROOT/config/environments/production.rbには
   「ActionController::AbstractRequest.relative_url_root = ‘/redmine’」を追記する
2.「http://独自ドメイン/」の場合は、、、
  ・RAILS_ROOT/public/.htaccessに「RewriteBase /」を追加し、
  ・RAILS_ROOT/config/environments/production.rbには
   「ActionController::AbstractRequest.relative_url_root = ”」を追記する
今回自分は1を採用した。ご参考までに。

■おまけ

シェル一発でfcgiをインストールするスクリプト
(とはいっても上記コマンドをまとめただけですが)をgistに設置しました
gemコマンドが使える状態を確認した上でご自由にお使いください

ずっとローカルPCに残していたSubversionのインストールメモをこの機会にエントリにした。
導入先はさくらインターネットの共有レンタルサーバ(スタンダード)で
さくらにSubversionをインストールを参考にさせていただきました。

■導入ルール

  • インストールはすべてソースインストール(てかそれじゃないと無理なはず)
  • インストール先は「$HOME/local/svn」
  • 導入前のソースコードは「$HOME/local/svn/src」にダウンロード

■下準備

インストール&作業ディレクトリの作成
mkdir -p $HOME/local/svn/src
cd ~/local/svn/src

環境変数PATHにSubversionの実行コマンドの参照先を通す
echo "export PATH=$HOME/local/svn/bin:$PATH" >> ~/.bashrc

■swigのインストール

CやC++で書かれたプログラムやライブラリを他の言語から使用するためのOSSツール

wget http://jaist.dl.sourceforge.net/sourceforge/swig/swig-1.3.40.tar.gz
tar xzvf swig-1.3.40.tar.gz
cd swig-1.3.40
./configure --prefix=$HOME/local/svn
make
make install

■neonのインストール

WebDAVクライアントライブラリ

wget http://www.webdav.org/neon/neon-0.29.6.tar.gz
tar xzvf neon-0.29.6.tar.gz
cd neon-0.29.6
./configure --prefix=$HOME/local/svn --with-ssl --with-libs=/usr/local --enable-shared
make
make install

■Subversionのインストール

Apacheのサポートライブラリであるaprとapr-utilを用いる
DLしたSubversionのディレクトリ配下に両者を移動し、configureオプションで指定する

wget http://www.meisei-u.ac.jp/mirror/apache/dist//apr/apr-1.4.5.tar.gz
tar xzvf apr-1.4.5.tar.gz
wget http://www.meisei-u.ac.jp/mirror/apache/dist//apr/apr-util-1.3.12.tar.gz
tar xzvf apr-util-1.3.12.tar.gz
wget http://subversion.tigris.org/downloads/subversion-1.6.16.tar.gz
tar xzvf subversion-1.6.16.tar.gz
mv apr-1.4.5 subversion-1.6.16/apr
mv apr-util-1.3.12 subversion-1.6.16/apr-util
./configure --prefix=$HOME/local/svn --without-berkeley-db --with-swig=$HOME/local/svn/bin/swig --with-neon=$HOME/local/svn --with--with-ssl --with-libs=$HOME/local/svn --disable-static
make
make install

■気になったこと

さくらにSubversionをインストールでは
Subversionのconfigureオプションにpython関連の指定があったが
特に付与せずともインストールはうまくいった。なくてもいける…かも?

■おまけ

シェル一発でSubversionをインストールするスクリプト
(とはいっても上記コマンドをまとめただけですが)をgistに設置しました
ご自由にお使いください

JavaScriptコーディング ベストプラクティス 高速かつ堅牢なコードを効率よく書くためにの主に第4章で紹介されている「高速化のためのベンチマークコレクション」をもう少し突っ込んで調べてみたくなったので調べてみました。

今回は第1回目(2回目があるかは知らないよ)として、書籍では4.2.19「スコープ内外への変数へのアクセス速度」です。
追加した検証内容とあわせるために、無名関数を即時実行する方法に若干の修正をしています。ローカル変数が最も速いのは調べるまでもないのでブラウザはChrome10の結果のみ記載します。決して手を抜いた訳じゃあないよ。

// (1) window.aへのアクセス
for(var i = 0; i < 1000000; i++){
  window.a = 'abc';
}

// (1’) 関数内でwindow.aへのアクセス(書籍にも記載)
(function(){
  for(var i = 0; i < 1000000; i++){
    window.a = 'abc';
  }
})();

// (2) window['a']へのアクセス
for(var i = 0; i < 1000000; i++){
  window['a'] = 'abc';
}

// (2’) 関数内でwindow['a']へのアクセス
(function(){
  for(var i = 0; i < 1000000; i++){
    window['a'] = 'abc';
  }
})();

// (3) 暗黙のグローバル変数へのアクセス
for(var i = 0; i < 1000000; i++){
  a = 'abc';
}

// (3’) 関数内で暗黙のグローバル変数へのアクセス
(function(){
  for(var i = 0; i < 1000000; i++){
    a = 'abc';
  }
})();

// (4) ローカルスコープに参照をコピーしたwindow.aへのアクセス
(function(w){
  for(var i = 0; i < 1000000; i++){
    w.a = 'abc';
  }
})(window);

// (5) ローカルスコープに参照をコピーしたwindow['a']へのアクセス
(function(w){
  for(var i = 0; i < 1000000; i++){
    w['a'] = 'abc';
  }
})(window);

// (6) 関数内でローカル変数aへのアクセス(書籍にも記載)
(function(){
  var a = '';
  for(var i = 0; i < 1000000; i++){
    a = 'abc';
  }
})();

結果は以下の通り。

(1) 1685ms
(1’) 705ms
(2) 1690ms
(2’) 718ms
(3) 1290ms
(3’) 307ms
(4) 190ms
(5) 191ms
(6) 7ms

ローカル変数は別格なのでここでは放っておきますが、グローバル変数については様々なアクセス方法がある中で、大きく分けて5つのポイントが見えました。

  1. ドット参照も添字参照も違いはない
  2. 暗黙のグローバル変数はちょっと速い(ただし第3者からみてvarつけ忘れか狙ったのか判断しづらいので使ってほしくない)
  3. 明示的にwindowオブジェクトから参照するのが最も遅い
  4. ただしローカルスコープから参照させると一気に改善する(よくいわれてるよね)
  5. 同じグローバル変数への参照でもfunction内部で実行すると速度が2倍速くなる

特に最後のポイントは意外でした。他はともかく(やる前から大体見当のつくものだし)これだけはどう解釈していいのか分かりません。1つ言えるのは、日頃から無名関数の即時実行してローカルスコープを作るコードを書く癖があればそれだけで多少速度改善に貢献していたということですね。

また気になった高速化のポイントがあれば調べてみたいと思います。

JavaScriptの勢いはすごいっすね。Publickeyさんでも紹介されていましたが、日に日にJavaScriptの重要性は増しているようです。

特に2010年から、これまでのブラウザ上の環境としてのみではなく、node.jsをはじめとしたサーバサイドや、Titaniumをはじめとしたスマートフォン向けのネイティブアプリなど、もはやWebを取り巻く技術はJavaScriptを中心にまわり始め、自分のようなJavaScript大好き!な子にはたまらない状況になってきています。

さらにCPANやRubyGemsのようなライブラリ管理や、rvmのような複数のバージョンを簡単に切り替えてくれるツールにあたるものがnode.js周辺にも現れ、どんどん使いやすくなりウハウハですね。過去に何度かnode.jsは使いましたが、これら関連ツールによりかなりスッキリしたのでインストールメモということでエントリにしました。

なお、OSはCentOS 5.5で、OSインストール時も最小限のベースパッケージのみにしてあります(さすがにgccはインストール済み)インストール先はすべてユーザディレクトリ配下とし、ソースコンパイル系は「~/local/[ソフト名]」githubからチェックアウトしてきたものは「~/github」というルールで進めています。

とはいえ、大半はこちらを参考にさせていただいています。いつも拝見しておりますありがとうございます! node.jsとnpmのインストール

gitのインストール

node.jsにおけるrvmとして代表的なものがnaveと呼ばれるもののようです。githubから利用するのがベターなのでgitを先にインストールします。

// まずは最新版のgitをソースからインストールするよ
$ wget http://kernel.org/pub/software/scm/git/git-1.7.4.1.tar.bz2
$ tar -jxf git-1.7.4.1.tar.bz2
$ cd git-1.7.4.1
$ ./configure --prefix=~/local/git-1.7.4.1
$ make
GIT_VERSION = 1.7.4.1
    * new build flags or prefix
    CC daemon.o
daemon.c:1 から include されたファイル中:
cache.h:17:18: error: zlib.h: そのようなファイルやディレクトリはありません
In file included from daemon.c:1:
cache.h:22: error: expected ‘)’ before ‘strm’
cache.h:23: error: expected ‘)’ before ‘strm’
cache.h:24: error: expected ‘)’ before ‘strm’
make: *** [daemon.o] エラー 1

zlib.hがないと怒られました。rpmパッケージ群をgrepしたら開発ツールがなかったのでさくっとyumで早速インストールし、リトライ!無事インストール完了。

$ rpm -qa | grep zlib
zlib-1.2.3-3
zlib-1.2.3-3
$ sudo yum install zlib-devel
$ make
$ sudo make install

nave経由でnode.jsのインストール

では早速naveをチェックアウトし、nave経由でnode.jsをインストール。最新版は「latest」を引数にとり、バージョンを指定したい場合はバージョン番号を指定する。

$ git clone git://github.com/isaacs/nave.git
$ cd nave
$ ./nave.sh install latest
######################################################################## 100.0%
Checking for program g++ or c++          : /usr/bin/g++ 
Checking for program cpp                 : /usr/bin/cpp 
Checking for program ar                  : /usr/bin/ar 
Checking for program ranlib              : /usr/bin/ranlib 
Checking for g++                         : ok  
Checking for program gcc or cc           : /usr/bin/gcc 
Checking for gcc                         : ok  
Checking for library dl                  : yes 
Checking for openssl                     : not found 
Checking for function SSL_library_init   : not found 
Checking for header openssl/crypto.h     : not found 
/home/iwakou/github/nave/src/0.4.1/wscript:303: error: Could not autodetect OpenSSL support. Make sure OpenSSL development packages are installed. Use configure --without-ssl to disable this message.
Failed to configure 0.4.1
fail

あれ?怒られた。OpenSSLがないと。おそらく先ほどと同様開発ツールが抜けていると思ったら案の定そうだった。yumでさくっと入れてリトライ、うまくnode.jsがインストールできました。

$ rpm -qa | grep openssl
openssl-0.9.8e-12.el5_5.7
openssl-0.9.8e-12.el5_5.7
$ sudo yum install openssl-devel
$ ./nave.sh install latest

インストールしたnode.jsを環境変数「$PATH」に通す場合や、インストール済みのバージョンを標準のnave.shから簡単に行うことができるようです。

# インストール済みのバージョンを確認する
$ ./nave.sh ls
# 環境変数「$PATH」に通す(latestはない場合インストールから入るので危険?!)
$ ./nave.sh use 0.4.1
# 常時「$PATH」を通しておく場合は「~/.bashrc」に書いておくと良いよね
$ ~/.bashrc
if [ -f ~/github/nave/nave.sh ]; then
	~/github/nave/nave.sh use 0.4.1
fi

ただし、useで$PATHを通すと.bashrcを再読み込みする(というかカレントユーザで再ログイン)しているような動きをとり、若干気持ちが悪い(psで見るとずっと.nave.shが常駐している)ので、結局nave標準の方法は使わず、純粋に使いたいバージョンのbinディレクトリを自分で$PATHに追加することで対応しています。
(この現象は自分だけでしょうか?詳しい方は教えてください)

npmのインストール

最近はnode.jsとセットで取り上げられることが多くなったnpmをインストール。すっかりおなじみnode.js系のライブラリ管理システムですね。ついでにメジャーなライブラリ「soket.io(いまをときめくWebSocketsの機能を提供してくれる優れもの)」と「express(Webアプリケーションのルーティングを支援するフレームワーク。RailsとSinatraを足して2で割ったような感じ)」に加え、個人的に最も使いやすそうなテンプレートエンジン「ejs」をインストール。

curl http://npmjs.org/install.sh | sh
$ npm install socket.io
$ npm install express
$ npm install ejs

というわけで、カレントユーザの配下にnaveとnpmでスッキリインストールできました!

前回エントリsummersonic 2010 に行ってきた(1)に引き続き、サマソニ参戦レポート。今回は2日目を書きます。まず先に書いておくと、2日目は寝坊し、AA=から見る予定が大幅に狂った。。。起床してダッシュで幕張に向かい、14:00(だったかな?)からのスタート。orz

The Drums (14:45~)

毎年サマソニは必ずと言っていいほど将来のビッグアーティスト候補を招集するんだけど、今回はThe Drumsだった模様。なかなか打率も良く、過去にはMando DiaoやKasabian、Arctic Monkeysがサマソニで初来日し、大ブレイクしていったような気がする。
聴いた感じ、申し訳ないけど普通のUKロックにしか聞こえなかった。印象も弱く飽きてしまったので途中退散。ちゃんとCD聞けば違うのだろうか…。

Sum41 (15:40~)

よくよく考えると、今年のサマソニは洋楽Punkにハマるキッカケをくれたバンド(OffspringとSum41)両方がでてるんだなぁ。ちなみにSumは今回で4回目。今回の来日直後に大阪でデリックが暴行被害にあったということで心配だったけど、ライブは全然パワフルだった。
「The Hell Song」から始まり、主にDoes This Look Infected?の曲を中心にまんべんなく代表曲をやった感じ。ラストは確か「Still Waiting」「Fat Lip」「Pain For Pleasure」だったかな。やっぱり最後はスティーボが締めた。今回はマリンのスタンド上部から観たんだけど、遠くから(かつ上部から)パンクキッズを客観的に見ると楽しい!モッシュのうねりやサークルピットの位置など、もろもろよく見えた。次も高見見物をしてみようかな。

Hole (16:50~)

すぐさまメッセに戻りHoleへ。是非カート・コバーンの嫁を一目観たかった。いったいどれほどのパンクな女性なのか。(もちろん事前にLive Through ThisとNobody’s Daughterを聴いて予習はした)
とにかくラウドで声もラウド。本当に女性の声なのかと思うくらい特徴的で存在感がある、好きな音好きな声。曲は新旧まんべんなくやった感じ。時折笑顔を見せるので、今日は機嫌がいいのかな?と思った(これは個人的な偏見です。パンクな女性はクセがある印象なので)

番外:マイコーりょう (18:05~)

一旦休憩をとった際、Side Showでマイコーりょうがやってた。下手すると出演アーティストに匹敵するくらいすげー盛り上がり。ムーンウォークとか体傾けるやつとか(名前知らない)するたびに大歓声。Twitterのサマソニハッシュタグをみてて「いまのところマイコーりょうがベストアクト」と書いてた人いたけど、ありうるw

SLASH (18:20~)

最初の15分だけ観た。どうやらガンズの曲をたっぷりやったらしいがガンズを聴いてないのでわからない…。さすが世界屈指のギタリスト、めちゃくちゃうまいしカッコいい。事前情報でB’z稲葉さんがサポートボーカルで乱入するって聴いてたので期待してたけど、結局見ることはできなかった(すげー興味あったのに…)

jonsi (18:55~)

Sigur Rosは知ってるけど聴いたことはない。でも気になってたので最初の20分だけみて、途中からAtari Teenage Riotへ向かおうと思ってた。
が、あまりにも感動的で結局最後まで観た。恐らく今年のサマソニでベストアクトかもしれん、本当に素晴らしいライブだった。jonsiのあまりにも美しいファルセットボイスと幻想的な音が混ざり、さらにバックではビジュアルエフェクトを駆使して全体が独特の世界観。まるで万華鏡を覗いてるかのような、そんな感じ。近くでは泣いている女性を何人か見かけた。
これは年末の単独は行くしかない。翌日すぐさまCDを買いに走った。

Pixies (20:30~)

ついに今年のサマソニラストであり、個人的大本命のPixies。どれだけ生Pixiesを体感できることを心待ちにしてたことか。Nirvanaのカート・コバーン、Weezerのリヴァース・クォモ、Radioheadのトム・ヨーク、多くの偉大なアーティストが尊敬してやまないご先祖様(もはや風貌はおじさんおばさんにしか見えないけど)。巨漢フランシスが若干痩せたようにみえたんだが?
肝心のライブは、「Cecilla Ann」から始まり2曲目に早速「Bone Machine」が飛び出す出だし。中盤で「Broken Face」で観客がアハンアハンの合唱。終盤に入るとついに「Debaser」「Gigantic」「Where is my Mind」の神曲にテンションMAX、ちょっと泣きそうになった。そしてアンコールは「Here Comes Your Man」を今日一番の大合唱で締めくくった。
jonsiが新発見という意味で感動を与えてくれたとすれば、Pixiesは悲願が叶ったという意味で感動。セットリストも大好きなSurfer RosaとDoolittleを中心にプレイしてくれて大満足。唯一、名曲「Monkey Gone To Heaven」をやらなかったのが残念だったけど…。

以上、サマソニレポでした。来年は何が来るかな?フジロックはどうかな?また一年をかけてワクワクが始まりそう。

毎年、何かしら夏フェスには参戦してますが、今年はsummersonic 2010に行ってきた。ちなみにサマソニは03(2日目)、04(両日)、05(2日目)、06(2日目)、09(1日目)と参戦して今回5回目。今年の印象は(個人的嗜好から観て)オルタナ・グランジ祭り!つーわけで両日参戦した今回のサマソニのレポ書きます。内容は薄いよw

FACT (11:00~ )

11時前に幕張に到着し、即座にFACTを観にマリンへ。このバンドは2004年位から何度か観たことあったけど、当時は和製Strung Outって騒がれてたなぁ。ピロピロのギターと手数の多いドラムが特徴的なスクリーモ。Bullionから出したCDがめちゃめちゃカッコよかった覚えがある。でも2年前位にVAGRANTと契約して一気に大衆ウケする音になって「あれ?」とおもったけどそれはそれでハマった。

開始10分は見逃したけど、今回もやはりFACT(VAGRANT契約後)以降の曲中心だった。音は相変わらずカッコいい。でも相変わらず声量弱い(聞こえない!)ラストはやっぱり「Fact of Life」で締めた。

3OH!3 (11:45~)

同時刻に大好きなNorthern19がやってたけど、一度観てみたかったのでコッチを選択。最近のThe BamboozleやVans Warped Tourの常連。本国の人気ってスゲーのかな?
今回はじめて聞いたけど、もはやPop Punkも通り越してエレクトロ系。ホント最近多いね。知ってる曲はなかったので「あー、ノリいいな」という印象。

All Time Low (13:45~)

Hit The Lightsと並び、ポストFall Out Boyと3,4年前に話題になったバンド。初期のEPも聴いてThe Bamboozle2007でも観たけど、なんかありきたりなPop Punkなんだよなぁ。ただ、本国ではアイドルばりの人気、日本もティーンの女の子にメチャ人気。イケメンだからか。

自分は「This is How we do」目当てだったんだけど結局やってくれなかった。。。←これだけは神曲だと思ってる

KREVA (13:30~)

時間があいたので取り敢えず観てみた。知ってる曲あんまないけど「ひとりじゃないのよ」は結構好きだったので観たかいあった。

矢沢永吉 (14:35~)

サマソニみたいな夏フェスのいいところは、興味あるけどわざわざライブには行かないアーティストを観るきっかけを作ってくれるところだと思う。今年に関しては間違いなく永ちゃんでした。とにかく熱狂的なファンがいるんだね。観客の集まり具合は過去の午後イチにプレイしたバンドの集客を見てきた感じ、ELLEGARDEN(06年)を除けば一番多かったんじゃないかと思う。あと登場前からの歓声がすごかった。

観た感想は、うまく言えないけどただただ感動。さすが日本のロックレジェンド。「止まらないHA~HA」「時間よとまれ」などもろもろプレイして、念願のタオル投げも体験できた。これはまた改めて観に行きたい(リアルに)。

Broadway Calls (15:10~)

見逃した…

Nada Surf (16:20~)

90年代半ばにポストWeezerと呼ばれたバンドということで、気になって観てみた。完全に大好物のパワーポップなんだけど、1曲も聞いたことないからか、うーん…楽しめなかった。CD買うなり借りるなりしてじっくり聴きたいと思う。

Nickelback (16:55~)

このバンドも興味はあっても単独ではまず見ない部類なのでかなり楽しみだった。個人的神曲「Someday」を超期待して望んだんだけど…やらねぇ!(あとあと大阪ではやったと聴いて凹んだ)かろうじて「Photograph」はやってくれた。しかし…声しぶいなー。

The Offspring (18:10~)

海外Punkを聴くキッカケをくれた、高校時代の青春バンド。どれだけCDを聴いただろう…、2年前のsummersonic afterで一度観て今回は2回目。とにかく観客のモッシュ&ダイブ&サークルピットがすごかった印象(自分はもう引退した)
驚かされたのは1曲目「All I Want」からいきなり飛ばして、早くも2曲目に「Come out and Play」を持ってきたこと。これ前列体力もたねーだろ。。。後続も「Staring At The Sun」「Head Around You」「One Fine Day」と名曲オンパレードで(よくよく考えたら名曲多すぎてあんまり順番関係ないw)後半ついに「Pretty Fly」が飛び出して最高潮、ラストは「The Kids Aren’t Alright」で締めた。
全体的にAmericanaを中心にやってた印象だったな。それにしてもいつ観てもスゲー盛り上がりだ。

The Smashing Pumpkins (20:05~)

個人的1日目の大本命はスマパン!もはやイハもダーシーもジミーもいないけど、自分はビリーさえいれば十分スマパンです。新しいメンバーは、イハの代わり→うまいけど地味、ダーシーの代わり→タレ目で超カワイイ、ジミーの代わり→19歳!といった感じ。これは正式メンバー?
肝心のライブは、所々に名曲を織り交ぜながら、オフィシャルサイトで44ヶ月連続無料ダウンロード中の新曲を加えた構成だった。やっぱファンは正直で、昔の曲ほど盛り上がる。最近の曲は聴きこむ印象。個人的には「Today」のイントロで鳥肌がたった。あとラスト「tonight tonight」からアンコール「天使のロック」の流れに震えた。
知ってる曲&盛り上がる曲ははオフスプの方が圧倒的に多かったけど、とにかくもう2度と見れないと思ってた&初めてのスマパンが見れたことにただ感動した。ハマるのが遅かっただけに、今回のサマソニは本当最高のタイミング。
ちなみに当日のセットリストは以下の通り(SMASHINGPUMPKINS.JPさんより引用)

  1. Astral Planes
  2. Ava Adore
  3. Hummer
  4. As Rome Burns
  5. A Song for a Son
  6. Today
  7. Bullet with Butterfly Wings (wrong guitar) (tease)
    > Bullet with Butterfly Wings (tease)
    > Bullet with Butterfly Wings
  8. Eye
  9. United States
  10. Love Is the Sweetest Thing [Ray Noble]
  11. Owata
  12. 1979
  13. Stand Inside Your Love
  14. Tarantula
  15. Tonight, Tonight
  16. Cherub Rock

Pavement (22:30~)

初日のラストはローファイの王者Pavement。今年限りの再結成でスマパンの次に楽しみにしてた。終電が近づいてたので最初の30分だけだったけど、1曲目がまさかの「Cut Your Hair」でテンションめっちゃアガった。そしてこれは狙ったのかどうか分かんないけど「Shady Lane」をプレイ。スマパンとかあと誰だっけ?罵倒した曲。そういえばスマパンの時にビリーが「Pavementが(ゴニョゴニョ…)」みたいなことが聞こえたけど、まだ犬猿の仲なのか?
最後まで観れなかったけど大満足のライブでした。

2日目レポートに続く。

あんまり鍵が必要なsshログインをやらないので今後のためにメモ。
AmazonEC2とかNIFTY CloudとかのIaasサービスに.pemキーを使うケースは多いのかな?

とりあえず払い出された.pemキーを使って早速ログインを試みる

$ ssh -i [.pemキーのパス] [ユーザ名]@[サーバドメインorサーバIP]

怒られちゃった。。。

Permissions 0644 for '[.pemキー名]' are too open.
It is recommended that your private key files are NOT accessible by others.
This private key will be ignored.
bad permissions: ignore key: [.pemキー名]
Permission denied (publickey,gssapi-with-mic).

パーミッションが駄目らしい。あくまで個人的な話ですけど「Permissions」とワードが出た瞬間、いつものクセで文書まともに読まんと速攻権限追加を行っちゃう。ところが「755」も「777」も同様に怒られた。あれ?

よーく読んだら「みんなアクセスできるから権限をもっと下げろ」といってることに気づく。
なるほどです。とりあえず「600」にしてみたらすんなり通ったのでそのままいきます。

パーミッションネタ=権限追加 とすぐ認識するのってよくないすね。

JavaScriptで複数のHTMLElementを取得し、その全てにイベントを設定しようとした場合
意識していないと案外ハマりそうな落とし穴を見つけたのでメモ。
個人的には理由に気づくまで「???」だったんですが、よくよく考えると当たり前の事実。。。

サンプルに以下のHTMLを用意してみました

簡単な5つの画像を表示するHTMLがあるとします。
ただし、すべてデフォルトではloading画像が表示され、本来表示する画像ではありません。

<html>
<body>
<h1>HTMLCollectionとイベント同時処理テスト</h1>
<div>
    <img id="after1" name="replace" src="loading.gif" />
    <img id="after2" name="replace" src="loading.gif" />
    <img id="after3" name="replace" src="loading.gif" />
    <img id="after4" name="replace" src="loading.gif" />
    <img id="after5" name="replace" src="loading.gif" />
</div>
</body>
</html>

そこでJavaScriptからdiv要素の中にあるloading画像を本来の画像に差し替えます。
ここでは分かりやすいように、各ノードのid名と同じ.gifファイルがあるとします。
※かなり設定に無理がありますが大目に見てください。。。

var oldImgs = document.getElementsByName("replace");

for(var i=0,j=oldImgs.length; i<j; i++)
    replace(oldImgs[i]);

function replace(oldImg){
    var newImg = new Image();
    newImg.onload = function(){
        oldImg.parentNode.replaceChild(newImg, oldImg);
    };
    newImg.src = oldImg.id + ".gif";
}

この程度のものだったら特にエラー等は発生しませんが、
上記のコードでは差し替える画像の数が膨大であった場合、ブラウザによっては
任意のノードがreplaceChildされるタイミングでエラーになることがあります。
自分の場合はIE6で複数の外部サイトに置かれた画像20枚に差し替えたとき発生しました。
また、リロード(キャッシュクリア含む)では発生せず、
リンクからページを表示させた場合に発生するというものでした。
つまり、文法的には誤りがあるわけではなさそうです。

デバッグしていくと、どうやら引数で受け取るoldImg(差し替え対象のノード)に
ときたま「undefined」が混じっているようでした。
なぜにundefined?getElementsByTagNameで取り損ね発生?
いや、仮にそうだとしたら既に致命的なバグがあるとお祭り騒ぎだし、
実際にgetElementsByTagName単体で実行した場合、取りこぼしがない。。。
エラー原因となったreplaceChildを実行させなかった場合もundefinedが渡らない。

何が起きた?

ブラウザが搭載しているJavaScriptエンジンの速度差が関係していました。
上記サンプルで注目すべきは「onload」イベントで「ノード置換していた」事です。
この置換のタイミングが画像の取得完了をトリガーにしていて
場合によっては、メイン処理完了を待たずしてイベントが発生するケースがあります。

現在は激しいブラウザ戦争により日々JavaScriptの高速化が進み、
もしイベントを処理の前段で定義し、複雑なメイン処理がその後にあっても
イベント発生前にすべての処理が終わっていることが多いです。
しかし、IE6のような遅いエンジンでは、処理量やイベントの発生条件を定義した場所や内容によっては
順序が前後するケースが可能性として出てきます。

加えて、イベントから呼ばれる処理の中でDOM操作がある場合
メイン処理上にイベント内で操作されるノードもしくは関係の深いノードを
直接参照する記述にしていると、モロにDOM操作結果の影響を受けます。
上記サンプルの場合はoldImgsを直接のループ対象として取り扱っていた点がそれに当たります。
oldImgsの要素ノードがreplaceされたことで、同じnameを持つHTMLCollectionの数が
途中で変化したことになり、突如ループ中の添字に対応する要素ノードが合わなくなったわけです。

解決方法は至って簡単

要素が変化する恐れのある、いわゆる「動的な」ノードリストは直接処理対象としないことです。
つまり、影響を一切受けない「静的な」ノードリストに退避させ
添字に対応するノードの存在を担保することで確実に欲しいノードを手に入れることができます。
静的なノードリストとしての退避先としてはArrayが最適です。

一番簡単な方法は、テンポラリーなArrayを用意し、それを参照対象とすることです。

var oldImgs = document.getElementsByName("replace"),
    i, j = oldImgs.length, tmpImgs = [];

for(i=0; i<j; i++)
    tmpImgs[i] = oldImgs[i];

for(i=0; i<j; i++)
    replace(tmpImgs[i]);

function replace(oldImg){
    var newImg = new Image();
    newImg.onload = function(){
        oldImg.parentNode.replaceChild(newImg, oldImg);
    };
    newImg.src = oldImg.id + ".gif";
}

また、広く知られたJavaScriptのイディオムを使う方法もあります。
Arrayクラスのsliceメソッドが、引数省略時にまんまArrayにして返却する特性を利用する方法です。
JavaScript1.6以降であれば「Array.slice」のみで実行することができますが
それ以前のバージョンサポートを考慮し、従来の「Array.prototype.slice.call(またはapply)」
を使用したほうがいいです。この記法のメリットはワンライナーで書けることですが、
IEではエラーとなるため(厳密にはargumentsには使用でき、DOMノードリスト系は使用できません)
使用には注意が必要です。。。

var oldImgs = Array.prototype.slice.call(document.getElementsByName("replace"));

for(var i=0,j=oldImgs.length; i<j; i++)
    replace(oldImgs[i]);

function replace(oldImg){
    var newImg = new Image();
    newImg.onload = function(){
        oldImg.parentNode.replaceChild(newImg, oldImg);
    };
    newImg.src = oldImg.id + ".gif";
}

結論

動的なノードリストに関わる機会としては以下のケースが多いと思います。

  • getElementsByNameを使う → HTMLCollectionが返る
  • getElementsByTagnameを使う → HTMLCollectionが返る
  • childNodesを使う → NodeListが返る

もし実装途中に「これはもしかして?」と思ったときは、常時instanceofで確認し、
「HTMLCollection」と「NodeList」のどちらかに該当したら迷わずArrayに退避させて(変換して)
そちらをベースに処理するクセを身につけておくのがオススメです。

すでに周知の事実かと思いますが、少なくとも自分は知らなかったのでまとめ。

Web開発におけるクロスブラウザ問題は、jQueyやPrototype.jsなどのJSライブラリを使うことで簡単に吸収できます。しかし事情により、使用を極力控えたい場合があるかもしれません。

  • 1サイト複数開発会社体制(ルール決めとかないとエラいことになる)とか
  • Webマスターが知らない間にライブラリ依存のJSコードを別ページに流用とか
  • しかもWebマスターが頻繁に変わる(流用が忘れ去られる)とか

prototype拡張でクロスブラウザ対応するとしたら

よりラッピング前の記法に近く、よりオブジェクト指向的(JavaScriptは厳密にはprotoytpeベースのオブジェクト指向ですが)な書き方をするとしたら、やはりprototype拡張を上手に駆使することではないでしょうか。
よくある例としてイベントアタッチ部分のクロスブラウザ対応を例にしてみます。独自でDOMオブジェクトにラッパーメソッドを定義するとした場合、大体の方は既存のクラスに対してこのように拡張することを考えるのでは。

// DOMContentLoadedやwindow.onloadまでサポートする場合は
// トップレベルオブジェクト(Object)に定義が必要(速度は二の次で)
Object.prototype.bind = function(e, f){
    this.addEventListener ?
    this.addEventListener(e, f, false) :
    this.attachEvent("on"+e, f);
};
document.getElementById("hoge").bind("click", function(){
    alert("clicked");
});

当方IE6、IE8、Firefox3.6で確認しましたが、Firefoxはまぁ順当ですね普通に動きました。しかし、IE系は「bind?なにそれ」と怒られてしまいました。恐らくChrome、Safari、Opera当たりも基本的にECMA仕様にのっとっていますから動くでしょうね。つまりIEだけがおかしい。

ちなみにObject以外で拡張をしたらどうなるか。イベントアタッチ対象が<button>とした場合を例にツリーを徐々に下げて(Object.prototype.bindの部分を置き換えて)確認したところ、結果は以下の通りでした。

  • Object…メソッドコール時に怒られる
  • Node…そもそもNodeなんていないと怒られる
  • Element…そもそもElementなんていないと怒られる
  • HTMLElement…そもそもHTMLElementなんていないと怒られる
  • HTMLButtonElement…そもそもHTMLButtonElementなんていないと怒られる

…いない?いないとはどういう事か。仮にツリー構造の通りにクラス名定義がされていないとしても何かしら生成元は存在するはず。早速身元確認をしてみる。

//<button id="hoge">があるとして
var hoge = document.getElementById("hoge");

alert(typeof hoge); //=> "object"
alert(hoge.constructor); //=> "undefined"

一応自分はobjectだと言ってくれた。でも親御さんはいないと主張している。いったいキミはどこから来たんだ…。
取り敢えずわかったことは、既存クラスにprototype拡張をしてもIEは「いない」か「つながってない」と言われるらしい。

不本意だが解決策はある

以下の方法だったら一応動かすことはできる。

var hoge = document.getElementById("hoge");

// パターン1:call(もしくはapply)メソッドを経由する
Object.prototype.bind = function(e, f){
    this.addEventListener ?
    this.addEventListener(e, f, false) :
    this.attachEvent("on"+e, f);
};
Object.bind.call(hoge, "click", function(){
    alert("clicked");
});

// パターン2:関数化する
function bind(o, e, f){
    o.addEventListener ?
    o.addEventListener(e, f, false) :
    o.attachEvent("on"+e, f);
}
bind(hoge, "click", function(){
    alert("clicked");
});

すげー負けた気分になるのは僕だけでしょうか…。
もしもっとスマートな案があれば教えてください。