プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

マウス選び

半年ほど前だったかな?しばらくメインに使っていた ELECOM の マウス (M-XG2UB) が壊れました。

エレコム 有線マウス BlueLED 5ボタン Lサイズ ブラック M-XG2UBBK

エレコム 有線マウス BlueLED 5ボタン Lサイズ ブラック M-XG2UBBK

そんなに使い勝手も悪くなかったんですが、もっといいのを探してみよう!と思ったのが、運の尽き。

しばらく、マウスに悩まされることになってしまいました。 先日、知り合いからの紹介でやっと落ち着いたので、そこまでの顛末を自分のメモとしてまとめておきます。

ご注意

いろいろ書いていますが、あくまでも個人の感想です。特に、マウスのような人がダイレクトに操作するものの使い勝手の良し悪しは、その人の使い方とか好みに大きく影響されると思いますので、マウスそのものが悪いというよりは、私と相性が悪かったというふうに理解してください(なので、別の人の場合は全く当てはまらないことも多々あると思います)。

1台目

さて、マウスが壊れてしまっては、仕事にならないので、近所の電気屋に買いに走りました。 そこで、買ったのは、サンワサプライの エルゴブルーLEDマウス (MA-ERG7) というやつ。

サンワサプライ エルゴブルーLEDマウス MA-ERG7

サンワサプライ エルゴブルーLEDマウス MA-ERG7

手首に負担のかからないデザインだったかな?そんな感じのうたい文句に惹かれて決めました。昔、ワイヤレスマウスを使って、反応が悪いという苦い思い出があったので、今回も有線を選びました。

f:id:junichim:20171203230728j:plain

f:id:junichim:20171203230750j:plain

しかし、これが自分の使い方にあわないのなんの・・・

1日使っただけで、これは仕事にならん、となりました。 エルゴノミクスデザインって書いてあったの、期待してたんだけどなー。どうも自分には合いませんでした。

2台目

で、このままではらちが明かないので、数日後また近所の電気屋へ。 でも、地方都市の悲しさか、マウスの種類の少なさもありますが、マウスが売ってても、触って試せないんですよね。 なので、パッケージだけで判断しないといけないのが辛いところ。

あれこれ悩んだ末に選んだのが、 Buffalo の プレミアムフィット (BSMBW500L)というマウスでした。 有線でもよかったのですが、1台目を有線で買ったばかりというのと、まあ昔とは違うだろうとワイヤレスを試してみることにしました。

(上はMサイズ、実際買ったのはLサイズ)

手に取って試せなかったので、若干の不安が残りつつも、使い始めてみると、そんなに悪くない感じ。

f:id:junichim:20171203230817j:plain

これは行けるかな?と思いきや、サイドボタンが非常に押しづらい。 誤操作を防止するためのサイドボタン、ということのようですが、これが自分には合わなかったようです。 とはいえ、サイドボタンはそんなに頻繁に使うほうではないので、しばらく使ってみることにしました。

しばらく使ってみましたが、どうにも使いにくい。サイズをLサイズにしたこともあるようですが、自分の使い方だと、ボタンを軽く押すことができないようで、長時間仕事していると手が痛くなってきます。

困ったぞ、これは。

ちょっと考えてみる

マウス選びにこんなに悩むとは初めての経験でした。

PCを本格的に使い始めたのは、今や懐かしい、Windows95 の時代です。でも、キーボードもマウスもだいたい、会社で支給されたものやPCを買ったときの付属品でなんの過不足もなく使っていた派でした。なので、BTOとかでPC買うときも、だいたい一番安いマウスを選んでおいて問題ない、という感じでした。

まあ、手で使う道具は好みもあるから、世の中にはマウス選びで悩んでいる人も多くいることだろうと思って、調べてみると、

matome.naver.jp

のように、いろいろと見つかりました。

マウスの持ち方には大別して3種類あるそうです。

自分の場合は、この『つかみ持ち』に近い感じのようです。しかも、自分のマウスの使い方を観察していると、マウスの後ろ側(ボタンのない側)に手を置く感じで、ボタンも先端ではなく後ろ側に近い側で押す癖があるようです。 そう考えると2台目に試したマウスなどはマウスの先端を押すと快適にクリックできます(でも、自分のスタイルじゃないので、継続して使えないんですけどね)。

さて、使い方のスタイルが分かっても、じゃあ具体的にどの商品が良いんだ?ということはわからないままです。 ということで、使いにくいマウスを使いながら、以前使っていたやつを買いなおすか、また新しいのを試すか(でも地方なので試してから買えないので外したらどうしよう・・・)というのを日々感じながら、時間が経っていきました。

