2009-10-28
Firefox の Pencil 拡張機能をダメ出しに使う
ダメ出しってなんだ。annotation のことだ。
Firefox に Pencil という拡張機能があるんですが,たいてい(GUI アプリの)デザインプロトタイプに使えるなどと紹介されてます。
たしかに,シェイプとして Windows や Linux などの GUI ウィジェットが多数登録されているので,ドラッグアンドドロップで気軽に画面をつくることができます。んでも実際にそれをやってみるとしんどい。
そもそもなんでこいつを Firefox の拡張機能としてリリースしたんだ。そういう用途なら XUL アプリにしとけばよかったじゃないか。
と思っていろいろいじったり調べたりしてたら Firefox の画面キャプチャを Pencil ドキュメントに簡単に貼れることがわかりました。しかも annotation 用のシェイプもいくつか用意されてます*1。
ということは。
デザイナーの方が作ったウェブページのデザインモックを「ここをこうしてね」とかフィードバックするのに使えるんじゃないか。だから Firefox の拡張機能なのかー。
操作手順は以下のとおり。
- Firefox の「ツール」メニュー → 「Pencil Sketching...」で Pencil アプリを立ち上げる
- Pencil の「Document」メニュー → 「Save As...」を選択し,ドキュメントを保存する
- Firefox の「ツール」メニュー → 「Send to Pencil Document...」で,現在ブラウザに表示されている内容を Pencil ドキュメントに貼り付ける
- Pencil の「Untitled Page」ページタブで右クリックして「Resize to fit contents...」メニューを選択する
- この手順を踏むことで,ドキュメントを拡張してキャプチャ画像全体が表示されるようにしています。
- 「padding」を設定することができます。普通には 0 で構わないと思います。
- ページタブ右クリックメニューの「Properties...」で手でドキュメントの大きさを調整してもいいです。
あとは左ペインの「Annotation」系シェイプや「Common Shapes」系シェイプをペタペタ貼ってダメ出ししていきます。
最後に「Document」メニュー → 「Save」で保存しつつ,「Export Page as PNG...」で画像としてエクスポートしてデザイナにメールで送りつければよいでしょう。
サンプルとしてこんな感じ(いや別に Google にダメ出ししたいわけではないです;あくまでサンプル)
なお,ひとつの Pencil ドキュメント(ページ)に貼ることのできるキャプチャ画像は 1 枚だけではありません。複数枚貼り付けることもできます。また(もともとの機能として)外部画像ファイルを読み込んで貼り付けることもできます*2。
複数枚貼ったらページサイズを大きくしないといけなさそうですが,画像はリサイズすることができるので*3小さくしてやればよろしい。
四隅系のハンドルをドラッグするとおおまかなアスペクト比を保ったまま拡大縮小が可能ですが,Pencil は基本的にグリッド単位で位置調整されるので結構狂ったりします。そんなときは,画像の右クリックメニューから「Actions」メニュー →「Correct Ratio by Width」や「Correct Ratio by Height」を選択すれば,正しいアスペクト比になります。
複数枚の画像の幅などを揃えたい場合は,手作業で揃えるか(先ほど述べたように基本的にグリッド単位で動くのでそんなに難しくない),複数枚選択して「Shape」メニューから「Make Same Width」や「Make Same Height」を選択すればいいです。
そんなふうにして作ったのがこれ。
ちょっとした操作手順書や画面説明書ならこれで作れそう。
細かいところに手が届かない部分はありますが基本的な機能はそこそこしっかりしているので,お手軽にダメ出し文書や操作手順書を作るにはこれでいいんじゃないかと思います。
*1:といっても,「吹き出し」と「矢印」くらいですが。あと番号用丸形シェイプ。
*2:「Common Shapes」から「Bitmap Image」シェイプを貼り付けて,右クリックメニュー「Actions」から「Load Linked Image...」を選択すると画像ファイルを選択することができます。PNG 画像だけではなく,JPEG など Firefox のサポートする画像形式の画像を読み込むこともできます。「Load Embedded Image...」の役割はわかりません。
*3:ただし,WYSIWYG でリサイズすることしかできない(サイズを数値で指定してリサイズすることができない)。また,拡大縮小にともなうスムージングはしてくれない。
2009-01-19
JavaScript でかんたん XUL アプリに挑戦
こんにちは!
みなさんガジェットつくってますか!
なんだか最近、色々な種類があるみたいですね!
(以下略!)
そしたら意外と簡単だった…!
これならぼくにも作れそう!!
ってことで、ちょっとメモしておきますね!
どれにしようかな…!
こんな感じで考えていくと…
XUL で作られたツールなら,いつも使っているよ!
(Firefox とか Thunderbird とかね)
つくるのむつかしそう?
XUL のアプリって C から libxul をゴリゴリ触らないとダメなんじゃないの?
なんて思っていた時期がぼくにもありました…!
大丈夫!XULRunner を使えば(HTML に似た)XUL と JavaScript だけでできるよ!
だからホームページ作るのと同じくらい簡単に感じる人もいるかもしれないですね!
ブラウザ上のページだと、JavaScriptとかで他のサイトの情報を取得できなかったり
ファイルの読み書きできなかったりと、色々な制約があるんだけど、
XULRunner なら XPCOM もあるから
そんな制約なしで、ウイルスでも何でも好きなものがバンバンつくれます!
やったね!
つくるための準備
準備は Ubuntu Linux 8.10 でのやりかたです!
Windows とか Mac とか一般的な OS 使ってる人はどうせニヤニヤしながら眺めているだけだろうから,ほんとにやりたい人は Getting started with XULRunner | MDN を参考に自分で適当にやっちゃってください!
(Ubuntu だととくになにもしなくても*2 XULRunner が入っていたから省略するよ!)
ちゃんと設定できてるかな?
端末を開いて,xulrunner って入れてみよう!
なんかでてきたら XULRunner はインストールされてるよ!
よし!つくろう!
ぼくはいつも ~/tmp/ にガラクタファイルを溜め込んでいってるので,
~/tmp/myapp ってフォルダを作ってみました!
はい!今回つくるやつは「myapp」っていう XUL アプリです!
作業用フォルダに必要なフォルダを用意する
シンプルな XUL アプリの場合,だいたい下記のようなフォルダ&ファイル構成になるよ!
/myapp
/chrome
/content
main.xul
chrome.manifest
/defaults
/preferences
prefs.js
application.ini
だから,まずディレクトリをきっておこう!
% cd myapp % mkdir -p chrome/content defaults/preferences
作業用フォルダに必要なファイルを用意する
4つのファイルを用意しよう!
ひとつが,XUL アプリの情報を設定する application.ini ファイル。
もうひとつが,使用するリソース(画像とか JavaScript ファイルとか)の場所のレイアウトを指定する chrome.manifest ファイル。
さらにもうひとつが,設定を書くための prefs.js ファイル*3。
最後が,メインになる main.xul ファイル!
XUL アプリの情報を設定する application.ini ファイル
作業用フォルダの直下に新しく「application.ini」ってファイルを作ってね!
% vi application.ini
中身は…
[App] Vendor=dayflower Name=My App Version=1.0 BuildID=20090119 ID=xulapp@example.org [Gecko] MinVersion=1.9 MaxVersion=1.9.0.*
これをコピペでok!
(ほんとは Vendor とか ID を適宜書き換えてほしいけど…)
リソースレイアウトを設定する chrome.manifest ファイル
作業用フォルダの chrome/ フォルダ以下に chrome.manifest ファイルを作ろう!
% vi chrome/chrome.manifest
中身は…
content myapp file:content/
たったこれだけ!これもコピペでok!
念のためにちょっと解説?すると,XUL アプリケーションや Firefox 拡張機能では,使用するファイル(画像とか CSS とか html とか xul とか js とか)を chrome/ フォルダ以下につっこむんだけど,一般的にはこの chrome/ フォルダ以下を JAR ファイル(ZIP 形式)で圧縮して配布することが多いんだ。だけど上記のように書くと,圧縮はしてなくて,chrome/content/ フォルダ以下にそのままおいてあるよ,という意味になるよ!
設定ファイル prefs.js ファイル
作業用フォルダの defaults/preferences/ フォルダ以下に prefs.js ファイルを作ろう!
% vi defaults/preferences/prefs.js
中身は…
pref("toolkit.defaultChromeURI", "chrome://myapp/content/main.xul"); pref("browser.dom.window.dump.enabled", true);
これもまたコピペでok!
念のために説明すると,上の行は XULRunner にメインウィンドウとして使われる XUL ファイルの名前を教えてあげるための設定だよ!「chrome://」という形式からもわかるように,これは chrome.manifest にさっき設定したマッピングと関連している。さきほど chrome の myapp の content は file:content/*4 って設定したので,chrome://myapp/content/main.xul という表記は,(chrome/)content/main.xul というファイルを指定していることになるんだ。ここはまあわかんなくてもok!
下の行は,のちほど dump() という関数でデバッグ用出力を可能にするための設定!そのた JavaScript コンソールにデバッグ情報を出力する方法もあるけど,その場合の設定は Debugging a XULRunner Application | MDN をみてね!
XUL ファイル
いよいよ chrome/content/main.xul ファイルを作る番だね!
% vi chrome/content/main.xul
中身は…
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet href="chrome://global/skin/" type="text/css"?> <window id="main" title="Konnichiha Konnichiha" width="400" height="300" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <script> <![CDATA[ function start() { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { view(xhr); } }; xhr.open('get', 'http://b.hatena.ne.jp/hotentry'); xhr.send(null); } function view(xhr) { dump(xhr.getAllResponseHeaders()); document.getElementById('message').value = xhr.responseText; } ]]> </script> <textbox id="message" multiline="true" rows="10" readonly="true" value="こんにちはこんにちは!"/> <button id="pushme" label="ひみつボタン" oncommand="start()"/> </window>
これもコピペでオッケー!
これは textbox の id をかえたくらいで,ほとんどはまちちゃんのコードのコピペだよ。JavaScript + DOM ってすばらしいね!
実行しよう!
端末を起動して,作業フォルダに移動…
% cd ~/tmp/myapp
さっきつくったやつを実行…!
% xulrunner application.ini
できた!やった!なんかうごいた!
ひみつボタンを押したら,はてなブックマークのソースコードが表示されたよー。
改造しよう!
XUL ファイルとか JavaScript は,Mozilla Firefox と同じやつが使われてるらしいですよ!
てことは,普段ホームページ作りの時に「あぁこれ IE だと使えないからなぁ」
なんて諦めていたやつが色々つかえるかもしれないですね!
あと prototype.js とか jQuery みたいな便利ライブラリも普通に使えるよ!(たぶん)
やった!すごい!べんり!
だけど XUL アプリケーションのちょっとまずいところ
謎なファイルって書いたけど,みんなも HTML を勉強するとき色々覚えたよね?
<input type="checkbox"> って書くとチェックボックスをだせるとか。
XUL の場合,その代わりにたとえば <checkbox> と書けばいいんだ。
つまり,新しいタグが増えたと思えばいいんだよ!
それに <colorpicker> とか素敵なウィジェットも揃っているよ!
くわしくは XUL controls | MDN をみてね!
- アプリケーションの配布がたいへん
今回の Ubuntu Linux の場合,たいていは xulrunner はもともとインストールされている。
けど,Windows とかの場合は,ユーザに XULRunner をダウンロード*5させなきゃいけない。
(まぁ Windows の場合解凍するだけで大丈夫らしいし,Mac OS X の場合はインストーラ形式になってるよ)
2009-01-20 追記:
id:teramako XUL, xulrunner ネタを取られた...orz // 悔しいので一つネタを。xulrunnerじゃなくてもFx3からは firefox -app application.ini で起動できたりするよ
http://b.hatena.ne.jp/teramako/20090119#bookmark-11728256
ごめんなさいごめんなさい!
それはともかく有益な情報をありがとう!
Firefox 3 だと,わざわざ xulrunner をインストールしなくても,
Firefox のバイナリから XUL アプリケーションを動かせるんだね。
これでアプリケーション配布の間口がちょっと広くなるね!
2009-01-20 追記おわり
アプリケーションの配布と同時にインストールも行うようにできるよ。
そもそも AIR の場合,アプリケーションの標準的な配布方法が定まっているのが大きいね!
参考になるページ
公式のページに参考になることが色々書いてあるよ!
みんな作って、どんどこ公開しちゃえばいいんじゃないかな!
(できれば、ぼくが見て勉強できるようにソースコード付きで…!)
おわりに
いわずとしれてるけど,これは下記のすばらしい記事へのオマージュだよ!
あとは私感だよ!
*1:原典をみればわかるけど,Windows や Mac OS X で動かすのも,たいして難しくはないよ!
*3:これはいかにも必須じゃなさそうだけど,XULRunner にメインウィンドウとなる XUL ファイルの名前をわたすために使います。
*4:これは chrome/ フォルダからの相対パス指定だよ。
*5:http://releases.mozilla.org/pub/mozilla.org/xulrunner/releases/1.9.0.5/runtimes/ とかにあるよ。
*6:HTML でいうところの & みたいな書き方のことだよ!XUL だとこの DTD を自分で用意することで,自分オリジナルな実体宣言ができるんだ。あとは,その参照先は英語の場合「foobar」だよ,みたいに DTD に書けば,世界中のみんなから使ってもらえるアプリケーションになるよ!
2008-12-09
はてブコメントの並び順を変えるグリモン書いた
はじめて Greasemonkey 書きましたよ。おかしなところがあったら教えてください。
さいしょ はてなブックマークのコメントを昇順に並べ替えるGreasemonkey を使ってたんですけど,いろいろ不満があったので書き換えてみました。原型はとどめてない。
light じゃない版あったのカー→Sort HB Comment for Greasemonkey。じゃあこれいらないや。
- ページを読み込んだ段階では,ソートボタンを付与するだけで何もしない
- 問答無用でソートするとコメント数が多いページで待ちが多くなるので
- 何種類かのボタンを指定できる
- ソート順を指定する関数を指定できる
- ソート中は「ソート中」って出る
まぁ「指定できる」ってのは,コード(setup() 部分)書き換えてくださいねっていうレベルなんですけれど。
ほんとは silog - script/SBMCommentsViewer とか使えばいいんでしょうけど,結構ブクマの entry ページとかよく見るんですよ。
// ==UserScript== // @name Sort HB Comment 2 // @namespace http://d.hatena.ne.jp/dayflower/ // @description Sort Hatena Bookmark Entry Page // @include http://b.hatena.ne.jp/entry/* // @include http://b.hatena.ne.jp/entry/?mode=more&url=* // ==/UserScript== (function () { setup([ { // 逆順 (コメント優先) label: '\u25bd\u9006\u9806', criteria: function (a, b) { // first criteria: comment var ac = a.getAttribute('class') || ''; var bc = b.getAttribute('class') || ''; if (bc.match(/nocomment/)) { if (! ac.match(/nocomment/)) return -1; } else { if (ac.match(/nocomment/)) return 1; } // second criteria: original order (reverse) return b.xHatebuOrder - a.xHatebuOrder; } }, { // 元の順序 label: '\u25bd\u6b63\u9806', criteria: function (a, b) { return a.xHatebuOrder - b.xHatebuOrder; } } ]); var items; // GLOBAL function setup(confs) { var marks = document.getElementById('bookmarked_user'); if (! marks) return; if (marks.childNodes[1].textContent // 非表示に設定 .match(/\u975e\u8868\u793a\u306b\u8a2d\u5b9a/)) return; var res = document.evaluate( '//h2[@class="comment bookmark-list"]/span/span[@class="count"]', document.body, null, 7, null ); if (res.snapshotLength <= 0) return; var area = res.snapshotItem(0); for (var i = 0, n = confs.length; i < n; i ++) add_button(area, confs[i]); } function init_items() { var marks = document.getElementById('bookmarked_user'); var items = []; if (1) { var t = marks.getElementsByTagName('li'); for (var i = 0, n = t.length; i < n; i ++) { items[i] = t[i]; items[i].xHatebuOrder = i; } } else { var res = document.evaluate('li', marks, null, 7, null); for (var i = 0, n = res.snapshotLength; i < n; i ++) { items[i] = res.snapshotItem(i); items[i].xHatebuOrder = i; } } return items; } function do_sort_comments(criteria) { if (items == null) items = init_items(); items.sort(criteria); var marks = document.getElementById('bookmarked_user'); var newlist = document.createElement('ul'); newlist.setAttribute('class', marks.getAttribute('class')); for (var i = 0, n = items.length; i < n; i ++) newlist.appendChild(items[i]); newlist.setAttribute('id', marks.getAttribute('id')); marks.parentNode.replaceChild(newlist, marks); } function add_button(area, conf) { var link = document.createElement('a'); link.style.cursor = 'pointer'; link.style.color = '#fff'; link.innerHTML = conf.label || '\u25bd'; if (conf.title) link.title = conf.title; link.addEventListener('click', function (e) { var me = e.target; // TEXTNODE var backup = me.firstChild.nodeValue; // ソート中… me.firstChild.nodeValue = '\u30bd\u30fc\u30c8\u4e2d\u2026'; window.setTimeout( function () { do_sort_comments(conf.criteria); me.firstChild.nodeValue = backup; //me.parentNode.style.visibility = 'hidden'; }, 0 ); e.preventDefault(); }, true); var button = document.createElement('span'); button.appendChild(document.createTextNode('\u3000[')); button.appendChild(link); button.appendChild(document.createTextNode(']')); area.appendChild(button); }
はじめて Greasemonkey 書いて感じたこと。
- デバッグがめんどくさい
- エラー時に firebug console に出力される内容がちょっと変だったり。環境依存?
- でも DOM 操作とか非常に勉強になる
- Firefox でしか動かない JavaScript を書くくせがつきそう
- 自作スクリプトのインストールがめんどくさい
- HTMLCollection の
sort()ができなかったんで,Array にコピーしてます-
Array.prototype.sort使ってみたけどうまくいかなかったです
-
Firefox の places.sqlite からブックマークをとりだす
新規インストールしたマシンに旧マシンの Firefox のブックマークを移行しようと思いました。
で,どうせ bookmarks.html でしょと思ってみてみたら,どうも内容が乏しい。
調べてみたら Firefox 3 では places.sqlite というファイルにブックマークはじめアクセスした URL を記録しているみたいですね。
さいわいプロファイルフォルダをまるごととってあったので places.sqlite を上書きしようかと思ったんですが,そうすると新マシンでとったブックマークがなくなってしまうのでちょっと困ります。
なので places.sqlite の構造をみてみました。
% sqlite3 places.sqlite SQLite version 3.5.9 Enter ".help" for instructions sqlite> .tables moz_anno_attributes moz_favicons moz_keywords moz_annos moz_historyvisits moz_places moz_bookmarks moz_inputhistory moz_bookmarks_roots moz_items_annos
moz_bookmarks というテーブルがあやしい。
sqlite> .headers on sqlite> SELECT * FROM moz_bookmarks; id|type|fk|parent|position|title|keyword_id|folder_type|dateAdded|lastModified 1|2||0|0||||1209528568635986|1219119864784935 2|2||1|0|ブックマークメニュー|||1209528568636177|1228180489548243 3|2||1|1|ブックマークツールバー|||1209528568636276|1225854151400802 4|2||1|2|タグ|||1209528568636372|1209528568636992 5|2||1|3|未整理のブックマーク|||1209528568636468|1224748978301927 ...... snip snip snip ...... 60|1|44|3|2|Google|0||1209530922956848|1212462725554602 ...... snip snip snip ......
ブックマークのタイトルはとれてますが,URL がみあたりません。
moz_bookmarks_roots テーブルをみてみると,
sqlite> SELECT * FROM moz_bookmarks_roots; root_name|folder_id places|1 menu|2 toolbar|3 tags|4 unfiled|5
こちらではなかったみたい。これは名前のとおり,ブックマークツリーのルートみたいですね。
では,general な名前の moz_places をみてみると,
sqlite> SELECT * FROM moz_places LIMIT 5; id|url|title|rev_host|visit_count|hidden|typed|favicon_id|frecency 1|place:queryType=0&sort=8&maxResults=10|queryType=0&sort=8 &maxResults=10||0|1|0||0 2|place:folder=BOOKMARKS_MENU&folder=UNFILED_BOOKMARKS &folder=TOOLBAR&queryType=1&sort=12 &excludeItemIfParentHasAnnotation=livemark%2FfeedURI&maxResults=10 &excludeQueries=1|folder=BOOKMARKS_MENU&folder=UNFILED_BOOKMARKS &folder=TOOLBAR&queryType=1&sort=12 &excludeItemIfParentHasAnnotation=livemark%2FfeedURI&maxResults=10 &excludeQueries=1||0|1|0||0 3|place:type=6&sort=14&maxResults=10|type=6&sort=14&maxResults=10||0|1|0||0 4|https://en-us.add-ons.mozilla.com/en-US/firefox/bookmarks/ |/en-US/firefox/bookmarks/|moc.allizom.sno-dda.su-ne.|0|0|0|1|140 5|http://en-us.www.mozilla.com/en-US/firefox/central/ |/en-US/firefox/central/|moc.allizom.www.su-ne.|0|0|0|2|140
こっちに URL が格納されているみたい。こちらにも title がありますが,こちらはもともとの title なのかな。
で,当て推量してると moz_bookmarks の fk フィールドと moz_places の id フィールドが対応しているみたい*1。
なので,結合して表示してみましょう。
sqlite> SELECT moz_places.url, moz_bookmarks.title ...> FROM moz_bookmarks, moz_places ...> WHERE moz_bookmarks.fk IS NOT NULL ...> AND moz_bookmarks.fk = moz_places.id ...> AND moz_places.url NOT LIKE 'place:%' ...> ORDER BY moz_bookmarks.id; url|title https://en-us.add-ons.mozilla.com/en-US/firefox/bookmarks/|Get Bookmark Add-ons http://en-us.www.mozilla.com/en-US/firefox/central/|Getting Started http://en-us.www.mozilla.com/en-US/firefox/help/|Help and Tutorials http://en-us.www.mozilla.com/en-US/firefox/customize/|Customize Firefox http://en-us.www.mozilla.com/en-US/firefox/community/|Get Involved http://en-us.www.mozilla.com/en-US/firefox/about/|About Us http://www.google.co.jp/|Google
おー。いい感じです。
#!/usr/bin/perl use strict; use warnings; use DBI; my $file = shift; if (! defined $file) { die "database places.sqlite not specified"; } my $dbh = DBI->connect("dbi:SQLite:dbname=${file}") or die $DBI::errstr; my $sth = $dbh->prepare(<<'END_SQL') SELECT moz_places.url, moz_bookmarks.title FROM moz_bookmarks, moz_places WHERE moz_bookmarks.fk IS NOT NULL AND moz_bookmarks.fk = moz_places.id AND moz_places.url NOT LIKE ? ORDER BY moz_bookmarks.id; END_SQL or die $dbh->errstr; $sth->execute('place:%') or die $dbh->errstr; my @items; while (my $rec = $sth->fetchrow_hashref()) { #use YAML; #print Dump($rec); my ($url, $title) = map { $rec->{$_} } qw( url title ); for ($url) { s'"'"'go; } for ($title) { s'&'&'go; s'<'<'go; s'>'>'go; } push @items, <<"END_ITEM"; <DT><A HREF="${url}">${title}</A> END_ITEM } if (@items) { my $items = join q{}, @items; print <<"END_HTML"; <!DOCTYPE NETSCAPE-Bookmark-file-1> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> <TITLE>Bookmarks</TITLE> <H1>Bookmarks</H1> <DL><p> ${items} </DL><p> END_HTML }
で
% perl bookmark.pl $(BOOKMARKPROFILE)/places.sqlite
実行すると,
<!DOCTYPE NETSCAPE-Bookmark-file-1> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> <TITLE>Bookmarks</TITLE> <H1>Bookmarks</H1> <DL><p> <DT><A HREF="https://en-us.add-ons.mozilla.com/en-US/firefox/bookmarks/">Get Bookmark Add-ons</A> </DL><p>
うまくできました。
あとはこのファイルから不要な項目を削って「ブックマークの管理」から「HTML からインポート」すればいいはず。
ほんとうはブックマークフォルダの階層構造もとれるんでしょうけど,面倒だしそこまでもとめていない*2のでこれでいいやと思いました。
あと,favicon もとろうと思えばとれますが,bookmarks.html の場合,内部にアイコンがうめこまれているのに対し,places.sqlite の場合,moz_favicons テーブルからアイコンの URL を取得してブラウザキャッシュのアイコンファイルを利用しているのではないかなー。



