Hatena::ブログ(Diary)

Office L テクニカルノート このページをアンテナに追加 RSSフィード

2012年06月06日

Jasmine の matcher で遊んでいるので

最近仕事とは別に JavaScript のテストフレームワーク Jasmine で遊んでいます。

理解を深める目的で、日本語化しながらちまちまテスト書いてみている(丸コピーして日本語化して自分用に追記してる)ので、ちょっと公開してみたり。

bitbucketのプライベートリポジトリに他のやつのテストを書くついでに書いたので、そっちで公開できないからベタで張り付けちゃうという暴挙。

JasmineSpec.js

/**
 * Jasmine のテストの書き方のテスト
 */
describe('Jasmine の機能テスト', function() {
  var obj01 = null;

  /**
   * 全体用初期化
   * どのitメソッド呼び出しの前にも呼ばれる
   */
  beforeEach(function() {
    obj01 = [1, 2, 3, 4, 5];
    obj02 = [1, 2, 3, 4, 5, 6];
  });

  /**
   * 全体用後片付け
   */
  afterEach(function() {
    obj01 = null;
    // obj02 = null;  // あえて初期化しない
  });

  /**
   * describe 自体も入れ子にできる
   * (全体が describe で囲まれているのを忘れないで)
   */
  describe('describe 自体を入れ子にできる', function() {
    it('block', function() {
      expect(obj01.length).toEqual(5);
      expect(obj02.length).toEqual(6);
    });
  });

  /**
   * describe はテスト結果のブロッキングをしてくれる
   */
  describe('describe はテスト結果をブロッキングして表示してくれる', function() {
    // it の第一引数のテキストが同じであっても影響はでない
    it('block', function() {
      // 自身のネスト内にEachがあればソレが使われる

      // そのため、元の情報は失われる
      expect(obj01.length).not.toEqual(5);

      // 内部のEach(下を参照)で上書きしたから
      expect(obj01.length).toEqual(4);

      // 外のEachも呼ばれているので
      expect(obj02.length).toEqual(6);
    });

    // describe 内では順序は関係がない
    beforeEach(function() {
      obj01 = [1, 2, 3, 4];
    });
  });

  /**
   * assert に相当するのはexpect メソッドと Matcher メソッド
   */
  describe('Matcher紹介', function() {

    describe('.toBe()は', function() {
      it('===と同じ', function() {
        // obj01 === obj01 当然同じもの
        expect(obj01).toBe(obj01);
      });
      it('オブジェクトとして同じかどうか', function() {
        // obj01 === obj02 コピーしたら同じもの
        var obj02 = obj01;
        expect(obj01).toBe(obj02);
      });
      it('中身が同じだけではだめ', function() {
        // obj01 !== obj03 中身は同じでもオブジェクトが違う
        var obj03 = [1, 2, 3, 4, 5];
        expect(obj01).not.toBe(obj03);
        // 中の値が同じであることは toEqual()で確認できる(後述)
        expect(obj01).toEqual(obj03);
      });
    });


    describe('.toEqual()は', function() {
      it('===と同じ動きをする', function() {
        expect(123).toEqual(123);
      });
      it('typeが違うとマッチしない。==とは違うということ', function() {
        expect(123).not.toEqual('123');
      });
      it('中の値が同じなら異なるオブジェクトも同じとして扱う', function() {
        obj01 = [1, 2, 3];
        obj02 = [1, 2, 3];

        // 中の値が同じなので
        expect(obj01).toEqual(obj02);

        // ちなみに toBeだと異なる(別のオブジェクトなので)
        expect(obj01).not.toBe(obj02);
      });
    });


    describe('.toMatch()は', function() {
      var str;
      beforeEach(function() {
        str = 'This is test case';
      });
      it('正規表現でマッチ', function() {
        expect(str).toMatch(/test/);
      });
      it('なので大文字小文字を区別する', function() {
        // マッチしないから .not
        expect(str).not.toMatch(/TEST/);
      });
      it('ただし演算子は使える', function() {
        // i は大文字小文字を無視
        expect(str).toMatch(/TEST/i);
      });
      it('日本語にもマッチする', function() {
        str = 'これはテストケースです';
        expect(str).toMatch(/テスト/);
      });
    });


    describe('.toBeDefined()は', function() {
      it('定義されていることを期待する', function() {
        var a = {
          foo: 'foo'
        };
        // 定義されているのでマッチ
        expect(a.foo).toBeDefined();
        // 定義されていないのでマッチ
        expect(a.bar).not.toBeDefined();
      });
      it('var で宣言しなくても大丈夫', function() {
        def = 'OK';
        expect(def).toBeDefined();
      });
      it('そのタイミングで変数としてイキならOK', function() {
        expect(obj01).toBeDefined();
        // さて、このobj01の中身は?(やってみよう)
      });
    });

    describe('.toBeUndefined()は', function() {
      it('定義されていないことを期待する', function() {
        var a = {
          foo: 'foo'
        };

        expect(a.foo).not.toBeUndefined();
        expect(a.bar).toBeUndefined();
        expect(undefined).toBeUndefined();
      });
      it('変数のスコープに注意', function() {
        // def はvarなしで呼ばれた(上のdescribe)
        expect(def).not.toBeUndefined();
      });
      it('undefinedにした変数もundef', function() {
        var def = undefined;
        expect(def).toBeUndefined();
      });
    });

    describe('.toBeNull()は', function() {
      it('nullであることを期待する', function() {
        expect(null).toBeNull();
      });
      it('nullが代入された変数', function() {
        var a = null;
        var foo = 'foo';

        expect(a).toBeNull();
        expect(foo).not.toBeNull();
      });
      it('何も代入していない変数はundefined', function() {
        var a;
        expect(a).not.toBeNull();
      });
    });

    describe('.toBeTruthy()は', function() {
      it('TRUEと判断される値(状態)であることを期待する', function() {
        var a, foo = 'foo';

        expect(foo).toBeTruthy();
        expect(a).not.toBeTruthy();
      });
      it('例えば true', function() {
        var a = true;
        expect(a).toBeTruthy();
      });
      it('例えば 1', function() {
        var a = 1;
        expect(a).toBeTruthy();
      });
    });

    describe('.toBeFalsy()は', function() {
      it('FALSEと判断される値(状態)であることを期待する', function() {
        var a, foo = 'foo';

        expect(a).toBeFalsy();  // 値がないので
        expect(foo).not.toBeFalsy();
      });
      it('例えば false', function() {
        var a = false;
        expect(a).toBeFalsy();
      });
      it('例えば NaN', function() {
        var a = NaN;
        expect(a).toBeFalsy();
      });
      it('例えば 0 (zero)', function() {
        var a = 0;
        expect(a).toBeFalsy();
      });
      it('例えば "" (空)', function() {
        var a = '';
        expect(a).toBeFalsy();
      });
    });

    describe('.toContain()は', function() {
      it('値が含まれていることを期待する', function() {
        var a = ['foo', 'bar', 'baz'];

        expect(a).toContain('bar');
        expect(a).not.toContain('quux');
      });
      it('変数もうまく動く', function() {
        var a1 = 'A1';
        var a2 = 'A2';
        var a3 = 'A3';
        var a = [a1, a2, a3];

        expect(a).toContain('A1');
        expect(a).toContain(a2);
      });
      it('文字列もうまく動く', function() {
        var a = 'abcdefg';

        expect(a).toContain('a');
        expect(a).not.toContain('z');
      });
    });

    describe('.toBeLessThan()は', function() {
      it('より小さいことを期待する', function() {
        var pi = 3.1415926, e = 2.78;

        expect(e).toBeLessThan(pi);
        expect(pi).not.toBeLessThan(e);
      });
      it('文字は文字コード順', function() {
        var a = 'a', b = 'b';

        expect(a).toBeLessThan(b);
        expect(b).not.toBeLessThan(a);
      });
    });

    describe('.toBeGreaterThan()は', function() {
      it('より大きいことを期待する', function() {
        var pi = 3.1415926, e = 2.78;

        expect(pi).toBeGreaterThan(e);
        expect(e).not.toBeGreaterThan(pi);
      });
      it('文字は文字コード順', function() {
        var a = 'a', b = 'b';

        expect(b).toBeGreaterThan(a);
        expect(a).not.toBeGreaterThan(b);
      });
      it('真偽値を比較してみると', function() {
        // true が大きい
        expect(true).toBeGreaterThan(false);
        expect(false).not.toBeGreaterThan(true);
      });
    });

    describe('.toBeCloseTo()は', function() {
      it('数学的に近い値であることを期待する', function() {
        var pi = 3.1415926, e = 2.78;

        expect(pi).not.toBeCloseTo(e, 0.1);
        expect(pi).toBeCloseTo(e, 0);

        var r2 = 1.41421356;
        expect(r2).not.toBeCloseTo(1.5, 0);
        expect(r2).toBeCloseTo(1.5, 0.1);
        expect(r2).toBeCloseTo(1.5, 0.2);

        var x = 1000.1;
        expect(x).toBeCloseTo(1000, 0.1);
      });
    });

    describe('.toThrow()は', function() {
      it('exception が throw されることを期待する', function() {
        var foo = function() {
          return 1 + 2;
        };
        var bar = function() {
          // a が宣言されていないのでエラーが発生する
          return a + 1;
        };

        expect(foo).not.toThrow();
        expect(bar).toThrow();
      });
    });
  });

  /**
   * 処理しない
   * 一時的に処理しないようにすることができる
   */
  describe('処理しないこともできる', function() {
    it('xdescribe と xit は処理されない', function() {
      expect(123).toEqual(123);
    });
    xdescribe('このdescribeは処理されない', function() {
      it('親が処理されないと入れ子の処理もされない', function() {
        expect(123).toEqual(123);
      });
    });
    describe('このdescribeは処理される', function() {
      xit('が、ここは処理されない', function() {
        expect(123).toEqual(123);
      });
      it('ここは処理される', function() {
        expect(123).toEqual(123);
      });
    });
  });

});

