iMacのトラブルを解決したい

最近家ではWindows機をほとんど使用しなくなり、二年前位に購入したiMacを使い続けています。
いつものようにスリープ状態から復帰しようとすると、まったく反応がなくなってしまいました。
こんなことは珍しいことではないので、後ろにある電源ボタンを長押しして再起動をかけました。
すると、、、、

の画面のままOSが起動してきません。
りんごのマークの下の丸いindicatorが止まっています。普段はぐるぐると回っています。
10分以上放置しても起動しないし、何度再起動しても同じ所で止まります。


とりあえず、Appleのサポートサイトで検索してみると以下が一番近い事象のように思えます。

Mac OS X v10.6:起動時にグレーの進行状況バーがアップルロゴの下に表示される

http://support.apple.com/kb/TS3148?viewlocale=ja_JP


どうやらHDDに原因があるみたいなので、ディスクユーティリティを試すことにしました。

ディスクユーティリティを試す
1. Mac OS X Install Disc から起動する/インストールディスクを挿入して、「C」キーを押しながらコンピュータを再起動します。
2. コンピュータがディスクから起動したら、インストーラの「ユーティリティ」メニューの「ディスクユーティリティ」を選択します。
   (Mac OS X 10.4 以降では、お使いの言語を最初に選択してください)。
   重要:インストーラの最初の画面で「続ける」をクリックしないでください。クリックすると、再度ディスクから起動してディスクユーティリティにアクセスしなければなりません。
3. 「First Aid」タブをクリックします。
4. ハードドライブアイコンの左側にある三角アイコンをクリックし、ハードディスクのボリュームとパーティションの名前を表示します。
5. お使いの Mac OS X ボリュームを選択します。
6. 「修理」をクリックします。ディスクユーティリティによりディスクがチェックされ、修復されます。

http://support.apple.com/kb/TS1417?viewlocale=ja_JP


ところが、ディスクユーティリティを使用してチェックしても問題は発見されません。
Windowsの自作機であれば、さっさとDISKを交換するのですが、ネットで検索したところiMacは敷居が高そうですね。

落胆して、最後に起動DISKを抜き取って再起動したところ、何事も無かったかのように起動するようになりました。何故?
暫くTimeMachineでバックアップをとりつつ様子をみたいと思います。


次回の購入時、AppleCareには入ろうと思いました。
購入後一年以内なら後から購入できますし、ハードディスク交換となった場合でも自宅まで取りに来てくれるらしいので
購入しなかったのが悔やまれます。。。。

勉強会に参加してきて

先日念願のJenkins勉強会に参加してきました。
受付で「懇親会に参加しない人はそのまま席についてくださ〜い」と言っていたので
そのまま受付を素通りし、どこに座ろうかなと席探している途中で川口さんを見かけました。
向こうは知らない顔だろうけど、こっちはよく知っている顔だったので反射的に挨拶をと思い、
「こんにちは〜」と挨拶をしたら「こんにちは〜」と返してもらえました。
挨拶終わったあとで「もう19:00だろうに『こんにちは』ってどうよ?」と自問自答しながら、
川口さんの座っている席の右後方へ座りました。いま考えると会場は80名ぎりぎりくらいの席数で
立ち見など居なかったものの、最終的にはほとんどの席が埋まっていました。
ここはチャンスとばかりに川口さんの隣に座って、いろいろ世間話でもすれば良かったのにと後悔。。。


会場全体の人々をみて思ったのは、、、

  • NotePC携帯率が高い。そしてMacBook多い。
  • 7対3くらいの割合で私服が多い。(スーツ姿少数派)
  • なんかうまく言い表せない独特の雰囲気。。。(←なんだそりゃ)


前の日記にも書いたとおり、「LL言語使ってないのになぁ〜」と思っていたのですが、
途中で勉強会参加登録時のアンケートについて[twitter:@cactusman]さんから一言あり、
今回の参加者は60/80位の割合でJavaでJenkinsを利用しているとのこと。
「ほ〜っ」としました。


今回の発表は川口さんも含め全員で6名だったのですが、皆さん慣れているというか、
とてもスムーズで聞きやすかったと思いました。
プログラムはhttp://kokucheese.com/event/index/10622/に概要が書かれています。
個人的に気になったのは、三番目の発表の
「これで君のインテグレーションは――始まりも、終わりもなくなった」〜RailsプロジェクトでふつうにJenkins 〜」で、
開発スタイルについて少し触れられているのですが、IRCをコミュニケーションツールとして使用して
Jenkinsのビルド結果などもボット経由で送られるように設定し、開発者がIRCに流れてくる情報だけに集中していれば
仕事ができるようになっている環境というものがいいな〜って感じました。
ひょっとして、参加した方々はみんなそんな環境で開発しているのだろうか。。。。うちでも出来るだろうか。



