@blog.justoneplanet.info

日々勉強

Manifest Version 2

これの訳。結構適当。

  • コンテントセキュリティ・ポリシーはデフォルトで`script-src ‘self’; object-src ‘self’にセットされる。content_security_policyのドキュメントに長々と書いたけど、これは開発者に様々な影響を与えるよ
  • パッケージのリソースはデフォルトでimageやscriptのsrcとして外部のウェブサイトを参照できない。もしウェブサイトからパッケージに含まれるリソースをロードできるようにしたいなら、web_accessible_resourcesのマニフェスト属性を通してホワイトリストに明示する必要がある。これはとりわけ挿入されたコンテントスクリプトを通してウェブサイトのインターフェースを構築する拡張機能に関連する。
  • background_pageのプロパティがscriptとpageプロパティを内包するbackgroundに変わった。
  • chrome.extension.getTabContentsesとchrome.extension.getExtensionTabsはなくなった。chrome.extension.getViews({ “type”: “tab” })を代わりに使ってね
  • Port.tabはなくなった。代わりにPort.senderを使ってね

ブラウザアクションの変更

  • マニフェストのbrowser_actionsとchrome.browserActionsはなくなった。代わりに単数形のbrowser_actionとchrome.browserActionを使ってね
  • browser_actionのiconsプロパティは削除された。代わりにdefault_iconプロパティやchrome.browserAction.setIconを使ってね
  • browser_actionのnameプロパティは削除された。代わりにdefault_titleプロパティやchrome.browserAction.setTitleを使ってね
  • browser_actionのpopupプロパティは削除された。代わりにdefault_popupプロパティやchrome.browserAction.setPopupを使ってね
  • browser_actionのdefault_popupプロパティはもはやオブジェクトとして指定できない。文字列でなければならない

ページアクションの変更

  • マニフェストのpage_actionsとchrome.pageActions APIはなくなった。代わりに単数形のpage_actionとchrome.pageActionを使ってね
  • page_actionのiconsプロパティは削除された。代わりにdefault_iconやchrome.pageAction.setIconを使ってね
  • page_actionのnameプロパティは削除された。代わりにdefault_titleやchrome.pageAction.setTitleを使ってね
  • page_actionのpopupプロパティは削除された。代わりにdefault_popupやchrome.pageAction.setPopupを使ってね
  • page_actionのdefault_popupプロパティはもはやオブジェクトとして指定できない。文字列でなければならない
  • chrome.self APIは削除された。代わりにchrome.extensionを使ってね

緊急地震速報 by Extensionを作ったときの感謝をこめて

「緊急地震速報 by Extension」を作って経験したことなどをまとめました。今回は後編です。前編は会社のブログに書きました。

僕は生産設備を持っていませんので食料をはじめとした物流における支援は難しいのかもしれません。しかしながらシステムエンジニアとして間接的な支援や情報における支援はできます。僕は、天災における「破壊」を修復するのは人々の「生産」と考えるとともに、その「生産」の一部分を担う者として頑張っていきたいと思います。

東北地方太平洋沖地震の後、余震が頻発し緊急地震速報の警告音も頻繁に耳にするようになりました。警告音に焦らされる一方で、本当は落ち着いて揺れに対処しなければならないと思っていました。そこで緊迫感を与えないような緊急地震速報を出せないものかと今回の制作にいたりました。(なので初期バージョンには音がなかったのです)

また、本当は「緊急地震速報 by Chrome Extension」という名前で登録しようとしたのですが「Chrome」というワードは使用ができないので「緊急地震速報 by Extension」という名前になりました。

■プロキシ経由での接続

大きな会社などではプロキシ経由でインターネットに接続するようになっていて配信サーバと接続ができないようでした。

変更前

ポート12001番を使用していました。

var hosts = [
    '123.123.123.123:12001'
];

変更後

ポート443番を使用するように変更しました。

var hosts = [
    '123.123.123.123:443'
];

HTTPSで使用するポートを用いることにより一部の方の接続が可能になりました。

さらに変更後

ポート443番、80、8080番、12001番を使用するように変更しました。

var hosts = [
    '123.123.123.123:443',
    '123.123.123.123:80',
    '123.123.123.123:8080',
    '123.123.123.123:12001'
];

これによって判明したのは1/3〜1/4の利用者の方は443にしか接続できなかった事です。

参考

■マルチバイト文字列のbroadcast

今回、Websocketサーバからbroadcastする際、node-websocket-serverを使用したのですが日本語を正しく送信できませんでした。

解決策

wsServer.broadcast('\\u3092');

こうすることでクライアント側には\u3092という文字列が送信されるようになります。

ちょっとライブラリの中をのぞいてみます。

server.js

broadcastメソッドです。

this.broadcast = function(data) {
    manager.forEach(function(client) {
        clientWrite(client, data);
    });
};

上述のとおりforEachで回してます。clientWriteメソッドも確認します。

function clientWrite(client, data) {
  if (client && client._state === 4) {
    client.write(data, 'utf8');
  }
}

utf8としていされてwriteされています。

manager.js
Manager.prototype.forEach = function(callback, thisArg) {
    var current = this._head;
    while (current !== null) {
        callback.call(thisArg, current.connection);
        current = current._next;
    }
};

this._headは連結リストの先頭の要素のようです。

this._head = client;

clientオブジェクトが入っているようです。

var client = {
    id: connection.id,
    _next: null,
    connection: connection
};

接続IDと接続、次の要素を保持しています。

connection.js
function write(connection, data) {
    debug(connection.id, 'write: ', (new Buffer(data)).inspect());
    if (connection._socket.writable) {
        return connection._socket.write(data, 'binary');
    }
    return false;
}

binaryと指定されていますね。完全に読み切るには少々時間がかかるので適宜更新します。

参考

■正規表現

情報はtwitterのUser Streams API経由で取得していたのですが、ご利用者の方から震度やマグニチュードだけを簡略化して欲しいとの要望がありました。そこで正規表現を使用し文字列を整形して表示することにしました。ところが一部のご利用者には元の文章がそのまま表示されていました。

解決策

以下のようにして日本語をマッチさせるときに16進表現を使用することで解決しました。

var reg = new RegExp('\u9707\u5EA6([3-9]\u5F37*\u5F31*)', 'ig');
text.match(reg);
var scale = RegExp.$1;
// filter : simplify
if(localStorage["simplify"] !== "false"){
    var reg = new RegExp('([0-9]*/[0-9]*/[0-9]*)', 'ig');
    text.match(reg);
    var date = RegExp.$1;

    var reg = new RegExp('([0-9]*\:[0-9]*)', 'ig');
    text.match(reg);
    var time = RegExp.$1;

    var reg = new RegExp('\u30DE\u30B0\u30CB\u30C1\u30E5\u30FC\u30C9([0-9\.]*)', 'ig');
    text.match(reg);
    var magnitude = RegExp.$1;

    var reg = new RegExp('\u3001(.*?)\u306E', 'ig');
    text.match(reg);
    var place = RegExp.$1;
    
    if(date != '' && time != '' && place != '' && scale != '' && magnitude != ''){
        text = date + " " + time + " " + place + "\n\u9707\u5EA6" + scale + "\n\u30DE\u30B0\u30CB\u30C1\u30E5\u30FC\u30C9" + magnitude;
    }
}

// filter : scale
switch(localStorage["scale"]){
    case "7":
        if(parseInt(scale, 10) < 7){return false;}
        break;
    case "6":
        if(parseInt(scale, 10) < 6){return false;}
        break;
    case "5":
        if(parseInt(scale, 10) < 5){return false;}
        break;
    case "4":
        if(parseInt(scale, 10) < 4){return false;}
        break;
}

ブラウザ側の言語設定は各々異なります。通信時の文字コードを指定しても解決するかもしれません。

■twitterとの接続

node.jsを使い、以下のようなコードでtwitterと接続してます。

var client = http.createClient(
    80,
    "stream.twitter.com",
    false,
    false,
    {
        "username" : "hogehoge",
        "password" : "fugafuga"
    }
);
var request = client.request(
    "GET",
    "/1/statuses/filter.json?follow=123456789",
    {
        "host" : "stream.twitter.com"
    }
);
request.end();
request.on(
    "response",
    function(response){
        //sys.puts("response");
        var chunk = '';
        response.on(
            "data",
            function(data){
                // データ受信処理
            }
        );
        response.on(
            'end',
            function(){
                // twitterから接続を切られた時
            }
        );
    }
);

twitter切断時

実はたまに接続を切られます。切断される可能性を考慮し以下のようなコードを使用してます。

var getRequest = function(){
    var request = client.request(
        "GET",
        "/1/statuses/filter.json?follow=123456789",
        {
            "host" : "stream.twitter.com"
        }
    );
    request.end();
    request.on(
        "response",
        function(response){
            response.on(
                "data",
                function(data){
                    // データ受信処理
                }
            );
            response.on(
                'end',
                function(){
                    // twitterから接続を切られた時
                    r = getRequest();// 再接続
                }
            );
        }
    );
    return request;
}
var r = getRequest();

通信は必ず切れるものと考えてコードを書かなくてはいけませんね。さらに実は以下のようなスクリプトも実行してます。

request.on(
    "response",
    function(response){
        //sys.puts("response");
        var chunk = '';
        response.on(
            "data",
            function(data){
                // データ受信処理
            }
        );
        response.on(
            'end',
            function(){
                // twitterから接続を切られた時
                throw new Error('twitter disconnected me!!');
            }
        );
    }
);

node.jsにおいてcatchできなかったErrorはプロセスを終了させます。従って以下のようなシェルスクリプトと組み合わせてプロセスが終了してないか定期的にチェックし、終了していた場合は再起動することで接続を維持しています。

#!/bin/sh
while true
do
    isAlive=`ps -ef | grep "my-websocket-server.js" | grep -v grep | wc -l`
     if [ $isAlive -ge 1 ]; then
        echo "process is alive"
    else
        node my-websocket-server.js.js
        echo "process is dead"
    fi
    sleep 3
done

■アップデート

拡張機能のアップデートは自動で行われますが、新バージョンを登録してすぐに全ユーザのアップデートが完了するわけではありません。意外にも早く直後にアップデートされる方もいれば、時間がかかる方もいます。1時間で10%程度の方がアップデートされるようです。一方、90%のユーザはアップデート前のクライアントでサーバに接続しますので考慮して更新しなければなりません。

■起動

ちなみにですが以下のコマンドでWebSocketサーバを起動してます。

nohup ./check.sh > log.txt &

接続数を調べるには以下のようなコマンドを使ってます。

lsof -i:12345 | grep "node" | wc -l

■twitterからの文字列

システムの設計の問題にもなりますが、twitterからの文字列が正しくパースできないようなケースが稀にあります。入力は受け手側が意図する形式になるとは限らないということです。

文字列をパースできるように条件分岐する
但し、ブラックリスト方式に近いので未知の正しくない文字列はパース出来ない
データストアを作って保存に対してbroadcastのトリガを引かせる
全てのサーバが正しくパースできなかった事はないので非常に有用だが、失敗する確率はわずかながらある

■サーバ負荷

node.jsの素晴らしさを実感する毎日ですが、接続数が1万数千を超えるとさすがに0.5〜1秒程度遅延します。早く多くの方に届けるべき情報ではあるものの、一方で多くの方が接続すると遅延が生じやすくなります。サーバは個人で賄っているので限度があります。非常に難しい問題です。財閥の末裔だったらデータセンターごと買うのになと思う毎日です。

■まとめ

僕は水や電気の節約には賛成です。しかしながら根拠が不明瞭な自粛ムードには反対です。冒頭で述べました通り、破壊を修復するのは生産であり、手を止めて遠慮する事では無いと思います。何もできることがないと考えた結論の自粛より、いつも通り働き、学び、生活する方が生産的だと僕は考えます。まだまだ対応できていない事ばかりで完璧ではありませんが今後とも宜しくお願いいたします。早く余震が収まるといいですね。(●´⌓`●)

