2012年10月31日水曜日

xmodmapでvimっぽくカーソル動かせるようにした

左手マウスのおすすめ
http://www.biwa.ne.jp/~chiro/kannkyou/mausu.htm
これを見て、試してみました。

気付いたことは
・左手は案外不器用で、軽いマウスだとなかなかポインタが定まらない
・これまでCtrlキーを常にインレンジにおさめていた左手が動くことで
 ショートカットキーを案外打ち損ねる
・右手をあまり動かさないようになると、思ったよりカーソルやPage Up/Down,Home/Endが
 遠く感じるようになる

特に最後のが結構意外で、結構右手首を小指側にぐっと曲げるような動きになってしまいます。

私はデスクのできる限り奥にモニタとキーボードを置き、
デスクの上に両肘をがっちりついてタイピングするのですが、
これまではマウスを動かすため右腕は頻繁に肘を浮かさざるを得ず、
そのためカーソルなどへも特に気にせず手を動かしていました。
ですが、右手の動きが減ると今度はそこが気になり、
しばらくすると少し右手首が痛くなってきてしまいました。

カーソルをvimっぽくhjklあたりで動かせればいいのにな…と思い、
xmodmapを書いてみました。

CapsLockを押しながらhjklでカーソル、
y/bをHome/End、u/nをPageUp/Downにしてみました。
間違って押すと鬱陶しいCapsLockも殺せて一石二鳥。

ついでに勢い余ってgにBackSpace,スペースバーにEnterまで割り当ててみたものが以下。

~/.Xmodmap
clear Lock
remove Control = Mode_switch
keycode 66 = Mode_switch
keycode 29 = y Y Home Home
keycode 30 = u U Prior Prior
keycode 42 = g G BackSpace BackSpace
keycode 43 = h H Left Left
keycode 44 = j J Down Down
keycode 45 = k K Up Up
keycode 46 = l L Right Right
keycode 56 = b B End End
keycode 57 = n N Next Next
keycode 65 = space NoSymbol Return
ちなみに一応書いておくと環境はUbuntu 12.10、英語キーボードです。

慣れたら相当快適なんじゃないかという予感を感じております。

#HHK使えばいいんじゃねとか禁止w

ちなみにエントリの趣旨的にもはやどうでもいいことですが
個人的にはマウスのボタンは入れ替えない方が使いやすく感じました。

2012年10月21日日曜日

Ubuntu 12.10入れた(VirtualBox編)

Ubuntu 12.10。

というわけでまずはメインの職場の開発環境であるVirtualBox (on Win7) に
クリーンインストールしてみた。

以前のバージョンまで、VirtualBoxのゲストでは3Dアクセラレータを有効にすると
フルスクリーンにした時に描画がフリーズしてしまうという現象が出てしまい、
(参照→ http://www.youtube.com/watch?v=WOLv-9VwcTc
Unity 2Dでしか使えず。
まあその後結局 xubuntu で使っている。
とりあえずインストールは普通に終了。
その後VirtualBox Guest Additionをインストールする必要があるが、
VirtualBox 4.1.22に付属のGuest Additionは、
Ubuntu 12.10のXの方がバージョンが新しいせいかインストールに失敗。

さてどうしようかなと思ったが、 何のことはなく
sudo apt-get install virtualbox-guest-additions
でOK。

そして問題のフルスクリーン。
一応フリーズはせずちゃんと動く…が。
重い。重いぞこれ。
とりあえずCompiz ConfigでFadingやAnimationを切って
何とかまあ許容できるかなというレスポンスになった。

そして次にランチャー。
画面は出来るだけ広く使いたくてランチャーは隠れていてほしいので
System SettingsのAppearanceのBehaviorタブで(私は英語でインストールしているので)で
Auto-hide the Launcherをonにした…ら、残念なことが。


ランチャーが非表示になったところの壁紙の色がおかしいまでなら全然構わないのだが、
そこにウィンドウを持っていったらその謎の帯の下に入ってしまうという残念な現象。
これは致命的。

というわけでさっさと諦めてxubuntuにする。さようなら新Unity。
色々新機能付いたLensとか見るまで行かなかったよ。

sudo apt-get install xubuntu-desktop
そしてXubuntuで再起動し、色々アプリをapt-get install。
それと私は開発用のIDEにはAptana Studio 3を使っているのでダウンロードして展開。
ランチャーに登録。同梱のアイコンを設定…


なんだこれ。
どうやらxpm形式の扱いがうまくいかなくなってる。
convert icon.xpm -resize 48x48 icon.png
変換したpngを割り当てればOK。

そして、仕事上Google Talkをよく使うため、Empathyを設定。
Empathyを起動し、アカウントを追加しようとしたところ、
こんなダイアログが表示される。


うん?

Empathyは、今回のUbuntuの目玉の一つである「ネットワークサービスアカウントの管理」に
関係していたはず。
ここの「Personal」の並びに「Online Accounts」というのがあったはずだが、それがない。
kupferでOnline Accounts打ってみるとアイコンは出るが、
やはり同じ画面に。

どうやらまあ要するにXubuntuだとだめ、という状態である模様。
ログアウトしてUbuntuで入りなおして設定したら、
Xubuntuの方でもEmpathyがちゃんと動いた。
まあ一度設定したらしばらく変更する事はないものなのでよしとする。

というわけでUbuntuというかXubuntu12.10。
特に何が変わった感じはしません。
そりゃXubuntuだしね。

変わったか?と思ったこととすれば、mozcの変換候補で
同音異議語に「用例」が出るようになってる。
これはありがたい。

あとXubuntuの壁紙はグラデーションの右下に○がいくつか並んでるようなものだけど
これはシンプルかつスタイリッシュでいいと思う。

以上、何かあんまり他の人の役に立たなそうなUbuntuインストール記。

2012年9月21日金曜日

PHPのarrayの入れ子を作るのに苦労して=&とunsetを使って何とかした話

PHPで、

こんな感じのDBから読んできたデータから、


こんな構造を作りたいなと思ったのです。

こんな感じかな。
<?php
//ここから
function row($type,$typeName,$value1,$value2){
    return array("type" => $type,
                 "typeName" => $typeName,
                 "value1" => $value1,
                 "value2" => $value2);
}
$rows = array(row(1,"あ","ABC","DEF"),
            row(1,"あ","AAA","BBB"),
            row(1,"あ","XXX","YYY"),
            row(2,"い","BEEF","PORK"),
            row(2,"い","COFFEE","TEA"),
            row(2,"い","MILK","COCOA"));
//ここまではサンプルデータを作っているところなので本題とは関係なし。
//データはソートはされているものとする。

$tree = array();    // $treeが最終的なルート配列オブジェクト
$prevType = null;   // Typeが変わったらこの処理をする…というためのもの
foreach($rows as $r){  //1行ずつ読む
    if($prevType !== $r["type"]){ //もしTypeが変わったら
        // 変更チェック用の変数を更新し
     $prevType = $r["type"];
        // 親のノードを新規作成し、$typenodeを差し替え
        $typenode = array("type" => $r["type"],
                          "typeName" => $r["typeName"],
                          "values" => array()); // 親のノードは子を格納する配列を持つ
        // 作った親のノードをルート配列に追加
        $tree[] = $typenode;
    }
    // 子のノードを作成
    $valuenode = array("value1" => $r["value1"],
                        "value2" => $r["value2"]);
    // 今の時点で $typenode で親ノードが参照出来るはずで、
    // それに対して"values"で引ける子ノード格納用配列に、
    // 子のノードを追加
    $typenode["values"][] = $valuenode;
}
実行してみた結果。
( ಠ益ಠ)
ステップ実行してみると、
        :
        // 作った親のノードをルート配列に追加
        $tree[] = $typenode;
    }
        :
    // 今の時点で $typenode で親ノードが参照出来るはずで、
    // それに対して"values"で引ける子ノード格納用配列に、
    // 子のノードを追加
    $typenode["values"][] = $valuenode;
}
この下の方の$valuenodeを追加しているところで、
「$typenode」には追加されるものの、
「$treeからたどれる『$typenodeと同じものであるはずのもの』」
には追加されているように見えない。
        $tree[] = $typenode;
で、$typenodeそのものがコピーされてしまっているように見える。
本当は違っててその後変更が発生しそうになった時にコピーされるんだろうけど。