そうそう! 川口さんの発表の内容がSlideShareにて共有されています。
http://www.slideshare.net/kohsuke/rubyjenkins


心残りは懇親会に参加できなかったことですね。
用事の調整がつかなくて。。。
次回は懇親会にも参加してみたいと思います。

勉強会に参加したい

本日、念願のJenkins勉強会に参加できる予定です。
http://kokucheese.com/event/index/10622/


今回のテーマはLL言語プロジェクトにおけるJenkinsの運用について」
とのこと。。。わたし自身はLL言語のプロジェクトに関わったことがないのですが、ネタも体験談も提供できるはずもなく、
貴重な枠を1つ消費してしまって、たいへん恐縮に思っていたりします。。。。


後日、感じたことなど報告できたらと思います。

Groovyでテーブルのデータを取得したい(6)

取るに足らないことなんですが、同じようなことで未来も躓きそうなので。


SafeArrayを作成して、for文でぐるぐる回すところなのですが、

  for(r in rows){
      if(1==rowNumber){
          r.each{ safeArray.putAt([rowNumber,colNumber++],it.key) }
          rowNumber++
      }
      colNumber = 1
      r.each{
          if( it.value instanceof oracle.sql.TIMESTAMP )
              it.value = sdf.format(it.value.dateValue())
           safeArray.putAt([rowNumber,colNumber++],it.value)
      }
      rowNumber++
  }

の、

    if( it.value instanceof oracle.sql.TIMESTAMP )
        it.value = sdf.format(it.value.dateValue())

がどうしても綺麗にしたくて。。。
かと言ってOracleのTimeStamp型をやめるわけにもいかず。。。


でmetaClassにメソッドを動的に追加して、for文の中では追加したメソッドを実行すれば良いのではという
発想で書き直したのが以下のコードです。

import java.text.SimpleDateFormat
import org.codehaus.groovy.scriptom.ActiveXObject
import org.codehaus.groovy.scriptom.SafeArray
def sql = groovy.sql.Sql.newInstance('jdbc:oracle:thin:@localhost:1521:ORCL','userid','password','oracle.jdbc.driver.OracleDriver')
def xlApp = new ActiveXObject('Excel.Application')
def username = "INIT"
def workbook = xlApp.workbooks.Add
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
oracle.sql.TIMESTAMP.metaClass.toString = {sdf.format(delegate.dateValue())}
sql.eachRow("SELECT table_name FROM user_tables WHERE table_name LIKE 'BIZ_AB_%'"){ rs->
    def rows = sql.rows("SELECT * FROM " + rs.table_name +" WHERE create_user_cd ='" + username + "'")
    if( rows.size() > 0 ){
        def worksheet = workbook.worksheets.Add
        worksheet.name = rs.table_name
        def (long rowNumber, long colNumber) = [1,1]
        SafeArray safeArray = new SafeArray(org.codehaus.groovy.scriptom.SafeArray.VARIANT,1..rows.size()+1,1..rows[0].size())
        for(r in rows){
            if(1==rowNumber){
                r.each{ safeArray.putAt([rowNumber,colNumber++],it.key) }
                rowNumber++
            }
            colNumber = 1
            r.each{ safeArray.putAt([rowNumber,colNumber++],it.value.toString())}
            rowNumber++
        }
        worksheet.Range(worksheet.cells(1,1),worksheet.cells(rows.size()+1,rows[0].size())).Value = safeArray
    }
}
xlApp.visible = true


思ったとおり、速度的には早くなってませんが「綺麗」にはなっています^^;
Groovyで実装したクラスだけでなく、ライブラリのクラス(ここではoracle.sql.TIMESTAMP)に
対しても拡張できるところがすごいですね。(バージョン1.6以降らしいですけど)

Groovyでテーブルのデータを取得したい(5)

先日の日記で、SafeArrayを使用してスクリプトの時間短縮にチャレンジしたのですが、
まだまだ時間がかかるため、もっと改良できないかと思案中。。。


ただ、SafeArrayのコンストラクタには2次元以上の配列を受け取るものが存在しないので
無理なのかと思っていたのですが、putAtというメソッドを発見しました。
http://groovy.codehaus.org/modules/scriptom/1.6.0/scriptom/apidocs/org/codehaus/groovy/scriptom/SafeArray.html