拡張機能への要望

今まで通り@mi_eqbotまでお願いいたします。自分のブログよりも確実にチェックしてます。w

その他開発などへの興味

@mitsuaki_iまでお願いいたします。

Google Chromeの拡張機能で顔文字を簡単に使えるツール

わざわざ「顔文字」と検索して、ctrl + 「c」でコピーし、サイトに戻ってctrl + 「v」でペーストするなんて面倒でないですか?このツールを使えば簡単に顔文字が使えるようになります。

■インストール

こちらのサイトで行えます。

■iPhone版

こちらをご覧ください。

■android版

こちらをご覧ください。

■使い方

こちらのサイトで紹介していただきました。ありがとうございます!

■アップグレードについて

Google Chromeには拡張機能の自動アップグレード機能がついてますので、しばらくしますと最新バージョンが自動的にブラウザにインストールされます。いちはやく試したい方は、設定→tools→拡張機能→拡張機能を今すぐ更新、の手順で最新版に更新することができます。

ver. 1.1.3

バージョン1.1.3

Internet Explorer 9(IE9)β版をインストールしてみる

■インストール

わくわくすっぞ!((o(^∇^)o))

Internet Explorer 9のインストール

更新プログラムのチェックはありがたいが結構長くかかる。

Internet Explorer 9をインストールしています