なのでこうしてみた。=&で参照渡し的な何かになるはずと聞いて。
        $tree[] =& $typenode;
実行してみた結果。
(╬ಠ益ಠ)

今度は、二週目の
        // 親のノードを新規作成し、$typenodeを差し替え
        $typenode = array("type" => $r["type"],
                          "typeName" => $r["typeName"],
                          "values" => array()); // 親のノードは子を格納する配列を持つ
        // 作った親のノードをルート配列に追加
        $tree[] =& $typenode;
の上の方のところで「新しいノードを作って$typenodeを差し替えた」だけのつもりが、
既に一周目でセットした$tree[0]の要素までも差し替わってしまった。

参照渡し…ってそこまで参照なの!?
これ、そもそもマインドモデルが上の図と違ってて、模式図で表せない。

最終的にこうしたら何とかなった。
$tree = array();
$prevType = null;
foreach($rows as $r){
    if($prevType !== $r["type"]){
        $prevType = $r["type"];
        unset($typenode);
        $typenode = array("type" => $r["type"],
                          "typeName" => $r["typeName"],
                          "values" => array());
        $tree[] =& $typenode;
    }
    $valuenode = array("value1" => $r["value1"],
                        "value2" => $r["value2"]);
    $typenode["values"][] = $valuenode;
}
差し替える前にunsetをする事で、
$typenodeというシンボルと実体との紐付けが解放されるので、
あらためて作ったarrayをセットしても既存のデータ構造に影響を与えない。

なんだこの仕様。

array関数で新たに配列作って変数に代入する、って
「mallocしてそのポインタを返す」的な感覚かと思ってたら、
「返す先のポインタがあったら指している領域に上書きする」みたいな
日本語すら怪しくなるような動きもするとは。
理解に苦しむ。

2012年9月18日火曜日

mroongaのデータを壊してテーブルも消せなくなったのを何とかした風

先週末ハマった件のメモ書き。
これで合っているかどうか保証も何も全く無いので
参考にする場合は自己責任で。

mroongaをストレージモードで使った開発中、
安直な設計でテーブル作って膨大なデータのinsertクエリを実行してしまった。

全然戻ってこないのでクエリのキャンセルをしたのだがそれでも戻ってこず。
mysqldのrestartも実行したが戻ってこず。
仕方なくkill -9で抹殺。

その後再起動し、この設計じゃダメだなと思いdrop tableしようとしたら
drop tableも戻ってこない。

プロセスリストを見てみると
select count(*) into @discard from `information_schema`.`PARTITIONS`
というSQLをdebian-sys-maintが実行していて全然戻ってきていない。
こいつがロックしている線が濃厚。


当該のSQLやdebian-sys-maintでググってみると
「debian系のおせっかいだからスクリプトいじって黙らせちゃえよ」
みたいな記事が見つかるが、
それもなんだかイカン気がする。

やけくそでmysql止めて
/var/lib/mysql/【スキーマ名】.mrn.*
のファイルを全消しして
再起動してdrop tableしてみる。
瞬時にdisconnected from server的なメッセージが出て、
mysqldのプロセスIDが変わってる。
悪化/(^o^)\

repair tableとかあがいてみる。
「このエンジンはリペアとかないよ」的なメッセージが出る。

そこでふと、以前mysqlのバージョンだけ上がってmroongaプラグインが読み込めなくなって
mysqlの起動が出来なくなってヒイコラした時、
その後drop tableは普通にできたよなーという記憶が。

ということでUNINSTALL PLUGINして、dropしてみる。
…成功!


あらためてINSTALL PLUGINして、テーブル作ってまともな量insert。
無事動作している模様。


多分こうなった場合、
  1. UNINSTALL PLUGIN
  2. drop table
  3. mrnファイル削除
  4. INSTALL PLUGIN
  5. create table
とすればいいのかなという気がしているけど
実はまずいのかもしれない。不明。


やってみる場合自己責任で。

2012年8月6日月曜日

ubuntuでusermod -Gでやらかしてsudo出来なくなった場合

開発PCの/var/lib/mysqlの中のファイルをいちいちsudoせずに参照したくなった。
ubuntuのユーザ名はadmin。
mysqlグループでの権限追加して、自分もmysqlグループに入ればいいだろ。
$ sudo chmod g+rx /var/lib/mysql
$ sudo usermod -G mysql admin
ログアウトしてログイン。
$ cd /var/lib/mysql
よし入れた。
おっと、見たいのはこの中のデータベースごとのディレクトリ内。
$ cd db1
bash: cd: db1: Permission denied
おおっと、データベースごとのディレクトリにも権限を足さないといけない。
$ sudo chmod g+rx db1
[sudo] password for admin:admin is not in the sudoers file.  This incident will be reported.
?…!! やっちまった!

usermod -G は所属グループを上書きするので,
元々所属していたsudoグループから引っ剥がされてしまった!
もとい、引っ剥がしてしまった orz


まあまあ、ありがちありがち。
一度深呼吸して、PCをブチ切り再起動。

grubで[recovery mode]を選択して起動し、rootシェルを選択。
# mount -o rw,remount /
# usermod -G adm,cdrom,sudo,dip,plugdev,mysql admin
# reboot
再起動で復活。

後の方のusermod -G以降は、ほぼ同じ設定で立てていたVMから拾ってきたもの。
そういうのが無い方でやらかしてすぐだった方は
/etc/group- に直前の設定が残っているので
rootシェルで入ったあとすぐ参照して控えましょう。

複数回usermodやっちゃった方は南無。
でもとりあえずadmとsudoぐらい入っておけば何とかなるでしょう。

2012年6月18日月曜日

Wineで3Dなソフトがうまく動かないとき

普段使っているのはIntelのしょぼいグラフィックチップのPCなのだが
Windows用の3DなソフトをWineで動かしてみようとしたら
Unhandled page fault on read access
なんていうのが出た。

色々調べてみたところ、テクスチャの圧縮展開ライブラリ関係に問題があるらしい。
まあそりゃそもそもmesaドライバだしな。

libtxc-dxtn-s2tc というのを入れると改善するかも、とのこと。
sudo apt-get install libtxc-dxtn-s2tc-bin libtxc-dxtn-s2tc0
おお。魔法のようだ。

2012年6月17日日曜日

Win7でユーザのログインIDなどを変更する


Windows 7 は基本的にユーザの表示名が使われるようになっているので
表示名だけ変えれば普段は気にならないが、
リモートデスクトップなどで繋ぐ時に混乱の元になる。

リモートデスクトップで繋ぐ際に指定するユーザ名称を変更するには、
  管理ツール→コンピューターの管理


  コンピューターの管理→システムツール→ローカル ユーザーとグループ→ユーザー
を開き


  「名前」をクリックして変更。
基本的にはこれでOK。

ただしこれだとユーザフォルダの名前が古いままで若干気持ちが悪い。
ユーザフォルダの名称を揃えるには、別な管理者アカウントでログインし、
C:\Users\の下のフォルダ名称を変更した上で、
レジストリエディタで
  HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\ProfileList

の下の
  ProfileImagePath
の値をそれに揃えてやる事で、
次に該当ユーザでログインした際に辻褄が合う。 
この過程で、フォルダ名を変えようとして管理者アカウントでログインする時に
「ユーザの切り替え」をしてしまうと、元のユーザフォルダは使用中になっていて変更できないので
PCごと再起動する方がよい。

また、PCを再起動して別な管理者アカウントでログインしただけなのに
既に使用中になっていることもある。
自分の場合、Windows Media Playerのサービスがアクセスしていた。
 管理ツール→サービス
を開き、
 Windows Media Player Network Sharing Service
を「停止」させたところ、フォルダ名の変更ができた。

フォルダ操作をしようとしたときに「使用中です」となってしまう場合、
Unlocker を使うと何のプログラムがロックしているのか分かって便利。

2012年6月14日木曜日

ubuntuにapache-google-apps-ssoをインストール

https://github.com/epotocko/apache-google-apps-sso
ApacheのレイヤーでGoogle Apps認証かけちゃうというもの。
mod_auth_memcookieというモジュールとphpを使ってる。

まずapt関係で必要なものをゲット。
apt-get install memcached php5-memcache
apt-get install apache2-prefork-dev libmemcache-dev
次に、mod_auth_memcookieをビルド。
http://sourceforge.net/projects/authmemcookie/files/
からソースをDLし展開。
tar zf mod_authmemcookie_v1.0.2.tar.gz
cd mod_authmemcookie_v1.0.2
ubuntuの場合apxs2のインストールパスが違うので、Makefileを修正。
MY_APXS=/usr/sbin/apxs2
        ↓