skipのxdescribeとxitまでやったら、次はスパイなんだけど、まだよく把握できてないので、とりあえずここまで。

.toBeCloseTo()がイマイチよくわかんない。

もっと使いこなせるようにじゃんじゃん写経せねば。というところ。

2012年06月03日

Mac で Twitter / bootstrap をもっと使いこなす準備とか。

仕事が忙しいと言い訳して、久しくブログ書いてなくてちょーダメっぷりを発揮しています。

皆様いかがお過ごしですか。

今日は http://twitter.github.com/ title=Twitter / Bootstrap] をもっと使いこなすためにhttps://github.com/twitter/bootstrap/blob/master/README.mdのDevelopersまわりのメモなど残してみようと思います。

通常、bootstrapを普通に使うだけなら、ダウンロードしてそのまま使えばいいだけですが、開発やってる人はlessやtestが使えるほうがいいよねってゆうか、使えよ、的な。

今までのさぼりっぷりは棚に上げて、さっそくもろもろ準備してみましょう。

といっても、やることは書いてあるので、インストールしてみてハマったところなどを残すだけなんですけれども。

ちなみに Mac OS X 10.7.4 Lion でやってます。bootstrapは現時点での最新2.0.4を使いました。

やり終わった後に思い出しながら書いてるのでちょっと前後したりするかもしれませんがご愛嬌ってことで。