インストール完了。再起動を命ぜられる。これはUX的に良くない。( ゚ ρ ゚ )

Internet Explorer 9がインストールされました

■起動

早い!インストールしているプラグインの差があるので単純に比較はできないがChromeに迫るような勢いがある★

Internet Explorer 9を使ってみる

■遷移とか

JavaScriptを多用したサイトもストレスなく閲覧が可能だ。SVGとかもイケてまう!Firefox3.6よりも遥かに滑らかに動き、Chromeよりはわずかに重い程度だ。(*^◇^)/゚

■不具合

IE9では現在のところjQueryのドラッグ&ドロップが動作しない。゜(´□`。)°゜

Firefox3.6で旧バージョン用のプラグインを動かす

URL欄に以下のように打ち込む。

about:config

右クリックで項目を追加する。「真偽値」を選択だ。項目名は以下の通りだ。

extensions.checkCompatibility.3.6

値は「偽」(=false)だ。

false

3.6にアップデートしたらlive http headersが動かなくなってしまったので対処。

IEではJavaScriptでobject要素にembedを挿入できない

以下のコードを実行した時にIE6~8でエラーが発生する。appendChildやreplaceChildを使用してもできない。

var objectElm = document.createElement('object');
objectElm.setAttribute('classid', 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000');
objectElm.setAttribute('codebase', codebase);
objectElm.setAttribute('width', '240');
objectElm.setAttribute('height', '320');
var embedElm = document.createElement('embed');
embedElm.src = url;
embedElm.setAttribute('quality', 'hign');
embedElm.setAttribute('pluginspage', pluginUrl);
embedElm.setAttribute('type', 'application/x-shockwave-flash');
embedElm.setAttribute('width', '240');
embedElm.setAttribute('height', '320');
objectElm.appendChild(param1);
objectElm.appendChild(param2);
objectElm.appendChild(embedElm);//error - invalid argument(引数が無効です。)

クライアント側で

■解決策1

条件分岐して、IEのみobject要素に包括せず、embedのみを出力する。

var embedElm = document.createElement('embed');
embedElm.src = url;
embedElm.setAttribute('quality', 'hign');
embedElm.setAttribute('pluginspage', pluginUrl);
embedElm.setAttribute('type', 'application/x-shockwave-flash');
embedElm.setAttribute('width', '240');
embedElm.setAttribute('height', '320');
objectElm.appendChild(param1);
objectElm.appendChild(param2);
if(!!(window.attachEvent && !window.opera)){
    document.getElementById('flash').appendChild(embedElm);
}
else{
    objectElm.appendChild(embedElm);
    document.getElementById('flash').appendChild(objectElm);
}

■解決策2

object要素の後ろに殻のembed要素を挿入する。恐らくオリジナル。

var embedElm = document.createElement('embed');
embedElm.src = url;
embedElm.setAttribute('quality', 'hign');
embedElm.setAttribute('pluginspage', pluginUrl);
embedElm.setAttribute('type', 'application/x-shockwave-flash');
embedElm.setAttribute('width', '240');
embedElm.setAttribute('height', '320');
objectElm.appendChild(param1);
objectElm.appendChild(param2);
document.getElementById('flash').appendChild(objectElm);
if(!!(window.attachEvent && !window.opera)){
    document.getElementById('flash').innerHTML += '<embed></embed>';
}
else{
    objectElm.appendChild(embedElm);
}

なぜかチャント動くようになる。

参考

Firefox3.5

インストールしました。ほとんど見た目は変わらないのですが、タブをドラッグしたときの挙動が少しだけ異なってますね。あと、新しいタブを追加するボタンが追加されてますが、個人的にはありがたくないボタンです。ただし、ほとんどのユーザには使いやすいと思われます。

credit

噂の通りJavaScriptの速度が半端なく早いですね。Google Chromeも早いんですが、使い慣れている+性能となるとFirefoxしかない、というのが個人的な結論です。Gmailもすぐに立ち上がります。

gmailスタンバイ

Firefox3.5ダウンロード

Internet Explorer 8インストール(画面キャプチャ付き)

■まずIE8のダウンロード

http://www.microsoft.com/japan/windows/products/winfamily/ie/function/default.mspx

Internet Explorer 8がインストールできるのはWindows XP, Vista, Server2008のみだ。気になるのだがMicrosoft(マイクロソフトは)簡単に過去製品(Windows2000とか)を見捨てないであげて欲しい。サポートは長めにしてやるってのが誠意だろうに。それに古いブラウザを使ってる人が結構残ってしまうから、Web開発の立場からしても困るんです。

■さてダウンロードしたら

ダブルクリックしてインストール。するとまぁこんなのが出てくる。

インストール時の警告画面

実行をクリック

■クリックすると

インストールの開始といわれる。後で再起動が必要になるのでココで全てのアプリを終了させておく事をお勧めする。

インストールの開始

ロゴが横に潰れてるのが正直気になった(笑)。中身が潰れてなければイイが・・・

■次へをクリックすると

ライセンスの同意

当然だがライセンスには同意しなくちゃならん。同意したくないアウトローな人は諦めるべし

■同意したら

更新プログラムのインストールも勧められる。

更新プログラムのインストール

やはりセキュリティには気をつけた方がイイ世の中なのでチェックは入れておくべきだろう。

■次へを押すと

インストールが進む。んで完了。

再起動

最初に触れたが、この時点で再起動を迫られる。無理せず再起動することを勧める。

■再起動するとIE8が使えるようになる

初めての起動をすると、コンナ画面が出る

Internet Explorer 8へようこそ

こんにちは的な挨拶だ。「以前よりも早く動く」とか「アクセラレータ・・・」との事。まぁ使ってみなけりゃ分からないわな。

■次へをクリックすると

お勧めサイトを有効にする

おすすめサイト機能を有効にするか聞いてくる。面白そうなので「はい」にしてみた。どうやらユーザーの好みに応じたサイトをお勧めしてくれるらしい。

■次へいくと

設定の選択画面だ

設定の選択

細かい設定が変更できるらしいのだが時間もないので「高速設定」で今までの設定を引き継いでしまう事にする。マイクロソフトは大半のユーザーが「高速設定」を選ぶ事を知ってるはずだ。

■次はお気に入りのインポート

お気に入りのインポート

普段使ってるブラウザがIEでない人はココでチェックを入れよう。コレで設定は終わりだ!

■実際に使ってみた

実際の画面

まぁレイアウトが崩れることはない。マイクロソフトがプッシュするだけあって動きもIE7に比べたら全然滑らかである。

アクセラレータ

こんな感じでテキストを選択すると右側に半透明のアイコンが出る。

アクセラレータ

うーん便利。似たような機能は他のブラウザでも使えるが相手サイトに行かずとも翻訳が出来るのは素晴らしい。

URL蘭

アドレスバー

Google Chromeと同じように「履歴」と「検索へ」をマージして表示してくれる。

開発者ツール

開発者ツール

Firefoxは開発者に好かれてシェアを伸ばした。Microsoftはそれを学んだのだろう。

ウェブスライス(Web Slices)

一番注目されている!?機能だ。対応しているページに行くとツールバーに小さな緑色のアイコンが表示される。

ウェブスライス

クリックし購読すると、画面のようにサイトに行かなくても更新がチェックできるのだ。切り売り、まさにWeb Slicesだ。今後、IE8ユーザーが増えるにしたがってこの機能は一般的になるかもしれない。但し、今のところサイトが対応してないとスライスは出来ない。RSSに似ているが、その違いを簡単に言ってしまうと「ページの要約」と「ページの切り抜き」の違いだ。

■おまけ

タスクバー

今までIE憎しと、テストくらいにしか使ってなかったブラウザだったが、何だかタスクバーに入れてやりたい位の気持ちにはなった。常用するかどうかは今後の気分しだい。

JavaScriptの実行速度については一般ユーザーには気にならない程度になってるだろう。Firefox2では、SetTimeoutを使ったアニメーションが酷くコマ落ちしたが、あんな現象が起こらなければ、JavaScriptの速度をオレのような開発者以外が気にするような事は少ないと思う。Gmailを除けば・・・

■Firefox信者にはコチラ

FirefoxでWebSlices(microformat)には対応できないのっ!?・・・とか思ってしまった方、アドオンで実現できますよ。