第一引数、第二引数ともにObject型をとりますが、第一引数には行列を表すリストを指定できます。(←いろいろ試してみた結果)
第二引数には、設定したい値を指定します。
putAtで行列データを挿入していくためには、コンストラクタで行列数をRange(1..N)指定してやる必要があるようです。(←いろいろ試してみた結果)


SafeArray safeArray = new SafeArray(型の種類,1..行数,1..列数)


これで行数分(約4万回)worksheet.rangeをコールしていた部分が、一気にテーブル分(19回)に減ります。
改良したコードは以下の通りです。

import java.text.SimpleDateFormat
import org.codehaus.groovy.scriptom.ActiveXObject
import org.codehaus.groovy.scriptom.SafeArray
def sql = groovy.sql.Sql.newInstance('jdbc:oracle:thin:@localhost:1521:ORCL','userid','password','oracle.jdbc.driver.OracleDriver')
def xlApp = new ActiveXObject('Excel.Application')
def username = "INIT"
def workbook = xlApp.workbooks.Add
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
sql.eachRow("SELECT table_name FROM user_tables WHERE table_name LIKE 'BIZ_AB_%'"){ rs->
    def rows = sql.rows("SELECT * FROM " + rs.table_name +" WHERE create_user_cd ='" + username + "'")
    if( rows.size() > 0 ){
        def worksheet = workbook.worksheets.Add
        worksheet.name = rs.table_name
        def (long rowNumber, long colNumber) = [1,1]
        SafeArray safeArray = new SafeArray(org.codehaus.groovy.scriptom.SafeArray.VARIANT,1..rows.size()+1,1..rows[0].size())
        for(r in rows){
            if(1==rowNumber){
                r.each{ safeArray.putAt([rowNumber,colNumber++],it.key) }
                rowNumber++
            }
            colNumber = 1
            r.each{
                if( it.value instanceof oracle.sql.TIMESTAMP )
                    it.value = sdf.format(it.value.dateValue())
                safeArray.putAt([rowNumber,colNumber++],it.value)
            }
            rowNumber++
        }
        worksheet.Range(worksheet.cells(1,1),worksheet.cells(rows.size()+1,rows[0].size())).Value = safeArray
    }
}
xlApp.visible = true


これで約19秒で実行できるようになりました。(140秒→19秒)
もっと劇的に早くできる方法はないか、模索中です。

Groovyでテーブルのデータを取得したい(4)

先日の日記で書いたGroovyスクリプトを実行してみたところ、少ない件数では問題ありませんが、
ちょっと多いデータだと全然スクリプトが帰ってきませんでした。
試しに19テーブル、合計約4万件のデータが抽出されるような状況で試したところ、
5分以上かかってもスクリプトが応答しなかったので、これは使い物にならないと思い改良することに。
テーブルのデータ件数は、以下のようになっています。

テーブル名 件数 テーブル名 件数
BIZ_AB_PROJECT 5 BIZ_AB_VALIDATE 34
BIZ_AB_WIDGET 36 BIZ_AB_ENTITY 46
BIZ_AB_BEHAVIOR 48 BIZ_AB_VALIDATE_RULE 88
BIZ_AB_DATA_DOMAIN 119 BIZ_AB_LOGIC 145
BIZ_AB_LAYOUT 155 BIZ_AB_PROP_MASTER 156
BIZ_AB_DTO 256 BIZ_AB_LO_BEHAVIOR 302
BIZ_AB_KEYBIND 431 BIZ_AB_L_BEHAVIOR 566
BIZ_AB_ENTITY_FIELD 663 BIZ_AB_DTO_FIELD 1947
BIZ_AB_L_WIDGET 2116 BIZ_AB_PROP 14833
BIZ_AB_PROP_VALUE 17406

先日のコードだと1つ1つの行列ごと、つまり1つのセルごとにEXCEL関数をコールしていることになるので、
上のデータで試すと約4万行×20列分コールされることになります。

r.each{ worksheet.Cells(rowNumber,colNumber++).value = it.value } // これが約80万回コールされる

これをせめて行単位にコールすることができれば、もう少し短縮できるのではないかと。80万→4万
これには、SafeArrayを使用することにします。
SafeArrayには、org.codehaus.groovy.scriptom.SafeArrayと com.jacob.com.SafeArrayがあるので注意してください。
使用するのは、org.codehaus.groovy.scriptom.SafeArrayです。

