Twitter の最新の200件の home_timeline をテキストとして読む

Equifax_Secure_Global_eBusiness_CA-1.cer は Equifax Secure Global eBusiness CA-1 (Base-64 encoded X.509) をダウンロードしたもの.
sed のホールドスペースって初めて使ったけど、使いこなせれば色々と面白いことが出来そう. ひたすら入れ替えることになる気はするけどw
2010-01-10 コード修正: 実体参照の処理を追加
2010-01-19 コード修正: 実体参照の処理を修正

wget https://twitter.com/statuses/home_timeline.atom?count=200 \
  --ca-certificate Equifax_Secure_Global_eBusiness_CA-1.cer \
  --http-user hoge \
  --http-password uso800 \
  --auth-no-challenge \
  --output-document - \
  --output-file /dev/null \
  | egrep '^      <title>|      <updated>' \
  | sed -n 's/^      <title>//
            s|</title>$||
            s/^\([^:]*\):/(\1)/
            s/&amp;/\&/
            s/&lt;/</
            s/&gt;/>/
            s/&amp;/\&/
            h
            n
            s/^      <updated>//
            s|</updated>$| |
            s/[0-9\-]*T//
            s/:..+00:00//
            G
            s/\n//
            p' \
  | perl -pe 'use HTML::Entities;
              binmode STDOUT, ":utf8";
              decode_entities($_);
              s/^(\d\d)/sprintf("%02d", ($1 + 9) % 24)/e' \
  > home_timeline.txt
cygstart home_timeline.txt

2点間の距離を計算する

ヒュベニの距離計算式Python のコードに落としてみた.

import math
a2 = 6378137.0 ** 2
b2 = 6356752.314140 ** 2
e2 = (a2 - b2) / a2
def distance_by_hubeny(p1, p2):
    def d2r(deg):
        return deg * (2 * math.pi) / 360
    (lon1, lat1, lon2, lat2) = map(d2r, p1 + p2)
    w = 1 - e2 * math.sin((lat1 + lat2) / 2) ** 2
    c2 = math.cos((lat1 + lat2) / 2) ** 2
    return math.sqrt((b2 / w ** 3) * (lat1 - lat2) ** 2 + (a2 / w) * c2 * (lon1 - lon2) ** 2)

てすつ

>>> print distance_by_hubeny([139.76608157157898,35.68137872227962],  [135.49497485160828,34.70190356670296])
403982.095331

Google Maps は 403.53km だと言っているけど、0.11%のズレなら誤差だろうと思うことにする.

KML Creator

恐らく Firefox 3.5 専用. 右クリックでポチポチマーカーを置いていって、最後にボタンを押してクリップボードに突っ込む. マーカーは左クリックでドラッグして位置修正が出来ます. 起動直後とボタン押した際にダイアログが出ますがOKしてやってください.
2009-12-18 コード修正: blue.png がキャッシュに載っていないと動作しない不具合を修正. 具体的にはイメージ生成を img.onload に移した.
2012-06-02 コード修正: Firefox 12 での UniversalBrowserRead の削除にともなって、UniversalXPConnect に修正.

