2014年11月29日

encoding.js 1.0.12 リリースしました

JavaScript 文字コード変換ライブラリ encoding.js 1.0.12 リリース しました

アップデート内容

  • UTF-8 <=> JIS 変換テーブルのバグ修正 (文字化けが直りました)
  • JIS X 0208 を対象にした変換テストが通るようになりました
  • ファイルサイズが約60% 減りました
  • 実行速度が向上しました
  • convert で引数にオブジェクトが渡せるようになりました

UTF-8 <=> JIS 変換テーブルのバグ

UTF-8 から JIS, JIS から UTF-8 への変換テーブルが変なことになってました。
変換テーブルは MS 基本コードポイント (Unicode) を参照していましたが、 UTF-8 に変換する際に無効なコードポイントになってしまい文字化けが発生していました。
MS 基本コードポイントと IBM 基本コードポイントの差は以下のようになっています。

コードポイント:
文字名 IBM CP (Unicode) MS CP (Unicode) IBM CP (UTF-8) MS CP (UTF-8)
― (全角ダッシュ) U+2014 U+2015 E28094 E28095
~ (波形ダッシュ) U+301C U+FF5E E3809C EFBD9E
∥ (二重縦線) U+2016 U+2225 E28096 E288A5
- (負符号) U+2212 U+FF0D E28892 EFBC8D
U+00A2 U+FFE0 C2A2 EFBFA0
U+00A3 U+FFE1 C2A3 EFBFA1
U+00AC U+FFE2 C2AC EFBFA2

encoding.js の場合、MS コードポイントのまま変換しようとしていまい、対応する文字がなく '?' などになってしまっていました。
これは元々直したつもりでいたのですが、 encoding.js 1.0.10 Line 2973 あたりを見てみると以下のようになっていて
  1. 0xEFBC8F:0x213F,0xEFBCBC:0x2140,0xE3809C:0x2141,0xEFBD9E:0x2141,0xE288A5:0x2142,  
そもそも 0x2141 が消しきれてなくて重複していたり、対応する JIS テーブルに文字がなくて変換すると 1文字分消えてしまったりと、 バグが多かったのですが
今回、IBM 基本コードポイントの差分によって変換してあげることで、ぶじ文字化けが解消されました。

JIS X 0208 を対象にした変換テストが通るようになりました

この変換テーブルの修正により、JIS X 0208-1997 (JIS規格 第一・第二水準漢字) を対象にした変換テスト (UTF-16, UTF-8, Shift_JIS, EUC-JP, ISO-2022-JP(JIS)) が通るようになりました。 また、Unicode サロゲートペア の処理も修正しています。

ファイルサイズが約60% 減りました

encoding.js では、変換テーブルだけでかなりのサイズを占めています。
前バージョンまでは、JIS→UTF-8 テーブルと UTF-8→JIS テーブルの 2つを保持していたのですが、
今回、UTF-8→JIS のみを静的に持ち、JIS→UTF-8 変換が必要になった際、動的にもう一つのテーブルを生成するようにしました。
生成されるのは呼ばれた最初の 1回のみです。
その際の速度が気になり、ベンチとってみましたが 約 2~5ms 程度で問題ないと思われます。
ファイルサイズは非minifyで 261KB (min: 219KB) だったのが 152KB (min: 116KB) になり、約60% 減らすことができました。

実行速度が向上しました

前までは、変換テーブルに文字があるかないかを、if (TABLE[c] === void 0) { ... } みたいな感じで判断していましたが、
これは非常に遅く、また in を使うより hasOwnProperty が速く、実行環境にもよりますが
  1. var hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);  
  2. if (hasOwn(obj, key)) { ... }  
のように bind して使うよりも hasOwnProperty.call(obj, key) のほうが若干速かったため、後者を採用しています。

変換速度は、1MB の日本語テキスト (UTF-8) に対して SJIS に文字コード変換した場合、平均 約 50ms. (EUC-JP, JIS 等も同程度)、
UNICODE (UTF-16) から UTF-8 とその逆は約 5ms ほどで、前よりだいぶ速くなりました。

convert で引数にオブジェクトが渡せるようになりました

