読者です 読者をやめる 読者になる 読者になる

素人がプログラミングを勉強していたブログ

プログラミング、セキュリティ、英語、Webなどのブログ since 2008

連絡先: すかいぷ:javascripter_  か javascripter あっと tsukkun.net skypeのほうがいいです

Get mouse coordinates on Yosemite using JavaScript Automation(ターミナルからマウス座標をゲットする)

英語で調べたけどぜんぜん出てこないので英語で書く。Yosemiteでターミナルからマウス座標をゲットするコマンドはこれ。 osascript -l JavaScript -e "ObjC.import('Cocoa');console.log(JSON.stringify($.CGEventGetLocation($.CGEventCreate(null))))"

In OS X 10.10 (a.k.a. Yosemite), Apple has deprecated Ruby 1.8 along with support for "osx/cocoa" module in favour of AppleScript's AppKit and JavaScript Automation. I found it quite inconvenient since it used to be quite easy to get access to OS X's internal information such as mouse coordinates without needing any external binary files prior to Yosemite. After searching on the Internet for a while, however, I found an alternative way to do it in Terminal using JavaScript Automation introduced in Yosemite. So here's how to do it.

Firstly, open up Script Editor and switch the language from ActionScript to JavaScript. You can now write JavaScript in Script Editor, in which you have access to most of the functionality available in Action Script like Mail.inbox.messages[0].subject(). You will also get this magical ObjC bridge called $.

ObjC.import('Cocoa');
$.NSBeep();

(More information available at JavaScript for Automation Release Notes)

You can use the following code to obtain the mouse coordinates:

ObjC.import('Cocoa');
ObjC.import('stdio');

var c = $.CGEventGetLocation($.CGEventCreate($()));
$.printf('%d %d\n ', c.x, c.y);

Secondly, there's also a builtin command called osascript, which supports JavaScript as well. Type in

osascript -l JavaScript -e "ObjC.import('Cocoa');console.log(JSON.stringify($.CGEventGetLocation($.CGEventCreate(null))))"

in Terminal, and you'll get something like

{"x":920.4453125,"y":698.9140625}

You can execSync the above code and then JSON.parse it to get the mouse coordinates in Node.js. I can think of many other interesting things including creating a native app on top of JavaScript Automation, though it will not look so JavaScript-y.

To sum it up, using JavaScript Automation will become a standard now that Apple seems to have lost its interest in Ruby. I think JavaScript Automation is worth investigating because most of the knowledge can be applied to Objective C and other languages that bridge Cocoa APIs.

References:

  1. YosemiteからRuby1.8が削除されたのでAppleScriptでのウィンドウのサインズ変更の取り扱いを変更した - rcmdnk's blog
  2. JavaScript for Automation Release Notes
  3. JavaScript for OS X Automation by Example -Telerik Developer Network

array.indexOf(value) >= 0で要素が含まれてるか検索すると失敗する場合がある

indexOf(val) >= 0の話

配列に要素が含まれているかのチェックに

[1, 2, 3].indexOf(2) >= 0; // true

のようなコードを使っている場面を極めて頻繁に(それ以外を使っているのを見ることは稀なくらい)見るが、

function contains(a, v) {
  return a.indexOf(v) >= 0;
}

は厳密にはJavaScriptでは正しく動くとは限らない。上記コードのどこが間違っているのか、下記の解説を見る前に考えてみてほしい。こんなシンプルなコードにも、バグがある。

解説

containsがどのように動くべきなど明白だというのは間違いである。実は微妙な問題がたくさんある。 まず、致命的な部分をあげると、最初のナイーブな実装だと

contains([NaN], NaN) // false

となってしまう。明らかに意図した動作と異なり、バグである。 これは

NaN === NaN // false

という意味不明なJavaScriptNaNの仕様によるもので、indexOfも同様に===を使用しているので、こうなる。 訂正: コメントで指摘されたが、NaN !== NaNはほぼ全ての言語で採用されているIEEEの数値処理の仕様に基づいている(つまり不可解な仕様ではなくごく一般的な動作な)だけで、JavaScript自体の仕様上のミスではなかった。NaNまわりはハマりやすいポイントではあるので、気をつけたい。 contains関数では

contains([NaN], NaN]) // true