3台目

そんな日々だったのですが、先日名古屋であった FOSS4G というイベントに参加する機会がありました。

peatix.com

たまたま、早めに名古屋につくことができたので、これはチャンスとばかり、名古屋駅前のビックカメラへ。 マウス売り場を見て、愕然。お試しのできるマウスの数のなんと多いことか!

昔、関東に住んでいたころは何かあるとすぐ都内に出ていたのでこれが当たり前だったんだよなー、と過去を振り返りつつ、改めてこれが地方と都会の差か、と思い知らされつつ、お目当てのマウスを探します。

実は、この少し前に、私がマウス選びに難儀しているということを知った友人から、Logicool の M705 がおすすめだよ、ということを聞いていたので、それを試してみるのが第一の目的でした。

Logicool ロジクール ワイヤレスマラソンマウス M705t

Logicool ロジクール ワイヤレスマラソンマウス M705t

で、触った第一印象は、これいい感じ!というもの。何がって、ボタンを軽く押せる感じが気に入りました。 あれこれ迷ってる暇もなく、即決です。

家に帰ってきてから、早速使い始めたのですが、快適ですねー。サイドボタンも快適に押せます。 数日使ってますが、今のところ何の不満も出てきません。

このマウス買った話をしたら、別の友人もこれ使っていたそうで、ある意味定番の商品の一つだったようです(店員さんもそんなこと言ってました)。 なんにしても、これで、しばらくマウスに悩まされることもなくなりそうです。

マウス選びにはまらないようにご注意ください。

マッピングパーティを開催しました

先日(といっても一か月以上前になりますが)9/29(土)に『伊勢河崎でマッピングパーティ』と題して、三重県伊勢市の河崎地区を舞台にマッピングパーティを開催しました。 せっかく開催したイベントなので、当日を振り返りながら、あれこれとメモをまとめておきます。

connpass.com

オリエンテーション

当日は、ファシリテータとして @kudarisenmon さんをお迎えして、小学生を含む8名の方が参加しました。

ほとんどの方が初めて OpenStreetMap に触れるという事情もあり、最初にファシリテータの方から OpenStreetMap とは何かという説明からしていただきました。 続いて、マッピングパーティについてのお話や、各地の事例、イベント当日の流れなどの説明を頂きました。

f:id:junichim:20171029235045j:plain

フィールドワーク

オリエンテーションのあとは、実際に外に出て、フィールドワークです。実は、今回のイベントを企画するまではフィールドワークといっても漠然と単に歩くだけだと思ってましたが、結構準備することも多かったので、簡単にまとめておきます。

準備編

一応、フィールドワーク前に、事前に実際に歩いて、どのあたりをイベントで歩くと面白そうかな?という事前ロケをしています。これを元に、当日歩くルートを決めました。

実際に作成したルートは下記になります。

フルスクリーン表示

uMapというサービスを使ってます。

フィールドワークのやり方もいろいろあるようです。

  • 紙の地図を使って、自分たちで歩いて、気になるところをメモ
  • Mapillary などのアプリを使い記録

Mapillary はスマホを持って歩くと、一定秒数ごとに写真を撮ってくれます。それをあとからアップロードすると撮影時の位置情報を元に、地図と写真を紐づけてくれるようなサービスです。 例えば、今回の河崎付近だと、こんな感じで見ることができます。

今回は前者の紙でメモしながらのマッピングをメインにしました(当日は、 Mapillary に挑戦した方もいらっしゃいましたよ)。 紙の地図も参加者に渡す必要があるので、事前に印刷しておきます。OpenStreetMapだと印刷できるんですよ!印刷が! 今回は、FieldPaper を使って河崎近辺を印刷しました。

当日編

さて、準備の話はこれぐらいにして、実際のフィールドワークの際にメモする気になるところは人によってまちまちですが、例えば、

  • お店などの情報
  • 郵便ポスト
  • バス停
  • 石碑
  • 神社
  • 駐車場
  • 説明版
  • その他いろいろ

などなど、何でもOKです。ただ、個人の住居などは除いておきます。また、メモと一緒に、あとからマッピングする際の参考になるよう、写真も撮っていきます。

自分のメモした紙はこんな感じになってました。 f:id:junichim:20171107003202j:plain

他人が見たらわかんないですねw 自分も今見たらわかんないですwww