convert の第二引数に Object を渡せるようになりました。
  1. // 以前の指定の仕方 (SJISに変換)  
  2. var sjisArray = Encoding.convert(unicodeArray, 'SJIS''UNICODE');  
  3.   
  4. // Object で指定  
  5. var sjisArray = Encoding.convert(unicodeArray, {  
  6.   to: 'SJIS',  
  7.   from: 'UNICODE'  
  8. });  
前のように 第二引数を to, 第三引数を from として文字列で渡しても動きます。


文字化けという大きなバグを修正しているので、アップデートをおすすめします。

Download


Node.js では、encoding-japanese というモジュール名になっています
  1. npm install encoding-japanese  
  1. var encoding = require('encoding-japanese');  

上のようにして利用できます。

encoding.convert() は Buffer に対しても使えます(配列で返ります)

Demo

Repository




2014年10月16日

LZアルゴリズムでBase62に圧縮するJavaScriptライブラリ書きました

LZSS(LZ77) 圧縮アルゴリズムで文字列を圧縮/解凍します。
圧縮された結果は Base62 (0-9A-Za-z) からなるバイナリセーフな文字列になります。
サイズ制限のある localStorage や sessionStorage, cookie など、 例えば localStorage は 5MB 使えたとしても UTF-16 の場合、実質的に 2.5MB 分になってしまします。
圧縮結果は内容にもよりますが おおよそ 60~80% 程度のサイズになります。
例外として、繰り返しのない文字列は1~2割程度サイズが増えることがあります。

追記

2014-10-24 現在、高速化にすべく見なおして圧縮率も上がりました。
繰り返しのない文字列 (例えば U+0000 - U+FFFF 1文字ずつなど) も大幅なサイズ増加なく圧縮できます

  1. var data = 'hello hello hello';  
  2. console.log(data.length); // 17  
  3.   
  4. var compressed = lzbase62.compress(data);  
  5. console.log(compressed); // 'tYVccfrgxGL'  
  6. console.log(compressed.length); // 11  
  7. console.log(compressed.length < data.length); // true  
  8.   
  9. var decompressed = lzbase62.decompress(compressed);  
  10. console.log(decompressed); // 'hello hello hello'  
  11. console.log(decompressed === data); // true  

Download

※バージョンが違うとフォーマットも違う可能性があります。できるだけ最新バージョンをご利用ください

Demo

Repository




2014年9月25日

JavaScriptが実行できるリアルタイムオンラインエディタ作ってみました

複数人で同期して編集できるWebエディタを探していたのですが、 見つからず・・・

jsfiddlejsdo.it は同時編集できないため、ちょっと探してたのとは違って、
Scratchpad はリアルタイムで編集できてよいのですが、JavaScriptが実行できない。
CodePen は同期するのに PRO アカウントが必要らして、諦めて、仕方ないので作ってみました。

追記:
SyncFiddle はリニューアルし、使用しているフレームワークの構成が変わりました。
URL は http://syncfiddle.net/ になりました。

仕様とか

  • アクセスするとランダムにid振ったページ空間に飛ぶ
  • そのURLを共有すると複数人で同時編集できる
  • 相手のことがわかるのはidだけ
  • コードとカーソル位置がわかる
  • JavaScript コンソールがある
  • その時のHTMLコードを .html で保存できる
  • ページの破棄という機能はないですが、コードを空にしてユーザ数 0 になるとそのうち消える
  • プライベートタブ(シークレットタブ)とか使ってみるとわかりやすいかも

レイアウト

  • PHP フレームワーク PunyApp
  • JavaScript Backbone + r.js
  • エディタは CodeMirror の HTML5 mixed モード

こないだ公開したフレームワーク PunyApp のテストも兼ねて作ってみたのですが、 なにしろサーバが古くて大変。最初は WebSocketにしようと思ったけどフレームワークのテストにならないので pollingしてます。今更ですがサーバーから立て直したほうがよかったです。一応公開してますが、サーバが不安定になるかもしれないです。
Backbone.js と r.js (require.js)、前から触ってみたくて、今回はじめて使ってみました。
自由度が高くて、View周りとかちょっと道を外れると ぐしゃってしまうので注意が必要ですが、 自分にとっては使い心地がよかった。まだまだ勉強中です。



2014年9月6日

軽量PHPフレームワークPunyAppというの作りました


最近、ちまちまとPHP を書くことがあって、 ちょっとしたWebアプリ等作るときに
CakePHP などのある程度規模のあるフレームワークを使うまでもないかなって思うことが多々あり、
そういった用途に 小規模向けなフレームワーク (マイクロフレームワーク) PunyApp というのを作りました。