となるべきだ。

他にも、微妙な問題がある。 例えば、

[ ,,, ] [0] === undefined // true

であるが

0 in [ ,,, ] // false

であり、JavaScriptには、length以下に、holeと呼ばれる存在しないindexが存在する可能性があって、

[,,,].forEach(function () {alert(1); })

ではalertは一度も呼ばれない。indexOfも同様に存在しない要素をスキップするので

contains([,,,], undefined) // false

となる。これを仕様と呼ぶのかバグと呼ぶのかは考え方次第であるが、とりあえずforEachやindexOfにあわせて、holeは検索に含めないことにする。 ただし注意点として、最近はarrayのfor-inは順序が保証されているようだが

for (var i in a) {
  if (a.hasOwnProperty(i)) {

  }
}

は使ってはいけない。 なぜかというと

var a = [];
a['z'] =1;

の'z'までループしてしまうからだ。 また

for (var i = 0; i < a.length; i++) {
  for (i in a) {}
}

も同様にダメで、なぜかというと

Array.prototype[0] = 'a';

があると動作がおかしくなるからだ。というか

Array.prototype[0] = 'a';
var a = [, ];
a.indexOf('a') // 0
[,].forEach(function () { alert(1); }) // alert(1)される

のようにforEachとindexOfはプロトタイプチェーンを辿るので、この部分も難しいところであるが、今回はcontainsではプロトタイプチェーンを辿らないように実装した。

もう一点、これは余談だが、扱いの微妙な値がJavaScriptにはある。+0と-0である。一見同じようにみえる値だが、両者は厳密には異なる。

1/0 // Infinity

である一方、

1/-0 // -Infinity

であるからだ。

[-0].indexOf(+0) // 0

であるので、ここでは慣例に従って-0と+0はcontainsでは区別しないことにする。

さて、indexOfでは検索しはじめる位置を第3引数で指定できる。

[0].indexOf(0, 1) // false

となる。 もしこれに-Infinityを指定したらどうだろうか。

[0].indexOf(0, -Infinity) // 0

となり、きちんと、一瞬で答えが返ってくる。これも実装すべきだろう。

さて、おおよそ全ての値で動く実装を下記にあげる。

function contains(array, value, startIndex) {
  var hasOwnProperty = Object.prototype.hasOwnProperty;

  if (startIndex > array.length) { // for efficiency and also handling Infinity
    return false;
  } else if (startIndex === -Infinity) {
    startIndex = 0;
  } else {
    // when startIndex isn't specified make it 0
    // if startIndex is an invalid value, just make it 0 to behave like indexOf
    startIndex = +startIndex || 0;
  }

  for (var i = startIndex; i < array.length; i++) {
    // when array is sparse and value is undefined, ignore non-existent indices
    // 0 in [, ] returns true when Array.prototype[0] = 3
    // Therefore, hasOwnProperty must be used
    if (hasOwnProperty.call(array, i)) {
      var item = array[i];
      
      // when item is NaN and value isNaN
      if (item !== item && item !== value) {
        return true;
      } else if (value === item) {
        return true;
      }
    }
  }
  return false;
}

実行結果。

// regular values
contains([0, 1, 2], 0) // true
contains([0, 1, 2, 3], 0, 1 ) // false

// irregular values
contains([0], '0') // false
contains([NaN], NaN) // true
contains([,,], undefined) // false
contains([-0], +0) // true

contains([0], 0, -Infinity) // true
contains([0], 0, Infinity) // false
contains([0], 0, NaN) // true

ここまで読んで分かったと思うが、array.indexOf(val) >= 0が常に動かないことへ対処は、真面目にやろうとすると長い。長い上に他のJSのネイティブのAPIの仕様もちょっとずつおかしいので、プログラムを書く時点でNaNやInfinity, 穴のある配列を作らないように作るのがベターである。

scrollイベントが呼ばれすぎることへの対処

onscrollを監視していると大量にeventが来てパフォーマンスが劣化するというのはよく聞く話で、 underscore.jsなどでイベントをthrottleやdebounceさせて対処していることが多い。 ただ、scrollに応じてスタイルを変更させたりする場合は、0.1秒くらい遅れがあると視覚的にカクカクしがちで、仕方なくsetTimeout(fn, 0)でthrottleさせることも多いと思う。