// nodeまわり
// node.js をforeverとかで使ってない、まだnode.jsで遊んでない人は homebrew があるといいです。

// node.jsをインストール
$ brew install node

// node.js のバージョンチェック
$ node --version

// npm のインストール
$ curl http://npmjs.org/install.sh | sh

// npm のバージョンチェック
$ npm --v

// README.md にあるとおり、必要なものを入れる
$ npm install recess uglify-js jshint -g

// なんか connect モジュールがないとかってエラーになることがある?
// 後でどうにでもなるので、メジャーなフレームワークつっこめば一緒に入る。
$ npm install express -g

// これで、bootstrap の make が出来るようになるので、bootstrapのホームディレクトリでmakeする
$ cd /path/twitter/bootstrap
$ make

// 何をやってるかは Makefile 読むといいと思われ。

// testまわり
// 個人的には後でJasmineで書き換えちゃったりしようかとか思っているけど、
// とりあえず動かすのが大事なので、phantom.jsをインストール。

$ brew install phantomjs

// テストは下記で
$ make test 

// もしかしたら connect がないってエラー出るのこっちだったかもw

// watch まわり。
// less フォルダ中の .less ファイルの変更監視をして、自動的にmakeしてくれる。TDDってか。
// watchr (スペル注意)を使うので、gem でインストール。

$ gem install watchr

// マックだとこれがいるって書いてあったので一緒にインストール(よくわかってない)

$ gem install ruby-fsevent

// 環境によるのかわからないけど、一度ターミナルからログアウトしないと変更が反映されなかった。
// うちのマックはRuby環境をrbenvで管理してるせいかも?

$ make watch

// これで less フォルダの書き換えをすると自動的に反映されてcssが書き出しされる。
// はずだったんだけど、うまくいかないみたい。