MY_APXS=/usr/bin/apxs2
ビルド&インストール。
make
sudo make install
apacheのロードスクリプトを書く。
/etc/apache2/mods-available/auth_memcookie.load
#一行で書く
LoadModule mod_auth_memcookie_module /usr/lib/apache2/modules/mod_auth_memcookie.so
有効化。
sudo a2enmod auth_memcookie

引き続き、phpなどの設定。

/var/www/auth ディレクトリを認証モジュール用に使い、
その他サイト全体を認証の対象とすることにする。

https://github.com/epotocko/apache-google-apps-sso
の中のsrc/public直下のphpファイルと、src/GAppsディレクトリ自体を
/var/www/auth/下にコピー。
git clone https://github.com/epotocko/apache-google-apps-sso.git
cd apache-google-apps-sso/src
sudo mkdir /var/www/auth
sudo cp -rf GApps /var/www/auth/
sudo cp -rf public/* /var/www/auth/.
次にphp-openid。
12.04ならばaptで入れたものでもOKだった。
apt-get install php-openid
10.04だとバージョンが古くてうまく動かなかったので、公式から落としてきて
その中のAuthディレクトリを/var/www/auth/以下にコピーする。
git clone https://github.com/openid/php-openid.git
cp -rf php-openid/Auth /var/www/auth/
ここから下は https://github.com/epotocko/apache-google-apps-sso
公式の情報と基本的に同じ。

/var/www/auth/settings.phpファイルを更新。
コメントアウトされていない二行を編集。
GApps_Session::$BASE_URL = 'http://【ホスト名】/auth/'; //動かすホスト名
GApps_Session::$DOMAIN_NAME = '【Google Appsドメイン名】';
apacheの設定を書き足す。
default編集するなり、別ファイル作ってVirtualHostに入れるなり。
<IfModule mod_auth_memcookie.c>
    <Location />
        Auth_memCookie_CookieName GOOG_SESSIONID
        Auth_memCookie_Memcached_AddrPort 127.0.0.1:11211
        ErrorDocument 401 "/auth/login.php"
        Auth_memCookie_Authoritative on
        AuthType Cookie
        AuthName "GApps Login"
    </Location>
</IfModule>

<LocationMatch "^/(?!auth)">
    Require valid-user
</LocationMatch>
apache再起動。
sudo /etc/init.d/apache restart

2012年6月10日日曜日

gitで名前やメールアドレスを置換する

毎回調べてしまうので自分用メモ。
git filter-branch --commit-filter '
if [ "$GIT_COMMITTER_NAME" = "【修正前の名前】" ]; then
    GIT_AUTHOR_NAME="【修正後のAUTHORの名前】"
    GIT_AUTHOR_EMAIL="【修正後のAUTHORのメールアドレス】"
    GIT_COMMITTER_NAME="【修正後のCOMMITTERの名前】"
    GIT_COMMITTER_EMAIL="【修正後のCOMMITTERのメールアドレス】"
fi
git commit-tree "$@"
' HEAD

2012年6月9日土曜日

DjangoのURL namespacesのところを和訳した


https://docs.djangoproject.com/en/dev/topics/http/urls/#url-namespaces
何回流し読みしてもよく分からないので、和訳した。

URL namespaces
URL ネームスペース

Namespaced URLs are specified using the : operator. For example, the main index page of the admin application is referenced using admin:index. This indicates a namespace of admin, and a named URL of index.

ネームスペースに関連付けられたURLは、:演算子を使い表現されます。例えば、adminアプリケーションのメイントップページは admin:index で参照されます。これはadminネームスペースのindexと名付けられたURLを示します。

Namespaces can also be nested. The named URL foo:bar:whiz would look for a pattern named whiz in the namespace bar that is itself defined within the top-level namespace foo.

ネームスペースは入れ子にできます。 foo:bar:whiz というURL名は、それ自身がfooというトップレベルのネームスペース内に定義されているbarというネームスペース内のwhizと名付けられたパターンを指します。

When given a namespaced URL (e.g. myapp:index) to resolve, Django splits the fully qualified name into parts, and then tries the following lookup:

与えられたネームスペースに関連付けられたURL(例…myapp:index)を解読する場合、Djangoは完全記述された名称を要素単位に分割し、以下の検索を試みます。

1. First, Django looks for a matching application namespace (in this example, myapp). This will yield a list of instances of that application.

まず、Djangoは一致するアプリケーションネームスペースを探します(この例の場合myapp)。該当するインスタンスのリストが抽出されます。

2. If there is a current application defined, Django finds and returns the URL resolver for that instance. The current application can be specified as an attribute on the template context - applications that expect to have multiple deployments should set the current_app attribute on any Context or RequestContext that is used to render a template.

もしカレントアプリケーションが定義されていれば、Djangoはそのインスタンスに対するURLリゾルバを探して返します。カレントアプリケーションはテンプレートコンテキストの属性として特定されます。複数デプロイされる事が想定されているアプリケーションは、テンプレートをレンダリングする時に使われるContextおよびRequestContextにcurrent_app属性がセットされるべきです。

3. The current application can also be specified manually as an argument to the reverse() function.

カレントアプリケーションはreverse()関数の引数として明示的に指定も出来ます。

4. If there is no current application. Django looks for a default application instance. The default application instance is the instance that has an instance namespace matching the application namespace (in this example, an instance of the myapp called myapp).

もしカレントアプリケーションが指定されない場合、Djangoはデフォルトアプリケーションインスタンスを探します。デフォルトアプリケーションインスタンスとは、アプリケーションネームスペースと一致するインスタンスネームスペースを持つインスタンスです(この例の場合myapp、と呼ばれているmyappのインスタンス(訳注:namespace="myapp",app_name="myapp"という事ですかね))

5. If there is no default application instance, Django will pick the last deployed instance of the application, whatever its instance name may be.

もしデフォルトアプリケーションインスタンスが無い場合、Djangoは最後にデプロイされたアプリケーションのインスタンスを取り上げます。そのインスタンス名(訳注:インスタンスネームスペース名?)が何であれ。

If the provided namespace doesn't match an application namespace in step 1, Django will attempt a direct lookup of the namespace as an instance namespace.

もし与えられたネームスペースがステップ1のアプリケーションネームスペースにマッチしない場合、Djangoはインスタンスネームスペースであるとして直接検索を試みます。

If there are nested namespaces, these steps are repeated for each part of the namespace until only the view name is unresolved. The view name will then be resolved into a URL in the namespace that has been found.

もしネームスペースが入れ子になっている場合、ビュー名が解決されるまでネームスペースの各要素ごとにこれらのステップが繰り返されます。ビュー名は見つかったネームスペース内のURLとして解決されます(訳注:ここ適当。ここに限らないけど)。

To show this resolution strategy in action, consider an example of two instances of myapp: one called foo, and one called bar. myapp has a main index page with a URL named index. Using this setup, the following lookups are possible:

この解決手順を順を追ってお見せするため、例として2つのmyappのインスタンスを考えます。片方はfoo、もう片方はbarです。myappのトップページのURLにはindexという名前がついています。この設定に基づき、以下の検索が可能です。

・If one of the instances is current - say, if we were rendering a utility page in the instance bar - myapp:index will resolve to the index page of the instance bar.

もしどちらかのインスタンスがカレントならば…すなわち、barインスタンスのユーティリティページをレンダリングしていた場合、myapp:indexはbarインスタンスのトップページとして解決されます。

・If there is no current instance - say, if we were rendering a page somewhere else on the site - myapp:index will resolve to the last registered instance of myapp. Since there is no default instance, the last instance of myapp that is registered will be used. This could be foo or bar, depending on the order they are introduced into the urlpatterns of the project.

もしカレントインスタンスが無い場合…すなわちサイト内の何か別なページをレンダリングしていた場合…myapp:indexはmyappのうち最後に登録されたインスタンスに対して解決されます。デフォルトインスタンスが無いので、登録されたmyappの内最後のインスタンスが使われます。fooでもbarでも、プロジェクトのurlpatternsに登録された順に依存します。

・foo:index will always resolve to the index page of the instance foo.

foo:index は常にfooインスタンスのトップページとして解決されます。

If there was also a default instance - i.e., an instance named myapp - the following would happen:

もしデフォルトインスタンスもあった(インスタンス名がmyappとなっていた)場合、以下のようになります。

・If one of the instances is current - say, if we were rendering a utility page in the instance bar - myapp:index will resolve to the index page of the instance bar.

もしどちらかのインスタンスがカレントならば…すなわち、barインスタンスのユーティリティページをレンダリングしていた場合、myapp:indexはbarインスタンスのトップページとして解決されます。

・If there is no current instance - say, if we were rendering a page somewhere else on the site - myapp:index will resolve to the index page of the default instance.

もしカレントインスタンスが無い場合…すなわちサイト内の何か別なページをレンダリングしていた場合…myapp:indexは、デフォルトインスタンスのトップページとして解決されます。

・foo:index will again resolve to the index page of the instance foo.

foo:index はこの場合もfooインスタンスのトップページとして解決されます。

和訳したけど正直なところイマイチピンとこない。
とりあえずインスタンスネームスペースの方がアプリケーションネームスペースより粒度が小さい…という解釈でいいのだろうか。

2012年6月7日木曜日

Glipperがエラーで落ちまくるのを直す

Ubuntu 12.04 preciseにしてからなぜかGlipperがエラーで落ちまくっていた。

単に再インストールしたら直った。
sudo apt-get remove glipper
sudo apt-get autoremove
sudo apt-get install glipper

2012年6月4日月曜日

あるディレクトリ以下のファイルの拡張子の一覧を取得するワンライナー

find -type f | sed -e 's/^.*\([\.|\/].*\)$/\1/' | sort | uniq
拡張子無しの場合はファイル名を出す。ような動きになるはず。

こういうの書くときsedよりperl使うようにしようかなー。
perlの正規表現の方がメジャーだし。
いい思い出ないけど。

2012年5月31日木曜日

Vimで文字コード変更

MySQL4にEUCで入っているデータをUTF-8に変換しようとして、
mysqldumpでSQL出してnkfで文字コード変換した。

それを流し込んだところ、SQLの構文エラーが出る。
よく見てみたところ、SQL内の文字列の終わりのクォーテーションが無い。
(1,2,'あいうえお1かきくけ,'さしすせそ')
みたいになっている。

nkfの変換前のデータをあらためて調べてみると、
その部分にマルチバイト文字の前半がゴミとして挟まっていた。
(1,2,'あいうえお1かきくけゴミ','さしすせそ')
こんな感じ。
nkfだとそのゴミを直後のクォーテーションと絡めて消してしまうようだ。

さほど巨大ではないSQLだったので、Vimで変換した。
Vimで開き、
:e ++enc=eucjp-ms
:set fileencoding=utf8
:wq!
これでEUC→UTF-8に変換して保存できる。

該当箇所のゴミは「?」になるようだ。
(1,2,'あいうえお1かきくけ?','さしすせそ')

2012年5月26日土曜日

virt-managerでlibvirtdに繋ぐ場合

何も考えずにlibvirtdインストールして動かして、
そこにvirt-managerインストールして動かして接続しようとすると
Not Connectedの状態になって繋がらない。
でもsudoで動かすと繋がる。

そんな場合はユーザをlibvirtdグループに追加すればよい。
sudo usermod -a -G libvirtd 【自分のユーザ名】
設定したら一度ログアウトしてログインしなおす。

2012年5月21日月曜日

mysqldumpでlocalhostのポート指定

リモート環境のmysqlをsshポートフォワード経由でlocalhost:13306にマップして接続し、
ローカル環境のmysqlとスキーマ等の違いを確認するためにmysqldumpを使った。
manを見る限り、ポート番号は -P または --port= で指定出来ると書いてある。

mysqldump -h localhost -P 13306 -u XXX -p XXX -d --compact XXX > out.sql
そしてローカルのmysqlに対し同様に出したsqlと比較。

奇跡の完全一致。

そんなバカな。

ローカルのmysqlを停止させて実行してみる。
mysqldump: Got error: 2002: Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2) when trying to connect
やっぱり。

エラーメッセージからするに、ドメインソケットを使ってるっぽい。
-P 指定していてもお構いなしっていうのはどっちかというとバグなんじゃないのかな。

強制的にTCPを使用させればうまくいく。
mysqldump --protocol=TCP -h localhost -P 13306 -u XXX -p XXX -d --compact XXX > out.sql

2012年5月3日木曜日

mysql5.5のcharset指定

ubuntu 12.04のmysqlは5.5。

DBのデフォルトの文字コードをutf8にするのに前までは
/etc/mysql/conf.dの下に charset.cnf とか適当な名前で
[mysqld]
default-character-set=utf8
と書いていたけど、5.5だとエラーになってしまう。

[mysqld]

character-set-server=utf8 
に書き換える。

2012年4月28日土曜日

Ubuntu 12.04入れてみていくつか

Ubuntu 12.04入れてみました。
ネイティブで11.10が動いているもののアップグレードと、
VirtualBox上にクリーンインストールと。

気付いた点を何点か。

まず11.10からのアップグレードの方。
  • アップグレードの場合、まずパッケージファイルをダウンロードした後に
    一つずつインストールされていきますが、
    私の場合そのインストール中にウィンドウやランチャーなどが消え
    壁紙だけの状態になってしまいました。

    やむなく電源を落として再起動したところ、途中で固まってしまう状態に。

    解決策は、grubで古いカーネルのリカバリモードを選択して起動し、
    そこからdpkgを選択してインストールの続きを行うこと。
    設定ファイルが修正されていて、残すか上書きするかを聞いてきたりしたときは
    見づらいですが頑張って読みましょう。 
   それ以外は特になし。

次に12.04のクリーンインストールの方。
  • ランチャーをAuto hideにするとうまく動作しません。
    マウスカーソルを左端に持っていっても表示されません。
    http://ubuntuforums.org/showthread.php?t=1965991

    どうやらバグのようです(ちなみに11.10からアップグレードした方は普通に大丈夫)。
    修正を待ちましょう。
  •  フォントの変更がデフォルトではできません。
    gnome-tweakをインストールします。
  • こっちの環境では英語キーボードを使っていて、Alt+「`」でiBusのon/off切り替えをするのですが
    デフォルトだと「同じアプリ内のウィンドウのスイッチ」として動作してしまいます。
    1. System Settings...から
    2. [Keyboard]-[Shortcuts]-[Navigation]と辿り、
    3. [Switch Windows of an application]がデフォルトで[Disabled]となっているのですが、
      一度それに何か適当なショートカットキーを割り当て、削除します。
      これで解決。

  • 開発にAptana Studio 3を使っているのですが、
    ダウンロードして展開してaptana_studio_3を起動しても
    ランチャー上で固定できません。
    解決策として、
  1. alacarte を起動
  2. Programmingを選択して「New Item」をクリック
  3. メニュー項目の設定をして保存する
  4. dash homeから3.で作った項目を検索し、クリックして実行する
  5. ランチャーに出てきたアイコンを固定する
とするのが楽。

Ubuntuにmecab+groonga+mroongaをソースからインストール

Ubuntuにmecab+groonga+mroongaをソースからインストールする。

mroongaのサイトにある手順ではリポジトリ追加してapt-get install、で
それはもう簡単にインストールできたのですが
その後mysqlがアップデートされたらうまく動かなくなってしまったので
ひと通りソースからビルドしました。

以下はバイナリやライブラリは/usr/bin/,/usr/lib/など、
confは/etc/に配置する手順です。
  1. ビルドに必要なものをインストール
    sudo apt-get install build-essential
    sudo apt-get install libtool
    sudo apt-get install autoconf
    sudo apt-get install apt-src
    sudo apt-get install libmysqlclient-dev
  2. mecabをビルドしてインストール

    http://mecab.googlecode.com/svn/trunk/mecab/doc/index.html#download
    ここからのリンクでソースをゲット。
    今はmecab-0.993.tar.gzでした。
    tar zxf mecab-0.993.tar.gz
    cd mecab-0.993
    ./configure --prefix=/usr \
        --sysconfdir=/etc \
        --with-charset=utf8
    make
    sudo make install
    sudo ldconfig
  3. mecabの辞書をビルドしてインストール

    上のリンク先の「IPA辞書」をダウンロード。
    今はmecab-ipadic-2.7.0-20070801.tar.gzでした。
    tar zxf mecab-ipadic-2.7.0-20070801.tar.gz
    cd mecab-ipadic-2.7.0-20070801
    ./configure --prefix=/usr \
        --sysconfdir=/etc \
        --with-charset=utf8
    make
    sudo make install
  4. groongaをビルドしてインストール

    https://github.com/groonga/groonga/tags
    から、タグ振ってあるものをダウンロード。
    今回はgroonga-groonga-v2.0.1-0-g700532f.tar.gz
    というファイル名でダウンロードしました。
    tar zxf groonga-groonga-v2.0.1-0-g700532f.tar.gz
    cd groonga-groonga-4627bd1
    ./autogen.sh
    ./configure --prefix=/usr \
        --sysconfdir=/etc \
        --with-default-encoding=utf8
    make
    sudo make install
    sudo ldconfig
  5. mroongaをビルドしてインストール

    mysqlのソースをaptでゲット。
    apt-src install mysql-server
    今回はmysql-5.1-5.1.62というディレクトリにソースが落ちました。

    https://github.com/mroonga/mroonga/tags
    から、タグ振ってあるものをダウンロード。
    今回はmroonga-mroonga-v2.01-0-g8378adf.tar.gz
    というファイル名でダウンロードできました。
    tar zxf mroonga-mroonga-v2.01-0-g8378adf.tar.gz
    cd mroonga-mroonga-1bfcbe2
    ./autogen.sh
    ./configure --prefix=/usr \
        --sysconfdir=/etc \
        --with-mysql-source=$PWD/../mysql-5.1-5.1.62 \
        --with-mysql-config=/usr/bin/mysql_config \
        --with-default-parser=TokenMecab
    make
    sudo make install
  6. apparmorの設定を変更

    ubuntuではmysqldの動きはapparmorで制限されていて、
    このままではMecabの辞書もgroongaの設定ファイルも参照できないので、
    アクセス出来るように設定を追加します。

    以下の内容のファイルを作成します。
    /etc/apparmor.d/abstractions/mysql-server-mroonga
    /usr/lib/groonga/plugins/ r,
    /usr/lib/groonga/plugins/** rm,
    /etc/mecabrc r,
    /usr/lib/mecab/ r,
    /usr/lib/mecab/** r,
    以下のファイルに、追記します。
    /etc/apparmor.d/local/usr.sbin.mysqld
    #include <abstractions/mysql-server-mroonga>
  7. mysqlにプラグインを登録

    mysqlにログイン。
    mysql -uroot -p
    password:
    プラグイン登録。
    mysql> INSTALL PLUGIN mroonga SONAME 'ha_mroonga.so';
    funtionの登録。
    mysql> CREATE FUNCTION last_insert_grn_id RETURNS INTEGER soname 'ha_mroonga.so';
 以上で、動くようになりました。

この情報は2012/04/26頃の情報です。

2012年4月15日日曜日

2012年4月11日水曜日

ubuntu oneがうまくアップロードされなくなった場合(ubuntu)

以前のエントリでUbuntu OneのWindows版クライアントが
うまく動作しなくなった場合の対策を書いたが、
Ubuntuの方もファイルがあるのにうまくアップロードされていない、という現象がたまに起きる。

自宅で書いたサンプルコードをUbuntu Oneディレクトリ内にgit pushして、
翌日やる気満々で職場のPCでpullしてobjectファイルが無い、と出ると
かなり精神的ダメージがでかい。

Windows版の対策と同じような処理をするのは
こんなシェルスクリプトでいけそう。

u1refresh.sh
#!/bin/bash
u1sdtool -q
rm ~/.local/share/ubuntuone/syncdaemon/tritcask/*
u1sdtool --start

実行後しばらく待つと、再度同期が始まる。はず。

ご利用は自己責任で。

2012年4月8日日曜日

FireFoxをTLSv1で繋がせる

FireFox11.0でhttpsで通信すると、SSLv3で接続される。

何が問題かというと、
SSLサーバをVirtualHostでリバースプロキシしているところにアクセスしようとしたとき。
Client Helloの時にサーバ名が渡されないので、
アクセスしようとしているVirtualHostで設定している証明書が渡されず、
エラーとなってしまう。
ChromeだとOK。

サーバ側の設定で何とかできないか調べたけど結局良く分からない。
とりあえずWorkaroundとしてはこれ。
https://addons.mozilla.org/en-US/firefox/addon/force-tls/
Force TLSというアドオンを入れ、URLを設定する。
これでひとまずはエラーが出ないようになる。

2012年4月6日金曜日

Django+MySQL+Cast as SIGNED INTEGERでTruncated incorrect INTEGER valueでUnicodeEncodeErrorなところから逃げ延びる

Django+MySQLで、unicodeの全角文字と数字が混じった列のdistinctな一覧を
【数字の昇順】→「文字順」で取得したい。
単純に文字順にしてしまうのは 1,10,11,2,3,4 になるのでだめなパターン。

QuerySet APIの distinct はPostgreSQLでしかサポートされていないので、
DBのViewを書いた。

create view app_view1 as
select distinct col1,
    case when length(col1) = 0 then 0
                when cast(col1 as UNSIGNED INTEGER) > 0 then cast(col1 as UNSIGNED INTEGER)
                else 2147483647 end as sort
from table1

ちなみに本題とはあまり関係ないけどModelはこんな感じ。
class View1(models.Model):
    col1 = models.CharField(max_length=10,blank=True,primary_key=True)
    sort = models.IntegerField()
    class Meta:
        app_label="app"
        ordering=["sort","col1"]
        managed=False
文字はsortを十分に大きくしておいた上でsort昇順→col1昇順にすればいいはず。

MySQL Workbenchからだとゴキゲンに動作する。

実際に実行する。タイトルのような文字列を叫んで憤死する。

原因としては、実際にはMySQL内で実行した際にcastで「Truncated incorrect INTEGER value:'【文字列】'」というwarningが出ており、
それをMySQLdbモジュールが拾おうとしてしまって、【文字列】部分がUnicodeになっているせいでUnicodeEncodeErrorになるという
余計な事すんなよというもの。

何とかする方法を考える。
・MySQLdbをいじる(UnicodeEncodeErrorを吐かないようにする)→できればやりたくない
・Djangoをいじる(warningを拾わないようにする)→できればやりたくない
・継承で何とかする→djangoのdb backendを作れば何とか出来るんだろうができればやりたくない
・MySQLでWarningを出さないようにできないか→MySQL Suppress Warningとかでググる。死屍累々。
・あきらめてPython上で並べ替えをする→今回はいいがこんな感じので大量のデータに対してやろうとしたらどうするよ

SQLに立ち戻る。
要は数字だけ以外の場合に、CASTさえしなければよい。

MySQLにはREGEXPがあった。
create view app_view1 as
select distinct col1,
    case when length(col1) = 0 then 0
                when col1 REGEXP '^[[:digit:]]+$' then cast(col1 as UNSIGNED INTEGER)
                else 2147483647 end as sort
from table1

何とか逃げ延びた。

MySQLでSELECT時に連番生成

OracleでいうROWNUM()みたいなやつがやりたい。

アドホッククエリとしては、こうすればできるっちゃできる。
SELECT @rownum:=@rownum+1 rownum, t.* FROM (SELECT @rownum:=0) r, table1 t;

でもこれをViewにしようとしたら、MySQLはView内でサブクエリ使えない。

詰んだ。

2012年3月30日金曜日

Flash見ながらUbuntuのアップデートかけたら詰みかけた

昨日自宅でUbuntuを起動し、ニコ動を見ながら作業をしていたところ、
Update Managerが出てきました。

アップデートの内容としてはadobe-flashpluginとkernel。
何の気無しにアップデート開始したら、途中で固まってしまい。
あーやっぱりニコ動動かしっぱなしじゃだめかーと思いブラウザを閉じて
再度Updateを試みたものの、やはり途中で失敗。

再起動してやりなおすかと思い再起動したところ、無線LANが認識されない。
syslogを見てみると、全くモジュールが読み込まれていないように見える状態。
また、vimで開いて気付いたのはキーバインドがUS配列になっている事。
カーネルだけ入ってモジュールが入ってない状態になってしまた/(^o^)\

有線LANは認識されていたので、ルータに有線で繋いでアップデートの続きをしたところ、
全て無事復活。

無線の環境しか無い状態とか、有線LANポートが無いノートとかだったら詰んでたかも。
今思うと多分起動時に前のバージョンのカーネルで起動すれば大丈夫だったのかも知れないけど。

flashのアップデートがかかったときには、ブラウザは閉じましょう。

2012年3月28日水曜日

Zend_Db_Tableでinsert時に新しいidが返ってこなかったけど解決

Zend_Db_Table使ってるモデルクラスではinsertすると
新しく振られた主キーが帰ってくるという説明になっているが
なぜか0が返ってくる。

調べてみる。これだ。
http://www.refreshinglyblue.com/2008/11/03/zend_db_table-not-returning-last_insert_id/

渡す連想配列に"id" => nullを付けたらうまくいった。

2012年2月29日水曜日

Eclipseでウィンドウタイトルに出続けるプロジェクト名を消す

EclipseのNavigatorビューでプロジェクトを右クリックして「Open in New Window」とすると、
ウィンドウタイトルにそのプロジェクト名が表示されて
そのプロジェクトだけ開いた状態のEclipseが新たに開いて結構便利。

でもふと気付くと、Eclipseを閉じて、再度開くとそれがそのまま。
Navigatorで「up」や「back」としてもウィンドウタイトルは変わらず、
閉じて開いてもそのまま保存され続けます。
更にはそのプロジェクトをcloseして閉じて開くと、事もあろうかエラーダイアログまで表示してきます。

別なプロジェクトを「Open in New Window」するとそちらに移りますが、
なんとなくそれもそれですっきりしない。

さほど実害はないのですが、気分の問題でこれをデフォルトに戻したいと思って試してみた。

1.ワークスペース内の
  /.metadata/.plugins/org.eclipse.ui.workbench/workbench.xml
 をエディタで開く。

2.二箇所修正します。
  <page focus="true" label="【プロジェクト名】 - 【パースペクティブ名】">
  となっている部分を
  <page focus="true" label="">
  に修正。

  <input factoryID="org.eclipse.ui.internal.model.ResourceFactory" path="/【プロジェクト名】" type="4"/>
  の行を削除。

3.保存してEclipseを開きます。

開いた直後はちょっと微妙な感じ(自分の場合はPyDev Explorerにプロジェクトが何も表示されない状態になった)になるけど
Navigatorなどを表示したり色々したところ大丈夫そう。

やってみる時は全て自己責任で。

2012年2月28日火曜日

IBusの再起動

FreeMindをちょっと使ってみているが、何かするとすぐキー入力が効かなくなる。
以下のコマンドで
ibus-daemon -drx
IBusを再起動してやればまた通るようにはなるが…
何とかしないと使ってられないな。

2012年2月25日土曜日

Ubuntu 11.10で複数のGmailアカウントの着信通知

最近のUbuntuはUnityのメールのアイコンにIMやメール、Ubuntu Oneなどの機能がまとまっています。
gm-notifyというパッケージをインストールすることで
ここでGMailの着信通知を受けることも可能ですが、
gm-notifyの場合、1アカウントしか対応できません。

そのかわりgnome-gmail-notifierならば、複数のアカウントを設定する事が可能です。
が、その場合今度はインストールして実行しただけでは、アイコンが表示されません。

以下の手順で、アイコンが表示されるようになります、
1.まずはgnome-gmail-notifierをインストール。
sudo apt-get install gnome-gmail-notifier
2.シェルで以下を実行、
gsettings set com.canonical.Unity.Panel systray-whitelist "['all']"
3.自動起動の設定。
  右上のアイコンで「Startup Applications...」(英語モードなので)をクリックし、設定を追加。
  内容はこんな感じ。
4.ログアウトしてログイン。

あとはアカウントの設定を追加する。

Unity 2Dを使っている場合でアイコンが表示されない場合は、
gsettings set com.canonical.Unity.Panel systray-whitelist "['Gnome-gmail-notifier']"
として再度ログアウトとしてログイン。

2012年2月24日金曜日

Aptana Studio 3は結局イマイチ

Aptana Studio 3をスタンドアロンでインストールしたら
xdebugでのPHPがデバッグ出来なくて残念だったのですが。

Eclipseのプラグイン版もあったなーと思ってそれを入れてみたところ、
やっぱりデバッグできなくなってしまいました。
ブレークポイントで止まってくれません。
「先頭でデバッグ」は止まるのですがそれじゃどうにも。

coffeeとかlessのシンタックスハイライトだけ出来りゃいいんだけどなあ。

ちなみにプラグインをアンインストールしたらとりあえず元の状態に戻れました。
PHPのデバッグは出来るようになっても、なにやら起動時に
An internal error occurred during: "Loading bundle: /home/XXXXXX/.eclipse/org.eclipse.platform_3.7.0_155965261/configuration/org.eclipse.osgi/bundles/174/1/.cp/bundles/coffeescript.ruble".
(LoadError) no such file to load -- ruble/ui
とか出たりPreferencesの画面やメニューバー[Window][Help]のところに「Aptana」みたいなのが残って
とても気持ちが悪い。

以下、自己責任で。
1.Eclipseを終了。
2.ホームディレクトリ以下にある
 .eclipse/org.eclipse.platform_3.7.0_155965261/plugins
 以下の、「com.aptana」で始まるディレクトリを全消し。
3.Eclipseを起動。
4.落ちたらeclipseに関するプロセスが動いていないか確認して動いていたら殺す。
5.3に戻る

2012年2月12日日曜日

djangoのmodels.pyの分割

models.pyを分割してみた。

こんな感じのdjangoアプリがあるとして
+ [app]
    + models.py
    + views.py
    + その他
models.pyの中にはモデルクラスAaaとかBbbとかがあるとする。

こんな感じにしてみた。
+ [app]
    + [models]
        + __init__.py
        + Aaa.py
        + Bbb.py
    + views.py
    + その他

Aaa.py は普通にこんな感じに書くだろうとして、
# -*- coding: UTF-8 -*- 
from django.db import models

class Aaa(models.Model):
    name = models.CharField(max_length=50)

    class Meta(object):
        app_label = 'app'

__init__.pyはこう書けばこれはこれでいいっぽいんだけど
from Aaa import *
from Bbb import *

思いつきの開発中にモデルを色々こねくり回す事を考えると
ソースファイル作ったり消したりした後に
いちいち__init__.pyを直すのも面倒だなーと思い、
何とかならないか色々試行錯誤した挙句…。
__scope = locals()

def __modelLoader():
    import inspect
    import os
    curdir = os.path.dirname(__file__)
    for file in os.listdir(curdir):
        root,ext = os.path.splitext(file)
        if root[0] not in ['_','.'] and ext == ".py":
            obj = __import__(root,globals(),locals())
            for att in dir(obj):
                if att[0] not in ['_']:
                    attobj = getattr(obj,att)
                    if inspect.isclass(attobj):
                        __scope[attobj.__name__] = attobj

__modelLoader()
del __scope

とてもとてもうさんくさい。
配列外のlocals()の戻り配列に追加とか、アリなのか?

とりあえず、動いてはいるっぽい。
新しくCcc.pyを書き足してmanage.py syncdbすると新しくテーブルも作られた。

どう考えても、modelが固まったら普通にimportの列挙に替えるべき…。

2012年2月8日水曜日

Windows版Ubuntu Oneがうまく動かなくなった場合の対処法

ふと、Windows7にいれたUbuntu Oneがまともにファイルの同期をしてくれていない事に気付いた。
常駐プロセスなどを立ち上げ直してみてもダメ。

情報を探す。あった。
http://ubuntuforums.org/showpost.php?p=11495412&postcount=7

途中のパスがXP仕様なので、Windows7向けに書くと

1.タスクマネージャで「ubuntu」と入っているexeを全て終了させる。
2.C:\Users\【ユーザ名】\AppData\Local\xdg\ubuntuone\syncdaemon\tritcask にあるファイルを全消し。
3.Ubuntu Oneを起動する。

となる。
これでひとまず復活。

2012年2月4日土曜日

gitで過去を改ざんする(5/5)


ではgit rebaseでガッと行きます。
変更を施す一つ前のリビジョンを指定。
$ git rebase -i 40e910ba
こんなのがエディタで開きます。
pick f1cf7c1 途中まで(早春賦)
pick a5bdfe7 誤字を修正
pick b3d4dfa 歌詞を最後まで(早春賦)
pick 20899eb 途中まで(椰子の実)
pick fe623a8 レイアウトを修正
pick 85767e2 歌詞を最後まで(椰子の実)
pick 94fba12 作詞者を追加(早春賦)
pick 16d9acd 作詞者を追加(椰子の実)

# Rebase 40e910b..16d9acd onto 40e910b
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
こんなふうに変更して保存します。
edit f1cf7c1 途中まで(早春賦)
fixup a5bdfe7 誤字を修正
edit b3d4dfa 歌詞を最後まで(早春賦)
edit 20899eb 途中まで(椰子の実)
fixup fe623a8 レイアウトを修正
edit 85767e2 歌詞を最後まで(椰子の実)
edit 94fba12 作詞者を追加(早春賦)
fixup 16d9acd 作詞者を追加(椰子の実)
(以下略)
詳細はコメントになっている部分を読んでください。
fixupとしているものは、その上の行に混ぜ込まれます。
editは、コミットログを書き換えるためです。

保存するとこんなメッセージが出てきます。
Stopped at f1cf7c1... 途中まで(早春賦)
You can amend the commit now, with

 git commit --amend

Once you are satisfied with your changes, run

 git rebase --continue

--amendでコミットログを書き換えます。
$ git commit --amend -m "早春賦を途中まで"
[detached HEAD 79526ef] 早春賦を途中まで
 1 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 sousyunfu.txt
$
一旦終わったように見えますが、まだrebaseの途中です。
$ git rebase --continue
[detached HEAD 63992fe] 早春賦を途中まで
 1 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 sousyunfu.txt
Stopped at b3d4dfa... 歌詞を最後まで(早春賦)
You can amend the commit now, with

 git commit --amend

Once you are satisfied with your changes, run

 git rebase --continue
同様にやっていきます。
$ git commit --amend -m "早春賦を最後まで"
$ git rebase --continue
$ git commit --amend -m "椰子の実を途中まで"
$ git rebase --continue
$ git commit --amend -m "椰子の実を最後まで"
$ git rebase --continue
$ git commit --amend -m "作詞者を追加"
$ git rebase --continue
一番最後にこう出ます。
Successfully rebased and updated refs/heads/work_3.
$



Eclipseで見てみると…
出来上がりです!
ORIG_HEADの枝はこの後mergeか何かすれば動いて消えるので、気にしなくてもOKです。



おっと、ブランチ名がwork_3では格好がつかない。
$ git branch -m work_3 master



完了。

gitで過去を改ざんする(4/5)


分割したので、次は結合していきます。
目的の形に結合しながら作っていく事もできますが、
まずcherry-pickを使ってまず並べ替えてしまう事にします。



スタートはこの状態。(3/5の最後の状態)
40e910ba「初期コミット」からbranchを作ります。
(0b291edf「途中まで(早春賦)」からでもいいですが)
$ git branch work_3 40e910ba
$ git checkout work_3



cherry-pickしていきます。
$ git cherry-pick 0b291edf
[work_3 f1cf7c1] 途中まで(早春賦)
 1 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 sousyunfu.txt
こんなことになりますが気にせずcherry-pickしていきます。
$ git cherry-pick 36e6ca31
[work_3 a5bdfe7] 誤字を修正
 1 files changed, 1 insertions(+), 1 deletions(-)

$ git cherry-pick eccb4de3
[work_3 b3d4dfa] 歌詞を最後まで(早春賦)
 1 files changed, 2 insertions(+), 0 deletions(-)
途中経過。



「作詞者を追加」はおいておいて、椰子の実の方をcherry-pick。
$ git cherry-pick 8eb28748
[work_3 8e9bf2c] 途中まで(椰子の実)
 1 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 yashinomi.txt

$ git cherry-pick dcf7a7f6
error: could not apply dcf7a7f... レイアウトを修正
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add ' or 'git rm '
hint: and commit the result with 'git commit'
おおっと。
椰子の実

<<<<<<< HEAD
名も知らぬ 遠き島より
流れ寄る 椰子の実一つ
=======
名も知らぬ遠き島より
流れ寄る椰子の実一つ
故郷の岸を離れて
汝はそも波に幾月
>>>>>>> dcf7a7f... レイアウトを修正
きちんと修正。
椰子の実

名も知らぬ遠き島より
流れ寄る椰子の実一つ
保存してaddしてcommit。
$ git add yashinomi.txt
$ git commit -m "レイアウトを修正"
[work_3 fe623a8] レイアウトを修正
 1 files changed, 2 insertions(+), 2 deletions(-)

$ git cherry-pick 17293681
error: could not apply 1729368... 歌詞を最後まで(椰子の実)
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add ' or 'git rm '
hint: and commit the result with 'git commit'
また失敗。
行の末尾に改行が入っていなかったのが問題だったかな。

直す。
椰子の実

名も知らぬ遠き島より
流れ寄る椰子の実一つ
故郷の岸を離れて
汝はそも波に幾月
addしてcommit。
$ git add yashinomi.txt
$ git commit -m "歌詞を最後まで(椰子の実)"
若干ゴタゴタしましたがこんな形に。



作詞者も追加。
$ git cherry-pick 667a4a79
$ git cherry-pick 670d4aff
こうなった。



確認。
$ git diff master
OK。
これで並べ替え完了。



要らないブランチを削除。
$ git branch -d work_1
$ git branch -d work_2
masterも一旦削除。
$ git branch -d master

少しゴニョゴニョしているのでORIG_HEADがうろうろしているのは無視してください。

つづく。

gitで過去を改ざんする(3/5)


次は「歌詞を最後までと作詞者を追加、を1ファイルずつにわけつつ歌詞と作詞者も別に」をやります。
基本的にやることは一緒ですが、歌詞の追加と作詞の追加を別コミットにするためにgit addで-pオプションを使います。



「歌詞を最後までと作詞者を追加」をwork_2ブランチとします。
$ git branch work_2 6c25eb04
$ git checkout work_2



同様にreset。
$ git reset 8eb28748
ORIG_HEADが移動した事で紐付けが無くなったブランチは非表示になりました。



ここで、git add を -pオプション付きで実行します。
$ git add -p sousyunfu.txt
diff --git a/sousyunfu.txt b/sousyunfu.txt
index bd56e50..6b6961a 100644
--- a/sousyunfu.txt
+++ b/sousyunfu.txt
@@ -1,4 +1,7 @@
 早春賦
+吉丸一昌
 
 春は名のみの 風邪の寒さや
 谷の鶯 歌は思えど
+時にあらずと 声も立てず
+時にあらずと 声も立てず
Stage this hunk [y,n,q,a,d,/,s,e,?]? 
この作詞者と歌詞の部分を分けたいので、sを入力します。
Stage this hunk [y,n,q,a,d,/,s,e,?]? s
Split into 2 hunks.
@@ -1,4 +1,5 @@
 早春賦
+吉丸一昌
 
 春は名のみの 風邪の寒さや
 谷の鶯 歌は思えど
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? 
何となく先に歌詞の方をaddしたいので、nを入力します。
Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]? n
@@ -2,3 +3,5 @@
 
 春は名のみの 風邪の寒さや
 谷の鶯 歌は思えど
+時にあらずと 声も立てず
+時にあらずと 声も立てず
Stage this hunk [y,n,q,a,d,/,K,g,e,?]? 
ここをaddしたいので、yを入力します。
Stage this hunk [y,n,q,a,d,/,K,g,e,?]? y

$



commitします。
$ git commit -m "歌詞を最後まで(早春賦)"
こうなります。

diffはこうなります。
歌詞の部分だけがコミットされました。



残りの作詞の部分をコミットします。
$ git add sousyunfu.txt
$ git commit -m "作詞者を追加(早春賦)"



もう一方も同様に。
$ git add -p yashinomi.txt
(略)
$ git commit -m "歌詞を最後まで(椰子の実)"
$ git add yashinomi.txt
$ git commit -m "作詞者を追加(椰子の実)"
こうなりました。



またrebaseします。
$ git checkout master
$ git rebase work_2

ひとまず分割は完了。

gitで過去を改ざんする(2/5)


まず今のヒストリーの中で、必要なところを分解したブランチを作成してみます。

分解する必要があるのは以下。
・途中まで、を1ファイルずつに
・歌詞を最後までと作詞者を追加、を1ファイルずつにわけつつ歌詞と作詞者も別に

やっていきましょう。

「途中まで」をwork_1ブランチに分割し、チェックアウト。
$ git branch work_1 e444489f
$ git checkout work_1
Eclipseの画面で見るとこんな状態。



git resetで、「『途中まで』のコミットをする直前の状態」に時間を巻き戻します。
$ git reset 40e910ba
Eclipseの画面で見るとこんな状態になります。
ディレクトリツリーはこうなって、ファイル追加前の状態になっています。
ファイルもこの通り「途中まで」の内容のままです。



一つずつコミットしていきます。
$ git add sousyunfu.txt
$ git commit -m "途中まで(早春賦)"
こんな状態になります。



もう1ファイルもコミット。
$ git add yashinomi.txt
$ git commit -m "途中まで(椰子の実)"
こうなりました。



この状態でe444489f「途中まで」と 8eb28748「途中まで(椰子の実)」は全く同じ内容になっているはずです。
確認方法はこう。
$ git diff e444489f 8eb28748
何も出なければ、差異なし。



さてここで、今のmasterを8eb28748「途中まで(椰子の実)」(=work_1)から959f5666「歌詞を最後までと作詞者を追加」に繋がった形にしてみます。
まずは今いる位置をwork_1からmasterに移動します。
$ git checkout master
こうなります。HEADがmasterの位置に来ます。



そして、git rebaseを実行。
$ git rebase work_1
First, rewinding head to replay your work on top of it...
Applying: 途中まで
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
Applying: 歌詞を最後までと作詞者を追加
Applying: 誤字を修正
Applying: レイアウトを修正
$
これでこんな事になります。

つづく。

gitで過去を改ざんする(1/5)

過去を改ざんしてみる。

サンプルのリポジトリの初期状態はこんな感じ。


それぞれ状態はこんな感じ。
リビジョン(コメント)sousyunfu.txtyashinomi.txt
初期コミット
.projectファイル(特に意味はない)
途中まで
早春賦

春は名のみの 風邪の寒さや
谷の鶯 歌は思えど
椰子の実

名も知らぬ 遠き島より
流れ寄る 椰子の実一つ
歌詞を最後までと作詞者を追加
早春賦
吉丸一昌

春は名のみの 風邪の寒さや
谷の鶯 歌は思えど
時にあらずと 声も立てず
時にあらずと 声も立てず
椰子の実
島崎藤村

名も知らぬ 遠き島より
流れ寄る 椰子の実一つ
故郷の岸を離れて
汝はそも波に幾月
誤字を修正
早春賦
吉丸一昌

春は名のみの 風の寒さや
谷の鶯 歌は思えど
時にあらずと 声も立てず
時にあらずと 声も立てず
レイアウトを修正
椰子の実
島崎藤村

名も知らぬ遠き島より
流れ寄る椰子の実一つ
故郷の岸を離れて
汝はそも波に幾月

これを最終的にこんな風にしてみようと思います。
リビジョン(コメント)sousyunfu.txtyashinomi.txt
初期コミット
.projectファイル(特に意味はない)
早春賦を途中まで
早春賦

春は名のみの 風の寒さや
谷の鶯 歌は思えど
「途中まで」+「誤字を修正」
早春賦を最後まで
早春賦

春は名のみの 風の寒さや
谷の鶯 歌は思えど
時にあらずと 声も立てず
時にあらずと 声も立てず
「歌詞を最後までと作詞者を追加」+「誤字を修正」ー作詞者
椰子の実を途中まで
椰子の実

名も知らぬ遠き島より
流れ寄る椰子の実一つ
「途中まで」+「レイアウトを修正」
椰子の実を最後まで
椰子の実

名も知らぬ遠き島より
流れ寄る椰子の実一つ
故郷の岸を離れて
汝はそも波に幾月
「歌詞を最後までと作詞者を追加」+「レイアウトを修正」ー作詞者
作詞者を追加
早春賦
吉丸一昌

春は名のみの 風の寒さや
谷の鶯 歌は思えど
時にあらずと 声も立てず
時にあらずと 声も立てず
椰子の実
島崎藤村

名も知らぬ遠き島より
流れ寄る椰子の実一つ
故郷の岸を離れて
汝はそも波に幾月
作詞者を追加

続く。

2012年2月1日水曜日

mysqldump使って特定の行をinsert文の形で取り出す

単なるmysqldumpの使い方メモ。

誤って消してしまったデータを別なサーバに復元したバックアップからピンポイントで戻すために使う。

mysqldump -u【ユーザ】 -p【パスワード】 【スキーマ名】 【テーブル名】 --compact -t "--where=【where句】"

パイプで繋いで、mysqlコマンドで戻し先に直接突っ込むもよし。

2012年1月7日土曜日

Djangoで起動時にCoffeeScriptとLessのコンパイルをする

書いてみた。

どう書くのが作法的に良いのかはよく分かっていないが
Djangoのアプリケーションディレクトリの__init__.pyに書いて
それなりに動いたのでよしとする。

.coffeeと.lessは、アプリケーションディレクトリ以下 static/js および static/css にあるとする。

# myapp/__init__.py
import os
import os.path as path
import glob

staticpath = path.join("myapp","static")

def buildCoffee():
    curpath = path.abspath(os.curdir)
    dirpath = path.join(staticpath,"js")
    os.chdir(dirpath)
    for cfile in glob.glob("*.coffee"):
        cmtime = os.stat(cfile).st_mtime
        jsname = path.splitext(cfile)[0] + ".js"
        jmtime = os.stat(jsname).st_mtime if path.isfile(jsname) else 0
        if jmtime < cmtime:
            os.system("coffee -bc " + cfile)
            print ("compiled: " + cfile)
        else:
            print ("skipped: " + cfile)
    os.chdir(curpath)

def buildLess():
    curpath = path.abspath(os.curdir)
    dirpath = path.join(staticpath,"css")
    os.chdir(dirpath)
    for lfile in glob.glob("*.less"):
        lmtime = os.stat(lfile).st_mtime
        cssname = path.splitext(lfile)[0] + ".css"
        cmtime = os.stat(cssname).st_mtime if path.isfile(cssname) else 0
        if cmtime < lmtime:
            os.system("lessc " + lfile + " > " + cssname)
            print ("compiled: " + lfile)
        else:
            print ("skipped: " + lfile)
    os.chdir(curpath)
   
buildCoffee()
buildLess()
一応.coffeeおよび.lessファイルと、コンパイル済みの.jsと.cssの更新日付を見て
更新されてる時だけ再コンパイルするようにしてる。

UbuntuにCoffeeScriptとLessのコンパイラをインストール

何の大したこともなく。

sudo apt-get install nodejs npm
sudo npm install coffee-script
sudo npm install less
npmからsudoはやめろーと言われるけどしょうがない。

Ubuntu 11.10にAptana Studio 3をインストール

Aptana Studio 3を入れてみた。

まずはダウンロード。
http://aptana.org/products/studio3/download
一番下の「DOWNLOAD APTANA STUDIO 3」をクリック。

解凍。/opt以下に配置する。
cd /opt
sudo unzip ~/Download/Aptana_Studio_3_Setup_Linux_x86_3.0.7.zip
64bitの場合はファイル名が変わると思われる。

このまま/opt/Aptana Studio 3/studio3 を起動すれば動くけど
一部の機能を実行させると例外吐いて落ちる。
xulrunnerが入っていないからなのだが、ubuntuのリポジトリからは既に消えているので
wget -O xulrunner.deb http://launchpadlibrarian.net/70321863/xulrunner-1.9.2_1.9.2.17%2Bbuild3%2Bnobinonly-0ubuntu1_i386.deb
sudo dpkg -i xulrunner.deb
でインストールする。
64bitの場合は一行目は
wget -O xulrunner.deb http://launchpadlibrarian.net/70321329/xulrunner-1.9.2_1.9.2.17%2Bbuild3%2Bnobinonly-0ubuntu1_amd64.deb
こうっぽい。


OpenJDKでもちゃんと動いた。


ついでに、メニューに追加する。
Unity使ってるなら起動してクリックで固定でなんとでもなるんだろうけど
自分はlubuntuなので。
.desktopファイルを手で作るのも面倒なのでメインメニューツールで。
でもクリーンインストールだとalacarteが入っていない。その場合は
apt-get install alacarte
でOK。

こんな感じ。アイコンは解凍したディレクトリ以下のicon.xpmを指定。