scrollイベントは画面のフラッシュレートと同期していないので、マウスやトラックパッドの動きに応じて大量に呼ばれていて、setTimeoutも画面のフレッシュレートとは関係なく内部の実行タイマーに応じて動いている。よって、setTimeout(fn, 0)でthrottleしてもまだ無駄が多い。実験してみたところ、requestAnimationFrameを使うと少しだけマシになることがわかった。

結論から言うと、スクロールと画面の同期遅れを最小限にしたい場合はsetTimeoutではなくrequestAnimationを使ったほうがsetTimeout(fn, 0)より良くて、画面のチラツキが気にならないような場面ではsetTimeout(fn, 100)くらいを使うと良いと思う。

[Log] native: 484
[Log] throttled: 429
[Log] smartly throttled: 341

これは、下記のテストコードを適当なページで走らせて上下にスクロールさせた結果。

setInterval(function () {
  console.log("native: %d", nNative);
  console.log("throttled: %d", nThrottled);
  console.log("smartly throttled: %d", nSmartThrottled);
  
}, 1000);

var nNative = 0;

window.addEventListener('scroll', function () {
    nNative++;
}, false);

var tid;
var nThrottled = 0;
window.addEventListener('scroll', function (event) {
  clearTimeout(tid);
  tid = setTimeout(function () {
    nThrottled++;
  }, 0);
}, false);


var nSmartThrottled = 0;

function callback(e) {
  nSmartThrottled++;
}

var frameId;
function handleScroll(event) {
  cancelAnimationFrame(frameId);
  frameId = requestAnimationFrame(function () {
    callback(event);
  });
}


window.addEventListener('scroll', handleScroll, false);

forも明示的な加算も使わずに「1から100まで出力する」

1から100までforを使わずに、さらに明示的な加算も使わずに表示するもの、自分で思いついたバージョンを書いておく。非同期である。

var INTERVAL = 1000;
var d = Date.now();
var tid = setInterval(function () {
  var n = (Date.now() - d) / INTERVAL | 0;
  console.log(n);
  if (n == 100) clearInterval(tid);
}, INTERVAL);

自分の環境ではINTERVALは700まで安定的に動作した。テストを書いたので、自分の環境で正常に動作する範囲をテストしたい場合、下記のコードを使うと良い。node hundred.js>output.txtなどのようにしておいてcat output.txt|./test.zshとしてSuccessが表示されれば動いている。

#!/bin/zsh

I=1
while read -r LINE
do
  if [ $LINE -ne $I ]
  then
    echo "Failed: $LINE should be $I"
    exit 1
  fi
  I=$(($I + 1))
  if [ $LINE -eq "100" ]
  then
    break
  fi
done;

read -r LINE

if [ $LINE ]
then
  echo "Failed: Too many lines"
  exit 1
fi

echo "Success"

参考:

FacebookのReactで綺麗で高速なDOMのView操作

それほど新しい話題でもないが、FacebookReact | A JavaScript library for building user interfacesというDOMを抽象化したようなView操作のライブラリをリリースした。

Githubが出してるエディタのAtomが実験的にReactを採用したり、Instagramが採用していたり、エディタでReactのシンタックスがサポートされ始めたり、海外では実際に使われはじめていて、実際に使ってみたら思いのほか使いやすかったので、簡単に使い方を書いていこうと思う。

まず、ReactにはJSXという、htmlをJS内で書ける言語がある。オプショナルなものだが、使ったほうがコードが綺麗になるので、この記事では使っていく。下記コードはEdit fiddle - JSFiddleなどでコンパイルなしにそのままテストできるので、適当にコピーしながら確かめると理解が深まる。

/** @jsx React.DOM */

var div = <div>aaa</div>;

@jsxというノーテーションは、トランスパイラが

var div = React.DOM.div(null, 'aaa');

という風に変換するために必要になるimport文で、必ず必要になる魔法のようなもの。 ここで作成したdivは、実際のDOMとは違いバーチャルDOMと呼ばれるもので、

React.renderComponent(div, document.body);

のようにすると、document.bodyに、必要になった時のみdivが構築される。 必要になった時というのは、Reactは管理化にあるDOMの中身を全て把握していて