以前から自分だけで使ってて少しずつ更新して温めていたもので、 ある程度形になったので公開しました。
軽量で中小規模向けなもので、 おおまかな設計は CakePHP を参考にしてて、使い方も似てます。

PunyApp は MVC モデルで他のPHP拡張等は必要ありません。

ダウンロード

要件

  • PHP 5.2.0 +
  • mod_rewrite が有効 (Apache Server)

ライセンス

  • MIT

機能/特徴

  • MySQL, PostgreSQL, SQLite, Posql に対応
  • Controller, Model, Viewアクション
  • フォームのValidation
  • Viewテンプレート変数はデフォルトでHTMLエスケープされる
  • Session (データベース)
  • Cookie (デフォルトで暗号化)
  • データベースエラー時などのEvent
  • サンプルのログインフォームが入ってる


追記

以下の情報はバージョンアップに伴い古くなっているので https://github.com/polygonplanet/PunyApp を参照ください

レイアウト

  • ファイル構成
/application                → アプリケーションディレクトリ
    /controllers            → コントローラ
    /models                 → モデル
    /views                  → ビュー
    /libraries              → 共通ライブラリやヘルパー等
    /storage                → SQLiteなどのファイルベースデータベースやログを保管
        /logs               → /storage配下を書き込み可にしておく
        /databases          → 同様
    /settings               → 設定
        app-settings.php    → アプリケーション設定ファイル
        app-scheme.php      → データベーススキーマ
    /public                 → 公開ディレクトリ
        /css
        /js
        index.php
/lib                        → PunyApp内部ライブラリ
/vendors                    → 外部ライブラリ等を入れるディレクトリ
index.php

Controllers

コントローラのアクションは、GET や POST などのリクエストメソッドで切り分けができます。
  1. class SampleController extends PunyApp_Controller {  
  2.   
  3.   public $models = array('sample');  
  4.   
  5.   /** 
  6.    * GET /login 
  7.    */  
  8.   public function getLogin($params) {  
  9.     $this->view->render('sample/login');  
  10.   }  
  11.   
  12.   /** 
  13.    * POST /login 
  14.    */  
  15.   public function postLogin($params) {  
  16.     $has = $this->sample->hasUser($params['id'], $params['pass']);  
  17.     if ($has) {  
  18.       $this->session->userid = $params['id'];  
  19.       $this->redirect('home');  
  20.     }  
  21.   
  22.     // ...  
  23.   
  24.     $this->view->render('sample/login');  
  25.   }  
  26.   
  27.   /** 
  28.    * Any /login (あらゆるリクエストメソッドに対応) 
  29.    */  
  30.   public function anyLogin($params) {  
  31.     // ...  
  32.   }  
  33.   
  34.   /** 
  35.    * Before /login (前処理) 
  36.    */  
  37.   public function beforeLogin($params) {  
  38.     if (!empty($this->session->userId)) {  
  39.       $this->redirect('home');  
  40.     }  
  41.   }  
  42.   
  43.   /** 
  44.    * After /login (後処理) 
  45.    */  
  46.   public function afterLogin($params) {  
  47.     // ...  
  48.   }  
  49.   
  50.   /** 
  51.    * GET /home 
  52.    */  
  53.   public function getHome($params) {  
  54.     // ...  
  55.   }  
  56. }  
before や after で前処理などが設定できます。
any は、すべてのリクエストメソッドに対応します。
メソッド名を any だけ (function any() {}) にすると、404 にならずに any が実行されます。
引数 $params はリクエストパラメータが渡されます。

コントローラのメソッド名の命名規則は、

リクエストメソッド名 + アクション名

になります。
GET に対応する hoge だったら、getHoge になります。

URL は、
http://www.example.com/コントローラ名/アクション名

となります。
アクション名は、リクエストメソッド名を外した名前です。
SampleController で getHoge の場合は、
http://www.example.com/sample/hoge
という感じになります。 ファイル名は sample.php です

AnyController (any.php) という名前にすると、すべてのリクエストに対応します。

Models