最後の watch については、Mac OS X には watch コマンドがないので、 homebrew でインストールするとか、dmgを拾ってきてインストールとかいくつか手段があるようなのだけど、自分の開発環境で試してみたところ、パスと権限の問題に引っかかって、結局うまくいかなかったので却下にした。

たぶん/var/wwwとかにおいて、パーミッションをフルオープンにするとかしないとうまくいかない気がする。

ぶっちゃけ、権限を甘くするくらいなら自動化を諦めて、make 叩いたほうがマシだと思うのでいいかなって。

そんなに頻繁にlessなんか処理しないしね。的なw

2012年02月28日

Capistrano で sudo でエラー sorry, you must have a tty to run sudo って時の対処方法

いつもどおりだけど久々にブログにメモしてみたり。

Capistrano でデプロイを書いてるんだけど、sudo した際に、

sorry, you must have a tty to run sudo

って言われた時の対処方法。

軽くぐぐると、

$sudo visudo

Defaults visiblepw

みたいなのがあるんだけど、これだとよくないらしい。

もうちょっとぐぐると、

default_run_options[:pty] = true

ってのがあって、Capfile に書いておくと問題なくなった。

万歳。

2011年12月03日

【Titanium Advent Calendar 2011:三日目】バージョンチェック

はじめに

この記事は、@astronaughtsさん企画の「Titanium Advent Calendar 2011」向けに書いています。

ちょっと宣伝1

いきなりで恐縮ですが、過日 Titanium Mobile で制作したアプリがリリースされているので紹介させてください。

クイズ早押しボタン

このアプリはあたまソフトさんによる企画で、私はプログラム部分だけ担当しました。先に述べたとおり、Titanium Mobile 製です。

クイズサークル等で早押し大会をするときに使えます。

iOS向けリリースになっていて、Andoridではまだ見た目の調整が必要ですが、とりあえず動作はします。私は未確認ですがiPadでも動作すると思います。

プログラム的な出来としてはイマイチ感が否めないとか、広告を出す予定だったのが、某社のSDKが正式に対応していなくて、サードパーティでモジュール化されていたものを取り込んだところ画面遷移で落ちまくる事象が頻発し、諦めた経緯があります。

Ti製アプリコレクターはぜひ買ってあげてください。(無償で開発したので私には特になにも起きませんがw)

今日の本題

で、今日の本題です。

みんないろいろ悩むところだけどあまり議論されていない(と思う)バージョンアップのチェック方法、です。

上記のアプリは、ユーザデータをSQLiteで管理しているのですが、何回か開発中にレイアウト変更をしました。

その都度DBを再作成していたのですが、これはリリース後に同じことをすると、蓄積したデータが消えてしまうのでよろしくありません。

そのため、アプリ内でバージョンを判別して、初回起動時、通常時、バージョンアップ時で処理を分けることにしました。

具体的なコードはこんな感じです(かなり端折っています)。

var V = Ti.App.getVersion();	// tiapp.xml の Version の値が入る
var CV = Ti.App.Properties.getString('CV',0);	// 第二引数は初期値
if (CV == 0){
	// 初回起動時(テーブルの生成とか)
}
if (CV < V){
	// バージョンアップ時処理(データの更新とか。バージョン毎の処理はこの中でやる)
}
Ti.App.Properties.setString('CV',V);	// Version の値を CV としてしまう(次回に備える)
// ここから通常処理

これにより、アプリの初回起動時はバージョン値(CV)を持っていないので、初期化処理が行われ、通常時は保持しているバージョン値があるので処理はスルーし、バージョンアップ後の初回起動時にバージョンアップ処理が行われるようになっています。

今日の本題は、そもそもコレでいいのか?もっといいやり方とかわかりやすいやり方はないかを聞きたいのと、コレでいいやって人には使ってもらってフィードバック欲しいなっていう二点です。

三日目なのにすごいささやかなネタで申し訳ありません m(_._)m

ちょっと宣伝2

排水管プロジェクト

上記のコードは乗っていませんが、Titanium のサンプルコードの KitchenSink に倣って、排水管(DrainPipe)という名前で Titanium Mobile のサンプルコードを蓄積するプロジェクトをやっています。

最近全然手を入れられていませんが、国際化対応、Android&iOS両対応準備、JSSがどんな感じになるのかを簡単にチェック、くらいができていて、もっとコードを集めたいと思っています。