<!DOCTYPE html>
<html>
<head>
<title>KML Creator</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<script type="text/javascript" src="http://maps.google.co.jp/maps?file=api&amp;v=2&amp;sensor=false&amp;key="></script>
<script type="text/javascript">
    var map;
    var markers = [];
    var cachedIcons = [];
    var maxIcons = 400;

    function createIconCache() {
        var img = new Image();
        img.onload = function() {
            netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
            var canvas = document.createElement("canvas");
            canvas.width = 32;
            canvas.height = 32;
            var context = canvas.getContext("2d");
            context.textAlign = "center";
            context.textBaseline = "middle";
            for(var i = 0; i < maxIcons; i++) {
                context.drawImage(img, 0, 0);
                context.strokeText(new String(i + 1), 16, 10, 14);
                cachedIcons.push(canvas.toDataURL());
            }
        }
        img.src = "http://maps.google.co.jp/mapfiles/ms/icons/blue.png";
    }

    function copyToClipboard(text) {
        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
        var cc = Components.classes;
        var ci = Components.interfaces;
        function createTransferable(text) {
            function createString(text) {
                var result = cc["@mozilla.org/supports-string;1"].createInstance(ci.nsISupportsString);
                result.data = text;
                return result;
            }
            var result = cc["@mozilla.org/widget/transferable;1"].createInstance(ci.nsITransferable);
            result.addDataFlavor("text/unicode");
            result.setTransferData("text/unicode", createString(text), text.length * 2);
            return result;
        }
        cc["@mozilla.org/widget/clipboard;1"].getService(ci.nsIClipboard).setData(createTransferable(text), null, ci.nsIClipboard.kGlobalClipboard);
    }

    function initialize() {
        map = new GMap2(document.getElementById("map_canvas"));
        map.setCenter(new GLatLng(35.685361261493114, 139.75308895111084), 8);
        map.setUIToDefault();
        map.disableDoubleClickZoom();
        GEvent.addListener(map, "singlerightclick", function(point, src, overlay) { 
            if (overlay instanceof GMarker) GEvent.trigger(overlay, "singlerightclick", point);
            else addMarker(point);
        });
        createIconCache();
    }

    function addMarker(point){
        var latLng = map.fromContainerPixelToLatLng(point);
        var icon = new GIcon();
        icon.image = cachedIcons[markers.length];
        icon.shadow = "http://maps.google.co.jp/mapfiles/ms/icons/msmarker.shadow.png";
        icon.iconSize = new GSize(32, 32);
        icon.shadowSize = new GSize(59, 32);
        icon.iconAnchor = new GPoint(15, 32);
        icon.infoWindowAnchor = new GPoint(0, 0);
        var marker = new GMarker(new GLatLng(latLng.lat(), latLng.lng()), {icon: icon, draggable: true});
        markers.push(marker);
        map.addOverlay(marker);
    }

    var kmlFormerPart =
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
        "<kml xmlns=\"http://earth.google.com/kml/2.2\">\n" +
        "<Document>\n" +
        "  <Style id=\"style1\">\n" +
        "    <LineStyle>\n" +
        "      <color>FFFFFF00</color>\n" +
        "      <width>6</width>\n" +
        "    </LineStyle>\n" +
        "  </Style>\n" +
        "  <Placemark>\n" +
        "    <name>Route</name>\n" +
        "    <styleUrl>#style1</styleUrl>\n" +
        "    <LineString>\n" +
        "      <tessellate>1</tessellate>\n" +
        "      <coordinates>\n";

    var kmlLatterPart =
        "      </coordinates>\n" +
        "    </LineString>\n" +
        "  </Placemark>\n" +
        "</Document>\n" +
        "</kml>\n";

    function toClipboard() {
        var result = "";
        for (var i = 0; i < markers.length; i++) {
            var marker = markers[i];
            result += marker.getPoint().lng() + "," + marker.getPoint().lat() + "\n";
        }
        copyToClipboard(kmlFormerPart + result + kmlLatterPart);
    }
</script>
</head>

<body onload="initialize()" onunload="GUnload()">
  <div id="map_canvas" style="width: 1000px; height: 660px"></div>
  <input TYPE="button" value="KML to Clipboard" onclick="toClipboard()">
</body>
</html>

Canvas で画像モノクロフィルタ

コードを書いた時間より、Web サーバにアップすると動くのにローカルで動かない理由が分からなくて首をひねっていた時間の方が長かったという. Firefox のセキュリティーポリシー謎すぎ・・・.