for (var i = 0; i < 100; i++) {
  React.renderComponent(div, document.body);
}

としても、実際のDOM構築やHTMLのDOM Treeの変更は1度しか行われないということである。 アプリの作成を行ってプロファイリングをすると、DOMの変更がボトルネックになっている場合が多いので、この方式は速度のでるアプリを開発するのに非常に有効である。

Reactでは、React.createClassを使って、カスタムエレメントのようなものを作成し、Viewをコンポネント化できる。

/** @jsx React.DOM */
var App = React.createClass({
    render: function() {
        return <div>aaa</div>;
    }
});

var app = <App />;
React.renderComponent(app, document.body);

このように、独自のカスタムエレメント風のものを生成することができる。基本的に要素はimmutableになっており、同様であるとみなされるものはReact内で再利用されたり、バーチャルDOMのdiffアルゴリズムに基づいて、自動的に再配置される。 よって、要素の変更時に全部一旦消して挿入し直したり、あまり考えずに自然な形で書いても、メモリを大量に消費する心配はだいぶ少なくなる。

カスタム要素には、属性として文字列やオブジェクトを渡すことができ、これはクラス内でthis.propsとしてアクセスできる。これはReactのページのサンプルからとったもの。

/** @jsx React.DOM */

var Hello = React.createClass({
    render: function() {
        return <div>Hello {this.props.name}</div>;
    }
});
 
React.renderComponent(<Hello name="World" />, document.body);

作成時に渡されるpropsは変更されないという想定がある。

ステート管理をしたい場合、別のオブジェクトであるthis.stateが専用に用意されており、getInitialStateメソッドで最初のthis.stateを生成することができ、その後はthis.setStateを利用してステート管理を行うことで、自動的にViewの更新が行われるようになる。ところで、JSXの属性は普通のHTMLの属性と違い、値は任意のJSオブジェクトを取ることができるので、

onClick={ this.onClick }

などで関数を渡してイベント登録を行うことになる。 ステート管理があるコードは

/** @jsx React.DOM */

var Hello = React.createClass({
    getInitialState: function () {
      return { name: "not clicked"  };
    },

    onClick: function () {
      this.setState( {name: "clicked" });
    },

    render: function() {
        return <div onClick={ this.onClick } >{this.state.name}</div>;
    }
});

React.renderComponent(<Hello />, document.body);

このような形になる。外部から後でView内のstateを変更したい場合は(MVCのように設計したい場合、modelからviewを変更できる必要がある)、 一般に、Modelを作成し、それを属性として渡す。ReactにはModelは付属しないので、Backboneや、好きなものを利用する。主動で作成するとこのような形になる。

/** @jsx React.DOM */

var Hello = React.createClass({
    componentWillMount: function () {
      // 本当は複数登録しても変にならないようにイベントとかを使う
      this.props.model.onTextUpdate = function () {
        // setStateを使ってもいいがオブジェクトが重複するのでmodelを使う時は主動でアップデートを指示するのがベスト
        this.forceUpdate();
      }.bind(this);
      
      
    },
    render: function() {
        return <div>{ this.props.model.getText() }</div>;
    }
});


var helloModel = {
  text_: "hi",
  onTextUpdate: function () {},
  setText: function (text) {
    this.text_ = text;
    this.onTextUpdate();
  },
  getText: function () {
    return this.text_;
  }
};

React.renderComponent(<Hello model={helloModel} />, document.body);


setTimeout(function () {
  helloModel.setText("dynamically updated outside the view!");
}, 1000);

基本的にはこれが全てで、componentDidMountメソッドの定義などView挿入時などのフックAPIReact | Working With the Browserにのっている。

一見独自のSyntaxがあったりして利用が難しいように見えるが、実はAPI自体は極めてシンプルで、このシンタックスを利用しなかったとしても、plainなJSからも普通に簡単に使える。競合であるWelcome - Polymerなどはpolyfillとしての性質や未来志向が強く、実際にサイトで使おうとするとライブラリが巨大かつReactに存在するようなバーチャルDOM管理などはあまりないので、今使うとしたらReactだと思う。