あれこれ見ながら歩いていると、予定の2時間があっという間に迫ってきました。 最後のほうは少し駆け足になってしまいましたが、なんとか調査を終えて、集合場所の会場に戻りました。

マッピング

さて、いよいよマッピングですが、その前に差し入れのお菓子とお茶を食べて飲みつつ一休憩です(差し入れありがとうございました!)。

参加者の方には事前に OpenStreetMapのユーザー登録を済ませておいてもらいましました。 PCを立ち上げて、ログインして、早速編集開始です。

マッピングでは、先ほどフィールドワークで調べたメモを元に、 OpenStreetMap に情報を入力していきます。 情報の入力、といってもピンとこないかもしれませんが、OpenStreetMap では地図上のすべてのモノが、個別の図形(四角形や多角形、線やそれらがつながったもの)として表現されています。 OpenStreetMap にログインして、編集モードに入ると、これらの図形を操作することができます。

f:id:junichim:20171107004526p:plain

こんな感じです。後ろの画像(航空写真)のうえに、白い線や、赤い半透明の四角形などがあると思いますが、これらが前述の図形になります。

マッピングでは、新たにこのような図形自体を登録したり、既存の図形にお店の名前や営業時間などの情報を追加したりしていきます。

具体的な入力方法については、@kudarisenmon さんや経験者の方から手ほどきを受けつつ、進めました。 もし、興味を持たれた方がいましたら、iDエディタ などを参考にトライしてみてください!

当日は実際にマッピングを行う時間が足りなくなったこともあり、それぞれが何点かマッピングするところまでで時間切れとなりました。

成果?

イベントだけの成果というわけではありませんが、後日、イベント前後のマップを比べると、

マッピングパーティ前 f:id:junichim:20171026153659p:plain

マッピングパーティ後 f:id:junichim:20171029234237p:plain

と一目でわかるように、ずいぶんと情報が充実しました。

伊勢だとメジャーな場所もまだまだ空白のままというところも多いので、この調子でどんどんと情報が充実していくといいですね。

さいごに

自分自身が今までマッピングパーティに参加したことがなかったので、イベントの主催をやりながら参加もするという立場でした。 経験がないということで、いろいろと不安もありましたが、いざ当日を迎えてやってみると、予想以上に楽しかったです。

イベントの相談・企画・広報・開催など、多くの方々にご協力頂き、ありがとうございました。

次は違う内容(違う場所を対象)にして、また開催したいと思います。

ところで、地方だと同じ活動をしている人たちがどれぐらいいるのか気になりませんか?ひょっとして自分だけだったら寂しいなー、とふと思うときがあります。 OpenStreetMap だと、自分と同じ地域て活動しているユーザーについて教えてくれるTwitterのbotがあるんですね!

twitter.com

これを知ってから、地方にもマッパーがいることがわかり、いろいろと心強いです。

なかなか万人受けしないかもしれませんが、少しでもマッピングパーティが広がるといいかなと思っています。

Cognito ユーザープールを単独で API GateWay と共に使う

前に書いた記事

Cognito ユーザープール使ってみました - プログラマーのメモ書き

では、Cognito ユーザープールを Cognito Identity Pool (Federated Identity) と一緒に使うようなことを書きました。

でも、よくよく考えてみると外部IDプロバイダで認証したIDを使う必要がないなら、Cognito ユーザープールのみを使って、AWSのサービスへは API Gateway 経由でアクセスするのが手っ取り早いのではないかと思い立ちました。

そこで、今回は、Cognito ユーザープールを単独で用いて、ユーザー認証後 API Gateway 経由で Lambda 関数を呼び出す方法を試してみました。 以下は、作業時のメモになります。

なお、Cognito ユーザープールの利用については前回の記事をベースにしているので、詳しくはそちらをご覧ください。

ユーザープールの作成~ログインまで

この部分は、前回の記事と同じなので、割愛します。 クライアント側のログイン処理とマイページの処理が少し変わるので、あとで説明したいと思います。

Lambda 関数の定義

ごく簡単な内容の Lambda関数を定義しておきます(Node.js で定義しています)。 処理内容は以下の通りです。

exports.handler = (event, context, callback) => {
    // TODO implement
    context.done(null, {message: "Hello API:" + event['email']});
};

event['email'] の部分ですが、次節で述べるように API Gateway で認証した情報を eventとして渡すことができ、それを出力しています。

API Gateway の定義