その他のこともいろいろやってた経緯があって、google code なのですが、最近 git も使える感じなので移動しようかなとか考えています。

これを読んでいる人の中で蓄積に付き合ってもいいぜ、とか言ってくれる方がいらっしゃいましたらご連絡ください。

自己紹介など

最後になりますが、ちょっとだけ自己紹介。

Office L という屋号でフリーランスのSE(みたいなこと)をやっています。Twitter / raki です。

IT業界18年目、フリーになって8年目のごく普通のおっさんで、既婚、子持ち、ヘビースモーカー、ノンアルコール、音ゲーマー(jubeat,REFLEC BEAT,ちょっとだけDDR)です。

現職は某「てれーれってれ」って感じのCMで有名な企業さんの、それとは別の部隊でSE兼PGみたいなことをしています。

業界歴が長いので結構な数の言語(BASICやCOBOLから始まってCやVB,VC,Perl,PHP,シェルも書きますし、もちろんObj-Cも書きます。SGML,xml,HTML,CSS,JSはjQuery派)やDBMSMySQL,PostgreSQL,Oracle,DB2,珍しいところだとInfoMixとかいじってた時期があります)やOS(Windows、Macはもちろん、Linux系OSってゆうか、SolarisAIXなどのUNIX OSとか、OS2なども)が使えます。ネットワークもそこそこいけますし、オペレータとしてならFireworksも使えます(このブログの過去記事参照)。ご推察のとおり、立派な器用貧乏です。

たぶん一番得意なのは橋渡しで、ITなんかちんぷんかんぷんな企画屋さんとかデザイナーさん、IT以外は知ったこっちゃないSIerの間で、うまいこと仕事を回したり、調整したり、通訳したりするところで結構真価を発揮するみたいです。

個人的にはコード書いてる時間が一番幸せですけど。

メインの仕事は大抵常に埋まってるってゆうか、埋めてもらっている(超強力で優秀で友人でもある営業さんがついている)のであんまり必要ありませんが、サブのお仕事とか企画やシステムのご相談とか勉強会講師の依頼とかご飯食べに行きたいとか友達になりたいとかデートしたいとか(※ただし艶女に限るww)、もろもろお問い合わせお待ちしておりますw


というわけで、明日は @papetto_tvさんでしょうか?

よろしくお願いします!

2011年09月23日

Titanium Mobile によるスマートフォンアプリ開発勉強会(DevHub西新宿)ってのをやってきました

今日はTitanium Mobile によるスマートフォンアプリ開発勉強会(DevHub西新宿) on Zusaarをやってきました。

今回は好きにやってねスタンスをとったので、あんまり事前準備とかしてなくて、ちょっと前に書いた別館記事を紹介する程度で、後はまだ動かせていない人のサポートをしてました。

内容的には特筆するほどのこともなく、淡々とコトが進んだので、反省と次回に向けてをリストアップ。

相変わらずイベントのトピを読まないで参加する人をどう扱うか。
読んでこないのは百歩譲って個人の自由としてもいいけど、結果として完全に出遅れてる人をどうサポートするか、は今後の課題。参加するほうもサポートするほうも、完全にあらららって感じになっちゃうからね。。。
結果として作業に開きがでてしまった場合にどうするか
上の件にも通じるけど、作業の開きができるとサポートしきれなかったり、そこだけ作業できなかったりってことがある。サポート用の初心者勉強会と、既にやってる人向けのハッカソンにしてたので、やれる人は好きに進めてくれればいいし、できてない人はサポートを受ければいいんだろうけど、勉強会的な一体感とか、コミュニケーション量に差が出るのは否めないね。
環境差をどう吸収するか
今回多かったのは MBA の Lion (あーうらやましいw)みたいだけど、MBP の SL や Windows な人もいて、正直全部の環境、個々の問題には対処しきれないなぁと思った。少人数の初心者をサポートすることには意味がある、と個人的に思っていたけど、継続してやっていく価値があるか、というとそうでもないと思った。つまりたぶん初心者サポート系の勉強会はもうやらないw
コミニュケーションメインにしたいんだけど、そうありたくないタイプの人をどう扱うか
そもそもうまくやれてないって言われると返す言葉もございませんって感じなんだけど、双方が非コミュじゃねぇ?w 時間的制約もあるけど、もう少し相互にコミュニケーションとれるようにしたい、と思っている。ただ、それを勉強会には求めてないよって人も多い気もするので、今後の課題かなと。
おやつの分量w
ネタのつもりじゃないけど、スイーツ(笑)を準備して女性も参加しやすいようにしてみたつもりなんだけど、女性参加者はおひとり。お徳用パックのおかしを買ってきてってことにしてたのだけど、結果として一人分が結構な量になってしまった。おやつに関しては、なしにするか、持ち出し覚悟でこっちで用意するか、実費程度負担してもらうか、って感じになると思うんだけど、今の所未定。でもおかしあるほうが自己紹介タイムとりやすいし、少なくても何もしてないところよりはコミニュケーションとれてるとは思っているんだけど。
思惑の違いをどうするか
これは勉強会後のアンケートにあった話だけど、ハッカソンのお題を一つにしぼって回答を用意したほうがいい、的なコメントをもらったんだけど、個人的には全くそうは思わないってゆうか、それってハッカソンの意味あるの?って感じで、どうしたもんかと。ハッカソンってやりたいことがある人が集まってこんなんやるぜーとか、こんなんやりたいぜーってことをするのであって、回答は用意してあるからこれやってみ、って言われてやるようなもんじゃないと思うのね。いや、意見は意見で別に全然構わないんだけど、こういった主催側の思惑と外れた思想で参加する参加者との認識とかのずれをどこでどう調整したらいいか、的なことも大きな課題かなと。