ここでカバーされていない部分はReact | Getting Startedを読むと良い。CSSのプロパティなどもHTML属性と同様に変更を保持してくれたり、もう少し機能がある。Polymerと違いscoped styleなどはないが、別に不便だとは思わない。CSSはclassNameを変更してcssファイルでやるのが管理する上で楽だと思うので、自分はあまり使っていない。

setTimeout, setIntervalを乗っ取って爆速にする

setTimeout() vs ハッカー、仁義なき戦いによると

function isNativeFunction(func, name)
{
    for (var o in func) {
        if (o === "toString") return false;
    }
    var match = func.toString().match(/^function (\S+)\(\)\s*{\s*\[native code\]\s*}$/);
    return (match && match[1] === name);
}

setInterval = function(){};
isNativeFunction(setInterval, 'setInterval'); // false

でsetIntervalが偽装されているか調べられると書いてあるが、そんなことはない。

自分が普段使っているブラウザはSafariなので他のブラウザではsetIntervalが上書きできないから下記コードは無効だが、setIntervalを書き換えたいと思う時など特定のときしかありえないので、Safariを使えばいいと思う

ほとんど全てのチェックを素通りするフェイクのsetIntervalの書き方をここに載せる(ネイティブかどうかを判別する方法を発見したら教えて欲しい)。ここではsetIntervalだけ上書きしているが、少しコードを追加すればsetTimeoutも上書きできる。

このコードを使うと、具体的には、setInterval(f, 1000);とすると、setInterval(f, 1)となり、スクリプト等でdocument-on時に走らせると全てが爆速になる。

(function () {

var nativeSetInterval = setInterval;
var nativeToString = Function.prototype.toString;

// ネイティブはfunction () {であるがsetInterval.length = 1で、Object.definePropertyで上書き不可能なので仮の引数を入れてごまかす
// この関数のtoString()については後から偽装するので大丈夫
var fakeSetInterval = function setInterval(_) {
  var fn = arguments[0];
  var ms = arguments[1];
  return nativeSetInterval.call(this, fn, ms / 1000);
}

// setInterval.toString()の結果を偽装 DontEnum等もネイティブ同様になるようにする
Object.defineProperty(Function.prototype, 'toString', {
  configurable: true,
  enumerable: false,
  value: function toString() {
    if (this == fakeSetInterval) {
      return 'function setInterval() {\n    [native code]\n}';
    }
    
    if (this == Function.prototype) {
      // Function.prototype.toString()対策
      return 'function () {\n    [native code]\n}';
    }
    
    // Function.prototype.toString.toString()対策
    if (this == Function.prototype.toString) {
      return 'function toString() {\n    [native code]\n}';
    }

    // 偽装する必要のないものは元のtoStringを呼ぶ
    return nativeToString.apply(this, arguments);
  },
  writable: true
});

// 改造済みのsetIntervalを注入

Object.defineProperty(Window.prototype, 'setInterval', {
  configurable: true,
  enumerable: true,
  value: fakeSetInterval,
  writable: true
});

})();

このコードを実行すると冒頭で引用したisNativeFunction(setInterval, 'setInterval') がtrueを返す。唯一考えられる対策はiframeなどの外部ページからFunction.prototype.toStringを取ってきてそれを使うことだが、

var toString = iframe.contentWindow.Function.prototype.toString;
toString.call(setInterval) == 'function setInterval() {\n  [native code]\n}';

このコードもiframe内で、ユーザスクリプトでdocument-start時にFunction.prototype.toStringを書き換えてしまえばいいので、意味がない。クライアント側で実行するコードは、全てユーザのコントロール下にあると思って書かないと、脆弱性の原因になるハッカーの勝利である。

引用元のサイトにあるように、ダウンロードサイトの待ち時間やゲームなどで、どうしても時間によるチェックをいれたい場合、サーバ側でタイマーを使って、待ち時間が経過するまではAPIがエラーを返すように作るしかないと思う。

はてなにログインしてると人のブログを見ただけでユーザー名がバレる

11 August 2014: はてなのサポートから連絡がきた。

いつもはてなをご利用いただきありがとうございます。

ご指摘いただきました件につきまして、ただいま対応を検討しております。
第三者に悪用される可能性もございますので、
もし、脆弱性を確認された場合には、先に弊社にご連絡いただき、
脆弱性が修正されるまで、ブログなどで詳細を公開されないようご協力いただけますと幸いです。