次に API Gateway を定義します。

  1. APIの作成を押します [f:id:junichim:20170924152442p:plain]
  2. API 名を適当につけます。 [f:id:junichim:20170924152600p:plain]
  3. 追加したAPIの『リソース』の『アクション』より『メソッドの作成』を選択し、GET を追加します。 [f:id:junichim:20170924152811p:plain]
  4. 『統合タイプ』でLambda関数を選択し、『Lambdaリージョン』で先ほどLamda関数を作成したリージョンを選択し、Lambda関数名も入力して、保存を押します。 [f:id:junichim:20170924153045p:plain]
  5. 『Lambda関数に権限を追加する』という確認ダイアログが出てくるので、OKを押します [f:id:junichim:20170924153142p:plain]
  6. 『アクション』より『CORSの有効化』を選択します
  7. 特に設定を変更する必要がなければデフォルト設定のまま『CORSを有効にして既存のCORSヘッダーを置換』ボタンを押します [f:id:junichim:20170924153427p:plain]
  8. 『アクション』より『APIのデプロイ』を選択して、この時点で一度デプロイしておきます。デプロイされるステージが未定義の場合は『新しいステージ』を選択し、ステージ名を適当に入れます(ここではprodとしました) [f:id:junichim:20170924153704p:plain] なお、 ステージエディターが立ち上がりますが、今回は特に設定を変更しません。

これで、 API Gateway が作成できました。

オーソライザー

次に、作成した API Gateway に対して、Cognito ユーザープールを使って、認可(認証に基づく認可)を得るために、オーソライザーを定義します。

  1. 作成したAPIを選択し、『オーソライザー』を選択します [f:id:junichim:20170924154227p:plain]
  2. 『新しいオーソライザーの作成』ボタンを押します
  3. 『名前』を適当に入力し、『タイプ』として『Cognito』を選択します [f:id:junichim:20170924154249p:plain]
  4. 『Cognitoユーザープール』として、作成済みのユーザープール名を入力します
  5. 『トークンのソース』として『Authorization』を入力します
  6. 『作成』をクリックします

これでオーソライザーが作成できました

メソッドの認可の設定

作成したオーソライザーを認可に使うため、メソッドの設定を変更します

  1. 『リソース』のGETメソッドを選択します [f:id:junichim:20170924154834p:plain]
  2. 『メソッドリクエスト』をクリックして、編集画面を開きます
  3. 『認証』(英文だと、Authorizationなので、本当は認可?)の編集アイコン(鉛筆のようなやつ)をクリックして、ドロップダウンリストより、作成したオーソライザーを選択します [f:id:junichim:20170924154857p:plain] なお、このとき、オーソライザーを作成済みにも関わらず、ドロップダウンリストに現れない場合は、ページをリロードすると表示されるようになりました(もっといい方法があれば教えてください)

本文マッピングテンプレート

最後に、Lambda関数を呼び出したユーザー(API Gatewayを呼び出したユーザー)の情報を伝えるための設定を行います

  1. 『リソース』でGETメソッドを選択します
  2. 『統合リクエスト』をクリックして編集状態にします [f:id:junichim:20170924200946p:plain]
  3. 『本文マッピングテンプレート』をクリックします [f:id:junichim:20170924201108p:plain]
  4. 『マッピングテンプレートの追加』をクリックして、Content-Typeとして application/json を入力します [f:id:junichim:20170924201226p:plain]
  5. パススルー動作の変更を行う旨の確認ダイアログが表示されるので、デフォルトの『はい、この統合を保護します』を選択します [f:id:junichim:20170924201345p:plain]
  6. テンプレートを定義します(内容は下記参照)
  7. 最後に『保存』ボタンを押せば、完了です

テンプレートの内容は、下記としました。

{
  "email": "$context.authorizer.claims.email",
  "sub" : "$context.authorizer.claims.sub"
}

テンプレートに指定できる項目については、