モデルは、PDO を使っているのもあり 基本的にプリペアドステートメントを使って実行します (プレースホルダ)。
  1. class SampleModel extends PunyApp_Model {  
  2.   
  3.   public function addUser($userid$email$pass) {  
  4.     // Insert  
  5.     $sample = $this->newInstance();  
  6.     $sample->userid = $userid;  
  7.     $sample->email = $email;  
  8.     $sample->pass = sha1($pass);  
  9.     return $sample->save();  
  10.   }  
  11.   
  12.   
  13.   public function deleteUser($userid) {  
  14.     return $this->delete(  
  15.       array('userid' => '?'),  
  16.       array($userid)  
  17.     );  
  18.   }  
  19.   
  20.   
  21.   public function getUser($userid) {  
  22.     return $this->findOne(  
  23.       array(  
  24.         'fields' => array('id''userid''email'),  
  25.         'where' => array('userid' => '?')  
  26.       ),  
  27.       array($userid)  
  28.     );  
  29.   }  
  30.   
  31.   
  32.   public function hasUser($userid$pass) {  
  33.     return $this->has(  
  34.       array(  
  35.         'where' => array(  
  36.           'userid' => ':userid',  
  37.           'pass' => ':pass'  
  38.         )  
  39.       ),  
  40.       array(  
  41.         ':userid' => $userid,  
  42.         ':pass' => sha1($pass)  
  43.       )  
  44.     );  
  45.   }  
  46. }  
  • array find ( array $query = array(), array $params = array())

find() の引数 $query は、 'distinct', 'fields', 'from', 'as', 'joins', 'where', 'group', 'having', 'order', 'limit', 'offset' が使えます。
  1. public function getUserByName($name) {  
  2.   return $this->find(  
  3.     array(  
  4.       'distinct' => false,  
  5.       'fields' => array(  
  6.         'U.id AS id''U.name AS name',  
  7.         'U.category AS cat''P.url AS url'  
  8.       ),  
  9.       'as' => 'U',  
  10.       'joins' => array(  
  11.         'type' => 'LEFT',  
  12.         'table' => 'profile',  
  13.         'as' => 'P',  
  14.         'on' => array('U.id' => 'P.id')  
  15.       ),  
  16.       'where' => array(  
  17.         'name' => ':name'  
  18.       ),  
  19.       'group' => 'cat',  
  20.       'order' => 'id DESC',  
  21.       'limit' => 10,  
  22.       'offset' => 5  
  23.     ),  
  24.     array(  
  25.       ':name' => $name  
  26.     )  
  27.   );  
  28. }  
ある程度のクエリは扱えます。

モデル内では $this->getDatabase() が PDO として使えるので、
  1. public function getName($id) {  
  2.   $sql = 'SELECT name FROM foo WHERE id = ?';  
  3.   $stmt = $this->getDatabase()->prepare($sql);  
  4.   $stmt->execute(array($id));  
  5.   return $stmt->fetchAll(PDO::FETCH_ASSOC);  
  6. }  
上のように直接クエリを書いてもいいですが、
直接クエリを書かずにモデルの find() や delete() 等を使うメリットとしては、
'created''modified' というフィールドが自動てセットされることが大きいです。 テーブル定義にあらかじめ created もしくは modified を定義しておくと、 insert (save), update のタイミングでそれぞれ現在時刻を設定します。
integer や int(11) で定義すると 現在の time() が設定されます。
datetime は Y-m-d H:i:s になります。
varchar(255) で定義すると現在時刻をミリ秒で設定します。
  • created : 作成された日時
  • modified : 更新された日時
これらはアプリケーション側で created, modified をパラメータに扱う場合は無視されます。

コントローラでのモデル定義は $models に使うモデル名(テーブル名)を記述します。
  1. class SampleController extends PunyApp_Controller {  
  2.   
  3.   public $models = array('sample');  
  4.   
  5.   public function getLogin($id) {  
  6.     $user = $this->sample->getUser( ... );  
  7.   }  
  8. }  

Views

  1. $this->view->text = 'Hello!';  
  2. $this->view->render('index');  
ビューでは PHP本来が持ってるテンプレートを使います。
  1. <html> 
  2.   <body> 
  3.     <h1>Sample</h1> 
  4.     <?php echo $text?> 
  5.   </body> 
  6. </html> 
テンプレート変数はデフォルトでHTMLエスケープされます。
  1. $this->view->text = '<script>alert(1)</script>';  
  1. <p><?php echo $text ?></p> // &lt;script&gt;alert(1)&lt;/script&gt; 