もしなにかご不明な点などございましたらご連絡ください。
どうぞよろしくお願いいたします。

しかしサポートにはこの記事のURLしか送っていないし、既に(一部ユーザによるDDoSも含めて)89656のスターがつくほど閲覧されているので、この記事を消してもしょうがない。よって、このまま放置する。読者は修正されるまで、決して悪用しないでほしい。

テスト RSSで見てる人は直接開いてください

はてブで指摘があったが、このページで使用している脆弱性CSRF+タイミングアタックなので、たまたまローディングが遅かったなどの諸事情で違う人のIDが出ることがある。修正することも可能だが、面倒臭いのでそのまま放置する。失敗したらリロードしてほしい。id:tpro id:kazoo_oo id:aoi-sora

これがCSRFに分類されるかどうかは微妙なところだが、本人以外にスターを押させたくない場合はスターボタンをiframe内に配置する必要がある。(当然だが、iframe内にはCSRF tokenを入れるべきである)

ユーザー名に大文字や数字が含まれていた場合に動かなかったのを修正

10 August 2014: はてなに報告した。急いでいたので日本語が少しおかしいがまあ言いたいことは伝わると思う。

f:id:javascripter:20140810200216p:plain

はてな☆ログ で既出だった模様

Project Parfaitで尋常じゃない速さでpsdファイルからウェブサイトを組み立てる

Project Parfaitとは、adobeが開発してるβ版の、ウェブサイト作成支援のサービス。これを使うと、.psdのデザインファイルからHTMLを書き起こすのが異常に高速になるので、オススメしておこうと思う。

具体的には、psdファイルをアップロードすると、psdファイルの要素がレイヤー別に選択できるようになる。わかりやすいように画像で実例を出すと(一部塗りつぶしてあるが)

f:id:javascripter:20140803173442p:plain

このようになる。

あとは、Copy Textをクリックするとクリップボードに文字が選択されるので、HTMLファイルを書きながら

<li><a href="#">{テキストをペーストする}</a></li>

のように書いて、その後、Copy CSSをクリックし

li {
  /*CSSをペーストする*/
}

のように、貼り付けて上記の画像の場合はfont-weightがおかしいのでboldに手動で直して、widthやheightも不要なので消す。box-shadowやtext-shadowなどもそのまま再現されるので、手動で色々と考えて調整する必要がほぼなくなる。

あとは、要素の左上の絶対座標のx, yと、要素のサイズが同時に表示されているので、隣接する要素をクリックしたりして、計算機を片手にmarginやpaddingを算出して、手動でfloatなどを使ったりしていろいろ配置をいじれば完成。psdファイルは解像度が高めに作ってある場合が多いので、px座標が大きめになりがちであるが、気にせずにそのまま計算してcssに入れるとよい。 少し邪道だが、最後に

body {
  zoom: 0.8;
}

などで調整すればいいのである。あるいはそれが認められない場合は一通り仕上げてから、ツールで全ての数値を0.8かけて置換する。

psd内の画像をクリックすると選択した画像がダウンロードリストに入るので、psdファイルから画像を切り出すのも、非常に簡単。

CSS Spriteなどにしたい場合は後でまとめる必要があるが、それも後でツールを使えば良い。一般的なサイトをhtmlに起こす場合はProject Parfaitはかなりオススメである。

最近、WebサイトやWebサービスの制作の仕事を引き受けはじめて、色々と試行錯誤しはじめたのだが、いろいろ手探りにやりながらも、4〜5時間で10ページくらい作れた。その他、Webデザイン系だと、MacについてるDigital Color Meterなども常に起動しておくと便利。小規模なサイトはjQuery+プラグイン+自分で少し書いて、アプリや大規模なものはフレームワーク(AngularJSやReactJS、Backbone.jsなど)を使ってがっつり仕上げるというスタイルが、作業スピードを爆速にするためにいいのではないかと思う。試行錯誤して効率を上げていきたい。

複数の独自ドメインをGithub Pagesで運用する方法&.tokyoドメインをとった

昨日、.tokyoドメインの一般登録が始まったので、ムームードメインでprogrammers.tokyoを取得した。 用途を考えずに取ったので、何か使い道を思いつくまでは仮のindex.htmlでも置いておこうと思い、でもそのためにわざわざ月額払うのももったいないので、Github Pagesを使うことにした。

