今の考え2
まだ20数年の短い人生の中でけれど今時点から振り返って僕の中の人生の転換点は大きく1つだけある。それは高卒で働いていた工場退職したタイミングだ。
工場と言うものははっきりってクソだ。いや、クソだったのは環境のせいではなくそれに何の疑問も抱くことなく従っていた自分なのかもしれない。
工場は製品を生産する場所なので会社の売り上げの中心となる主力製品が製造されている場合がある。
そのため工場内は社外秘とされブラインドは真っ黒で常に閉まりきっている。今が朝なのか昼なのか、それとも日が落ちてすぐにドルなのか、それを確認するには時計を見るしかない。
40歳の同僚は休憩時間を楽しそうに同僚と喋るが仕事中は目が虚ろになってほんとにつまらなそうに仕事していた。僕もこの人と同じ高卒採用だからこのまま働き続けるといずれこうなることが既にわかってしまっていたのである。
俺はこのままこの会社に勤め続けてこの人のようなつまらなそうに仕事をすることになってしまうのだろうか。そう考えると不安になって夜も寝れない時があった。
当時の僕は相談する相手もろくになくてネットで調べるしかなく、高卒紹介賃金と調べると大雪の数千10,000円少ないと言う事実がわかった。
やめよう、そう思った。退職する決断をして次の日に班長に相談して退職したいと願いでた。
大雪のために会社内でお世話になった人たちに仕事の合間を縫って会いに行って会話をすることにした。中にはお前みたいな馬鹿な人間が退職して何になるんだ。と言われた。精神的にきつかった時待っていると退職を1階して3ヶ月後に僕が会社を辞めた。
その後1年半勉強して大学に進学した。
今の考え
僕は今大阪行きのバスに乗っている。なぜ大阪行きのバスに乗っているかと言うと、ある人に会いたいからだ。
僕は今大学3年生で夏休みの中にいる。大学1年生2年生の2年間でウェブプログラミングを学んで、この夏は快適なクーラーの効いた部屋からウェブプログラミングでリモート作業して生活費を捻出しようとしていた。
生活費を捻出しようとしていた。
僕はただ遊びに大阪に来ているわけではない。僕はこの大学3年生夏休みの際人生最後のチャンスだと思っている。3年後、5年後振り返ってみたと昨日、今日と言う日が人生最大の転換点だった思いたい。
IELTS 受けた
前書き
IETLS 高得点 取得ノウハウ紹介ではないので悪しからず。
俺英語めっちゃできるやん!
9/7, 9/8 僕は IELTS を受験した。
1日目は writing, reading, listening
2日目は speaking
というスケジュールで行われる。
Writing を初日の 一番最初に持ってくるあたり、受験生のパフォーマンスに気を使ってくれてる運営の優しさを感じるね。
“Passport Please”
過去に受けた試験と比べて IELTS で特徴的な点は以下だ。
ここがすごいよ IELTS
- 受験証はパスポート
- 拘束時間は最長 5時間
- 筆記用具、パスポート以外は全て預ける。
- 時間の振り分けを運営が提示してくれる。
- 得点の MAX が 9.0
- アナウンスは全て英語。日本人部屋でもだ。
1. 受験証はパスポート
文字通りである。
パスポート忘れたら?大人は時に無慈悲になる。
2. 拘束時間は最長 5時間
初日に 3技能を いっぺんにやる。8:45 に会場に入って 12:45 までぶっ通しだ。
試験が始まる前に コーヒー牛乳 (350ml) を飲み干し見事に漏れそうになる。
ちょっと、もらしました。
オムツ履いてくことをおすすめする。真剣に。
3. 筆記用具、パスポート以外は全て預ける。
中に持ち込めるのは、 - 鉛筆 - ケースをとった 消しゴム - パスポート - パスポートコピー のみである。時計もダメだよ!
4. 時間の振り分けを運営が提示してくれる。
優しいね。 「You should take about 20 min in this section.」 みたいなことが問題文の上に書いてあります。さらに、その目安区分時間ごとに試験官がアナウンスもしてくれます。
ま、従う必要はないけどリズムつけるために その通りに時間振り分けるといいかもね。 僕は従ったよ。テンポよく解けたよ。
5. 得点の MAX が 9.0
4技能それぞれ 9.0 ポイント持ってて その平均でスコアが出る。
6. アナウンスは全て英語。日本人部屋でもだ。
「初めて IETLS 受けるんだ〜」というそこのあなた。気をつけてください。
「試験の間の10分間は休憩時間ではありません。」ということも英語でアナウンスされます。
うんちは朝のうちにすませておくんだな!キラッ!
過去に受けたことある
足りないものは英語力
スピーキングが超できなかった。なんども聞き返したし、質問の意図にあった回答もできなかった。 スコアは出てないけど 平均届いてたらいいとこだろう。
勉強方法は?
読む
Reading は 語彙・文法レベルが大学入学レベルならあとはやり方で解けます。 そのやり方は
- 「設問見る」
- 「設問に固有名詞あれば印をつける」
- 「スクリプトの固有名詞に印をつける」
- 「各設問 20以内に解く」
ちなみに、センター試験も同じ方法で解いた。
聴く
Netflix がいいんじゃないかな UK アクセントがあるので、UK のドラマとかいいんじゃないかな。 今なら Sharock Homes とかおすすめ〜。
書く
普段から思考していることをその場で発揮することだと思う。 その議題について、ソースの情報の正しさが不安でも書いちゃえばいいだろう。
話す
一番できなかった。
原因
思考を日本語でしていること。
英語に翻訳する時間がかかるんだよな。 あらかたの英語は、聞いて日本語に訳さず意味を取ることはできようになったんだけど。
- 「英語で聞く」
- 「英語の構文を頭に浮かべる」
- 「日本語に訳す」 (分かり難かったとこだけ)
- 「日本語で思考する」
- 「英語に訳す」
- 「英語で話す」
2-4 が時間かかるから間が空くから不自然だった。
対策
- 英語で思考する癖を作る。
日常生活において、思考するタイミングってどこだろうって考えたときにアウトプットする時なんだろうと思う。
アウトプットは - 人と会話する - 考えを書く
が最も多くて簡単なんだよな。
だから、上記の方法をもっと具体化させて
「人と会話する」は meetup アプリを使って 英語ネイティブと会話する。 「考えを書く」は Twitter ・ブログで 英語を使ってつぶやいたり、Stack Overflow で回答したりする。
の作戦でいこうと思う。
努力自慢
やってることリスト〜
- IELTS 過去問解く
- ゼミの教授(オーストラリア人)に試験官になってもらい Speaking 練習
- 英語ネイティブの人を口説く。
- Grammar in use <- これめっちゃいい。
- Netflix (英語字幕 -> 字幕なし)
- 同僚と話す (外国人扱いされるの嫌そうだからあまりしない)
- 仕事で使うドキュメントは全て英語のものを見る。
Score
まだ出てないよ (9/25に出る) まだ点数出てないのにノウハウ語ってます。
(9/23) 更新 Ave 6.0 でした。
L: 5.5, R: 6.5, W: 5.5, S: 6.0
ワロタ。
Javascript に再入門した
Javascript 再入門
ふと、MDNのチュートリアル記事眺めてたら知らないことばかりだったのでまとめてみようかと思いました。 最初の方は Javascript に関係ないことが続きます。
以下からは 自分が気になったMDN の文を意訳しながら記述しています。
Web を始めよう
大文字小文字、スペースの扱い
MDN のチュートリアル記事では、ファイル名とフォルダー名はすべてスペースを入れずロワーケースで書かれている。
理由は2つ:
- 多くのコンピュータ、特にウェブサーバーは文字の小文字・大文字に敏感だから。
MyImage.jpg
とmyimage.jpg
は別のものと解釈されるので 文字の大きさを統一した方がしょうもない問題を回避できる。 - スペースの扱い方はブラウザやウェブサーバー、プログラミング言語で違うから。例えばファイル名にスペースを使ったら、あるシステムは 一つのファイルを二つと解釈するかもしれないし、あるサーバーはそのスペースを
%20
(URI に使われるスペースとして使われる文字)と置き換えるかもしれない。これは、ファイルとのリンクができなくなる問題を引き起こしかねない。アンダースコア "_" よりもダッシュ "-" を使ってロワーケースで書いた方が良い。
Google Search エンジンは "-" を言葉の区切りとして扱うがアンダースコアはそう扱わない。それらの理由でファイル名にはロワーケースにスペースなしが望ましい。
Javascript
Javascript はページで何してるの?
参照:What is JavaScript doing on your page?/MDN
ブラウザでウェブページをロードしたとき何が起きているのか? そのストーリーを簡単に解説すると、ウェブページをブラウザでロードした場合、実行環境(ブラウザのタブ)内で(HTML, CSS, Javascript) が実行される。
MDN ではこれを原材料(コード)を受け取り製品(ウェブページ)を生産する工場としてたとえながら説明している。
by What is JavaScript doing on your page?
Javascript は、HTML と CSS とが集められウェブページ上で一体となった後、ブラウザのJavascript エンジンによって実行される。これにより、ページの構造とスタイルはJavascriptが実行される前にすでに準備が完了されている状態となる。
このプロセスは非常に良いものだ。なぜなら、Javascript の非常に一般的な使い方は、Document Object Model API (DOM) を介してHTMLとCSS を修正しユーザーインターフェイスを更新することだから。もし、Javascirpt が、HTMLとCSSが準備完了になる前に、ロードされ実行されようとされたらエラーが起こるだろう。
Browser security
ブラウザのタブは実行するコード用につきそれぞれ専用の区分けされたバケットを持つ。これを専門用語で "execution environments" という。これにより、ほとんどの場合それぞれのタブ上のコードは完全に分かれて実行される。これは、安全面で良い基準です。もしこれがなかったらハッカーが他のウェブサービスからユーザの情報を盗むためのコードを書き始めるでだろう。
Script loading strategies
参照: Script loading strategies/MDN
実行時にロードするスクリプトを得ることに関わる懸念点がいくつかある。典型的な問題の例は、ページ上のエレメントを操作するJavascript(正確には、Document Object Model)を使おうとしている場合に、その対象の HTML がロードされる前に そのJavascript がロード、パースされ実行できない状況になること、であろう。
上記のような問題には解決策があるが、テキスト内の Javascript と 外部 Javasciprt で違う。
まず、テキスト内のJavasciprt では、以下のようにする。
document.addEventListener("DOMContentLoaded", function() { ... });
これは、ブラウザのHTML の ボディが完全にロードされパースされることを意味する "DOMContentLoaded" イベントのリスナーであるイベントリスナーである。Javascript はイベントが発火されるまでこのブロック内で実行されないので、エラーが回避できる。
ちなみにテキスト内の Javasciprt とは HTML の script エレメントに直接書かれたコードのことである。
次に、外部Javascriptでは以下のように defer
アトリビュートを追加する。これはブラウザーに <script>
タグに到達してもHTMLのコンテントをダウンロードし続けるように教えるものである。
<script src="script.js" defer></script>
これにより、HTMLと Javascirpt が同時にロードされる。
旧来の解決方法では、<body>
タグと対応する </body>
タグのすぐ前に <script>
タグが置かれていた。<body>
タグ内の HTML エレメントが完全にロード、パースされてから<script>
エレメントをロードしようとしたものだ。この解決方法の問題点は スクリプトのロード、パースが、HTML DOM が完全にロードされるまでブロックされることだ。これは、膨大な Javascirpt が必要な巨大なウェブページにおいて、主要なパフォーマンス問題を引き起こし、ウェブサイトの速度を低下させてしまう。
async and defer
ブロックされたスクリプトの問題を緩和させることのできる二つの方法がある。
defer と async だ。
非同期スクリプトはページの描画を妨害することなくスクリプトをダウンロードしスクリプトがダウンロードし終わったら即座にそのスクリプトを実行する。スクリプトが特定の順序で実行されるの保証はなく、残りのページが表示されることを止めないことだけしか保証されない。async
を使う一番いいタイミングはページのスクリプトがお互いに独立していて、ページ上の他のスクリプトに依存していない時だろう。
例えば、次のようなスクリプトエレメントがあるとしよう。
<script async src="js/vendor/jquery.js"></script> <script async src="js/script2.js"></script> <script async src="js/script3.js"></script>
このスクリプトがロードされる順番に依存することはできない。jquery,js
はscript2.js
と script3.js
の前か後にロードされるかもしれない。この状態で、jquery
に依存したスクリプト内の関数はエラーを発生させる。なぜなら、jquery
はそのスクリプトが実行される時定義されていないからだ。
defer
はページ上に出現した順番でスクリプトを実行し、スクリプトとコンテントがダウンロードされたら即座にそれらを実行する。
<script defer src="js/vendor/jquery.js"></script> <script defer src="js/script2.js"></script> <script defer src="js/script3.js"></script>
defer
を持つ全てのスクリプトはページに表示される順にロードされるので、上記の例では jquery.js
が script2.js
と script3.js
の前にロードされることと、script2.js
は script3.js
の前にロードされることがが保証される。
まとめ
- パースを待つ必要がなく、依存がなく独立して実行できる場合に、
async
を使う。 - パースを待つ必要があり、他のスクリプトに依存している場合は、
defer
を使ってロードして<script>
エレメントをブラウザに実行してほしい順に並べる。
var と let の違い
参照: The difference between var and letEdit/mdn
var hosting
参照:var hosting var と let の違いを調べる前に変数宣言のメカニズムについて言及しておく。
変数宣言は他のコードが実行されるよりも前に行われるため、変数をコードのどこかに宣言することはそれを一番上に宣言するのと同じである。これは次のことを意味する:変数は宣言する前に現れて使用されるのである。この挙動を hosting
という。変数の宣言が関数やグローバルコードの一番上に移動させらるからである。
bla = 2; var bla; // ...is implicitly understood as: var bla; bla = 2;
このような理由で、変数は常にスコープ内の一番上(グローバルコードや関数の一番上)に宣言して、どの変数が関数のスコープ内(ローカル)かということとスコープチェインで解決されるかをはっきりさせておくことが推奨されている。
ここで、hosting は変数宣言には影響はあるが、値の初期化には影響しないことを指摘しておく。値は割り当て指示に到達した地点で実際に行われる。
function do_something() { console.log(bar); // undefined var bar = 111; console.log(bar); // 111 } // ...is implicitly understood as: function do_something() { var bar; console.log(bar); // undefined bar = 111; console.log(bar); // 111 }
let
も var
同様にhosting されるが、変数が評価されるまで初期化されない。初期化される前に変数にアクセスするとReferenceError
を起こす。これを Temporal Dead Zone という(以下ではTDZ)という。
function do_something() { console.log(bar); // undefined console.log(foo); // ReferenceError var bar = 1; let foo = 2; }
スコープルール
参照: Scoping rules
let
で宣言された変数は宣言されたブロックの中にスコープを持ち、そのスコープが包含する全ての子ブロックにも同じスコープに属する。次の例での、let
と var
の大きな違いは var
のスコープはそれを閉じた関数内のすべてにわたっているといことである。
function varTest() { var x = 1; if (true) { var x = 2; // same variable! console.log("First value in let",x); // 2 } console.log("Second value in let",x); // 2 } function letTest() { let x = 1; if (true) { let x = 2; // different variable console.log("First value in let:",x); // 2 } console.log("Seconde value in let:" ,x); // 1 } console.log(varTest()) console.log(letTest())
The temporal dead zone and typeof
参照: The temporal dead zone and typeof
単に宣言されていない変数と undefined
を値としてもつ変数と違って、TDZの変数の型をチェックするために typeof
の演算子を使うと、ReferenceError
が起こる。
// prints out 'undefined' console.log(typeof undeclaredVariable); // results in a 'ReferenceError' console.log(typeof i); let i = 10;
Redeclarations
同じ関数やブロック内のスコープ内で同じ変数を再び宣言すると、SyntaxError
が起こる。
if (x) { let foo; let foo; // SyntaxError thrown. }
switch 文でも起こる。
switch(x) { case 0: let foo; break; case 1: let foo; // SyntaxError for redeclaration. break; }
しかし、上記は case クロージャーのなかにブロックをネストさせて新しくスコープされたレキシカル環境を作れば回避できる。
let x = 1; switch(x) { case 0: { let foo; break; } case 1: { let foo; break; } }
Typescript: Interface について調べた
Interface
Typescript の理念は 値が持つ "形" の型チェックに焦点を当てています。このことは、"ダックタイピング" や "構造部分型" などと呼ばれる。Typescript のインターフェイスはその型への名前付けの役割を果たします。
最初の Interface
function printLabel(labeledObj: { label: string }) { console.log(labeledObj.label); } let myObj = {size: 10, label: "Size 10 Object"}; printLabel(myObj);
上の例でコンパイルすることができる。printaLabel
関数の引数の数より関数呼び出しの方が多く引数として渡しているのになぜコンパイルが通るのでしょうか。それは、コンパイラーは、呼び出し側が、少なくとも必須型として定義されている型 (上記の例でいう { label: string }
)を満たしているかどうかをチェックしているからです。
上記の 型 { label: string }
に名前を付けるなら以下の通りになります。
interface LabeledValue { label: string; } function printLabel(labeledObj: LabeledValue) { console.log(labeledObj.label); } let myObj = {size: 10, label: "Size 10 Object"}; printLabel(myObj);
Readonly properties
readonly 修飾子のついたメンバは後から変更できません。
interface Point { readonly x: number; readonly y: number; } let p1: Point = { x: 10, y: 20 }; p1.x = 5; // error!
ReadonlyArray<T>
は Array<T>
と同じ
let a: number[] = [1, 2, 3, 4]; let ro: ReadonlyArray<number> = a; ro[0] = 12; // error! ro.push(5); // error! ro.length = 100; // error! a = ro; // error!
普通の方に readonly
型の値を割り当てるには型アサーションを行います。
a = ro as number[];
readonly vs const
readonly
と const
の使い分けはプロパティが readonly
変数が const
。
過剰プロパティ型チェック
interface SquareConfig { color?: string; width?: number; } function createSquare(config: SquareConfig): { color: string; area: number } { let newSquare = {color: "white", area: 100}; if (config.color) { // Error: Property 'clor' does not exist on type 'SquareConfig' newSquare.color = config.color; } if (config.width) { newSquare.area = config.width * config.width; } return newSquare; } // error Argument of type '{ colour: string; width: number; }' is not assignable to parameter of type 'SquareConfig'. Object literal may only specify known properties, but 'colour' does not exist in type 'SquareConfig'. Did you mean to write 'color'? let mySquareA = createSquare({ colour: "red", width: 100 }) let square = { colour: "red", width: 100 } let mySquareB = createSquare(square);
上記の例では mySquareA
に割り当てようとしている関数の呼び出しの引数が 型のメンバ color
ではなく colour
になっている。Typescript はこれをバグとみなし エラーを出してくれます。よく見ると 「もしかしてこれと間違えてる?」といったサジェストまでしてくれます。優しい。
定義してある型メンバ以外の値をあらかじめ予測できる場合は以下のように書く。
interface SquareConfig { color?: string; width?: number; [propName: string]: any; }
ところが、以下ではそのタイポしたオブジェクトを一度変数に代入して、その後その変数の値を引数として関数を呼び出すとエラーとならず呼び出すことができてしまいます。 なぜなら squareOptions
過剰プロパティ型チェックされずにコンパイルを通ってしまうからです。
let squareOptions = { colour: "red", width: 100 }; let mySquare = createSquare(squareOptions);
値に要求されているプロパティが一つもない変数は割り当てることができない。
let squareOptions = { colour: "red" }; let mySquare = createSquare(squareOptions); // error!
Indexable Types
インデックス可能な型はオブジェクトを索引するときに使う型と、索引されたものに合致する戻り型を意味するインデックスシグネチャを持ちます。
interface StringArray { [index: number]: string; } let a: StringArray = ["hello","world"] console.log(a[1]) // => world
上記のStringArray
インターフェイスはインデックスシグネチャを持ちます。そのインデックスシグネチャは StringArray
が number
で索引された時は string
が買えることを意味します。
インデックスシグネチャは二つの型をサポートしています。string
と number
です。 両方の型のインデックスを使うことはできるのですが、一つ条件があります。"number
型のインデクッスからの戻り型は、string
型のインデックスからの戻り型の子の型でなければならない。" ということです。
なぜなら、number
でインデックスを作成する場合、JavaScriptは実際にはオブジェクトにインデックスを作成する前にそれを文字列に変換するためです。つまり、100
(number) は "100" (string) でインデックスを作成することと同じです。
文字列インデックスは 全てのプロパティにインデックスの戻り型に一致するように求めるので、辞書型のパターンを表現するのにぴったりです。
interface NumberDictionary { [index: string]: number; length: number; // ok, length is a number name: string; // error, 'name' のかたは インデックスの子の型ではありません。 }
インデックスに readonly
を付けることもできる。
interface ReadonlyStringArray { readonly [index: number]: string; } let myArray: ReadonlyStringArray = ["Alice", "Bob"]; myArray[2] = "Mallory"; // error!
Class interface
静的クラスとインスタンスクラスの違い
class interface には二つの面があります。静的側面の型と、インスタンス側面の型です。例えば、コンストラクタシグネチャを持つインターフェイスを作って、そのインターフェイスを以下の実装しようとしたらエラーが出ます。
interface ClockConstructor { new (hour: number, minute: number); } class Clock implements ClockConstructor { currentTime: Date; constructor(h: number, m: number) { } }
なぜなら、インターフェイスを実装する場合、クラスのインスタンスの側面だけしかチェックされないからです。上記のコンストラクタは静的な領域に止まっているので、このチェックには含まれないのです。
下のように クラスの静的な側面とインスタンスの側面を使い分ける必要があります。
interface ClockConstructor { new (hour: number, minute: number): ClockInterface; } interface ClockInterface { tick(): void; } function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface { return new ctor(hour, minute); } class DigitalClock implements ClockInterface { constructor(h: number, m: number) { } tick() { console.log("beep beep"); } } class AnalogClock implements ClockInterface { constructor(h: number, m: number) { } tick() { console.log("tick tock"); } } let digital = createClock(DigitalClock, 12, 17); let analog = createClock(AnalogClock, 7, 32);
また上記の例は以下のようにシンプルに書き直すこともできます。
interface ClockConstructor { new (hour: number, minute: number); } interface ClockInterface { tick(); } const Clock: ClockConstructor = class Clock implements ClockInterface { constructor(h: number, m: number) {} tick() { console.log("beep beep"); } }
Extending Interfaces
クラスと同様にインターフェイスはお互いに拡張することができます。これによりインターフェイスのメンバーを他にコピーすることが可能にまります。
interface Shape { color: string; } interface PenStroke { penWidth: number; } interface Square extends Shape, PenStroke { sideLength: number; } let square = <Square>{}; square.color = "blue"; square.sideLength = 10; square.penWidth = 5.0;
Interfaces extending classes
インターフェイスがクラスを継承する場合、クラスのメンバーは継承しますが実装は継承されません。それははまるでインターフェイスが実装を提供することなくクラスのメンバーを宣言するかのようです。インターフェイスは 親のクラスのprivate
や protected
なメンバーまで継承します。これは private
や protected
なメンバーを持つクラスを継承したインターフェイスを作成する場合、そのインターフェイス型はそのクラスかそのクラスの子のクラスからしか実装できなくなることを意味します。
これは巨大な継承ヒエラルキーがあるけど特定のプロパティを持つ子クラスのみを扱いたいときに便利です。その子クラスは 親クラスから継承する以外は関連している必要はありません。
class Control { private state: any; } interface SelectableControl extends Control { select(): void; } class Button extends Control implements SelectableControl { select() { } } class TextBox extends Control { select() { } } // Error: Property 'state' is missing in type 'Image'. class Image implements SelectableControl { private state: any; select() { } } class Location { }
上記の例では、SelectableControl
はControl
の private
な state
プロパティを含むすべてのメンバを包含しています。state
はprivate
なメンバなのでControl
の子孫しかSelectableControl
を実装することができません。なぜなら、Control
の子孫だけが 同じ宣言という共通点を持つprivate
な state
メンバを持っていることになるからです。これはprivate
なメンバが互換可能になるために必須です。
Control
クラス内では SelectableControl
から private
なメンバのstate
にアクセスすることができます。 SelectableControl
は 効果的にselect
メソッドを持つことを知っている Control
のようにふるまいます。Button
と TextBox
クラスは SelectableControl
の子クラス(Control
から継承し、select
メソッドを持っているため)だけれど、Image
クラスと Location
クラスはそうではありません。
Oauth 1.0 について。
なんで調べたのか
Twitter の APIいじってた時に訳が分からなくなったので。
Oauth 1.0
参照先:https://tools.ietf.org/html/rfc5849#section-3
概要
OAuth は クライアント(1) にリソースオーナー(2) の代理でサーバー(3) のリソースにアクセス権限を与える方法を提供している。また、ユーザー代理リダイレクションを使って、リソースオーナが証明書(4)を自分のリソースに第三者がアクセスできるプロセスも提供している。
例えば、webサービスを使っているユーザー(リソースオーナー)が印刷サービス(クライアント)に、写真共有サービス(サーバー)に保管されているそのユーザーのプライベートの写真へのアクセスを、印刷サービスにユーザー名やパスワードを教えることなく、認めることができる。証明書を教えない代わりに、ユーザーは印刷サービスが特定の代理証明書を発行することを承認する。
(1) Webサービスの管理人のこと
(2) エンドユーザー、つまりそのサービス利用者のこと
(3) twitter 等のこと
(4) ユーザ名やパスワード等
OAuth が生まれた経緯
以前のクライアント・サーバー間のモデルではクライアントは自分の証明書を使ってサーバーに保管されているクライアント自身のリソースにアクセスしていた。
しかし、分散型Web やクラウド計算機の使用する機会が増えるにつれて、第三者のアプリケーションはそれらに保管されているリソースにアクセスする必要が出てきた。
OAuth は上記のモデルに第三の役割、リソースオーナーを導入した。OAuth モデルではクライアント(リソースオーナーではなく、その代理の存在)はリソースオーナーによって管理されているがサーバーに保管されているリソースへのアクセスを要求する。それに加えて、OAuth によってサーバーはリソースオーナーの権限だけでなくリクエストを送ってきているクライアントの身元を確認する。
クライアントがリソースにアクセスするために、まずリソースオーナーから許可を得なければならない。この許可はトークンと共有された一致する秘密なもの二つの形式で表される。トークンの目的はリソースオーナーがクライアントに証明書を共有する必要をなくさせるためである。リソースオーナーの証明書と違ってトークンは限られた領域と有効時間内で発行され、無効になるときは独立してそれが行われる。
クライアントに特定の代理証明書を発行するには、二つの方法がある。一つが、エンドユーザーがサーバーに直接権限メソッドの使用をクライアントに認めるトークンを発行することを承認することで、エンドユーザー自身のリソースにクライアントがアクセスすることを承認する方法である。二つ目が、二つの証明書のセットを使う、承認されたHTTPリクエストを作る方法である。その二つの証明書セットのうちのもう1つは、その要求を代行するリソース所有者を識別する。
流れ
raspberry pi 3 に ubuntu を入れる。
参考:
Writing an SD Card Image Using Command Line Tools on OS X
RPi Easy SD Card Setup - eLinux.org
「Raspberry Pi 3」に「Ubuntu 16.04」を入れる(備忘録) - Qiita
MACでOSイメージを焼く - Qiita
OS イメージをダウンロード
元の ubuntu OS のバグを修正して個人で配布してくださっている聖人のおかげで作業が減った。ありがとうございます。
Raspberry Pi 3用Ubuntu Server 16.04.3 LTSイメージを更新 | 上田ブログ
これをローカルで解凍しておく。
SDカードのマウント場所を確認
$diskutil list /dev/disk0 (internal, physical): #: TYPE NAME SIZE IDENTIFIER 0: GUID_partition_scheme *121.3 GB disk0 1: EFI EFI 209.7 MB disk0s1 2: Apple_APFS Container disk1 121.1 GB disk0s2 /dev/disk1 (synthesized): #: TYPE NAME SIZE IDENTIFIER 0: APFS Container Scheme - +121.1 GB disk1 Physical Store disk0s2 1: APFS Volume Macintosh HD 114.2 GB disk1s1 2: APFS Volume Preboot 44.3 MB disk1s2 3: APFS Volume Recovery 517.0 MB disk1s3 4: APFS Volume VM 4.3 GB disk1s4 /dev/disk2 (external, physical): #: TYPE NAME SIZE IDENTIFIER 0: FDisk_partition_scheme *16.0 GB disk2 1: Windows_FAT_32 SYSTEM-BOOT 16.0 GB disk2s1
/dev/disk2
でマウントできることがわかった。
マウント and 転送
SD カードをアンマウントしておく。
$dsikutil umount "/Volumes/{SDカード名}
$sudo dd if=~/Downloads/ubuntu-16.04-preinstalled-server-armhf+raspi3-upgradable-20171223.img of=/dev/rdisk2
転送先 に r
をつけると通常より転送スピードが早くなる。
raw disk の略。
OS のイメージを焼いた後
約12時間後、イメージが焼き終わりラズパイに接続して起動するが、モニターにno signal
と出た。
その時の状況は、PWR LED と呼ばれる LED が常時点灯し、ACT LED と呼ばれる LED が不規則に点滅していた。
以下によると、ACT LED が不規則に点滅しているのは ラズパイが SD カードを読み取れている証拠だと言うことだった。OS 焼きは正常に終了していると考え、別の原因を探ると モニター出力が原因だった。
参考:STICKY: Is your Pi not booting? (The Boot Problems Sticky) - Raspberry Pi Forums
OS の ルートにある config.txt
に hdmi_force_hotplug=1
を付け足したら正常に起動した。
無線LAN接続
参考:wireless - Connect to WiFi network through Ubuntu terminal - Ask Ubuntu
$ iwconfig wlan0 essid WIFI_NETWORK_HERE key PASSWORD_HERE
root としてログインしないと実行できないので、root
でログインしようとするが、Authent Error
となる。なので、root
のパスワードを設定。
$ sudo passwd root $ su - # // login as root success!
参考:The 2 Best Ways to Become Root in Ubuntu - wikiHow