個人的雑感を最後にメモっておくと、せっかく多くの(そうでもないけどw)人が集まってる勉強会にきて、他の人とコミニュケーションとらずに帰っていくのってどうなのかしらと。

楽しいのかしら、それで、、、(このネタは少しあっためてから別の記事としてそのうち書こうと思います)

2011年09月16日

google+ API が公開されたそうなのでサンプル動かしてみた時にハマったことのメモ

昨日リリースされたんですかね?Google+ API  |  Google+ Platform for Web  |  Google Developersが使えるようになっていたので、早速サンプルを試してみました。

ローカル環境はxamppなのでphp選択ですがあしからずw

各自ドキュメントを読むのは当たり前として、Downloads  |  Google+ Platform  |  Google Developersから、Error 404 (Not Found)!!1に飛んで、スターターの zip ファイルをダウンロードして展開。

ついでにGoogle Code Archive - Long-term storage for Google Code Project Hosting.から最新のクライアントライブラリをダウンロードして、スターターの直下に展開。

xamppデフォルトなら htdocs 下に上記ファイルを展開。短いほうがアクセスしやすいので、フォルダ名を gpps(google plus php starterだから)に変更。

Google API Consoleでgoogle+APIをonにセット

左メニューの API Access で Create an OAuth2 client ID ってボタンを押して、必要事項を入力。プロジェクト名はなんでもいいみたい。url は https://localhost/gpps/ にセット。

Create client IDってすると、OAuthやったことがある人ならおなじみのなんちゃらキーとかが表示される。

gpps/index.php をエディタで開いて、26行目前後のところに値をセット。