<html>
<head>
<title>Canvas</title>
<script type="text/javascript">
    window.onload = init;
    var img = new Image();
    function init() {
        img.onload = filter;
        img.src = "test.jpg";
    }
    function filter(){
        netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
        var canvas = document.getElementById("canvas1");
        canvas.width = img.width;
        canvas.height = img.height;
        var context = canvas.getContext("2d");
        context.drawImage(img, 0, 0);
        for(var y = 0; y < canvas.height; y++) {
            var s = context.getImageData(0, y, canvas.width, 1).data
            var dst = context.createImageData(canvas.width, 1)
            var d = dst.data
            for(var x = 0; x < canvas.width; x++) {
                var i = x * 4;
                var v = Math.floor(s[i] * 0.299 + s[i + 1] * 0.587 + s[i + 2] * 0.114 + 0.5);
                d[i] = d[i + 1] = d[i + 2] = v;
                d[i + 3] = 255;
            }
            context.putImageData(dst, 0, y);
        }
    }
</script>
</head>
<body>
<canvas id="canvas1"/>
</body>
</html>

テキストを RTF に変換する

色付けや装飾をしないと余り意味が無いわけですが(^^;
入力は UTF-8 なテキストを stdin から、出力 stdout となっています.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from sys import stdin, stdout
write = stdout.write

font_name = u'MS Pゴシック'.encode('cp932')
font_size = 10

def rtf_encode(s):
  result = ""
  for c in s:
    if ord(c) > 0x7f:
      result += "\\'%x" % ord(c)
    else:
      if c in ['\\', '{', '}']:
        result += '\\'
      result += c
  return result

write(r'{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset128 %s;}}' % rtf_encode(font_name))
write('\r\n')
write(r'\viewkind4\uc1\pard\lang1041\f0\fs%d ' % (font_size * 2))
for s in stdin:
  write(rtf_encode(s.rstrip('\r\n').decode('utf-8').encode('cp932')))
  write('\\par\r\n')
write('}\r\n')

C# で InputBox (2)

id:NyaRuRu にオブジェクト初期化子を教えてもらったので書き換え. form は SuspendLayout が邪魔して使えないのが残念!

public static string InputBox(string Prompt, string Title, string DefaultResponse) {
    var form = new Form();
    form.SuspendLayout();
    var textBox = new TextBox() {
        Location = new Point(12, 84),
        Size = new Size(329, 19),
        Text = DefaultResponse
    };
    var okButton = new Button() {
        DialogResult = DialogResult.OK,
        Location = new Point(266, 9),
        Size = new Size(75, 23),
        Text = "OK",
        UseVisualStyleBackColor = true
    };
    var cancelButton = new Button() {
        DialogResult = DialogResult.Cancel,
        Location = new Point(266, 38),
        Size = new Size(75, 23),
        Text = "キャンセル",
        UseVisualStyleBackColor = true
    };
    var label = new Label() {
        AutoSize = true,
        Location = new Point(12, 9),
        Size = new Size(0, 12),
        Text = Prompt
    };
    form.AcceptButton = okButton;
    form.CancelButton = cancelButton;
    form.AutoScaleDimensions = new SizeF(6F, 12F);
    form.AutoScaleMode = AutoScaleMode.Font;
    form.ClientSize = new Size(353, 120);
    form.ControlBox = false;
    form.FormBorderStyle = FormBorderStyle.FixedDialog;
    form.ShowInTaskbar = false;
    form.StartPosition = FormStartPosition.CenterParent;
    form.Text = Title;
    form.Controls.AddRange(new Control[] { textBox, okButton, cancelButton, label });
    form.ResumeLayout(false);
    form.PerformLayout();
    if (form.ShowDialog() == DialogResult.OK) return textBox.Text;
    else return null;
}

RitchTextBox で論理行

GetLineFromCharIndex は WordWrap してると使い物になんねえ!

private void richTextBox1_DoubleClick(object sender, EventArgs e) {
    var l = 0;
    var t = richTextBox1.Text;
    for (var i = 0; i < richTextBox1.SelectionStart; i++) if (t[i] == '\n') l++;
}