1px透過GIF・PNGの最小base64表現

1px透過GIF 39bytes

R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7

data:image/gif;base64,R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7

1px透過PNG 68bytes

iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQI12NgYAAAAAMAASDVlMcAAAAASUVORK5CYII=

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQI12NgYAAAAAMAASDVlMcAAAAASUVORK5CYII=

使用例

#!/usr/bin/perl

use strict;
use warnings;
use CGI qw/:cgi/;
use MIME::Base64 qw(decode_base64);

print header('image/gif');
print decode_base64('R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7');
exit;

とか

<?php
header('Content-Type: image/gif');
echo base64_decode('R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7');
exit;
?>

とか。

文字列化

Array.map(atob("R0lGODlhAQABAGAAACH5BAEKAP8ALAAAAAABAAEAAAgEAP8FBAA7"), function(v){ return "\\x"+("0"+v.charCodeAt(0).toString(16)).slice(-2).toUpperCase(); }).join("");
// -> "\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x60\x00\x00\x21\xF9\x04\x01\x0A\x00\xFF\x00\x2C\x00\x00\x00\x00\x01\x00\x01\x00\x00\x08\x04\x00\xFF\x05\x04\x00\x3B"

Array.map(atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQI12NgYAAAAAMAASDVlMcAAAAASUVORK5CYII="), function(v){ return "\\x"+("0"+v.charCodeAt(0).toString(16)).slice(-2).toUpperCase(); }).join("");
// -> "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x01\x00\x00\x00\x01\x08\x04\x00\x00\x00\xB5\x1C\x0C\x02\x00\x00\x00\x0B\x49\x44\x41\x54\x08\xD7\x63\x60\x60\x00\x00\x00\x03\x00\x01\x20\xD5\x94\xC7\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82"

こっちはそのままprint/echoすればOK。

JavaScript: Iterator関数をhasOwnProperty代わりに使う

いちいちhasOwnPropertyを使わなくてよくする(ジェネレータの使いかた) - 素人がプログラミングを勉強するブログ

多分Firefox2/3限定。JavaScript1.7相当。

Iterator関数を噛ませる方法もあります。

Object.prototype.extend = function(){};

var o = {a:1,b:2,c:3};
for (var i in o) console.log(i);
/* ->
a
b
c
extend
*/

for (var i in Iterator(o)) console.log(i);
/* ->
["a", 1]
["b", 2]
["c", 3]
*/

for each (var i in Iterator(o)) console.log(i);
/* ->
["a", 1]
["b", 2]
["c", 3]
*/

こんな具合になってるので

for (var [i,v] in Iterator(o)) console.log(i);
/* ->
a
b
c
*/

for (var [i,v] in Iterator(o)) console.log(v);
/* ->
1
2
3
*/

[p[0] for (p in Iterator(o))]
// -> ["a", "b", "c"] keys

[p[1] for (p in Iterator(o))]
// -> [1, 2, 3] values

とか。

微妙に形が変わるのが微妙といえば微妙。


yieldもletも使ってないので、Firefox2のFirebugコンソールでも使えるあたりが強み。

あとArrayでも順序が保証されている(はず)なのでbreakの効くforEachとしても使える。

関連リソース

Iterators and Generators - MDC

One advantage of using Iterator() to access the contents of an object is that custom properties that have been added to Object.prototype will not be included in the sequence.

Iterator() can be used with arrays as well:

JavaScript 1.8 では配列が自動的に Iterator に変換されなくなった? - やんばるもじら

Greasemonkey: tish.user.js

tako3.comからJSONを取得の図

tish.user.js

tinyshell.user.jsを書き換えたもの。

シェルっぽい何か。

注意

  • Minibuffer(+LDRize)との併用不可
    • ショートカットキーが競合
    • &にしようかと思ったけどSHIFT同時押しが使いづらいのでやめた
  • コマンドの移植度が微妙
    • 実装したもの:cat cd clear cut date echo exit expr find go google grep hatena head inspect jot logout ls maketoc open parse printf prompt pwd rm save sed seq settimer sort tac tail tee tr uniq up wc wget xargs
    • seqが自然数でしか使えなかったり、sedがエディタになってなかったり、いろいろ

起動方法など

:ALT+xで起動。

clearコマンドもしくはCTRL+Lでクリア。

TAB2回で候補表示。候補が1つだけのときはTAB1回で補完。

ファイルシステムもどき

$ pwd
http://mayokara.info/note/
$ cat links|head > outfile
$ cat outfile
http://mayokara.info/note/
http://mayokara.info/note/1
http://mayokara.info/note/view/325
http://mayokara.info/note/view/257
http://mayokara.info/note/search/tag/個人的メモ
http://mayokara.info/note/search/tag/JavaScript
http://mayokara.info/
http://mayokara.info/note/view/325
http://mayokara.info/note/view/325#comment
http://mayokara.info/note/view/325#trackback
$ cat feeds
http://mayokara.info/note/rss2
$ cat //h2/a/@href
http://mayokara.info/note/view/325
http://mayokara.info/note/view/324
http://mayokara.info/note/view/323
http://mayokara.info/note/view/322
http://mayokara.info/note/view/321
http://mayokara.info/note/view/320
http://mayokara.info/note/view/319
http://mayokara.info/note/view/318
http://mayokara.info/note/view/317
http://mayokara.info/note/view/316

text,links,images,stext,slinks,simages,feeds,next,prevなどは読み込み専用で、現在のページ/選択範囲に対するさまざまな情報を返す。

スラッシュを含む指定はXPathとみなされる。

書き出したファイルはコマンド履歴とは異なり、そのタブを開いている間しか参照できない。

wget & parse

$ cat feeds
http://mayokara.info/note/rss2
$ cat feeds|wget -i -|parse //item/link
wget: waiting for response... http://mayokara.info/note/rss2
wget: HTTP/1.x 200 OK
wget: Date: Sat, 23 Aug 2008 11:38:15 GMT
wget: Server: Apache
wget: Last-Modified: Sat, 23 Aug 2008 11:33:34 GMT
wget: Content-Type: text/xml;charset=UTF-8
wget: Content-Encoding: gzip
wget: Content-Length: 13016
http://mayokara.info/note/view/325
http://mayokara.info/note/view/324
http://mayokara.info/note/view/323
http://mayokara.info/note/view/322
http://mayokara.info/note/view/321
http://mayokara.info/note/view/320
http://mayokara.info/note/view/319
http://mayokara.info/note/view/318
http://mayokara.info/note/view/317
http://mayokara.info/note/view/316
http://mayokara.info/note/view/315
http://mayokara.info/note/view/314
http://mayokara.info/note/view/313
http://mayokara.info/note/view/312
http://mayokara.info/note/view/311

wgetでresponseTextを取得し、parseでXPathを用いて抽出。

wget -i - -l3とすれば、標準入力の3行目を読み込む。

parse -jで入力をJSONとみなし、DOMツリーに変換する。

tako3.comからデータを取得

$ echo http://tako3.com/json/likely/ `pwd`|tr -d " "|wget -i -|parse -j //jsonarray|tee tako3|cat -n
wget: waiting for response... http://tako3.com/json/likely/http://mayokara.info/note/
wget: HTTP/1.x 200 OK
wget: Date: Sat, 23 Aug 2008 11:43:25 GMT
wget: Server: Apache
wget: Content-Type: text/plain
wget: Transfer-Encoding: chunked
     1  http://mayokara.info/blog/
     2  http://mayokara.info/
     3  http://d.hatena.ne.jp/mayokara384/
     4  http://mayokara.info/note/
$ open tako3 -l3

現在のロケーションに関する情報をtako3.comから取得する。

番号を振る前のデータをtako3というファイルにtee。

open tako3 -l3で3行目を開く。

echo ...|tr -d " "の代わりにprintf "%s%s" http://tako3.com/json/likely/ `pwd`でも可。

しょぼいカレンダーから直近の番組データを取得

$ wget "http://cal.syoboi.jp/rss.php?titlefmt=$(StTime) $(ChName) $(Title)"|parse //x:item/x:title|head
wget: waiting for response... http://cal.syoboi.jp/rss.php?titlefmt=$(StTime)%20$(ChName)%20$(Title)
wget: HTTP/1.x 200 OK
wget: Date: Sat, 23 Aug 2008 11:44:53 GMT
wget: Server: Apache/2.2.3 (Unix) PHP/5.2.5
wget: X-Powered-By: PHP/5.2.5
wget: Cache-Control: no-cache, must-revalidate
wget: Expires: Mon, 26 Jul 1997 05:00:00 GMT
wget: Content-Type: text/xml; charset=UTF-8
wget: Transfer-Encoding: chunked
08/23 21:00 文化放送(1134) A&G超RADIO SHOW~アニスパ!~
08/23 22:30 TOKYO MX 鉄腕バーディー DECODE
08/23 22:30 キッズステーション NARUTO -ナルト- 疾風伝
08/23 23:00 BS11デジタル 鉄腕バーディー DECODE
08/23 23:00 文化放送(1134) A&Gメディアステーション こむちゃっとカウントダウン
08/23 23:30 BS11デジタル ウルトラヴァイオレット コード044
08/24 00:00 tvk アニメTV
08/24 00:00 BS11デジタル 真ゲッターロボ 世界最後の日
08/24 00:30 tvk 薬師寺涼子の怪奇事件簿
08/24 01:00 tvk 狂乱家族日記

RSS1.0ではデフォルト名前空間があるのでXPathにx:が必要。

Twitterの「フォロー中」にリストされているユーザIDを取得

$ pwd
http://twitter.com/XXXXXX
$ inspect
inspect: 'id("friends")/span[@class="vcard"][1]/a[@class="url"][1]'
$ cat id("friends")//a/@href|cut -d / -f 4
XXXXXX
XXXXXX
XXXXXX
...

inspectでXPathを調べる。左/右クリックで終了。

@href、@srcはAbsolute URLに変換して返される(場当たり的対応)。

外部ファイルによる操作

// ==UserScript==
// @name           dot_tishrc
// @namespace      http://mayokara.info/
// @description    .tishrc
// @include        http://*
// ==/UserScript==

(function(){

var Shell = window.Tish;
if (!Shell) return;

Shell.addAlias('tako3', 'printf "%s%s" http://tako3.com/json/likely/ `pwd`|wget -i -|parse -j //jsonarray|tee tako3|cat -n');

Shell.addCommand("hitori-goto", function(STDIN, ARGV, $0){
    if (ARGV.length > 0) {
        var callback = function(res){
            Shell.println($0 + ": " + res.status + " " + res.statusText);
        };
        GM_xmlhttpRequest({
            method: "POST",
            url: "http://hitori-goto.appspot.com/say",
            data: "comment=" + encodeURIComponent(ARGV.join(" ")),
            headers: { "Content-Type": "application/x-www-form-urlencoded" },
            onload: callback,
            onerror: callback,
        });
        Shell.println($0 + ": waiting for response...");
    } else {
        return Shell.exec("wget http://hitori-goto.appspot.com/rss2|parse //item/title", "");
    }
});

})();

エイリアスやコマンドを追加できる。

cd、go/open

cdは引数のURLを開く。go/openは標準入力あるいはファイル内のURLを開く。

googleとかhatenaとか

$ google --code printf
http://www.google.com/codesearch?q=printf
$ hatena id:mayokara384
http://d.hatena.ne.jp/mayokara384/
$ hatena b:id:mayokara384
http://b.hatena.ne.jp/mayokara384/

URLを作って返すだけ。

JavaScript: defer関数でいろいろ

JavaScript: 普通に同期処理 - mayokara note

var defer = function(/* f1, f2, ... */){
    var self = this, fn = Array.prototype.slice.call(arguments);
    (function(/* arg2, arg3, ... */){
        var args = Array.prototype.slice.call(arguments);
        (fn.shift()).apply(self, [arguments.callee].concat(args));
    })();
};

この関数の説明をきちんと書いてなかったので補足。

bind

deferのthisが、引数に与えた関数すべてのthisになる。

defer.call(this, F1, F2, F3);

のように呼ぶことで、F1、F2、F3すべてにbind(this)(Prototype.js)するのと同じ効果が得られる。

wait(あるいはsleep、pause)

1秒のwaitを置く例。

defer(function(next){
    alert("1000ms wait");
    window.setTimeout(function(){ next("finished"); }, 1000);
}, function(next, str){
    alert(str); // -> (alert "finished")
});

deferもnextも、いくつでも引数を取れる。

nextに与えた第n引数は次の関数の第n+1引数になる。

第1引数はnext(次の関数を呼ぶ関数)で固定。

各関数の返り値は意味を持たない。defer自身も値を返さない。

setTimeoutの代わりに(GM_)XMLHttpRequestを入れれば、onloadが呼ばれるまで次の関数の実行を遅延できる。

loop

defer(function loop(next, i){
    i = i || 0;
    if (!(i < 5)) return next();
    console.log("count " + i);
    window.setTimeout(function(){ loop(next, i+1); }, 1000);
}, function(next){
    console.log("5 times loop finished");
});
count 0
count 1
count 2
count 3
count 4
5 times loop finished

nextをきちんと引き継げばloopもできる。

setTimeoutに与えた関数の中ではarguments.calleeが使えないので、ループさせる関数にloopという名前をつけ、それを使う。

前述のdefer.callでthisをbindしている場合は、それに合わせてloopにthisをセットする必要がある。

defer(function(next){
    next(0);
}, function loop(next, i){
    if (!(i < 5)) return next();
    console.log("count " + i);
    window.setTimeout(function(){ loop(next, i+1); }, 1000);
}, function(next){
    console.log("5 times loop finished");
});

毎回i = i || 0;を実行するのが無駄に感じる場合はこうする。

同様にして、特定の条件を満たすまで次の関数の実行を引き伸ばしたりできる。

parallel

defer(function(next){
    var obj = {},
        stock = function(key, value){
            obj[key] = value;
            // 全部揃ったらnextを呼ぶ
            if (obj.a && obj.b && obj.c) next(obj.a, obj.b, obj.c);
        };
    window.setTimeout(function(){ stock("a", "AAAAA"); }, 3000);
    window.setTimeout(function(){ stock("b", "BBBBB"); }, 2000);
    window.setTimeout(function(){ stock("c", "CCCCC"); }, 5000);
}, function(next, a, b, c){
    alert(a + b + c); // (alert "AAAAABBBBBCCCCC")
});

setTimeoutの代わりに、(GM_)XMLHttpRequestなどが入る。

objそのものを引き渡しても良い。

「ads-display-none」というデータベースをwedataに作った

アイテム - データベース: ads-display-none - wedata

ads-display-none

御察し下さい。


どなたでも自由に編集していただいて構いませんが、データベース名の頭3文字を良くお読みになった上、余計なものが含まれないようお願いします。

ブログパーツや単なるサイドバー、フッターなどは対象外です。

Fw: GNU Core Utilities Project Page

GNU Core Utilities - 概要 [Savannah]

各種コマンドのC実装がブラウザで見れる。

gitで管理されていて、srcディレクトリにコードがある。


static char const rfc_2822_format[] = "%a, %d %b %Y %H:%M:%S %z";
static char const rfc_3339_format[][32] =
  {
"%Y-%m-%d",
"%Y-%m-%d %H:%M:%S%:z",
"%Y-%m-%d %H:%M:%S.%N%:z"
  };
static char const iso_8601_format[][32] =
  {
"%Y-%m-%d",
"%Y-%m-%dT%H:%M:%S%z",
"%Y-%m-%dT%H:%M:%S,%N%z",
"%Y-%m-%dT%H%z",
"%Y-%m-%dT%H:%M%z"
  };

date.cより。メモ。

はてなブックマークのエントリページで特定ユーザのコメントを非表示にするUserCSS

長音表記のガイドライン無視>タイトル


@namespace url(http://www.w3.org/1999/xhtml);

@-moz-document url-prefix(http://b.hatena.ne.jp/entry/) {

#bookmark-user-mayokara384,
#bookmark-user-mayokara384,
#bookmark-user-mayokara384,
#bookmark-user-mayokara384,
#bookmark-user-mayokara384
{
    display: none !important;
    /* あるいは -moz-opacity: 0.5 !important; など */
}

}

userstyles.orgとかにあるのかもしれないけど、メモ。

mayokara384の部分を対象とするユーザ名に変える。

フィードをオートディスカバリーするXPath、Firefox互換

フィードをオートディスカバリーする XPath - IT戦記


http://mxr.mozilla.org/mozilla/source/browser/base/content/pageinfo/feeds.js#39

http://mxr.mozilla.org/mozilla/source/browser/base/content/utilityOverlay.js#639

'/x:html/x:head/x:link[@href and (contains(concat(" ",translate(normalize-space(@rel),"DEF","def")," ")," feed ") or (contains(concat(" ",translate(normalize-space(@rel),"AELNRT","aelnrt")," ")," alternate ") and not(contains(concat(" ",translate(normalize-space(@rel),"EHLSTY","ehlsty")," ")," stylesheet ")) and (starts-with(normalize-space(@type),"application/rss+xml") or starts-with(normalize-space(@type),"application/atom+xml") or ((starts-with(normalize-space(@type),"text/xml") or starts-with(normalize-space(@type),"application/rdf+xml") or starts-with(normalize-space(@type),"application/xml")) and contains(concat(" ",translate(normalize-space(@title),"RS","rs")," ")," rss ")))))]'

x:というのはデフォルト名前空間を取るためのprefixなので、resolver使わないなら消してもOK。

JavaScript: createDocumentFromJSONString

(GM_)XMLHttpRequestなどで取ってきたJSON文字列をDOMツリーに変換する関数を書いたのでメモ。

var createDocumentFromJSONString = function(str){
    var json = (new Function('return (' + str + ');'))(),
        jsonDoc = document.implementation.createDocument("", "json", null);
    if (json instanceof Array) {
        jsonDoc.documentElement.setAttribute("type", "array");
        json = { jsonarray: json };
    } else if (typeof(json) === "object") {
        if (json === null) {
            jsonDoc.documentElement.setAttribute("type", "null");
            return jsonDoc;
        } else {
            jsonDoc.documentElement.setAttribute("type", "object");
        }
    } else {
        jsonDoc.documentElement.setAttribute("type", ((typeof(json) === "boolean") ? String(json) : typeof(json)));
        jsonDoc.documentElement.textContent = String(json);
        return jsonDoc;
    }
    (function(o, elem){
        for (var i in o) {
            if (o[i] instanceof Array) {
                for (var j=0,l=o[i].length; j<l; j++) {
                    var tmp = {};
                    tmp[i] = o[i][j];
                    arguments.callee(tmp, elem);
                };
            } else if (typeof(o[i]) === "object") {
                var child = jsonDoc.createElement(i);
                if (o[i] === null) {
                   child.setAttribute("type", "null");
                } else {
                   child.setAttribute("type", "object");
                   arguments.callee(o[i], child);
                }
                elem.appendChild(child);
            } else {
                var child = jsonDoc.createElement(i);
                child.setAttribute("type", ((typeof(o[i]) === "boolean") ? String(o[i]) : typeof(o[i])));
                child.textContent = String(o[i]);
                elem.appendChild(child);
            }
        }
    })(json, jsonDoc.documentElement);
    return jsonDoc;
};

({
    count: "",
    title: "",
    bookmarks: [{
        comment: "",
        tags: ["", ""],
        timestamp: "",
        user: "",
    }, {
        comment: "",
        tags: ["", ""],
        timestamp: "",
        user: "",
    },
        ...
    ],
    url: "",
    ...
})

こんな構造のJSONが

<json type="object">
    <count type=""></count>
    <title type=""></title>
    <bookmarks type="object">
        <comment type=""></comment>
        <tags type=""></tags>
        <tags type=""></tags>
        <timestamp type=""></timestamp>
        <user type=""></user>
    </bookmarks>
    <bookmarks type="object">
        <comment type=""></comment>
        <tags type=""></tags>
        <tags type=""></tags>
        <timestamp type=""></timestamp>
        <user type=""></user>
    </bookmarks>
    ...
    <url type=""></url>
    ...
</json>

こんな構造のツリーに変換される(値は邪魔なので省略)。


JavaScriptの構文だとJSONからjson.bookmarks[*].userみたいな抽出がしたいとき、for文で回さないといけない(はず)。

DOMツリーに変換すれば、XPathで//bookmarks/userとできる。

追記

booleanのtrueとstringの"true"などの区別ができるように、type属性にobject/string/number/true/false/null(ルートのみarrayの場合あり・後述)のいずれかの文字列をセットするよう修正。

JSONでは真偽値がbooleanではなくtrue/falseと別々に定義されているようなので、それに従った。


また、ルートがobjectではなくarrayやstringだったときのための前処理を付け加えた。

ルートがarrayだった場合はdocumentElementを複数作れないので

<json type="array">
    <jsonarray type="object">
    </jsonarray>
    <jsonarray type="object">
    </jsonarray>
</json>

のようにjsonarray要素が作られ、documentElementのtype属性の値がarrayとなる。

XPathで参照する場合は//jsonarray/user/json/*/userのようにする(苦肉の策)。


true/falseの場合はtextContentにもtrue/falseという文字列をセットするが、nullの場合は空になるようにしてある。

Fw: 2churl.net

2ちゃんねるタイトルURLジェネレータ

2chの板名とキーワードを元に、最新スレッドに転送するURLを生成するサービス。