Github Pagesは、username.github.ioというレポジトリを作るとhttp://username.github.ioにウェブページが公開される機能と、projectというプロジェクトにgh-pagesのブランチを作ってそこに置くとusername.github.io/projectというディレクトリで公開される2つの機能がある。

自分のユーザ名のGithub Pagesは自分のページ用にとっておきたいし、projectページはうまく独自ドメインに割り当てられないので、サイト用に、Githubのorganizationを作成した。

具体的には、Create an organizationで、organization nameをprogrammers-tokyo、billing emailを自分のメールアドレスにし、無料のOpen Sourceとして、Create organizationをクリックし、javascripterアカウントとは別にorganizationを作成した。

そして、アカウントをorganizationのものに切り替えて、programmers-tokyo.github.ioという名前のプロジェクトを作成し、index.htmlと、

programmers.tokyo

とだけ書いたCNAMEファイルをコミット。

あとは、dnsをいじくれば完成なのだが、いろいろ検索して知ったのは、ムームードメインホスティングしているDNSは自由度が低いということで、

今回は、GEHIRNというところのDNSを利用した。ドメイン2個までは無料で、機能的には十分である。

wwwをつけないドメインの設定方法はムームードメイン+GitHub Pagesで独自ドメインを使う方法を参考に。AレコードとCNAMEを設定して、それからApex Aliasを設定する。

そんな感じで、とりあえず動くようになった。何かに使っていきたい。

ボキャブラリを増やすのに効果的な英単語解剖プロセス

解剖というほど大それたものではないのだが、最近、新規に英単語を覚えてボキャブラリを増す努力を始めた。

一押しの本

「日本人だけが知らない難解英単語: 阿部, 山村 啓人」という本を使っているのだが、これが予想以上に覚えやすくて、このレベルの英単語を覚えるならこの本一択、というほどおすすめできる。 proneの単語のページを引用すると、

prone
(形)〜しがちな;傾向のある;うつぶせの
(英英) (adjective) to be likely to do something or to be in the habit of doing something
(adjective) lying down

類義語: disposed to, inclined to
反意語: disinclined, unwilling

成句 prone position: うつぶせ
prone to depression: 鬱になりやすい
error-prone: 間違いを起こしやすい

例文:This is a quake-prone region. ここは地震が起きやすい地域だ

という感じ。上記は左ページで、右ページは解説が載っていて、proneがラテン語で「前に傾いた」という意味で、「前のめりの=うつぶせ、傾向がある」で好ましくない場合に使う、ということが解説してある。

英単語を使う上で重要なのは、コロケーションやコンテキスト、すなわち、どの場面でどの単語の前後でその言葉が使えるのかを覚えることで、

例えば、proneを「しがちな」とだけ覚えていると、I am prone to travelling on weekends=週末はよく旅行する、と書いてしまうが、これは英語ではかなり不自然で、I am prone to illness.病気がちだ、のような、悪い傾向の場合のみ使えるということを覚えていないと、使うときにも困るし、読むときにもニュアンスを取り違える

error-proneという成句も、proneの否定的な意味合いを覚えてると、なぜerror-inclinedやinclined to errorよりしっくりくるのかはっきりするし、納得しながら覚えると逆にerror-prone -> 否定的な傾向、という連鎖で単語の意味を思い出せるようになる。そういった点で、単語を覚える時は単語に関連した知識を同時に入れておくことが好ましい。

同様に、disposed to, inclined to という類義語も見ると、inclinedが「傾いている」という意味で、proneと同じような発想から派生した言葉だと想像がつく。また、似た単語は同じ前置詞を使う場合が多いことも感じ取れる。傾向を表すものは、toが多いと覚えるといい。

さらに少し調べると、disposed toとinclined toはどの文でもほぼ入れ替え可な言葉だとわかる。tend to do, be inclined to, be prone toという言葉のどれかを思いついたときに、同時に類語を簡単に入れ替えて響きを試せるようになって、文を書くときのバリエーションが増す。