$client->setClientId('ほにゃらら.apps.googleusercontent.com');
$client->setClientSecret('うにゃうにゃ');
$client->setRedirectUri('https://localhost/gpps/’);
$client->setDeveloperKey('ここは迷ったけどconsole のSimple API AccessのAPI Keyをセット');

ってしたら https://localhost/gpps/ でアクセスしてできあがり。

以下、環境差にもよるけどはまったところをメモ。

  • ssl を別要件で使っているときは設定に注意
  • zend等を入れていて.htaccessがフックしちゃうとかも注意
  • curl が必要なので xampp/php/php.ini で curl エクステンションのコメントを解除すること
  • http でやろうとするとうまくいかなかったのはなんでかなー
  • curl で Fatal error: Uncaught CurlException: 60: SSL certificate problem, verify that the CA cert is OK. Details: error みたいなのがでたら、オプションの問題なので /xampp/htdocs/gpps/google-api-php-client/src/io/apiCurlIO.php をエディタで開いて、112行目の

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

にしてあげれば大丈夫。でもこれ本番機でこんな設定にするなよ。。?

  • あとは、gpps/index.php がsjis 認識されて読み込んだAPIの結果が文字化けするのが気になったら、index.php の head の中に <meta charset="UTF-8" />いれてあげれば大丈夫。

出来上がったらindex.phpで他の戻り値を出力してみるとか、他のAPIを呼んでみるとかすればOK。

でもconsoleで見る限り1日1000回しかAPI呼べないようなので、遊びすぎには注意(遊びでそんなに使う人もいないダロ。。。)

2011年09月15日

jubeat copious 稼動記念ジャケ風壁紙

f:id:officel:20110916032311j:image:w360:right

巷では15日から jubeat の最新作 copious が稼動したようですが、仕事が忙しくて初日参戦できませんでした。

あんまりなので久しぶりに Fireworks の練習がてらまた壁紙を作りました。

まだあまり詳細画像が出回ってないのと、サントラジャケットに複数のバージョン(って言っても星の位置が違うだけ?)があって、どうしようかと思ったあげく、自分がさそり座なので背景の星はさそり座にしてしまいましたw

ちゃんとアンタレスもあるのよw

  • 今回は先日話題になってた JPEGmini - Your Photos on a Diet! を使ってサイズダウン
  • グラデにノイズをかけて質感アップ(?)
  • さらにぼかしもかけてスムーズに(?)
  • サントラジャケットよりもかなり下方向にグラデ移動

失敗したなーと思っているのは、

  • 星はちゃんと45度倒して◆にしてたんだけど、縦に配置したので■になっちゃったこと
  • 星の間の線若干手抜き。もう少しバランスとってもよかった
  • 透明パネル部の書き方もうちょい工夫できてもよさそうな。今はベタ塗りから透明度30%くらいで描画モード平均を使用してるんだけど、クリアな質感がいまいち。。。

iPhone ユーザの jubeater さんに使ってもらえれば。

宇宙人壁紙はまた今度。

2011年08月27日

(はじめての)Chrome拡張勉強会に行ってきました。

先日書いたとおり、今日は(はじめての)Chrome拡張勉強会 on Zusaarに行ってきました。

事前にちゃんと学習しましたし、前日には id:kidd-number5ID記法って慣れないな。。。)から資料の事前レビューを依頼されて見ていたので、とりたててやることはなかったのですが、先日のATND用拡張のATNDATTをZusaar移行して、ZuATTを作ってみました。

が、どはまりしたので、今日ははまったポイントなどをメモすることにします。

■manifest.json

・permissionsのURL指定誤り

 書き換える時に注意すればいいだけですが、最後の*を忘れていてAJAXが全然通らなかった。

・バージョンは初期値に

 元にしたATNDATTのままにしておくとよくない。いきなり1.1から始まるとかマジ。。。

■content.js(コンテンツスクリプト)

・間違えるほどのことはないけど、Twitter関係はZusaarで返らないので修正要

・本体に書き出すセレクタもATNDとは違う

■background.html(バックグランドページ)

・これが一番はまったところ。

 ATNDのAPIの結果とZusaarの結果のjsonのキーの違い ATND(events)に対してZusaar(event)。。。(いずれも出欠確認API)

 最初AJAXリクエストがパーミッションエラーで発行出来てなかったこともあって解決まで30分以上かかってしまった。

 これを解決するのに、バックグラウンドページのデバッグの仕方を教えてもらって、リクエストは飛んでる、戻り値をチェックするところ出来てる、でも戻りがnullになる、、、まできてようやっと"s"の違いに気がついたという。。。

 ちなみに、ATNDが表記誤り(eventって書いてあるけどevents配列が返る)のように見えるけど、実際配列なら"s"付が正しいかも。

いやはや、お恥ずかしい。

APIが似せて作ってあるからって結果も同じと思っちゃダメですなw

2011年08月24日

ATND用の google chrome extension を書いてみました。

我らが@先生が(はじめての)Chrome拡張勉強会 on Zusaarというのを主催されるので、事前勉強ということで作ってみました。

イベント開催支援ツール アテンド : ATNDのイベントページにて出欠表を書き出すだけの機能拡張です。初めてのエクステンションw

中身的な説明は勉強会当日にLTでぱぱっとするとして、とりあえず自前配布と自動更新のテストとして、サーバにアップしましたので、お手すきな chrome ユーザさんはテストしてみて感想などいただけると喜びます。

ATND Attendance

ページアクションになっていて、ATNDのイベントページを開いた時だけ有効になります。

アドレスバーのアイコンをクリックすると、画面下部に出席者及び補欠の人のリストが作成されます。それだけです。

本当はWEBのアドレスも欲しかったのですが、それはAPIレスポンスに含まれておらず、面倒なのでなくてもよしとしました。

(やるとしたらユーザ数分ページスクレイピングしないといけませんし。。。)