import java.text.SimpleDateFormat
import org.codehaus.groovy.scriptom.ActiveXObject
import org.codehaus.groovy.scriptom.SafeArray
def sql = groovy.sql.Sql.newInstance('jdbc:oracle:thin:@localhost:1521:ORCL','userid','password','oracle.jdbc.driver.OracleDriver')
def xlApp = new ActiveXObject('Excel.Application')
def username = "INIT"
def workbook = xlApp.workbooks.Add
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
sql.eachRow("SELECT table_name FROM user_tables WHERE table_name LIKE 'BIZ_AB_%'"){ rs->
    def rows = sql.rows("SELECT * FROM " + rs.table_name +" WHERE create_user_cd ='" + username + "'")
    if( rows.size() > 0 ){
        def worksheet = workbook.worksheets.Add
        worksheet.name = rs.table_name
        long rowNumber = 1
        for(r in rows){
            SafeArray safeArray = null
            if(1==rowNumber){
                worksheet.Range("A${rowNumber}:T${rowNumber}").Value = new SafeArray( r*.key.toArray() )
                rowNumber++
            }
            r.each{
                if( it.value instanceof oracle.sql.TIMESTAMP )
                    it.value = sdf.format(it.value.dateValue())
            }
            worksheet.Range("A${rowNumber}:T${rowNumber}").Value = new SafeArray( r*.value.toArray() )
            rowNumber++
        }
    }
}
xlApp.visible = true

依然として、対象とするテーブルがTIMESTAMP型を含んでいるため、変換のためにr.eachがありますが、
EXCEL関数はeachの外に出せます。
これで計測すると、約140秒で終了するようになりました。300秒かかっても応答がなかったころに比べれば
まだましですが、2分以上かかるのも考えものです。。。


EXCEL関数のworksheet.Rangeは範囲を指定できるので、SafeArrayに1行分のデータだけでなく、
すべてのデータを含めることができれば4万回→19回となり、だいぶ早くなるのではないかと思います。
ただ、SafeArrayのコンストラクタに複数行分を指定するようなものが見当たらないのですが。。。


もうすこし調べてみたいと思います。。

Groovyでテーブルのデータを取得したい(3)

今回は、テーブルのデータを取得してExcelに書き出すサンプルです。
このサンプルを使用するには、WindowsInstaller版のGroovyが必要になります。
そうでないバージョンを使用している場合は、個別にScriptomをインストール&設定が必要です。
わたしはWindowsInstaller版でない方を使用していましたが、WindowsInstaller版に乗り換えました。

import java.text.SimpleDateFormat
import org.codehaus.groovy.scriptom.ActiveXObject
def sql = groovy.sql.Sql.newInstance('jdbc:oracle:thin:@localhost:1521:ORCL','userid','password','oracle.jdbc.driver.OracleDriver')
def xlApp = new ActiveXObject('Excel.Application')
def username = "aoyagi"
def workbook = xlApp.workbooks.Add
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
sql.eachRow("SELECT table_name FROM user_tables WHERE table_name LIKE 'BIZ_AB_%'"){ rs->
    def rows = sql.rows("SELECT * FROM " + rs.table_name +" WHERE create_user_cd ='" + username + "'")
    if( rows.size() > 0 ){
        def worksheet = workbook.worksheets.Add
        worksheet.name = rs.table_name
        def(long rowNumber, long colNumber) = [1,1]  // Groovy 1.6より可能な変数宣言と初期化
        for(r in rows){
            r["CREATE_DATE"] = sdf.format(r["CREATE_DATE"].dateValue())
            r["RECORD_DATE"] = sdf.format(r["RECORD_DATE"].dateValue())
            if(1==rowNumber){
                r.each{ worksheet.Cells(rowNumber,colNumber++).value = it.key }
                rowNumber++
            }
            colNumber = 1
            r.each{ worksheet.Cells(rowNumber,colNumber++).value = it.value }
            rowNumber++
        }
    }
}
xlApp.visible = true

CSVファイルに書き出す方式と比べて、それほどにコードが膨らんでません。
「コードが短くて済むがGroovyの良さ」という訳ではありませんけど。


Excelのワークシートに書き出す部分で、VBAのようにworksheet.cells(i,j)を使用するところが気に入らないのですが、なんとか方法はないものか。。。
イメージ的にはWorksheet.Rangeに配列(ListやMap)を渡すような方法で書き込めれば、気持ちいいのですが。
少し調べてみると、SafeArrayを利用すると出来るようでした。

SafeArray safeArray = new SafeArray(org.codehaus.groovy.scriptom.SafeArray.VARIANT)
safeArray = ["a","b","c"].toArray()
worksheet.Range("A1:C1").Value = safeArray


ただ、配列型でないとSafeArrayが受け取ってくれないので、ひと工夫が必要になります。