反義語も、disinclined, unwillingとあり、inclinedのdis=否定だから、そのままだな、というのがまず理解できる。それから、unwillingということはwillingのun=否定だから、これが「〜しがちな」の否定となるということは、逆にwillingはinclinedと同義なのか?という疑問がでてきて、inclinedで検索をすると、

(省略) or willing to do something: he was inclined to accept the offer 

とあり、inclinedにも、「傾向がある」ではない、willingと同様の「〜したい」という使い方があることがわかる。ここまでくると、proneという単語というよりかは、prone関連の単語知識全般を制覇したに近い。1ヶ月後文章にproneが出てきたとして、ほぼ確実に思い出せるだろう。

英英辞典の本当の使い方

英単語を覚える上での、英英の定義の使い方だが、まず、同義の別表現を覚える為に使う。 prone toが

to be likely to do something

と同義で、うつぶせの時は

lying down

に対応してるんだな、downを向いてるということか、といったことを念頭に入れておく。

一般に、英英辞典では、定義と説明の品詞がほぼ同等になるようにしてあり、「cell prone to becoming malignant=悪性になりやすい細胞」であれば、「cell to be likely to become〜」のように、そのまま入れ替えられるようになっているので、そういった入れ替えを行いなががら意味を確かめていくことができる。英語で入れ替えながら読むと、日本語の説明で読んだだけではわからないニュアンスが感じられたりするので、英英も活用すべきである。

自作のススメ

覚えたい単語が「日本人だけが知らない難解英単語」に載っていない場合も多いと思うが、その場合は英単語帳を自作し同様のレイアウトで覚えることをおすすめする。記憶保持と、active vocabulary(聞いて意味がわかるだけでなく、自分で使える語彙)化のしやすさを考えると、最初に少し辞書を引いたり、類語をThesaurus(類語辞典)で調べたり、ノートに書いたりする手間は、かけるに値する。

類語を同時に覚えると、全部調べ上げて覚えなきゃいけない単語の絶対数は少なくなるので、調べてノートに書くと言っても全体から見たら使う時間はむしろ減るだろう。

ノートは何でもいいが、小さめの持ち運びしやすいサイズで、気軽に書ける安いものが好ましい。

おまけ

類語、反義語を覚えることの重要性をさらに強調しておくために、この前調べた英単語について書いておく。

理不尽な
absurd, unreasonable

unreasonableはun-reason-ableで、unが否定で、ableが可能の意味なので、「reasonできない」というという意味だと想像できる。ここで、reason=理由、という定義を反射的に思い出してしまうが、reason-ableなので、reasonは動詞の意味、「推論する、判断する、論理的に考える」という意味で、un-reasonable、論理的に判断できない=理不尽だとわかる。

同じ構造の「理不尽な」の類義語が幾つかある。

irrational, illogical

など。これらも同様である。irrational, illogicalの最初のir, ilは否定の意味の接頭辞だが、これはin=否定 (in the houseなどのinとは別の語源)が、in-rationalだと言いづらいので消えた形。rが重なるのは、irationalだと、母音+子音+母音で、最初の母音がアルファベット読みになる法則、つまり「イラショナル」ではなく「アイラショナル」と読まれてしまうことを防ぐため。

sensitive, sensible

sensitiveとsensibleなど似た紛らわしい言葉の使い分けなどはテストなどにも出ると思うが、 sensitiveは「(感覚を)感じやすい、理解のある」や「影響を受けやすい」、sensibleは「分別がある」で、意味はだいぶ違う。

どちらも語源はsenseだが、sensitiveはsensi-t-ive、接尾辞のiveは「傾向がある」という意味なのでsenseしがちな=感じやすいで、一方sensibleはsens-i-ble、bleはableと同じで、可能という意味なので、senseできる、sense可能な=分別がある、という意味となる。

まとめ

このように、英単語というのは個別に覚えていくよりも、有機的に同じ単語や似た単語、反対の言葉などを同時に覚えていく方がはるかに自然な英語をかけるようになるし、記憶も定着しやすい。 毎日10単語覚えて一週間後に70単語覚えるより、一日で30単語覚えるほうが、実は他の覚えた単語と連想して覚えやすいので、記憶に定着しやすい。なかなか、単語を覚える時間を1時間単位でまとめてとることは難しいが、どうせやるならまとまった時間を作って、効率的にリテラシーをあげたい。