Validation

リクエストパラメータのバリデーションはコントローラ内で行います。
  1. class SampleController extends PunyApp_Controller {  
  2.   
  3.   public $validationRules = array(  
  4.     'id' => array(  
  5.       'required' => true,  
  6.       'rule' => array('regex''/^[a-z0-9]{1,10}$/i'),  
  7.       'message' => 'Only letters and integers, max 10 characters'  
  8.     ),  
  9.     'email' => array(  
  10.       'required' => true,  
  11.       'rule' => array('email'),  
  12.       'message' => 'Invalid email address'  
  13.     ),  
  14.     'pass' => array(  
  15.       'required' => true,  
  16.       'rule' => array(  
  17.         array('minLength', 4),  
  18.         array('maxLength', 20)  
  19.       ),  
  20.       'message' => 'Min 4 characters, max 20 characters'  
  21.     )  
  22.   );  
  23.   
  24.   // ...  
  25. }  
バリデーションのルールは
email, url, ip, between, minLength, maxLength, regex
等が定義されています。または自分で定義します。

その他、コールバックが使えます。
  1. $this->validationRules['nickname'] = array(  
  2.   'required' => true,  
  3.   'rule' => array('callback'function ($value) {  
  4.     return preg_match('/^[ぁ-ん]/u'$value) && preg_match('/[!]$/u'$value);  
  5.   }),  
  6.   'message' => 'ひらがなではじまって「!」で終わらないとダメです'  
  7. );  
$this->validate() で実行します。 任意のルールを引数に渡すこともできます。
引数を省略すると $validationRules に対して実行します。
  1. class SampleController extends PunyApp_Controller {  
  2.   
  3.   // ...  
  4.   
  5.   public function postLogin($params) {  
  6.     if ($this->validate()) {  
  7.       // ...  
  8.     }  
  9.   }  
  10. }  
以下のViewメソッドからメッセージを取得できます。

追記

以下の情報はバージョンアップに伴い互換性があるかわかりません
詳細は https://github.com/polygonplanet/PunyApp を参照ください

  • 名前を指定して取得 : string getValidationError( string $name );
  • 最後のメッセージを取得 : string getLastValidationError( );
  • 全部取得 : array getValidationErrors( );
  • HTML<li>で全部取得 : string getValidationErrorMessages( array $attributes = array('style' => 'color:red') );