[http://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html:title]

などを参照してください。

なお、本文マッピングテンプレートの『リクエスト本文のパススルー』オプションに関するの詳しい説明については、下記記事がわかりやすかったです。 [http://dev.classmethod.jp/cloud/aws/api-gateway-mapping-template/:embed:cite]

クライアント側の処理

前回記事のクライアント側の処理と大きくは変わらないのですが、ログイン画面で承認された後の動作を若干変更し、マイページにAPI Gateway 呼び出し用のボタンと結果の表示を行い処理を追加します。

ログイン

今回は、 Cognito ユーザープール単独で用いる(Cognito Identity Pool を用いない)ので、ログイン後、Identity Pool と統合する処理が不要になります。 具体的には、

upsample.login = function() {
    var username = $('#inputUserName').val();
    var password = $('#inputPassword').val();
    if (!username | !password) { return false; }

    var authenticationData = {
        Username: username,
        Password: password
    };
    var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);

    var userData = {
        Username: username,
        Pool: upsample.UserPool
    };

    var message_text;
    var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
    cognitoUser.authenticateUser(authenticationDetails, {
        onSuccess: function(result) {
            console.log('access token + ' + result.getAccessToken().getJwtToken());

            $(location).attr('href', 'mypage.html');
        },

        onFailure: function(err) {
            alert(err);
        }
    });

}

となります。 また、htmlファイルにおいても、AWS SDK を読み込む必要がなくなっています。

マイページでのAPI Gateway の呼び出し

マイページのhtmlファイルで API Gateway を呼び出すためのボタンを追加しておきます。

ボタンが押された際に、API Gateway へアクセスして、その結果を表示します。

upsample.apiCalling = function() {

    var cognitoUser = upsample.UserPool.getCurrentUser();
    if (cognitoUser != null) {
        cognitoUser.getSession(function (err, sessionResult) {
            if (sessionResult) {
                var idToken = sessionResult.getIdToken().getJwtToken();

                $.ajax(
                    "https://API Gateway のURL",
                    {
                        type: 'GET',
                        contentType: 'application/json',
                        headers: {
                            Authorization: idToken
                        },
                        async: false,
                        cache: false
                    }
                )
                .done(function(data) {
                    $('#api_result').text('result: ' + JSON.stringify(data));
                })
                .fail(function() {
                    console.log("failed to call api");
                });
            }
        });
    }
}

呼び出し時は、 Authorization ヘッダーに Idトークンを指定すればOKです。 認証が切れた状態だと、ステータスコード 401 でレスポンスが返ってきます。

実験

では、実際にブラウザからアクセスしてみます。 ログイン画面を表示後、ログインするとマイページが表示されます。

f:id:junichim:20170924204848p:plain

ここで、『API実行』ボタンを押すと、 API Gateway 経由で Lambda が呼ばれ、ログイン時のユーザーのメールアドレスを含んだメッセージが返されます。

f:id:junichim:20170924204752p:plain

問題なく表示されていますね。

コンソールから試し

必要というわけでもないのですが、curlでも試してみます。

ログインを行っていない状態で

curl --include https://xxxx.execute-api.ap-northeast-1.amazonaws.com/ステージ名

とすると 401 が返ってきます。

次にブラウザでログイン後、ディベロッパーツールでIdトークンの値を取得して、curlで呼び出すと

curl --include https://xxxx.execute-api.ap-northeast-1.amazonaws.com/ステージ名 -H 'Authorization: Idトークンの値'

問題がなければ、

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 23
Connection: keep-alive
Date: Sat, 23 Sep 2017 14:04:50 GMT
x-amzn-RequestId: 29d9022d-a068-11e7-a3a1-ad50f52c7d3e
Access-Control-Allow-Origin: *
X-Amzn-Trace-Id: sampled=0;root=1-59c66a01-cdeca4ab25f31bc912c89815
X-Cache: Miss from cloudfront
Via: 1.1 e20489ede5d5a153bd489790cc8e71ab.cloudfront.net (CloudFront)
X-Amz-Cf-Id: awZjLU21X6F0SBrmnSQlezZPMap4Mxv2Arvoxg6TLYy5yLVFfggsbA==

{"message":"Hello API:test@example.com"}

のようなヘッダが返ってきます。 やはり、問題なさそうですね。

はまったところ

実は、最初、 API Gateway のドキュメント

Amazon Cognito ユーザープールを使用 - Amazon API Gateway

を参考にして、API Gateway のオーソライザーの設定でトークンのソースとして

method.request.header.Authorization

としていたのですが、このままでは 401 が返ってきてAPI Gateway にアクセスできません。

単に、

Authorization

のみでよかったのでした。 でも、これがわかるまで、半日ぐらいかかってしまったので、一応書いておきます。

参考

以下の記事を参考にさせていただきました。

Cognito User Poolsの機能と使い所 - たれぱんのびぼーろく

Cognito UserPoolを使ってAPIを保護しよう | HIGHWAY for AWS

API GatewayでCognito UserPools Authorizerを使う - Qiita

AWS Cognito の認証情報を API Gateway + Lambda で受け取りたい - Qiita

また、今回の一連のソースは Github にアップしてあるので、気になる方はご参考までどうぞ。

github.com