javascript:void(function(n){m=/profile_s\.gif$/;for(i=0;i<n.length;i++){if(m.test(n[i].src)){n[i].src='http://mattn.kaoriya.net/images/unk.gif'}}})(document.getElementsByTagName('img'))するんだ!
2008/03/31
タッパー
あぶないコード
C/C++のポインタの機能--参照渡しのような処理 - builder by ZDNet Japanで、Electric Fenceの紹介につなげる記事にしようと思ったのですが
electric-fence-win32 - Google CodeElectric Fenceのwin32版なんてものを見つけてしまった。
てっきりUNIX版と同様、リンクすれば動くと思って色々試したけど、どうやらそうじゃないみたい。
//#include <efence.h>オーバーランを検知してくれなかった。README.win32によると
#include <stdio.h>
int main( void ) {
char *a = (char*)malloc(12);
a[ 0] = 'H';
a[ 1] = 'e';
a[ 2] = 'l';
a[ 3] = 'l';
a[ 4] = 'o';
a[ 5] = ',';
a[ 6] = ' ';
a[ 7] = 'W';
a[ 8] = 'o';
a[ 9] = 'r';
a[10] = 'l';
a[11] = 'd';
a[12] = '\0';
return 0;
}
と書いてありました。てっきりスタートアップルーチンを入れ替えてくれてくれる物かと思って少しだけ期待してしまいました。Since you need to modify your own project anyway, simply add efence.c, page-win32.c, and print.c to your project.
mingw32ならば
Index: Makefileこんな風に修正して
===================================================================
--- Makefile (revision 7)
+++ Makefile (working copy)
@@ -9,7 +9,7 @@
MAN_INSTALL_DIR= /usr/man/man3
PACKAGE_SOURCE= README libefence.3 Makefile efence.h \
- efence.c page.c print.c eftest.c tstheap.c CHANGES COPYING
+ efence.c page-win32.c print.c eftest.c tstheap.c CHANGES COPYING
# Un-comment the following if you are running HP/UX.
# CFLAGS= -Aa -g -D_HPUX_SOURCE -DPAGE_PROTECTION_VIOLATED_SIGNAL=SIGBUS
@@ -26,7 +26,7 @@
# as well if using Sun's compiler, -static if using GCC.
# CFLAGS= -g -Bstatic -DPAGE_PROTECTION_VIOLATED_SIGNAL=SIGBUS
-OBJECTS= efence.o page.o print.o
+OBJECTS= efence.o page-win32.o print.o
all: libefence.a tstheap eftest
@ echo
@@ -63,7 +63,7 @@
tstheap: libefence.a tstheap.o
- rm -f tstheap
- $(CC) $(CFLAGS) tstheap.o libefence.a -o tstheap -lpthread
+ $(CC) $(CFLAGS) tstheap.o libefence.a -o tstheap -lpthreadGC2
eftest: libefence.a eftest.o
- rm -f eftest
mingw32-make CC=gcc libefence.aでlibefence.aが出来上がり、上のソースの冒頭の「//」を外して
#include <efence.h>あぶないコードに修正した後
#include <stdio.h>
int main( void ) {
char *a = (char*)malloc(12);
a[ 0] = 'H';
a[ 1] = 'e';
a[ 2] = 'l';
a[ 3] = 'l';
a[ 4] = 'o';
a[ 5] = ',';
a[ 6] = ' ';
a[ 7] = 'W';
a[ 8] = 'o';
a[ 9] = 'r';
a[10] = 'l';
a[11] = 'd';
a[12] = '\0';
return 0;
}
gcc -g -o dame.exe dame.c -lefenceとすれば、efenceビルドされたdame.exeが出来上がり実行すると、正しくクラッシュしてくれる。gdbで確認すれば
C:¥temp¥electric-fence-win32>gdb dame.exeとクラッシュ場所も分かると。でもUNIX版みたくソースは修正したくないなぁ。
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-mingw32"...
(gdb) run
Starting program: C:¥temp¥electric-fence-win32/dame.exe
...
Program received signal SIGSEGV, Segmentation fault.
0x00401396 in main () at dame.c:17
17 a[12] = '\0';
(gdb)
あとmallocでなく
char a[12];とした場合にクラッシュしてくれないのならば、威力半減ってところか。
意外と知られていないvimのtips(vimスクリプトを難読化)
Vim script line continuation? - vim_dev | Google グループ検証コードWell, it seems the new line continuation can be placed weirdly, which will make the vim script syntax file even messy when considering the line continuation. Any comments?
e
\c
\h
\o
\ "
\そ
\れ
\P
\l
\a
\!"
それPla!
2008/03/27
Internet Explorer 6で動作するAutoPagerize作った。
os0xさんが、マルチプラットフォームで動くしかもブックマークレットで起動出来るAutoPagerize for IE6公開されておられます。
「できた!」とほぼ同時にtwitterに書き込んでたのが笑った。
確かに、iframeを使えばXHRを使った場合と違ってresponseTextからcreateContextualFragment等で苦労する事無く、同じドメイン内のiframeだからDOM操作が出来ると...
諦め所がXPath(responseTextからcreateDocumentが出来ないという意味で)でなく、XHRを諦めるべきだったかも。
でけれた。
AutoPagerizeとか、oAutoPagerizeとか、jAutoPagerizeとかをベースに改造しようかと思ったけど、結局XPathでつまづいた。
AutoPagerizeを実現するには、カレントのdocumentとは別のdocumentに読み込んだHTMLを入れてページ部を抽出する必要があるんだけど、IE6ではカレントdocumentにappencChildしないとXPathセレクタが動かない(amachangのJavaScript-XPathで検証)。また、createRange/createContextualFragmentも動かないだろうし、どちみち駄目。
つまり、XPathは実現出来ない事になる。
諦めて、mala氏が作ったオリジナル、「GoogleAutoPager」をベースに作り直した。
で、最初はGoogleだけでいいかと思ったけど、欲が出てtwitterやtumblr、d.hatena.ne.jp、b.hatena.ne.jpでも動かせるようにした。
アイコンとかはありません。ダブルクリックで起動です。![]()
但し、セレクタとしてはCSSセレクタを使ってるので、特殊な調べ方は出来ない。しかもIE6なのでCSSのバージョンが低い。
セレクタライブラリとしてはjQueryを使用しています。動かす為にはTrixieが必要です。Trixieをインストール後
C:¥Program Files¥Bhelpuri¥Trixie¥Scripts¥に以下のリンクにあるiAutoPagerize.user.jsを放り込めばインストールは完了。現状、SITEINFOはベタ打ちです。今後SITEINFOサーバを用意するつもりもありません。ただ、codereposに置いておくので誰でも修正出来る様にしておきます。
ネーミングは、「OperaのがoAutoPagerize」なら「IEはiAutoPagerize?」くらいの思考能力で付けた名前です。
よろしかったらどうぞ。
iAutoPagerize
Tagged as: autopagerize, ie6
Bookmarks:
|
XPathのexprにはノードも書けるんだ
例えば
<div class="foo">こんなHTMLで
<p>
<span class="test1">title1</span>
</p>
<ul>
<li>list1</li>
<li>list2</li>
<li>list3</li>
</ul>
</div>
<div class="foo">
<div>
<span class="test1">title2</span>
</div>
<ul>
<li>list1</li>
<li>list2</li>
<li>list3</li>
</ul>
</div>
<div class="foo">
<div>
<span class="test2">title3</span>
</div>
<ul>
<li>list1</li>
<li>list2</li>
<li>list3</li>
</ul>
</div>
- class属性"foo"を持つdiv
- その孫にclass属性"test1"を持つspan
- 上の条件下にある上記divの孫にあるli
//div[@class="foo"]//span[@class="test1"]/../..//liこう書いてたんですが、これだとliの階層が深い場合に".."を書く個数が限定されてしまっていました。
で、今日知ったのですが、expr部には「@xxx="yyy"」といったexprだけでなくパスも書けるのを知った。
//div[@class="foo" and .//span[@class="test1"]]//liこれだとcurrent-contextとして
- class属性"foo"を持つdiv
上の例だとtitle1の下のliと、title2の下のliがマッチする。
ところで皆さんはXPathをテストしたい場合、何を使ってますか?
私はjAutoPagerizeを使っています。jAutoPagerizeはcho45氏作のAutoPagerizeクローンで、私は本家を使わずこちらを使っています。
なぜこれを使っているかというと、jAutoPagerize本来の機能も良いのですがXPathGeneratorが付いているからです。
jAutoPagerizeをインストールすると
というアイコンが画面右上に出るのですが、これをクリックすると![]()
といった形でXPathの入力画面が現れます。ここにXPathを書いて"TAB"キー等でフォーカスを外すと![]()
と赤くハイライトされるのです。視覚的にも分かりやすいですね。他直接ノードからXPathを取得するInspectボタンもクラス名を知るのに使えます。![]()
また、AutoPagerize対応でないページでアイコンが出ていなくても
XPathGeneratorこんなブックマークレットさえ用意しておけば、何時でもXPathGeneratorを表示出来るようになります。
XPathGeneratorかわいいよXPathGenerator
2008/03/26
Publish::Diigo書いた。
/lang/perl/plagger/lib/Plagger/Plugin/Publish/Diigo.pm - CodeRepos::Share - Tracwww.diigo.com...ブックマークレットから実行出来る専用ポスト画面がなかなかカッコイイ。
今回はこのブックマークレットのhackで作った。
これで、私が同期しているソーシャルブックマークは
- Publish::Delicious
- Publish::LivedoorClip
- Publish::Buzzurl
- Publish::LivedoorCilp
- Publish::Buzzurl
- Publish::GooBookmark
- Publish::NiftyClip
- Publish::Pookmark
- Publish::YahooBookmark
- Publish::FC2Bookmark
- Publish::BlueDot という名の Pubilsh::Delicious
- Publish::Magnolia という名の Publish::Delicious
- Publish::Diigo
以下、今後変わっていくかもしれないけどコード。
FriendFeedにAPIが出来たのでさっそく使ってみた
朝起きたらAPIが出来てました。確か昨日「/api」にアクセスしても無かったのになぁ。
FriendFeed Blog: FriendFeed API: Extend and improve FriendFeedさっそく使ってみました。APIはJSON、XML、RSS、ATOMで提供されており、クライアントライブラリとしてPHPとpythonのライブラリが用意されています。
We are very excited to announce the launch of the FriendFeed API, which enables developers to interact with the FriendFeed site programmatically. It's designed to make it possible for anyone to improve FriendFeed or integrate FriendFeed into other applications. You can develop a FriendFeed interface for a mobile phone, build a FriendFeed widget for your blog, or develop an application that makes it easy to post photos to your feed from your iPhone.
つまり、XMLフォーマットを使っているgtktwitterを改造してgtkfriendfeedなんて事も出来る訳ですね。
ApiDocumentation - friendfeed-api - Google Codetwitterと同じくprivateでなければ認証無しでアクセス出来ます。
friendfeed-api - Google Code
認証が必要な場合は、「remotekey」と呼ばれるアプリケーションキーを取得する必要があります。remotekeyは
FriendFeed - Remote Keyで取得出来ます。認証方法はBasic認証です。今日は認証を使わない例ですが、javascriptからjsonで私と、kuさんと、otsuneさんのフィードをミックス表示する例をサンプルとして上げておきます。
まずコード
<style type="text/css"><!--
#mattn_friendfeed {
margin: 1em;
font-family: Verdana;
width: 400px;
}
#mattn_friendfeed a {
color: blue;
}
.friendfeed-line {
padding-bottom: 1em;
}
.friendfeed-link {
font-size: small;
}
--></style>
<script type="text/javascript"><!--
function mattn_friendfeed_callback(data) {
var container = document.createElement('div');
for(var n = 0; n < data.entries.length; n++) {
var user = document.createElement('a');
var link = document.createElement('a');
var line = document.createElement('div');
var icon = document.createElement('img');
var br = document.createElement('br');
user.href = data.entries[n].user.profileUrl;
link.className = 'friendfeed-link';
link.href = data.entries[n].link;
link.appendChild(document.createTextNode(link.href));
icon.src = user.href + '/picture?size=small';
icon.setAttribute('align', 'left');
user.appendChild(icon);
br.setAttribute('clear', 'all');
line.className = 'friendfeed-line';
line.appendChild(user);
line.appendChild(document.createTextNode(' ' + data.entries[n].title + ' '));
line.appendChild(document.createElement('br'));
line.appendChild(link);
line.appendChild(br);
container.appendChild(line);
}
document.getElementById('mattn_friendfeed').innerHTML = container.innerHTML;
}
function show_mattn_friendfeed() {
document.getElementById('mattn_friendfeed').innerHTML = '<img src="http://mattn.kaoriya.net/images/ajax-loader.gif">';
var s = document.createElement('script');
s.charset = 'utf-8';
s.src = 'http://friendfeed.com/api/feed/user?nickname=mattn,otsune,ku0522&callback=mattn_friendfeed_callback';
document.body.appendChild(s);
}
--></script>
<input type="button" value="mattnのfriendfeedエントリを表示" onclick="show_mattn_friendfeed();" />
<br />
<em>mattnと、ku0522さんと、otsuneさんのmix表示</em><br />
<div id="mattn_friendfeed"></div>
そして実行例
Tagged as: api, friendfeed, javascript
Bookmarks:
|
2008/03/25
Firefox3でもmicroformat OperatorのhAtomやhFeedを有効にする方法
Firefox3からは、ブラウザ自身でmicroformatsを解析出来る仕組みが入ったのですが、その対応がOperatorに中途半端に入っている様です。
chromeからmicroformatsを扱う為には
Components.utils.import("resource://gre/modules/Microformats.js");というコードが必要なのですが、この処理がコメントアウトされていました。
実際には
$(FIREFOX_PROFILE)/extensions/{95C9A302-8557-4052-91B7-2BB6BA33C885}/chrome/operator.jarに含まれる
content/operator.jsが原因で、パッチで表すならば以下の様な感じ。
--- chrome/content/operator.js.orig Wed Mar 19 11:44:26 2008おしいなぁ...作者。もしくは開発時はバギーだったかな?
+++ chrome/content/operator.js Tue Mar 25 19:11:01 2008
@@ -77,7 +77,7 @@
/* Attempt to use the Microformats module if available (Firefox 3) */
if (Components.utils.import) {
try {
-// Components.utils.import("resource:///modules/Microformats.js");
+ Components.utils.import("resource:///modules/Microformats.js");
} catch (ex) {
/* Unable to load system Microformats - use builtin */
}
実際の作業としては「operator.jar」を解凍し上記パッチを当てた(もしくは手編集)後に再度zip(拡張子jar)化すればOK。見事以前までのmicroformat Operatorが帰ってきました。
相変わらずウチのサイトはmicroformatsだらけですが...
ところでFirefox3で扱えるmicroformats、「Describing microformats in JavaScript - MDC」を見るとどうやら自前でmicroformatの定義が出来る様です。今後draftとして拡張されていくであろうmicroformatsへの配慮ですかね。せっかくmicrosummaryのOperatorプラグイン作ってたのに、こっちの方向で作り直しか?
で、さらにドキュメントの例を見ていると
var adr_definition = {という記述が...。これOperatorのソースコードのままだね。ってことはOperatorのソースをFirefox3に持ってったのかな?
mfVersion: 0.8,
mfObject: adr,
className: "adr",
properties: {
"type" : {
plural: true,
types: ["work", "home", "pref", "postal", "dom", "intl", "parcel"]
},
"post-office-box" : {
},
"street-address" : {
plural: true
},
"extended-address" : {
},
"locality" : {
},
"region" : {
},
"postal-code" : {
},
"country-name" : {
}
}
};
とにかく簡単に拡張出来そうな仕組みなので、しばらく追ってみる。
Tagged as: firefox, firefox3, microformats, operator
Bookmarks:
|
2008/03/24
Google Visualizationを動的にロードしてGreasemonkey等で使用されているSITEINFOをGoogle SpreadSheetから取得する
使い方次第では、結構強力な物になりそうな気がする。spreadsheetとつながってるってやばいじゃんこれspreadsheetをバックエンドdbにしていろいろできるってことでしょ
ku's post on twitter
ちなみに
F's Garage:iPhone SDKを読み解くのに必須! Google AJAX Language APIを使ったブックマークWidget作った。多分以下の様にすれば行けるはず。(jsapiのクエリパラメータ「callback」と、loadの第三引数「callback」)
Google AJAX Language APIは、document.writeで翻訳機能読み込みのscript要素コードを出力するようにできており、ブックマークレットには必須の遅延ロードができないようなので、なんだかいろいろ苦労しちゃいました。
wikiも確かに管理しやすいかもしれないけど、Google SpreadSheetも可能性があると思う。
ちなみに今回作ったSITEINFOは簡単な物なので、「ネタフル」と「IDEA * IDEA」くらいしかない。
あと、クエリのfrom区には「sheet1」とか使えるのが分かった。![]()
以下、Google SpreadSheetからSITEINFOを読み込むサンプル
var siteinfo = [];とその実行結果。
function handleQueryResponse(response) {
var data = response.getDataTable();
if (!data || response.isError()) {
alert(response.getMessage() + ':' + response.getDetailedMessage());
return;
}
for (var row = 0; row < data.getNumberOfRows(); row++) {
siteinfo.push({
'name' : data.getFormattedValue(row, 0),
'link' : data.getFormattedValue(row, 1),
'url' : data.getFormattedValue(row, 2),
'xpath' : data.getFormattedValue(row, 3),
'base' : data.getFormattedValue(row, 4)
});
}
var html = '';
for (var n = 0; n < siteinfo.length; n++) {
html += '<b><a href="' + siteinfo[n].link + '">' + siteinfo[n].name + '</a></b><br />'
html += '<blockquote' + '><' + 'pre>';
html += '<b>url</b>:' + siteinfo[n].url + '<br />';
html += '<b>xpath</b>:' + siteinfo[n].xpath + '<br />';
html += '<b>base</b>:' + siteinfo[n].base + '<br />';
html += '<' + '/pre></' + 'blockquote>';
}
document.getElementById('ExampleSITEINFO').innerHTML = html;
}
function querySITEINFO() {
var query = new google.visualization.Query(
"http://spreadsheets.google.com/tq?key=psdg8ZffuCtcsEuIuzzd1Mw&pub=1");
query.setQuery("select A, B, C, D, E from sheet1 order by A desc");
query.send(handleQueryResponse);
}
function jsapi_loaded() {
google.load("visualization", "1", {"callback" : querySITEINFO});
}
function loadExampleSITEINFO() {
var s = document.createElement('script');
s.charset = 'utf-8';
s.src = 'http://www.google.com/jsapi?callback=jsapi_loaded';
document.body.appendChild(s);
}
IE6、Firefox、Safari3、Opera9.50bで動作確認。
Tagged as: api, google, javascript
Bookmarks:
|
意外と知られていないvimのtips(vimスクリプトでリバーシ)
Tagged as: tips, vim, vimscript
Bookmarks:
|
feedジェネレータとしてblosxomを使う
The Unofficial Blosxom User Group :: Using Blosxom as Feed Generatorblosxomの開発者の一人、Gavin Carr氏がblosxomを使って面白いアイデアを出しているようです。Gavin Carr, one of the Blosxom developers, recently posted a simple yet somehow not obvious idea on his blog: He uses Blosxom to automatically generate feeds for software which hasn't feeds, in this case the network monitoring system Nagios, so that he get's all Nagios events delivered to his feed reader.
A similar yet local use of this idea is to let blosxom or a wrapper script be called by your feed reader directly. Liferea (GUI, GNOME) and Snownews (text-mode, ncurses) have this feature and there is already a big repository of plugins. The same way as those plugins are called, you can easily use blosxom as a plugin to those two feed readers so you don't need to care about how to generate RSS, blosxom does that for you. You just need to set the environment variable PATH_INFO to
/index.rssbefore, e.g. by calling blosxom like this:env PATH_INFO=/index.rss blosxom.That way I currently monitor the NVidia Unix Drivers Portal Page for changes, using this script, the libwww-perl (LWP), wdiff, a little bit of Perl glue and of course Blosxom. (In this case I use Debian's version of Blosxom which is able to have several configuration per installation by adding a -f flag for config files.)
Hackery :: Blosxom4Nagiosと題した記事に記されている中では、Nagiosというモニタリングシステムの結果をフィード化するにあたり、snownewsやLifereaといったクライアント向けフィードリーダのフィード読み込みコマンドを利用するという例が紹介されています。
実際には記事の中で紹介されている、changes2rss.plというperlスクリプト内からblosxomを実行し、結果をRSSとして出力するという代物です。
なかなか面白いアイデアですね。フィード読み込みコマンドをサポートしているフィードリーダでしか有効ではないですが
- 情報収集
- システム監視
2008/03/21
知らない事あるなぁ...C言語
ロベールのC++入門講座を読んで C++ を初歩の初歩から再入門するよ - 前編 - ひげぽん OSとか作っちゃうかMona-うむ。しらんかった。確かに出力されるアセンブリも
[] 演算子は a[b] と b[a] はおなじ意味らしい。なんと!
それぞれ *(a + b) 、*(b + a) になるので等しいのですね。
となり、結果同じ操作なのだけれど、まさか文法的にコレが通るとは思ってなかった。![]()
int main(void) {知らない事だらけだ...
int a[3];
0[a] = 1;
1[a] = 2;
printf("%d,%d,%d,%d\n", a[0], a[1], 0[a], 1[a]);
return 0;
}
2008/03/19
自作のWindowsアプリケーションにJavaScriptで動作するプラグイン機能を実装する方法
最近のテキストエディタ等では、マクロ等と呼ばれる拡張言語を使用してエディタ本来の動作では実現出来ない色々な追加機能を実行する事が出来る様になっています。
今日は、既存のWin32アプリケーションにJavaScriptでマクロが実行出来る様にする為のtipsをご紹介。
拡張言語といってもJavaScriptの様に柔軟性のある言語を作り直すとなると程遠い工数を掛けてしまう事になりますが、Windowsには「ScriptControl」というスクリプト実行コンポーネントが用意されています。
今回はこれを使って外部にあるJavaScriptファイルを実行し、かつそのJavaScriptからアプリケーション内のオブジェクトを操作するまでを説明します。ScriptControlはCOMで実装されており、以下の様にインスタンスを生成します。
hr = CoCreateInstance(そしてJavaScript(JScript)を実行させる為にLanguageプロパティを設定してExecuteStatementを実行します。
CLSID_ScriptControl,
NULL,
CLSCTX_ALL,
IID_IScriptControl,
(void**)&pScriptCtrl);
hr = pScriptCtrl->put_Language(_bstr_t("JScript"));これだけで既存のアプリケーションからJavaScriptが実行出来るようになります。
hr = pScriptCtrl->put_Timeout(-1);
hr = pScriptCtrl->put_AllowUI(VARIANT_FALSE);
hr = pScriptCtrl->ExecuteStatement(A2BSTR("var a = 'test'"));
ただこれだけでは既存アプリケーションとの連携はまったく無く、面白味がありませんし単なる計算言語にしか成り得ません。
ブラウザ上で実行されるJavaScriptの様にwindowオブジェクトも無ければdocumentオブジェクトもありません。
つまりalertは使えません
このオブジェクトをJavaScript上に追加するのがAddObjectメソッドです。
AddObjectメソッドは名称指定でIUnknownオブジェクトをJavaScriptの実行スコープに追加出来ます。
ここに既存アプリケーションのオブジェクトを差し込む事になります。JavaScriptではメソッドを呼び出そうとする際にそのオブジェクトに対してIDispatchへのQueryInterfaceを試み、GetIDsOfNamesでdispIDを取得した後にInvokeメソッドを呼び出します。
この辺は、COMの知識のある方ならば既にご存知ですね。
で実装したIDispatchは以下の様なコードになりました。
class MyObject : public IDispatch単純に引数の文字列をメッセージボックスで表示する「say」メソッドと、引数の文字列をプログラムとして起動する「start」メソッドを実装しています。
{
private:
LONG m_cRef;
// method type
typedef HRESULT (MyObject::*Func)(DISPPARAMS*, VARIANT*);
// method structure
typedef struct _MY_OBJECT_METHOD_TABLE {
_MY_OBJECT_METHOD_TABLE(DISPID dispid, const char* name, Func fn) {
this->dispid = dispid;
this->name = name;
this->fn = fn;
}
DISPID dispid;
const char* name;
Func fn;
} MY_OBJECT_METHOD_TABLE;
// method table
std::vector<MY_OBJECT_METHOD_TABLE> myObjectMethodTable;
public:
// method: say
// show MessageBox
HRESULT say(DISPPARAMS* pDispParams, VARIANT* ret) {
USES_CONVERSION;
for(int n = 0; n < pDispParams->cArgs; n++) {
HRESULT hr;
VARIANT arg;
VariantInit(&arg);
hr = VariantChangeType(&arg, &pDispParams->rgvarg[n], 0, VT_BSTR);
MessageBox(0, OLE2T(arg.bstrVal), _T("MyObject"), MB_OK);
}
if (ret) {
VariantInit(ret);
V_VT(ret) = VT_BOOL;
V_BOOL(ret) = VARIANT_TRUE;
}
return S_OK;
}
// method: start
// start program by arguments
HRESULT start(DISPPARAMS* pDispParams, VARIANT* ret) {
USES_CONVERSION;
for(int n = 0; n < pDispParams->cArgs; n++) {
HRESULT hr;
VARIANT arg;
VariantInit(&arg);
hr = VariantChangeType(&arg, &pDispParams->rgvarg[n], 0, VT_BSTR);
ShellExecute(NULL, _T("open"), OLE2T(arg.bstrVal), NULL, NULL, SW_SHOW);
}
if (ret) {
VariantInit(ret);
V_VT(ret) = VT_BOOL;
V_BOOL(ret) = VARIANT_TRUE;
}
return S_OK;
}
// constructor
MyObject() : m_cRef(0) {
myObjectMethodTable.push_back(MY_OBJECT_METHOD_TABLE(1, "say", say));
myObjectMethodTable.push_back(MY_OBJECT_METHOD_TABLE(2, "start", start));
}
STDMETHODIMP QueryInterface(REFIID rid, LPVOID *ppv) {
*ppv = NULL;
if (::IsEqualIID(rid, IID_IUnknown)) {
*ppv = this;
AddRef();
return S_OK;
}
if (::IsEqualIID(rid, IID_IDispatch)) {
*ppv = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef() {
ULONG ref = InterlockedIncrement(&m_cRef);
return ref;
}
ULONG STDMETHODCALLTYPE Release() {
ULONG ref = InterlockedDecrement(&m_cRef);
return ref;
}
STDMETHODIMP GetTypeInfoCount(UINT *ptiCount) {
if (ptiCount) *ptiCount = 0;
return S_OK;
}
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **pptInfo) {
if (pptInfo) *pptInfo = NULL;
return S_OK;
}
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID) {
USES_CONVERSION;
for(UINT n = 0; n < cNames; n++) {
std::vector<MY_OBJECT_METHOD_TABLE>::iterator it = myObjectMethodTable.begin();
for(it = myObjectMethodTable.begin(); it != myObjectMethodTable.end(); it++) {
if (!strcmp(it->name, OLE2A(rgszNames[n]))) {
rgDispID[n] = it->dispid;
break;
}
}
if (it == myObjectMethodTable.end()) return E_UNEXPECTED;
}
return S_OK;
}
STDMETHODIMP Invoke(DISPID dispID, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) {
std::vector<MY_OBJECT_METHOD_TABLE>::iterator it = myObjectMethodTable.begin();
for(it = myObjectMethodTable.begin(); it != myObjectMethodTable.end(); it++) {
if (it->dispid == dispID) {
return (this->*(it->fn))(pDispParams, pVarResult);
}
}
if (it == myObjectMethodTable.end()) return E_UNEXPECTED;
return S_OK;
}
};
これを実行する「plugin.js」は以下の様になります。
MyObject.say('Hello');これを実行すると「Hello」というメッセージボックスが表示された後、このサイトがブラウザで表示される結果となります。
MyObject.start('http://mattn.kaoriya.net');
全体のソースコードは以下の通り。![]()
#include <atlbase.h>あとはこの「say」メソッドなり「start」メソッドなりを既存アプリケーションとの連携用メソッドとして実装すれば、見事JavaScriptによるプラグイン機能が実現出来ます。
#include <windows.h>
#include <string>
#include <vector>
#import <msscript.ocx> raw_interfaces_only, named_guids, no_namespace
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "shell32.lib")
class MyObject : public IDispatch
{
private:
LONG m_cRef;
// method type
typedef HRESULT (MyObject::*Func)(DISPPARAMS*, VARIANT*);
// method structure
typedef struct _MY_OBJECT_METHOD_TABLE {
_MY_OBJECT_METHOD_TABLE(DISPID dispid, const char* name, Func fn) {
this->dispid = dispid;
this->name = name;
this->fn = fn;
}
DISPID dispid;
const char* name;
Func fn;
} MY_OBJECT_METHOD_TABLE;
// method table
std::vector<MY_OBJECT_METHOD_TABLE> myObjectMethodTable;
public:
// method: say
// show MessageBox
HRESULT say(DISPPARAMS* pDispParams, VARIANT* ret) {
USES_CONVERSION;
for(int n = 0; n < pDispParams->cArgs; n++) {
HRESULT hr;
VARIANT arg;
VariantInit(&arg);
hr = VariantChangeType(&arg, &pDispParams->rgvarg[n], 0, VT_BSTR);
MessageBox(0, OLE2T(arg.bstrVal), _T("MyObject"), MB_OK);
}
if (ret) {
VariantInit(ret);
V_VT(ret) = VT_BOOL;
V_BOOL(ret) = VARIANT_TRUE;
}
return S_OK;
}
// method: start
// start program by arguments
HRESULT start(DISPPARAMS* pDispParams, VARIANT* ret) {
USES_CONVERSION;
for(int n = 0; n < pDispParams->cArgs; n++) {
HRESULT hr;
VARIANT arg;
VariantInit(&arg);
hr = VariantChangeType(&arg, &pDispParams->rgvarg[n], 0, VT_BSTR);
ShellExecute(NULL, _T("open"), OLE2T(arg.bstrVal), NULL, NULL, SW_SHOW);
}
if (ret) {
VariantInit(ret);
V_VT(ret) = VT_BOOL;
V_BOOL(ret) = VARIANT_TRUE;
}
return S_OK;
}
// constructor
MyObject() : m_cRef(0) {
myObjectMethodTable.push_back(MY_OBJECT_METHOD_TABLE(1, "say", say));
myObjectMethodTable.push_back(MY_OBJECT_METHOD_TABLE(2, "start", start));
}
STDMETHODIMP QueryInterface(REFIID rid, LPVOID *ppv) {
*ppv = NULL;
if (::IsEqualIID(rid, IID_IUnknown)) {
*ppv = this;
AddRef();
return S_OK;
}
if (::IsEqualIID(rid, IID_IDispatch)) {
*ppv = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef() {
ULONG ref = InterlockedIncrement(&m_cRef);
return ref;
}
ULONG STDMETHODCALLTYPE Release() {
ULONG ref = InterlockedDecrement(&m_cRef);
return ref;
}
STDMETHODIMP GetTypeInfoCount(UINT *ptiCount) {
if (ptiCount) *ptiCount = 0;
return S_OK;
}
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **pptInfo) {
if (pptInfo) *pptInfo = NULL;
return S_OK;
}
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispID) {
USES_CONVERSION;
for(UINT n = 0; n < cNames; n++) {
std::vector<MY_OBJECT_METHOD_TABLE>::iterator it = myObjectMethodTable.begin();
for(it = myObjectMethodTable.begin(); it != myObjectMethodTable.end(); it++) {
if (!strcmp(it->name, OLE2A(rgszNames[n]))) {
rgDispID[n] = it->dispid;
break;
}
}
if (it == myObjectMethodTable.end()) return E_UNEXPECTED;
}
return S_OK;
}
STDMETHODIMP Invoke(DISPID dispID, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) {
std::vector<MY_OBJECT_METHOD_TABLE>::iterator it = myObjectMethodTable.begin();
for(it = myObjectMethodTable.begin(); it != myObjectMethodTable.end(); it++) {
if (it->dispid == dispID) {
return (this->*(it->fn))(pDispParams, pVarResult);
}
}
if (it == myObjectMethodTable.end()) return E_UNEXPECTED;
return S_OK;
}
};
// load script and return the code
char* loadScriptAlloc(LPCTSTR pszFileName) {
HANDLE hFile;
DWORD dwFileSize, dwReadSize;
char* pszData = NULL;
hFile = CreateFile(
pszFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE) goto leave;
dwFileSize = GetFileSize(hFile , NULL);
if (dwFileSize == (DWORD)-1) goto leave;
pszData = (char*)calloc(dwFileSize + 1, 1);
if (!pszData) goto leave;
if (!ReadFile(
hFile,
pszData,
dwFileSize,
&dwReadSize, NULL)) goto leave;
leave:
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
return pszData;
}
int main(int argc, char *argv[]) {
USES_CONVERSION;
HRESULT hr = 0;
IScriptControl* pScriptCtrl = NULL;
char* pszCode = NULL;
MyObject* pMyObject = NULL;
CoInitialize(NULL);
hr = CoCreateInstance(
CLSID_ScriptControl,
NULL,
CLSCTX_ALL,
IID_IScriptControl,
(void**)&pScriptCtrl);
if (FAILED(hr) || !pScriptCtrl) goto leave;
hr = pScriptCtrl->put_Language(_bstr_t("JScript"));
if (FAILED(hr)) goto leave;
hr = pScriptCtrl->put_Timeout(-1);
if (FAILED(hr)) goto leave;
hr = pScriptCtrl->put_AllowUI(VARIANT_FALSE);
if (FAILED(hr)) goto leave;
pMyObject = new MyObject();
hr = pScriptCtrl->AddObject(_bstr_t("MyObject"), pMyObject, VARIANT_TRUE);
pszCode = loadScriptAlloc(_T("plugin.js"));
if (!pszCode) goto leave;
hr = pScriptCtrl->ExecuteStatement(A2BSTR(pszCode));
free(pszCode);
pszCode = NULL;
leave:
if (pszCode) {
free(pszCode);
pszCode = NULL;
}
if (pScriptCtrl) {
pScriptCtrl->Reset();
pScriptCtrl->Release();
pScriptCtrl = NULL;
}
if (pMyObject) {
pMyObject->Release();
pMyObject = NULL;
}
CoUninitialize();
return 0;
}
意外と少ないコードで実装出来るので皆さん昔に作ったアプリケーション等を拡張して見られてはどうでしょうか。
Tagged as: com, javascript, windows
Bookmarks:
|
2008/03/18
ブログにXML-RPC APIで、複数のファイルをアップロードするPythonスクリプト
ブログにXML-RPC APIで、複数のファイルをアップロードするRubyスクリプト:Goodpicpythonは楽でいいや。I love python!
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys, os, glob
import base64
import mimetypes
import xmlrpclib
if len(sys.argv) < 6:
print "usage: url blogid username password path [files ... or directory]"
sys.exit()
metaWeblog = xmlrpclib.Server(sys.argv[1]).metaWeblog
for arg in sys.argv[6:]:
if os.path.isdir(arg): arg = os.path.join(arg,'*')
for f in glob.glob(arg):
print metaWeblog.newMediaObject(
sys.argv[2], # blogid
sys.argv[3], # username
sys.argv[4], # password
{
'name' : "%s/%s" % (sys.argv[5], os.path.basename(f)),
'type' : mimetypes.guess_type(f)[0] or 'application/octet-stream',
'bits' : xmlrpclib.Binary(open(f, "rb").read())
})
使い方は
upload.py http://your.blog.server/xmlrpc your-blog-id username password upload-directory [local files or directory]
Tagged as: metaWeblog, python
Bookmarks:
|
Greasemonkeyで実行されるスクリプトはイケてるのか?
// ==UserScript==これOKでつか...
// @name broken source
// @namespace xxxxxx
// @description broken source
// @include http://*
// ==/UserScript==
})();
(function () {
イケるんですか...
Tagged as: greasemonkey
Bookmarks:
|
2008/03/17
blosxomでAmazon Web Serviceが使えるawxsomを改造してkeyword検索に対応出来るようにした
AWSWORD:ほにゃらら:※「ほにゃらら」は英数字もしくは「_」
と指定出来るようにした。
これまでの様に
ASIN:4844322893と書けば
となるし
AWSWORD:perl:と書けば
となる。
結果は一覧されるうちの先頭で表示され、キャッシュは全件「検索語.xml」で保存される。ファイル名の都合で英数字+「_」が制限になってます。
なおblosxom::templateを使ってないのは、mobrowserと干渉しても構わないようにです。
パッチは以下の通り。
--- awsxom.orig Thu Nov 30 22:12:17 2006ちなみに、先日図書館で見つけた本で面白いの見つけた。
+++ awsxom Tue Mar 18 09:32:22 2008
@@ -57,17 +57,20 @@
# ASIN/ISBNが書かれていたら置き換える
# テンプレート指定版
- s/(?:ASIN|ISBN):([A-Z0-9]{10}):(.*?):/to_html($1,$2)/ge;
+ s/(?:ASIN|ISBN):([A-Z0-9]{10}):(.*?):/to_html_asin($1,$2)/ge;
# テンプレート無指定版
- s/(?:ASIN|ISBN):([A-Z0-9]{10})/to_html($1,$default_template)/ge;
+ s/(?:ASIN|ISBN):([A-Z0-9]{10})/to_html_asin($1,$default_template)/ge;
+
+ # テンプレート無指定版
+ s/(?:AWSWORD):([a-zA-Z0-9_]*?):/to_html_word($1,$default_template)/ge;
return $_;
}
# ---------------------------------------------------------------------
# ASINからAmazonのアフィリエイト用HTMLを作成
-sub to_html {
+sub to_html_asin {
my ($asin, $template) = @_; # ASINとテンプレ名称
my $cache = "$cachedir/$asin.xml";
my $url = "http://webservices.amazon.co.jp/onca/xml?Service=AWSECommerceService&SubscriptionId=$devkey&AssociateTag=$asoid&Operation=ItemLookup&ItemId=$asin&ResponseGroup=Medium,Offers";
@@ -90,8 +93,57 @@
# テンプレートを展開。エラーの場合はエラー文字列を返す
my $form;
if (!defined($detail{"ErrorMsg"})) {
- $form = &$blosxom::template($blosxom::path, $template, 'html');
- $form =~ s/\$(\w+)/$detail{$1}/ge;
+ #$form = &$blosxom::template($blosxom::path, $template, 'html');
+ my $fh = new FileHandle;
+ if ($fh->open("< $blosxom::datadir/$template.html")) {
+ $form = join '', <$fh>;
+ $form =~ s/\$(\w+)/$detail{$1}/ge;
+ $fh->close();
+ }
+ }
+ else {
+ $form = "<p>" . $detail{"ErrorMsg"} . "</p>";
+ }
+
+ return $form;
+}
+
+# ---------------------------------------------------------------------
+# ASINからAmazonのアフィリエイト用HTMLを作成
+sub to_html_word {
+ my ($word, $template) = @_; # ASINとテンプレ名称
+ my $cache = "$cachedir/$word.xml";
+ my $url = "http://webservices.amazon.co.jp/onca/xml?Service=AWSECommerceService&SubscriptionId=$devkey&AssociateTag=$asoid&Operation=ItemSearch&Keywords=$word&SearchIndex=Books&ResponseGroup=Medium,Offers";
+ my $outfile = "$cachedir/$word.html";
+
+ # 取り込み直す必要はあるか?
+ if (!(-e $cache) || (-M $cache > ($EXPIRE / 24))) {
+ # AWSから情報を取得してキャッシュファイルに保存
+ # UserAgent初期化
+ my $ua = new LWP::UserAgent;
+ $ua->agent($ua_name);
+ $ua->timeout(60);
+ my $rtn = $ua->mirror($url, $cache);
+ }
+
+ # キャッシュからXMLを読み込んで解析
+ my $content = getFile($cache);
+ $content =~ s!.*?(<Item>.*?</Item>).*!$1!is;
+ my $asin = "";
+ $asin = $1 if ($content =~ /<ASIN>([^<]*)<\/ASIN>/);
+ return "" if !$asin;
+ my %detail = parseXML($content, $asin);
+
+ # テンプレートを展開。エラーの場合はエラー文字列を返す
+ my $form;
+ if (!defined($detail{"ErrorMsg"})) {
+ #$form = &$blosxom::template($blosxom::path, $template, 'html');
+ my $fh = new FileHandle;
+ if ($fh->open("< $blosxom::datadir/$template.html")) {
+ $form = join '', <$fh>;
+ $form =~ s/\$(\w+)/$detail{$1}/ge;
+ $fh->close();
+ }
}
else {
$form = "<p>" . $detail{"ErrorMsg"} . "</p>";
子供向け絵本らしいが、ちょっと笑った。
Tagged as: aws, awsxom, blosxom
Bookmarks:
|
意外と知られていないvimのtips(vimで__DATA__トークン)
スクリプトは
" DO NOT EDITこんな感じで使う側はこんな感じ
scriptencoding utf-8
let s:self = expand("<sfile>")
com! UseDataToken exe join(map(remove(readfile(s:self),5,8),"strpart(v:val,1)"),"|")
"__DATA__
"silent! unlet datatoken
"let datatoken=readfile(expand("<sfile>"))
"cal remove(datatoken,0,search("^\"__DATA__$")-1)
"cal map(datatoken,"strpart(v:val,1)")
"source datatoken.vimperlの様にファイルハンドルでないのが気持ち悪いか。
UseDataToken
silent! unlet d
let d = eval(join(datatoken))
echo d.author
echo d.version
echo d.date
"__DATA__
"{
"'author': 'mattn <mattn.jp@gmail.com>',
"'version': '0.001',
"'date': 'Mon, 17 Mar 2008'
"}
追記
タイトル変だったので直した
pythonからLingrに発言するモジュール作った
APIチュートリアル - Lingr Group on Hatenaを見つけた。さっそくpythonでモジュール作った。(既にありそう...)
API Tutorial in Lingr Developer Wiki
セッションの作成、入室、発言、退室をメソッドとして公開しています。
セッションの破棄はデストラクタでやってます。使い方は、__main__を参照。
#!/usr/bin/env pythonroom_idは部屋の検索から検索して、その部屋のURLの最後の部分がIDになります。
# -*- coding: utf-8 -*-
"""
Lingr API Module
"""
import httplib
import urllib
from xml.dom import minidom
__author__ = 'mattn <mattn.jp@gmail.com>'
__url__ = 'http://mattn.kaoriya.net/'
__version__ = "0.01"
"""
Lingr API Class
"""
class LingrAPI:
"""
initialize class variables and create session.
"""
def __init__(self, api_key, nickname):
self.api_key = api_key
self.nickname = nickname
self.session = None
self.conn = httplib.HTTPConnection("www.lingr.com")
self.conn.request('POST', '/api/session/create/',
body = "api_key=%s" % urllib.quote(api_key))
response = self.conn.getresponse()
data = response.read()
doc = minidom.parseString(data)
if doc.getElementsByTagName('status')[0].childNodes[0].data != 'ok':
raise Exception({
'code' : doc.getElementsByTagName('code')[0].childNodes[0].data,
'message' : doc.getElementsByTagName('message')[0].childNodes[0].data})
self.session = doc.getElementsByTagName('session')[0].childNodes[0].data
"""
destroy session.
"""
def __del__(self):
if self.session:
import urllib
from xml.dom import minidom
self.conn.request('POST', '/api/session/destroy',
body = "session=%s" % urllib.quote(self.session))
response = self.conn.getresponse()
data = response.read()
doc = minidom.parseString(data)
if doc.getElementsByTagName('status')[0].childNodes[0].data != 'ok':
raise Exception({
'code' : doc.getElementsByTagName('code')[0].childNodes[0].data,
'message' : doc.getElementsByTagName('message')[0].childNodes[0].data})
"""
enter room and return room_id
"""
def enter_room(self, room_id):
self.conn.request('POST', '/api/room/enter',
body = "session=%s&id=%s&nickname=%s"
% (urllib.quote(self.session), urllib.quote(room_id), urllib.quote(self.nickname)))
response = self.conn.getresponse()
data = response.read()
doc = minidom.parseString(data)
if doc.getElementsByTagName('status')[0].childNodes[0].data != 'ok':
raise Exception({
'code' : doc.getElementsByTagName('code')[0].childNodes[0].data,
'message' : doc.getElementsByTagName('message')[0].childNodes[0].data})
return doc.getElementsByTagName('ticket')[0].childNodes[0].data
"""
say message using ticket.
"""
def say(self, ticket, message):
self.conn.request('POST', '/api/room/say',
body = "session=%s&ticket=%s&message=%s"
% (urllib.quote(self.session), urllib.quote(ticket), urllib.quote(message)))
response = self.conn.getresponse()
data = response.read()
doc = minidom.parseString(data)
if doc.getElementsByTagName('status')[0].childNodes[0].data != 'ok':
raise Exception({
'code' : doc.getElementsByTagName('code')[0].childNodes[0].data,
'message' : doc.getElementsByTagName('message')[0].childNodes[0].data})
return doc.getElementsByTagName('occupant_id')[0].childNodes[0].data
"""
exit room
"""
def exit_room(self, ticket):
self.conn.request('POST', '/api/room/exit',
body = "session=%s&ticket=%s"
% (urllib.quote(self.session), urllib.quote(ticket)))
response = self.conn.getresponse()
data = response.read()
doc = minidom.parseString(data)
if doc.getElementsByTagName('status')[0].childNodes[0].data != 'ok':
raise Exception({
'code' : doc.getElementsByTagName('code')[0].childNodes[0].data,
'message' : doc.getElementsByTagName('message')[0].childNodes[0].data})
return doc.getElementsByTagName('status')[0].childNodes[0].data
# def find_room(title):
# self.conn.request('GET', '/search/rooms',
# body = "query=%s" % urllib.quote(title))
# response = self.conn.getresponse()
# data = response.read()
if __name__ == '__main__':
import sys
if len(sys.argv) < 2: sys.exit()
api_key = sys.argv[1]
nickname = sys.argv[2]
room_id = sys.argv[3]
message = sys.argv[4]
api = LingrAPI(api_key, nickname)
ticket = api.enter_room(room_id)
api.say(ticket, message)
api.exit_room(ticket)
今のところbot的な用途でしか使えない程のメソッドしか出してませんが、暇があればメソッドを追加していくかも。
あと、codereposに置いておくので良かったら弄って下さい。
Tagged as: chat, lingr, python
Bookmarks:
|
2008/03/14
capture.flickr.jsで本文テキストが選択されない様にするパッチ書いた
capture.flickr.js FirefoxでキャプチャしてFlickrにアップロードするJSActionsスクリプト #2008.03.13 « ZeroMemory
といってもCSSだけ...
--- capture.flickr.js.orig Thu Mar 13 21:55:18 2008ふむ。便利だ。
+++ capture.flickr.js Fri Mar 14 12:37:01 2008
@@ -7616,7 +7616,7 @@
document.addEventListener( 'mousedown', this.onmousedown, true );
var s = document.createElement('style');
- s.innerHTML = '* {cursor: crosshair !important;}';
+ s.innerHTML = '* {cursor: crosshair !important; -moz-user-select: none;}';
document.body.appendChild(s);
this.style = s;
},
Tagged as: firefox, jsactions
Bookmarks:
|
2008/03/12
jQueryで動くメディアビューワ「Shadowbox」を入れた
私としては、記事本文に記述される画像へのパスはサイトのURLとは切り離して考えるべきと思っているので、以下のプラグインを使っています。
imageref
# Bloxsom Plugin:ImageRef※今回の修正を含んだソースです。
# Author: Yasuhiro Matsumoto
# Version: 0.1
package imageref;
use strict;
my $images_url = "http://mattn.kaoriya.net/images";
sub start {1}
sub story {
my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
$$body_ref =~ s@<!--\s+imageref\s+thumb:([^:\. ]*)(\.\S+)?\s+-->@<a href="$images_url/$1$2" rel="shadowbox"><img src="$images_url/$1-thumb$2" alt="$1" border="0" /></a>@ig;
$$body_ref =~ s@<!--\s+imageref\s+thumb:([^:]+?):([^:\. ]*)(\.\S+)?\s+-->@<a href="$images_url/$2$3" rel="shadowbox"><img src="$images_url/$2-thumb$3" alt="$1" border="0" /></a>@ig;
$$body_ref =~ s@<!--\s+imageref\s+([^:\. ]*)(\.\S+)?\s+-->@<img src="$images_url/$1$2" alt="$1" border="0" />@ig;
$$body_ref =~ s@<!--\s+imageref\s+([^:]+?):([^:\. ]*)(\.\S+)?\s+-->@<img src="$images_url/$2$3" alt="$1" border="0" />@ig;
1;
}
1;
※少しvimの色付け変ですね...
これを使うと、記事本文に
以下の画像を見てください。<br />と書くことで
<!-- imageref パンダ:panda.png -->
<img src="http://mattn.kaoriya.net/images/panda.png" alt="パンダ" border="0"/>というHTMLが出力されます。例えばサイトの引越しや画像格納パスの変更で全ての記事に手直しをする必要が無くなる訳です。
また、このプラグインでは
以下の画像を見てください。<br />と書く事で
<!-- imageref thumb:パンダ:panda.png -->
<a href="http://mattn.kaoriya.net/images/panda.png"><img src="http://mattn.kaoriya.net/images/panda-thumb.png" alt="パンダ" border="0"/></a>と変換してくれる為、使い手側は「panda.png」とサムネイル画像「panda-thumb.png」を用意しておけばいい事になります。
実際は、「panda.png」から「panda-thumb.png」への画像変換は手作業で
convert panda.png -resize 300x200 panda-thumb.png※convertはImageMagick付属コマンド
とやってるのですが、ここも本当はオートメーション化したいと思っています。
で、今回はこのプラグインを紹介したかったのではなく、jQueryでサムネイル画像から実画像への表示をビジュアルに表現してくれる「Shadowbox」というプラグインを導入しました。
mjijackson » Shadowbox 1.0 releasedなぜ導入に至ったかというと、このimagerefプラグインを少し修正すれば簡単にShadowboxが使えるのでは無いかと思ったからです。
Shadowboxを使うためには、jqueryのロードは必要になります。そして初期化処理として
<script type="text/javascript"><!--というコードを書き、あとは
$(document).ready(function() {
Shadowbox.init();
});
--></script>
<a src="xxx-big.jpg">となっている部分に「rel="shadowbox"」を足して
<img src="xxx-small.jpg"/>
</a>
<a src="xxx-big.jpg" rel="shadowbox">とすれば良し。
<img src="xxx-small.jpg"/>
</a>
class属性ではなく、rel属性を使っているので少し気味が悪い気もしますがそんなの気にしない。
今回はこれをimagerefが勝手に出力してくれる様に修正したまでです。
これでいつも通りにimagerefを使えば
<blockquote>で
<!-- imageref thumb:giraffe-photo.jpg -->
</blockquote>
となる訳です。![]()
ちなみにこのShadowbox、画像だけでなく
twtter - mattnといったインラインHTMLやFlash、動画もサポートしている様です。結構手軽に導入出来る割に得られる効果が大きいかもしれません。
一度使って見られてはどうでしょうか?
関連記事
MOONGIFT: » クールに表示「Shadowbox.js」:オープンソースを毎日紹介
追記
shadowboxやめてjquery.lightbox(balupton edition)にしました。
Tagged as: jquery, shadowbox
Bookmarks:
|
2008/03/11
Google Reader Full Feedが使っているSITEINFOにtwitter.comの情報を追加した
有名な所では
※詳しくは便利なBOT - TwitterまとめWikiを参照。plagger
http://twitter.com/plagger
perl/plaggerに詳しい某氏のブックマークが流れているらしい。私も購読している。
hatebu
http://twitter.com/hatebu
はてなブックマークのホットエントリが流れています。私も購読しています。
nicovNEW
http://twitter.com/nicovNEW
ニコニコ動画情報が流れています。
perlnews
http://twitter.com/perlnews
charsberさんのエントリで知った。perlに関するニュース一覧。さっき購読しました。
で、これらのRSSフィードをフィードリーダで購読する時に思うのが
botのステータスって、本文に対象のリンクが含まれているからRSSのlink要素はtwitter-botのステータスページになってしまって、行きたいリンクには一度ステータスページを踏まなきゃならない。って事。しかもtwitterのアンカーって全部ターゲットが「_blank」。フィードリーダからすれば、ステータスページ、対象のリンク、と1つ余計なタブが開いてしまう事になります。
本文にtinyurlのリンクは書いてあるけど、アンカーになってないからリンク先に行くのが面倒臭い。
twitterbotautofollowlink.user.jsこんなグリモンで新しいタブを開かずに自動にページ遷移する事も出来るけど followする度に@include足して行くのはかっこ悪い。(ネタですから...)
で、良く考えたら
RSSはアンカーになってないけど、twitterのステータスページってアンカーになってるんだから、フィードリーダがそれをアンカー扱い出来ればいいのでは?で、先ほどSITEINFOにtwitter.comの情報を追加しておきました。
しかも先日作ったGoogle Reader Full Feedがあるじゃないか...
まぁ、本当ならばRSSのlink要素が対象のリンクになってるのがフィードリーダを使う側としては便利なんですけどね。
※リンクがアンカーになってます。
Tagged as: GoogleReaderFullFeed, siteinfo, twitter
Bookmarks:
|
2008/03/10
GoogleMapが静的画像で使える様になったのでGPSから取得した位置情報から地図を出すCGI作ってみた
Google Japan Blog: Google マップが携帯でも表示できるようになりましたHTTP::MobileAgent::Plugin::Locatorを使って緯度経度を取り、GoogleMapの静的画像を表示するサンプルを作ってみた。
ただGoogleMapの座標指定は測地系だったので
http://minken.net/mt/archives/locations.plの一部を使わせて頂きました。
Perlで投影系変換出来るモジュール誰か知りませんか?
ソースは以下の様な感じ。
#!/usr/bin/perl若干ずれるのはしょうがないか...
use strict;
use warnings;
use CGI;
use HTTP::MobileAgent;
use HTTP::MobileAgent::Plugin::Locator;
my $google_map_api_key = "ABQIAAAAS_2fKEdj-fsDOrnYqd4nthTGTkG1t9CC6WQns4yK382vvQcY9RS5JGW4WA0hwZKxfIpKeCjuMOMPIA";
sub geoconv {
...
}
sub llh2xyz { # 楕円体座標 -> 直交座標
...
}
sub xyz2llh { # 直交座標 -> 楕円体座標
...
}
sub deg2dms {
...
}
sub dms2deg {
...
}
my $q = CGI->new;
my $agent;
my $lat = '';
my $lng = '';
my $location = '';
eval {
$agent = HTTP::MobileAgent->new;
$location = $agent->get_location( $q );
($lng, $lat) = geoconv($location->lng, $location->lat, $location->datum)
};
print $q->header(-charset=>'Shift_JIS'),<<END;
<html>
<head>
<title>GoogleMap from GPS</title>
</head>
<body>
<h1>What is this?</h1>
Show the Google Map static image from your GPS location.<br />
END
if ($agent && $agent->is_non_mobile) {
print "<b>Are not mobile agent?</b>";
} else {
print "<a href=\"device:location?url=gmobile_map.cgi\" lcs>Where?</a>"
if ($agent->is_docomo);
print "<a href=\"device:location?url=gmobile_map.cgi\">Where?</a>"
if ($agent->is_ezweb);
print "<a href=\"gmobile_map.cgi\" z>Where?</a>"
if ($agent->is_softbank && !$agent->is_type_3gc);
print "<a href=\"location:auto?url=gmobile_map.cgi\">Where?</a>"
if ($agent->is_softbank && $agent->is_type_3gc);
if ($lat && $lng) {
print << "END";
<img src="http://maps.google.com/staticmap?center=$lat,$lng&markers=$lat,$lng,red&zoom=18&size=300x200&key=$google_map_api_key"><br />
latitude: $lat<br />
longitude $lng<br />
END
}
}
print "</body>\n</html>";
で、動いてる物は
http://mattn.kaoriya.net/cgi-bin/gmobile_map.cgi携帯端末からアクセス下さい。
キャリア毎のアンカー作ってくれるモジュールも欲しいなぁ...
Tagged as: google, gps, map, mobile
Bookmarks:
|
2008/03/07
Google Contact APIをPerlから叩いて連絡先一覧を取得してみる
perlならばcpanの「Net::Google::GData」とか使った方がいいかもしれない。
ただ、まだ「Net::Google::GData」は使ったこと無い。
でも↓くらいのほうが見通し良い。
昨日のcurlの場合と同様に、GoogleLoginに使用する「auth」を取得してサービスコード「cp」に一覧を要求している。
#!/usr/bin/perl実行結果は、めちゃめちゃ非公開なものなので、出せません><
use strict;
use LWP::UserAgent;
use HTTP::Request::Common qw(GET POST);
use URI::Escape qw(uri_escape);
use XML::LibXML;
use Data::Dumper;
my $gdata_user='your-account@gmail.com';
my $gdata_pass='your-password';
my $url = 'https://www.google.com/accounts/ClientLogin';
my %postdata = (
Email => $gdata_user,
Passwd => $gdata_pass,
accountType => 'GOOGLE',
source => 'Google-Contact-Lister',
service => 'cp',
);
my $req = POST($url, [%postdata]);
my $ua = LWP::UserAgent->new;
my $res = $ua->request($req);
my $google_auth = (split(/\n/, $res->content))[2];
$google_auth =~ s!^Auth=!!;
$url = 'http://www.google.com/m8/feeds/contacts/' .
uri_escape($gdata_user) . '/base';
$req = GET($url, [%postdata]);
$req->header(
Authorization => "GoogleLogin auth=$google_auth",
);
$res = $ua->request($req);
my $x = XML::LibXML->new;
my $doc = $x->parse_string($res->content)->documentElement;
my @nodes = $doc->getElementsByTagName('entry');
for my $node (@nodes) {
my @title = $node->getElementsByTagName('title')->[0]->getChildNodes();
my $gd = $node->getElementsByTagName('gd:email')->[0];
print $title[0]->toString() . "," . $gd->getAttribute('address') . "\n"
if @title && $gd;
}
CSV形式で名前とメアドが一覧されます。
Tagged as: gdata, google, perl
Bookmarks:
|
2008/03/06
意外と知られていないvimのtips(そろそろ FizzBuzz に飽きたvim編)
おもいっきり間違ってる。
後で直します。
追記2
直した。
vimも負けません。
そろそろ FizzBuzz に飽きた - にぽたん研究所Lingua::JA::Numbers無いなら作ります。
もちろんHiraganaだけですが...
scriptencoding utf-8期待する結果:
silent! unlet s:ndg
let s:ndg = [
\ {0: ''},
\ {0: 'じゅう'},
\ {0: 'ひゃく', 3: 'ぴゃく', 6: 'ぴゃく', 8: 'ぴゃく'},
\ {0: 'せん', 3: 'ぜん'},
\ ]
silent! unlet s:dig
let s:dig = [
\ {0: ''},
\ {0: 'まん'},
\ {0: 'おく'},
\ {0: 'ちょう'},
\ {0: 'けい'},
\ {0: 'がい'},
\ {0: 'じょ'},
\ {0: 'じょう'},
\ {0: 'こう'},
\ {0: 'かん'},
\ {0: 'せい'},
\ {0: 'さい'},
\ {0: 'ごく'},
\ {0: 'こうがしゃ'},
\ {0: 'あそうぎ'},
\ {0: 'なゆた'},
\ {0: 'ふかしぎ'},
\ {0: 'むりょうたいすう'}
\ ]
silent! unlet s:num
let s:num = [
\ {0: 'ぜろ'},
\ {0: 'いち'},
\ {0: 'に'},
\ {0: 'さん'},
\ {0: 'よん'},
\ {0: 'ご'},
\ {0: 'ろく', 3: 'ろっ'},
\ {0: 'なな'},
\ {0: 'はち', 3: 'はっ', 4: 'はっ'},
\ {0: 'きゅう'}
\ ]
" return japanese numeric string from 'num'
function! s:num2ja(num)
let str = "" . a:num
let len = len(str)
if str == 0
return s:num[0][0]
endif
if len >= 17*4+1
return s:dig[17][0]
endif
let n = 0
let ret = ""
while n < len
if str[n] != 0 && (str[n] != 1 || (len-n)%4 == 1)
let ret .= has_key(s:num[str[n]], len-n) ?
\ s:num[str[n]][len-n] : s:num[str[n]][0]
endif
if str[n] != 0
let ret .= has_key(s:ndg[(len-n-1)%4], str[n]) ?
\ s:ndg[(len-n-1)%4][str[n]] : s:ndg[(len-n-1)%4][0]
let ret .= has_key(s:dig[(len-n-1)/4], str[n]) ?
\ s:dig[(len-n-1)/4][str[n]] : s:dig[(len-n-1)/4][0]
endif
"echo ret
let n = n + 1
endwhile
return ret
endfunction
" generate array from 'start' to 'end'
function! s:gen_array(start, end)
let ret = []
let n = a:start
while n <= a:end
call add(ret, n)
let n = n + 1
endwhile
return ret
endfunction
for n in s:gen_array(1, 40)
echo (!(n % 3) || n =~ '3') ? s:num2ja(n) : n
endfor
:so NabeAtzz.vim
1
2
さん
4
5
ろく
7
8
きゅう
10
11
じゅうに
じゅうさん
14
じゅうご
16
17
じゅうはち
19
20
にじゅういち
22
にじゅうさん
にじゅうよん
25
26
にじゅうなな
28
29
さんじゅう
さんじゅういち
さんじゅうに
さんじゅうさん
さんじゅうよん
さんじゅうご
さんじゅうろく
さんじゅうなな
さんじゅうはち
さんじゅうきゅう
40
dankogai++ nipotan++ bram++
Tagged as: fizzbuzz, tips, vim
Bookmarks:
|
jQueryのjqAlbumParserプラグインかっこいい
jQuery: jqAlbumParser Plugin, parses out Flickr, Picasa clientside | The Book and the Coverカッコイイ。
実装するのもそれ程難しくないしサイトの端っこにでも貼り付けても面白いかもしれない。
動作としては、jqAlbumParserがFlickrのFeedをパースする物で、それを表示する為のプラグインがjqGalViewIIとの事。
よってコードは
<style media="all">こんな感じ。「$(document).ready」を使わず実行したいならば「.click()」の所を「.trigger('load')」にすれば自動で表示される。
@import url("/path/to/css/jqGalViewII.css");
</style>
<script type="text/javascript" src="/path/to/javascript/jquery-latest.js"></script>
<script type="text/javascript" src="/path/to/javascript/jqAlbumParser.js"></script>
<script type="text/javascript" src="/path/to/javascript/jqGalViewII.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$(".jqAlbumParser").jqAlbumParser({
pluginExec : function(){$(this).jqGalViewII();}
}).click();
});
</script>
<a href="http://api.flickr.com/services/feeds/photos_public.gne?ids=YOUR_FLICKR_ID"
class="jqAlbumParser wa:flickr">my flickr feed</a>
アンカーのクリックアクションで動作させたいならば、何も指定しないか「.trigger('click')」で行けます。
またfeedのURLの最後に「&tags=XXXX」とすれば、そのタグで絞り込める。簡単なソースで結構リッチなアルバムビューワが出来るって凄いなぁ。
以下、私のflickrで実行した例
Tagged as: jquery
Bookmarks:
|
curlを使ってコマンドラインからGDataにログインし、picasaに画像をアップロードする
Google Code FAQ - Using cURL to interact with Google data servicescurlを使ってコマンドラインからGDataにアクセスする方法。
濃いなぁ...苦笑。手順を追って説明してくれています。色々書かれていますが以下ではPicasaWebAlbumに画像をアップロードするまでの簡単な手順を示して行きます。
まず
https://www.google.com/accounts/ClientLoginにEmail、Passwd、accountType、source、serviceをパラメータ指定してGDataへのAuthトークンを取得しに行きます。
ここで返って来るのは3行程のデータで
SID=XXXXXXといった物が返ってきます。
LSID=YYYYYY
Auth=ZZZZZZ
認証に必要なのは最後の「Auth」です。以降のコマンドライン操作ではこの
Authorization: GoogleLogin auth=ZZZZZZというヘッダを加えてやれば、GDataのやり取りが出来る様になります。
まず、Authを取得する為に以下の様なコマンドを発行します。
curl -s https://www.google.com/accounts/ClientLogin \これで上記「Auth=ZZZZZZ」でいうZZZZZZの部分が取得出来ます。lh2は「Google Code FAQ - What is the service name in ClientLogin for each Data API?」にも書いてある通りPicasaWebAlbumのサービスコードになります。
-d Email=xxxxx@your-google-account.com \
-d Passwd=YoUr-GoOgLe-PaSsWoRd \
-d accountType=GOOGLE \
-d source=Google-Picssa-Upload \
-d service=lh2 | grep ^Auth= | sed 's/^Auth=//'
そしてPicasaへ画像をアップするには以下の様なコマンドを発行します。
curl -s http://picasaweb.google.com/data/feed/api/user/default \Slugヘッダはファイル名を指します。
-X POST \
--data-binary "@my_picture.jpg" \
-H "Content-Type: image/jpg" \
-H "Slug: my_picture.jpg" \
-H "Authorization: GoogleLogin auth=ZZZZZZ"
後はこれを汎用的にシェルスクリプトへ...
#!/bin/shこんな感じでしょうか...
# include 'GDATA_USER' and 'GDATA_PASS'.
. ~/.gdata
GDATA_AUTH=`
curl -s https://www.google.com/accounts/ClientLogin \
-d Email=$GDATA_USER \
-d Passwd=$GDATA_PASS \
-d accountType=GOOGLE \
-d source=Google-Picssa-Upload \
-d service=lh2 | grep ^Auth= | sed 's/^Auth=//'
`
FILE=`basename $1`
curl -s http://picasaweb.google.com/data/feed/api/user/default \
-X POST \
--data-binary "@$1" \
-H "Content-Type: image/jpg" \
-H "Slug: $FILE" \
-H "Authorization: GoogleLogin auth=$GDATA_AUTH" > /dev/null
実行には「$HOME/.gdata」に
GDATA_USER=xxxxx@your-google-account.comを書いておく必要があります。
GDATA_PASS=YoUr-GoOgLe-PaSsWoRd
パスワードが書かれていますからパーミッションに注意
これで引数に指定されたJPGファイルをPicasaWebAlbumのドロップボックスにアップロードされる様になっています。
もう少し凝れば、タグを付けたりアルバムを作ったりと出来そうです。またPicasaWebAlbumに限らずGDataを扱う物であれば、ちょっとした事にcurlを使えそうです。
色々やって見たいですが、今日はこの辺でおひらき。
なおC言語上の実装例ですが、CodeReposに上げてあるBlogWriterのコードAtomPP.cppで、Bloggerへのログインとポストしている部分も参考になるかもしれません。
「getBloggerAuth」あたり
コードめちゃめちゃ汚いですが...
Tagged as: curl, gdata, google, picasa, shell
Bookmarks:
|
2008/03/05
RPC-XML-Parser-Lite をつくってみた
RPC-XML-Parser-LibXML をつくってみた - TokuLog 改め だまってコードを書けよハゲhttp://svn.coderepos.org/share/lang/perl/RPC-XML-Parser-Lite/
RPC::XML::Parser というのがあり、これは expat ベース。RPC::XML::Parser::XS というのがあるのだが、これは libxml を直接つかった XS なのだ。
さらにRPC::XML::Parser::LibXML も要コンパイルなのだ。
というわけで、ためしに XML::Parser::Lite::Tree と XML::Parser:Lite::Tree::XPath をつかったものを作ってみた。機能的には一緒 & インターフェースもいっしょにしてみた。
ただ、perlへたっぴなので誰か添削ぷりーず
※要は、id:tokuhirom のパクリなのだ。
2008/03/04
リチャードストールマンがemacsのメンテナから引退するという話に思った事
リチャード・ストールマンが Emacs のメンテナを引退 - YAMDAS現更新履歴vimではBram氏がメンテナであり、Bram氏がGoogleに移籍してからも尚、ワンマンな体制をとり続けている。
Looking for a new Emacs maintainer or team
パッチを含む全てのリリースからリリースアナウンスまで全てをBram氏が行う。
パッチは皆vim-devに送るけれど、Bram氏がOKを出さない限り取り込まれない。
これまで、ほぼ例外なくそうだった。
Bram氏は引退について考えた事、あるんだろうか。
他のプロジェクトの様にBram氏の右腕とか、作らないんだろうか...
vimってBram氏引退したらどうなるんだろ...
今まで突飛な機能でも良いと思った機能は取り込んでくれる様なリーダー、マルチバイトに関する物は率先して取り組んでくれてる様なリーダーが、もし他の人に変わったら...とちょっとだけ心配になった。
spreadsheetとつながってるってやばいじゃんこれspreadsheetをバックエンドdbにしていろいろできるってことでしょ
Visual C++プログラマのためのCOM入門―はじめるWindowsシステムプログラミング (DeV selection)
みんなのPython 改訂版
まるごとPerl! Vol.1
新版Perl言語プログラミングレッスン入門編
サトシくんとめんたくん (cub label)
Google Maps APIプログラミング入門



![Validate my RSS feed [Valid RSS]](http://mattn.kaoriya.net/images/valid-rss.png)