とりあえず、参加者のアカウントがTwitterに紐付いているか、いるならURL、が出せているので、参加者をまとめてフォローするのに便利じゃないかと思います。

また、印刷(プレビューも含む)した時に前後に改ページをいれているので、イベントの出欠確認にも便利かなと。

コピペでZusaar版も作れるけど、ZusaarはそもそもTwitterで認証できるし、APIのレスポンスにデータが載ってこないのでとりあえず様子見です。

2011年08月01日

AQUOS PHONE THE HYBRID SoftBank 007SH を買いました

我が家の携帯は、主契約(ガラケー)、iPhone、嫁さんのガラケーのソフトバンク三台体制なのですが、ここんところずっと使ってなかった主契約のガラケー(920Tでした。くーまんね)を、アンドロイドの 007SH に機種変更してきました。

これまで主回線だった920Tは、iPhoneがあるからってことでずっとメインで使っていなくて、ただただ迷惑メール処理機と化していたのと、iPhone アプリ開発に Titanium Mobile を使うようになって、アンドロイドも欲しいなぁと思っていたので、主契約だけど開発機と割り切って機種変更することにしました。

前日までは、Twitterで HTC Desire HD がいいよと教えてもらっていたのですが、近場のSBショップも量販店も軒並み品切れ、取り寄せ、ということだったので、在庫のあった007SHに落ち着きました。

一番新しいし、ホットモックを触った感じでは他の機種よりさくさく動くみたいだし、開発用としては十分かなということで。

契約については、なるべくランニングコストを下げることを念頭に、

  • ホワイトプラン(980円)
  • パケットし放題S for スマートフォン(390円〜5,985円)
  • 継続でS!ベーシックパック(315円)、あんしん保障パック(498円?)、世界対応ケータイ(これは使うときにかかる)

になりました。

とりあえず、モバイルデータ通信をオフに設定して、Wi-Fiのみでどのくらいで運用できるのかをしばらく見ていきたいと思います。

(iPhoneがあるのでアンドロイドでやりたいことなんてあんまりないんだけれどもw)

ソフトバンクの契約あれこれに対する不満など思いつくまま

先のとおり、007SHに機種変更したわけですが、、、、本当に最近の(いや以前からだけども)携帯電話の契約の煩雑さとわかりにくさはどうにかならないんですかね?

あとショップでもそうだし、MySoftbank(携帯やWEBで見れる契約情報)もそうだけど、ユーザにわかってもらう、を完全に放棄してるとしか思えないんですよね。。。

というわけで、契約前、契約中、契約後、それぞれのフェーズでの不満などを思いつくまま書いてみたり。

あ、契約そのものは西大島のショップでやってもらったけど、対応は悪くなかったですよ。

特別格段にいいわけでもないけど、特に悪いところはなかった、あるとすればSB側システムの問題でしょう、というのだけ、お店の名誉のために先に書いておきます。

契約前

  • MySoftbank が使いにくい。
  • 契約ごとにしかログインできない上に、副回線のiPhoneの契約をiPhoneから変更できないとか
  • 変更するとどうなるかなどがまったくみえない
  • どういうプラン編成にすればいいのか、副回線も含めてトータルでどうなるかとか全然比較検討できない

契約中

  • 既存の契約状態から機種変更後の状態を比較したりがまったくない
  • 変更後の料金説明は手書きの合計算
  • パケットし放題のパケット量が全然見えない
  • 言わないと副回線についてとかは全然みない
  • 何がついてきて、何がついてこないかの説明がない
  • プランごとに違う割引サービスの額面が不明瞭

契約後

  • ついてこないシリーズ。充電器。卓上ホルダーが同梱されてるんだけど、充電アダプターはついてこない。別売りなんだそうな。カタログにも見えるところに載ってねーし。ショップでも言われなかったし。
  • ついてこないシリーズ。FONルーター。無料提供してくれるの?これ。紙が渡された手提げの中に入ってたんだけど。帰る前に言わない?普通。。。
  • モバイルデータ通信をオフにするとS!メールが使えないとか。アンドロイドマーケットが使えないとか。おいおい、Wi-Fiはなんのためにあるんだよ。。。てゆーか、そーゆうことは言ってくれよ。

もう十年以上も携帯番号変えていない(デジタルホン時代から同じ番号)なので、今更どうこう言うのもなんだし、他者のこともよく知らないけど、もうちょっとユーザの立場に立ってもの考えないと、サービス業とは言えないんじゃないの?と思いました。とゆーお話。