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()がイマイチよくわかんない。
もっと使いこなせるようにじゃんじゃん写経せねば。というところ。
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
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 に書いておくと問題なくなった。
万歳。
【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派)やDBMS(MySQL,PostgreSQL,Oracle,DB2,珍しいところだとInfoMixとかいじってた時期があります)やOS(Windows、Macはもちろん、Linux系OSってゆうか、SolarisやAIXなどのUNIX OSとか、OS2なども)が使えます。ネットワークもそこそこいけますし、オペレータとしてならFireworksも使えます(このブログの過去記事参照)。ご推察のとおり、立派な器用貧乏です。
たぶん一番得意なのは橋渡しで、ITなんかちんぷんかんぷんな企画屋さんとかデザイナーさん、IT以外は知ったこっちゃないSIerの間で、うまいこと仕事を回したり、調整したり、通訳したりするところで結構真価を発揮するみたいです。
個人的にはコード書いてる時間が一番幸せですけど。
メインの仕事は大抵常に埋まってるってゆうか、埋めてもらっている(超強力で優秀で友人でもある営業さんがついている)のであんまり必要ありませんが、サブのお仕事とか企画やシステムのご相談とか勉強会講師の依頼とかご飯食べに行きたいとか友達になりたいとかデートしたいとか(※ただし艶女に限るww)、もろもろお問い合わせお待ちしておりますw
というわけで、明日は @papetto_tvさんでしょうか?
よろしくお願いします!
Titanium Mobile によるスマートフォンアプリ開発勉強会(DevHub西新宿)ってのをやってきました
今日はzusaar.com - zusaar リソースおよび情報をやってきました。
今回は好きにやってねスタンスをとったので、あんまり事前準備とかしてなくて、ちょっと前に書いた別館記事を紹介する程度で、後はまだ動かせていない人のサポートをしてました。
内容的には特筆するほどのこともなく、淡々とコトが進んだので、反省と次回に向けてをリストアップ。
- 相変わらずイベントのトピを読まないで参加する人をどう扱うか。
- 読んでこないのは百歩譲って個人の自由としてもいいけど、結果として完全に出遅れてる人をどうサポートするか、は今後の課題。参加するほうもサポートするほうも、完全にあらららって感じになっちゃうからね。。。
- 結果として作業に開きがでてしまった場合にどうするか
- 上の件にも通じるけど、作業の開きができるとサポートしきれなかったり、そこだけ作業できなかったりってことがある。サポート用の初心者勉強会と、既にやってる人向けのハッカソンにしてたので、やれる人は好きに進めてくれればいいし、できてない人はサポートを受ければいいんだろうけど、勉強会的な一体感とか、コミュニケーション量に差が出るのは否めないね。
- 環境差をどう吸収するか
- 今回多かったのは MBA の Lion (あーうらやましいw)みたいだけど、MBP の SL や Windows な人もいて、正直全部の環境、個々の問題には対処しきれないなぁと思った。少人数の初心者をサポートすることには意味がある、と個人的に思っていたけど、継続してやっていく価値があるか、というとそうでもないと思った。つまりたぶん初心者サポート系の勉強会はもうやらないw
- コミニュケーションメインにしたいんだけど、そうありたくないタイプの人をどう扱うか
- そもそもうまくやれてないって言われると返す言葉もございませんって感じなんだけど、双方が非コミュじゃねぇ?w 時間的制約もあるけど、もう少し相互にコミュニケーションとれるようにしたい、と思っている。ただ、それを勉強会には求めてないよって人も多い気もするので、今後の課題かなと。
- おやつの分量w
- ネタのつもりじゃないけど、スイーツ(笑)を準備して女性も参加しやすいようにしてみたつもりなんだけど、女性参加者はおひとり。お徳用パックのおかしを買ってきてってことにしてたのだけど、結果として一人分が結構な量になってしまった。おやつに関しては、なしにするか、持ち出し覚悟でこっちで用意するか、実費程度負担してもらうか、って感じになると思うんだけど、今の所未定。でもおかしあるほうが自己紹介タイムとりやすいし、少なくても何もしてないところよりはコミニュケーションとれてるとは思っているんだけど。
- 思惑の違いをどうするか
- これは勉強会後のアンケートにあった話だけど、ハッカソンのお題を一つにしぼって回答を用意したほうがいい、的なコメントをもらったんだけど、個人的には全くそうは思わないってゆうか、それってハッカソンの意味あるの?って感じで、どうしたもんかと。ハッカソンってやりたいことがある人が集まってこんなんやるぜーとか、こんなんやりたいぜーってことをするのであって、回答は用意してあるからこれやってみ、って言われてやるようなもんじゃないと思うのね。いや、意見は意見で別に全然構わないんだけど、こういった主催側の思惑と外れた思想で参加する参加者との認識とかのずれをどこでどう調整したらいいか、的なことも大きな課題かなと。
個人的雑感を最後にメモっておくと、せっかく多くの(そうでもないけどw)人が集まってる勉強会にきて、他の人とコミニュケーションとらずに帰っていくのってどうなのかしらと。
楽しいのかしら、それで、、、(このネタは少しあっためてから別の記事としてそのうち書こうと思います)
google+ API が公開されたそうなのでサンプル動かしてみた時にハマったことのメモ
昨日リリースされたんですかね?Google+ API | Google+ Platform for Web | Google Developersが使えるようになっていたので、早速サンプルを試してみました。
ローカル環境はxamppなのでphp選択ですがあしからずw
各自ドキュメントを読むのは当たり前として、Downloads | Google+ Platform | Google Developersから、Google Code Archive - Long-term storage for Google Code Project Hosting.に飛んで、スターターの zip ファイルをダウンロードして展開。
ついでにGoogle Code Archive - Long-term storage for Google Code Project Hosting.から最新のクライアントライブラリをダウンロードして、スターターの直下に展開。
xamppデフォルトなら htdocs 下に上記ファイルを展開。短いほうがアクセスしやすいので、フォルダ名を gpps(google plus php starterだから)に変更。
Google Cloud Platformで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呼べないようなので、遊びすぎには注意(遊びでそんなに使う人もいないダロ。。。)
jubeat copious 稼動記念ジャケ風壁紙
巷では15日から jubeat の最新作 copious が稼動したようですが、仕事が忙しくて初日参戦できませんでした。
あんまりなので久しぶりに Fireworks の練習がてらまた壁紙を作りました。
まだあまり詳細画像が出回ってないのと、サントラジャケットに複数のバージョン(って言っても星の位置が違うだけ?)があって、どうしようかと思ったあげく、自分がさそり座なので背景の星はさそり座にしてしまいましたw
ちゃんとアンタレスもあるのよw
- 今回は先日話題になってた JPEGmini - Reduce file size, not quality を使ってサイズダウン
- グラデにノイズをかけて質感アップ(?)
- さらにぼかしもかけてスムーズに(?)
- サントラジャケットよりもかなり下方向にグラデ移動
失敗したなーと思っているのは、
- 星はちゃんと45度倒して◆にしてたんだけど、縦に配置したので■になっちゃったこと
- 星の間の線若干手抜き。もう少しバランスとってもよかった
- 透明パネル部の書き方もうちょい工夫できてもよさそうな。今はベタ塗りから透明度30%くらいで描画モード平均を使用してるんだけど、クリアな質感がいまいち。。。
iPhone ユーザの jubeater さんに使ってもらえれば。
宇宙人壁紙はまた今度。