コントローラ内では $this->view->getValidationError('hoge') のように取得できます。
ビュー内では以下のようにして表示できます。
  1. <div class="error"> 
  2.   <?php echo $this->getValidationError('param_name'?> 
  3. </div> 

インストールと設定

1. 展開したファイルをサーバーの任意のディレクトリに置きます

2. application/settings/app-settings.php を開いて設定します
  1. $settings = array(  
  2.   /** 
  3.    * System settings 
  4.    */  
  5.   'system' => array(  
  6.   
  7.     /** 
  8.      * Debug mode 
  9.      * 
  10.      * true = show errors 
  11.      * false = hide errors 
  12.      */  
  13.     'debug' => true// デバッグモードだとエラーが起きたとき表示される  
  14.   
  15.     /** 
  16.      * Timezone 
  17.      * 
  18.      * e.g., 'America/Chicago', 'Asia/Tokyo' etc. 
  19.      */  
  20.     'timezone' => ''// 日本の場合はここを 'Asia/Tokyo' に設定しておく  
  21.   
  22.     ...  
  23.   ),  
  24.   
  25.   /** 
  26.    * Database settings 
  27.    */  
  28.   'database' => array(  
  29.   
  30.     /** 
  31.      * Database engine 
  32.      * 
  33.      * Available engines: "mysql", "sqlite" and "posql". 
  34.      */  
  35.     'engine' => ''// 使用するデータベース  
  36.   
  37.     ...  
  38.   ),  
  39.   
  40.   /** 
  41.    * Session settings 
  42.    */  
  43.   'session' => array(  
  44.   
  45.     /** 
  46.      * Session engine 
  47.      * 
  48.      * Available engines: "php", "file" and "database". 
  49.      */  
  50.     'engine' => ''// セッションエンジンを設定  
  51.   
  52.     ...  
  53.   )  
  54. );  
3. データベーススキーマを作成します、または application/settings/app-schema.php に記述します

4. application/storage 配下のファイル、ディレクトリのパーミッションを「書き込み可」に設定します

5. 1 で展開したディレクトリにブラウザでアクセスしてみて、PunyApp ~と表示されたら成功です

6. 実際に作ってみましょう

サンプル

/sample/ にサンプルのログインフォームが入っています。
/sample/ にアクセスして確認できます。




なにかあれば以下のレポジトリのIssues, または @polygon_planet へお願いします。

レポジトリ




2014年4月20日

スマートウォッチPebbleを買ってみて

はじめに

Pebble というスマートウォッチ。

なんとなくウェアラブルな端末について調べてたら、
Pebble というのを知って、調べてるうちにどうやら JavaScript でアプリ開発できるとのこと。 すぐ購入。
理由としてはそれだけじゃないのですが、スマートフォンは家に忘れるから。とか、Pebble のオープンな環境がよかったからとか、 そんなこんなで届いて1週間ほど経ちました。
何も考えずに黒を買ってしまったのですが、赤かオレンジがよかったなぁ・・・と。バンドも変えられて、常に身につけて見えるものだから、 購入を考えてる方は好みの色がいいと思います。

さっそく作ってみた時計画面(Watchface)

Pebble

Pebble Appstore

Pebble は、スマートフォン側の「Pebble」というアプリを通して Bluetooth でやり取りして動いています。
「Pebble」アプリ内から Pebble Appstore に行けます。
Pebble Appstore から Pebbleアプリや時計画面(Watchface) などをインストールできます。
アプリの管理や設定も「Pebble」アプリ内でできます。
画面は E-Ink (厳密には違う?) で白と黒のドットで表されるアナログ感あふれるもの。 それゆえにバッテリーの持ちがすごくいい。

※この記事ではスマートフォン=Androidで書いています

Pebble JavaScript Framework


Pebble のアプリは、基本的に C言語で書いたものを出力しますが、JavaScriptで書くこともできます。
Pebble のプロジェクト内に C と JavaScript の両方のコードを含めることができ、 イメージ的には C で書いたものは Pebble 時計側で動き、JavaScript で書いたコードはスマートフォン側で動きます。
C と JavaScript 間でメッセージのやり取りができ、JavaScript で処理した結果を Bluetooth を通して C (時計側) で受け取れる感じです。
XMLHttpRequestなどの非同期処理、JavaScriptでやりやすいことは余裕のあるスマートフォン側に処理をさせて、 時計側がデータを受け取って表示。時計側の処理を最小限に抑えやすくなります。

Simply.js

これまでは、最低でも時計画面に出力するのに多少は C で書く必要がありました。
そこで、完全に JavaScript コードだけで完結できる Simply.js というアプリがあります。
Simply.js をインストールすると、URL を入力する設定欄がでてきて、ここに JavaScript (.js) のURLを入れると、 Pebble アプリと同様に動かすことができます。


自分のサーバや Dropbox などに .js ファイルを置いて実行できます。

参考: 以下の記事ではサーバのロードアベレージなどを表示させていました
ひとりぶろぐ » 2.0で面白くなったスマートウォッチPebbleを、JavaScriptゴリゴリでネット監視装置として使う

CloudPebble

Pebble の開発環境 CloudPebble は、クラウド上で C のソースがコンパイルできます。
コードは JavaScriptエディタ (CodeMirror)で書けて補完ウィンドウなどもでてきます。
スマートフォンのIPを入れておくと「build」ボタンを押した時に、
PC(ブラウザ)→スマートフォン→Pebble 経由で
書いたコードがアプリになってPebble時計にインストールされ結果が分かる仕組みです。
もはやブラウザだけで開発できる環境。

そして、CloudPebble では、任意の github プロジェクトのURLを入れて「import」ボタンを押すと、 Pebble アプリとして適切か判断した後、自分のプロジェクト内に取り込まれます。
自分のプロジェクトを github に export (push) するのも同様にできます。

新規作成時は C と Simply.js が選べます

実際使ってみて

メインで使ってる時計アプリは、Bluetooth切断時に長めのバイブ機能があるため、
スマートフォンを忘れることがなくなりました。
(ジェネレータで作ったものも同じ機能がつきます)

あとは、メールなどの通知が来た時、
  1. スマートフォンを出す
  2. 画面をタッチ
  3. 内容を確認
とやっていたのが、
  1. Pebbleを見る
だけになったり、
音楽の制御がリモコン感覚で楽になったり…

Android の場合、Tasker というアプリと Pebble の連携で、 ほとんどのことは自動化もしくは ON/OFF するだけで済むようになると思います。
マナーON/OFF、メディア音量調節、消音、マップ起動時にGPS有効、場所を指定してナビ起動、Pebbleから画面ロック/解除等…

変化といえば、あまりスマートフォン画面を見ることがなくなった。

今のところPebbleは日本語表示に難ありですが、 Pebble 日本語 (ひらがな, カタカナ) カスタムファームウェア | pebble 日本語表示 のおかげで助かってます。



何か間違い等ありましたらコメントか http://twitter.com/polygon_planet までお願いします

2014年1月29日

WSH/JScriptをECMAScript標準にするWSHModuleを作りました


WSH/JScript を ECMAScript-262 5th に可能な限り近づける WSHModule というのを作りました。

WSHModule はWSH/JScriptで構築されたJavaScriptのVMです。
可能な限りECMAScript5標準としてJavaScriptを実行します。 スクリプトは、モジュール空間 (Node.js 互換 *1) で実行されます。
WSHModuleは、ECMA-262標準に近づけるためのwscript.exeのアップグレード版として利用することも可能(かもしれません)。
用途によっては、Node.jsを使用したほうが手っ取り早いです。が、JScriptは、Windowsにバンドルされています。 WSHModuleはwscript.exeで実行されるように、UI向けです。 Windowsで拡張子 .js のバッチスクリプトを実行するときに、WSHModule.exe を通すことで、快適な環境になると思います。

*1: Node.js自体がCommonJSの仕様のうち「Module 1.0」と「Unit Testing 1.0」には一応準拠してるだけなので、CommonJS準拠とは言えません

機能

  • ECMAScript5標準の構文をサポート
  • モジュール空間
  • UTF-8で書ける
  • alert, confirm, prompt, setTimeout, clearTimeout, setInterval, clearIntervalが使える
  • (JScript Bug) catchなしのtry-finallyが書ける
  • (JScript Bug) String.prototype.substr, Array.prototype.indexOf, Array.prototype.splice などを ECMA-262標準に修正
  • WSHModule.exe ダブルクリックでシェル画面が開く
  • いくつかのWScriptで扱えない機能をモジュールとして追加(clip, console, fs, util 等)

ダウンロード

要件

以下の環境で動作します
  • Windows (32bit/64bit)
WSHModuleは、環境変数(PATHなど)を登録しないので、必要あれば任意に追加してください。

実行方法

WSHModule.exe "C:/path/to/myscript.js"
もしくは、 "C:/path/to/myscript.js" を WSHModule.exe にドラッグドロップ

簡単な方法:
  1. WSHModule.exe のショートカットをデスクトップ等に作成
  2. 任意のスクリプト(.js)をショットカットにドラッグドロップして実行

テスト

以下の手順で簡単なテストスクリプトが実行できます。
  1. cd WSHModule
  2. "bin/WSHModule.exe" "scripts/test.js"

ToDo

いろいろと大げさなこと言ってますが以下の項目が未実装です
  • Getter と Setter がない
  • "use strict" が使えない

サンプルコード

Hello World:
  1. alert(' hello   world  !'.split(/\s+/).filter(function(s) {  
  2.   return s;  
  3. }).map(function(s) {  
  4.   return s.charAt(0).toUpperCase() + s.slice(1);  
  5. }).join(' ')); // 'Hello World !'  

クリップボードを扱う例:
  1. // src/clip.js参照  
  2. var clip = require('clip');  
  3. var curClip = clip.getAsText();  
  4. alert('現在のクリップボード「' + curClip + '」');  
  5. clip.setAsText('test');  
  6. alert('クリップボードに「test」を設定しました');  

ファイルを扱う例:
  1. // fs は Node.js/fs とだいたい同じ仕様になってます(扱えるのはSyncのみ)  
  2. // http://nodejs.org/api/fs.html  
  3. // http://nodejs.jp/nodejs.org_ja/docs/v0.10/api/fs.html  
  4.   
  5. var fs = require('fs');  
  6. console.log(fs.readFileSync(__filename), 'このファイルの中身');  


なにかあれば以下のレポジトリのIssues, または @polygon_planet へお願いします。

レポジトリ