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

やーまんぶろぐ

気が向いた時にだけ書くブログ

Amazon Dash ButtonとMacを連携させてみた

Amazon Dash ButtonとMacを連携させてみました。

基本的には下の記事を参考にさせてもらってます。

qiita.com

Node.jsとnpmのアップデート

Node.jsとnpmが古い場合は事前にアップデートしておきましょう。
yamano3201.hatenablog.jp

$ node -v
v7.4.0

$ npm -v
4.0.5

Amazon Dash Button の購入

以前、購入したときの記事です。
yamano3201.hatenablog.jp

このとき購入した「食器用洗剤」の他に、「トイレットペーパー」と「ティッシュ箱」と今回の「Mac連携用」の計4つを購入しました。

Amazon Dash Button のセットアップ

1.Amazonアプリの左上ハンバーガーメニューより「アカウントサービス」

2.下部にあるDush端末の「新しい端末をセットアップ」

3.表示される通りDushボタンの電源を入れ、Wifiに接続

4.Wifiに接続完了すると商品を設定する画面が表示されるのでここでやめる。

ここは参考サイトそのままの手順になります。
ボタンを押したときのスマホへのPush通知をオフにするために、
Amazonアプリの「端末を管理」から、「このDash Buttonを無効にする」で無効にしておきます。

node-dash-buttonを使ってAmazon Dash ButtonのMACアドレスを取得

$ npm install node-dash-button
$ sudo node bin/findbutton
Watching for arp & udp requests on your local network, please try to press your dash now
Dash buttons should appear as manufactured by 'Amazon Technologies Inc.' 

# ここでAmazon Dash Button を押します

Possible dash hardware address detected: XX:XX:XX:XX:XX:XX Manufacturer: Amazon Technologies Inc. Protocol: arp

XX:XX:XX:XX:XX:XX の部分が取得できたMACアドレスになります。

node-applescript を使って Apple Scriptを動かす

ここではsayコマンドでMacに喋らせるScriptを用意しています。

$ npm install applescript
$ cat << EOF > script.applescript
tell application "System Events"
    say "test"
end tell
EOF

続いて、Amazon Dash Buttonが押されたタイミングで Apple Script を実行するJavaScriptを用意します。
XX:XX:XX:XX:XX:XX には事前に取得しておいたMACアドレスを入力します。

$ export MAC_ADDRESS=XX:XX:XX:XX:XX:XX
$ cat << EOF > app2.js
var applescript = require('applescript');
var dash_button = require('node-dash-button');
var fs = require('fs');
var dash = dash_button("${MAC_ADDRESS}", null, null, 'all'); 
dash.on("detected", function (){
    console.log("test");
fs.readFile('./script.applescript', 'utf8', function (err, script) {
        applescript.execString(script, function(err, rtn) {
            if (err) {
                // Error
                console.log(err);
            }
        });
    });
});
EOF

このJavaScriptも参考サイトそのままです。

動作確認

$ sudo node app.js

# ここでAmazon Dash Button を押します

test

ターミナルに「test」と出力され、Macからも声として出力されればOKです。

最後に

思ったより参考にしていた記事と変わらなくなってしまった。。
あとは好きなコマンドに変えれば面白いことできそうですね。アイデアは考え中です。

Node.jsとnpmのアップデート メモ

Node.jsとnpmのアップデートメモです。

$ sudo npm install -g n
$ sudo npm update -g npm

これで最新にアップデートできました。

$ node -v
v7.4.0

$ npm -v
4.0.5

LINEスタンプに「写真データ」が使えるようになりました。

けっこう前の話ですが、LINEスタンプに「写真データ」が使えるようになりました。

creator-mag.line.me

ということで、今回は人物の写真に挑戦してみました。

人物写真使用の注意点

人物写真を使用する場合は、同意書が必要になります。
同意書なしでリクエストすると同意書のテンプレートをもらえるので、まずはリクエストしてみましょう。

以下、注意点です。

  • 人物写真を使用する場合はスタンプに使用されている人数分の同意書が必要です。
  • ご本人(肖像が使用されている人)が満15歳以上の場合は、ご本人の署名が必要です。
  • ご本人が満15歳未満の場合は、ご本人と、その親権者など法定代理人の署名が必要です。
  • ご本人が年少者など署名できない場合には、ご本人の親権者による代筆と、その親権者など法定代理人の署名が必要です。

新作スタンプ

赤ちゃんスタンプを作成しました。スタンプに使用されている人物は1名なので、同意書を1枚作成してリクエストしました。
赤ちゃんは署名できないので、本人署名の代筆と法定代理人の署名が必要になります。
store.line.me

過去スタンプ

過去にも2つほどスタンプを作成しました。
yamano3201.hatenablog.jp
yamano3201.hatenablog.jp

最後に

親バカですが、赤ちゃんかわいいです。

Serverless Web Application Workshop をCLIでやってみた Lab 4: Product Update Blog

サーバーレスアーキテクチャ Advent Calendar 2016 の25日目の記事です。

「Serverless Web Application Workshop をCLIでやってみた Lab 3: Administrative Interface」 の続きになります。
yamano3201.hatenablog.jp

大枠はこちらを参考。
qiita.com

README記載のコンソール作業をCLIで置き換えて構築を確認していくというものです。
github.com

ワークショップは全部で4つあります。

  • Lab 1: Static Website Hosting
  • Lab 2: Beta Sign-up Mailing List
  • Lab 3: Administrative Interface
  • Lab 4: Product Update Blog

今回は最後のLab 4: Product Update Blog について書いていきます。

やること

管理者がアップデートできるブログ機能の構築。ブログ記事を保存するテーブルをDynamoDBで作成し、記事一覧を取得するLambdaと記事をポストをするLambdaとIAM roleを作成し、API Gateway(GET/POST resource)でLambda Proxy連携とCognito user pool認証を設定してウェブアプリから呼び出せるAPI endpointを作成してウェブアプリ側に埋め込む。ウェブアプリで管理者としてログイン後、記事のポストと最新記事一覧が表示される事を確認。

ブログ記事を保存するためのテーブルをAmazon DynamoDBで作成

$ export BLOG_TABLE=$(aws dynamodb create-table --table-name Wildrydes_Posts --attribute-definitions AttributeName=Blog,AttributeType=S AttributeName=Timestamp,AttributeType=N --key-schema AttributeName=Blog,KeyType=HASH AttributeName=Timestamp,KeyType=RANGE --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 | jq -r '.TableDescription.TableArn')

ブログ記事を保存するLambdaと、ブログ記事一覧を取得するLambdaを作成

  • ロジックはREADMEに書かれているコードをコピーします。
  • DynamoDBにブログ記事を保存するコードと、ブログ記事一覧を取得するコードになっています
  • コードはzip化して渡します。
$ cat << EOF > index.js
var aws = require('aws-sdk');
var dynamodb = new aws.DynamoDB({});

exports.handler = (event, context, callback) => {
 var body = JSON.parse(event.body);
 var params = {
   TableName: 'Wildrydes_Posts',
   Item: {
     Blog: { S: 'product-updates' },
     Timestamp: { N: body.Timestamp },
     Title: { S: body.Title },
     Body: { S: body.Body }
   }
 };

 dynamodb.putItem(params, (err, data) => {
   if (!err) {
      context.succeed({
       statusCode: '200',
       headers: { 'Access-Control-Allow-Origin': '*'},
       body: JSON.stringify({})
      });
   } else {
      context.fail(err);
   }
 });
};
EOF
$ zip -r create_post.zip index.js
$ export ACCOUNT=$(aws sts get-caller-identity | jq -r ".Account")
$ export CREATE_POST=$(aws lambda create-function --region us-east-1 --function-name CreatePost --role arn:aws:iam::${ACCOUNT}:role/LambdaDynamoDBRole --runtime nodejs4.3 --handler index.handler --zip-file fileb://create_post.zip | jq -r '.FunctionArn')
$ cat << EOF > index.js
var aws = require('aws-sdk');
var dynamodb = new aws.DynamoDB({});

exports.handler = (event, context, callback) => {
 var params = {
   TableName: 'Wildrydes_Posts',
   ScanIndexForward: false,
   KeyConditions: {
        Blog: {
            ComparisonOperator: 'EQ',
            AttributeValueList: [ { S: 'product-updates' } ],
        }
   }
 };

 dynamodb.query(params,(err, data) => {
   if (!err) {
     var posts = [];

     data.Items.forEach((item) => {
       posts.push({
         Timestamp: item.Timestamp.N,
         Title: item.Title.S,
         Body: item.Body.S
       })             
     });

     context.succeed({
       statusCode: '200',
       headers: { 'Access-Control-Allow-Origin': '*'},
       body: JSON.stringify({ Posts: posts })
     });
   } else {
     context.fail(err);
   }
 });  
};
EOF
$ zip -r get_all_posts.zip index.js
$ export GET_ALL_POSTS=$(aws lambda create-function --region us-east-1 --function-name GetAllPosts --role arn:aws:iam::${ACCOUNT}:role/LambdaDynamoDBRole --runtime nodejs4.3 --handler index.handler --zip-file fileb://get_all_posts.zip | jq -r '.FunctionArn')

Lambda連携とCognito user pool認証を設定したAPI Gateway作成

リソース作成

  • Wildrydes APIはすでに作成されているので、そこにpostsリソースを作成します。
$ export API=$(aws apigateway get-rest-apis | jq -r '.items | map(select(.name == "Wildrydes"))' | jq -r '.[].id') 
$ export ROOT_ID=$(aws apigateway get-resources --rest-api-id ${API} | jq -r '.items | map(select(.path == "\/"))' | jq -r '.[].id')
$ export RESOURCE=$(aws apigateway create-resource --rest-api-id ${API} --parent-id ${ROOT_ID} --path-part posts | jq -r '.id')

OPTIONSメソッド作成

  • CORSを有効化するためにemailsリソースにOPTIONSメソッドを作成します。
$ aws apigateway put-method --rest-api-id ${API} --resource-id ${RESOURCE} --http-method OPTIONS --authorization-type NONE --no-api-key-required --request-parameters '{}'
$ aws apigateway put-integration --rest-api-id ${API} --resource-id ${RESOURCE} --http-method OPTIONS --integration-http-method POST  --type MOCK --request-templates '{ "application/json": "{\"statusCode\": 200}" }' --passthrough-behavior WHEN_NO_MATCH
$ aws apigateway put-method-response --rest-api-id $API --resource-id $RESOURCE --http-method OPTIONS --status-code 200 --response-models '{"application/json": "Empty"}' --response-parameters "method.response.header.Access-Control-Allow-Headers=false,method.response.header.Access-Control-Allow-Methods=false,method.response.header.Access-Control-Allow-Origin=false"
$ aws apigateway put-integration-response --rest-api-id ${API} --resource-id ${RESOURCE} --http-method OPTIONS --status-code 200 --response-templates '{"application/json": ""}' --response-parameters '{"method.response.header.Access-Control-Allow-Headers": "'"'"'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"'"'" , "method.response.header.Access-Control-Allow-Methods": "'"'"'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"'"'", "method.response.header.Access-Control-Allow-Origin": "'"'"'*'"'"'"}'

POSTメソッド作成

  • postsリソースに対するPOSTメソッドを作成します。
  • 認証の設定でuser poolを設定したAuthorizerを設定します。
  • Lambda のCreatePost関数を POSTメソッドの送信先に設定します。
$ export AUTHORIZER=$(aws apigateway get-authorizers --rest-api-id ${API} | jq -r '.items | map(select(.name == "Wildrydes_Admin"))' | jq -r '.[].id')
$ aws apigateway put-method --rest-api-id ${API} --resource-id ${RESOURCE} --http-method POST --authorization-type COGNITO_USER_POOLS --authorizer-id ${AUTHORIZER} --no-api-key-required
$ aws apigateway put-integration --rest-api-id ${API} --resource-id ${RESOURCE} --http-method POST --integration-http-method POST --type AWS_PROXY --uri "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${CREATE_POST}/invocations" --content-handling CONVERT_TO_TEXT
$ aws apigateway put-integration-response --rest-api-id ${API} --resource-id ${RESOURCE} --http-method POST --status-code 200 --response-templates '{"application/json": ""}'
$ aws apigateway put-method-response --rest-api-id ${API} --resource-id ${RESOURCE} --http-method POST --status-code 200 --response-models '{"application/json": "Empty"}'
$ aws lambda add-permission --function-name CreatePost --statement-id prod --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn "arn:aws:execute-api:us-east-1:${ACCOUNT}:${API}/*/POST/posts"

GETメソッド作成

  • postsリソースに対するGETメソッドを作成します。
  • Lambda のGetAllPosts関数をGETメソッドの送信先に設定します。
  • prodステージにAPI を再デプロイします。
$ aws apigateway put-method --rest-api-id ${API} --resource-id ${RESOURCE} --http-method GET --authorization-type "NONE" --no-api-key-required
$ aws apigateway put-integration --rest-api-id ${API} --resource-id ${RESOURCE} --http-method GET --integration-http-method POST --type AWS_PROXY --uri "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${GET_ALL_POSTS}/invocations" --content-handling CONVERT_TO_TEXT
$ aws apigateway put-integration-response --rest-api-id ${API} --resource-id ${RESOURCE} --http-method GET --status-code 200 --response-templates '{"application/json": ""}'
$ aws apigateway put-method-response --rest-api-id ${API} --resource-id ${RESOURCE} --http-method GET --status-code 200 --response-models '{"application/json": "Empty"}'
$ aws lambda add-permission --function-name GetAllPosts --statement-id prod --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn "arn:aws:execute-api:us-east-1:${ACCOUNT}:${API}/*/GET/posts"
$ aws apigateway create-deployment --rest-api-id ${API} --stage-name prod

ワークショップ用に用意されたlab4のファイルをS3にsync

  • アプリコードは用意されたものをsyncします。
$ aws s3 sync lab4/ s3://${BUCKET_NAME}
$ open https://$(cat cloudfront.json | jq -r '.Distribution.DomainName')/admin

動作確認

  • ログインしてNew Blog Postに進みます。
  • TitleとBodyを記入してPOSTボタンをクリックします。
  • ブログページにリダイレクトされ、作成した投稿が表示されていることを確認します。

最後に

これで全4つのServerless Web Application Workshopが終わりになります。
コンソールから自動で作られてた設定を一つ一つCLIで確認できたので良い勉強になりました。
今回のように構築全てをCLIで行うのは現実的ではないので、中身を理解できたらCloudFormationなどの他の仕組みで構築するのが良いと思います。

Serverless Web Application Workshop をCLIでやってみた Lab 3: Administrative Interface

サーバーレスアーキテクチャ Advent Calendar 2016 の24日目の記事です。

「Serverless Web Application Workshop をCLIでやってみた Lab2: Beta Sign-up Mailing List」 の続きになります。
yamano3201.hatenablog.jp

大枠はこちらで紹介されています。
qiita.com

コンソールでの手順はREADMEに記載されています。
github.com

CLIに置き換えてみたものをメモしていきます。
作業はMacで、リージョンはバージニアを想定して書いてます。

ワークショップは全部で4つあります。

  • Lab 1: Static Website Hosting
  • Lab 2: Beta Sign-up Mailing List
  • Lab 3: Administrative Interface
  • Lab 4: Product Update Blog

今回はLab 3: Administrative Interfaceについて書いていきます。

やること

管理インターフェイスの作成。Cognito user poolを使って管理者を定義し、DynamoDBに記録されている登録ユーザ一覧を取得するLambdaとIAM roleを作成し、API Gateway(GET resource)でLambda Proxy連携とCognito user pool認証を設定してウェブアプリから呼び出せるAPI endpointを作成してウェブアプリ側に埋め込む。ウェブアプリで管理者としてログイン後、登録ユーザ一覧が表示される事を確認。

Cognito user poolを使って管理者を作成

  • まずはuser poolを作成します。
  • user poolに紐づく管理者を作成します。ユーザネームとパスワードで認証できます。
  • 後半でAPIGatewayのAuthorizerにuser poolを設定することで、ログインされたユーザのみAPIを呼び出せるように認可の設定をすることができます。
  • パスワードには大文字、数字、記号を入れて8文字以上の文字列を指定します。
$ export USER_POOL=$(aws cognito-idp create-user-pool --pool-name Wildrydes_Admin --admin-create-user-config AllowAdminCreateUserOnly=true | jq -r '.UserPool.Id')
$ export USER_POOL_CLIENT=$(aws cognito-idp create-user-pool-client --user-pool-id ${USER_POOL} --client-name web | jq -r '.UserPoolClient.ClientId')
$ aws cognito-idp admin-create-user --user-pool-id ${USER_POOL} --username yamano1023@gmail.com --temporary-password XXXXXX

LambdaとDynamoDBにアクセス可能なIAMロールの作成

  • LambdaとDynamoDBにアクセスできるIAMロールを作成しておきます。
  • ロールを作成してからポリシーをアタッチします。
$ export ASSUME_ROLE=assume_role.json
$ cat << EOF > ${ASSUME_ROLE}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
$ export LAMBDA_DYNAMODB_ROLE=$(aws iam create-role --role-name LambdaDynamoDBRole --assume-role-policy-document file://${ASSUME_ROLE} | jq -r  .'Role.Arn')
$ aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess --role-name LambdaDynamoDBRole
$ aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole --role-name LambdaDynamoDBRole

DynamoDBから登録ユーザ一覧を取得するLambdaを作成

  • ロジックはREADMEに書かれているコードをコピーします。DynamoDBから登録ユーザ一覧を取得するコードになっています。
  • コードはzip化して渡します。
$ cat << EOF > index.js
var aws = require('aws-sdk');
var dynamodb = new aws.DynamoDB({});

exports.handler = (event, context, callback) => {
 var params = {
   TableName: "Wildrydes_Emails"
 };

 dynamodb.scan(params, function(err, data) {
   if (!err) {
     var emails = [];
     data.Items.forEach((item) => emails.push(item.Email.S));

     context.succeed({
       statusCode: '200',
       headers: { 'Access-Control-Allow-Origin': '*'},
       body: JSON.stringify({ Emails: emails })
     });
   } else {
     context.fail(err);
   }
 });  
};
EOF

$ zip -r get_all_emails.zip index.js
$ export GET_ALL_EMAILS=$(aws lambda create-function --region us-east-1 --function-name GetAllEmails --role ${LAMBDA_DYNAMODB_ROLE} --runtime nodejs4.3 --handler index.handler --zip-file fileb://get_all_emails.zip | jq -r '.FunctionArn’)

Lambda連携とCognito user pool認証を設定したAPI Gateway作成

リソース作成

  • rest apiを作成します。
  • user poolを設定したAuthorizerを作成します。
  • emailsのリソースを作成します。emailsがそのままパスになります。
  • 今回のようにパスがルート直下の場合は、ルートIDを指定して作成します。
$ export API=$(aws apigateway create-rest-api --name Wildrydes | jq -r '.id')
$ export ACCOUNT=$(aws sts get-caller-identity | jq -r ".Account")
$ export AUTHORIZER=$(aws apigateway create-authorizer --rest-api-id ${API} --name Wildrydes_Admin --type COGNITO_USER_POOLS --identity-source 'method.request.header.Authorization' --provider-arns arn:aws:cognito-idp:us-east-1:${ACCOUNT}:userpool/${USER_POOL} | jq -r '.id')
$ export ROOT_ID=$(aws apigateway get-resources --rest-api-id ${API} | jq -r '.items | map(select(.path == "\/"))' | jq -r '.[].id')
$ export RESOURCE=$(aws apigateway create-resource --rest-api-id ${API} --parent-id ${ROOT_ID} --path-part emails | jq -r '.id')

OPTIONSメソッド作成

  • CORSを有効化するためにemailsリソースにOPTIONSメソッドを作成します。これを設定しないとブラウザからアクセスすることができないので注意が必要です。
  • メソッドリクエスト、統合リクエスト、統合レスポンス、メソッドレスポンスの4つを作成します。
    • リソースに対するメソッド (OPTIONS) を作成します。
    • MOCKタイプで統合リクエストを作成します。
    • メソッドレスポンスのレスポンスヘッダーにAccess-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Originを追加します。
    • 統合レスポンスでヘッダーのマッピングをします。
$ aws apigateway put-method --rest-api-id ${API} --resource-id ${RESOURCE} --http-method OPTIONS --authorization-type NONE --no-api-key-required --request-parameters '{}'
$ aws apigateway put-integration --rest-api-id ${API} --resource-id ${RESOURCE} --http-method OPTIONS --integration-http-method POST  --type MOCK --request-templates '{ "application/json": "{\"statusCode\": 200}" }' --passthrough-behavior WHEN_NO_MATCH
$ aws apigateway put-method-response --rest-api-id $API --resource-id $RESOURCE --http-method OPTIONS --status-code 200 --response-models '{"application/json": "Empty"}' --response-parameters "method.response.header.Access-Control-Allow-Headers=false,method.response.header.Access-Control-Allow-Methods=false,method.response.header.Access-Control-Allow-Origin=false"
$ aws apigateway put-integration-response --rest-api-id ${API} --resource-id ${RESOURCE} --http-method OPTIONS --status-code 200 --response-templates '{"application/json": ""}' --response-parameters '{"method.response.header.Access-Control-Allow-Headers": "'"'"'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"'"'" , "method.response.header.Access-Control-Allow-Methods": "'"'"'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"'"'", "method.response.header.Access-Control-Allow-Origin": "'"'"'*'"'"'"}'

GETメソッド作成

  • リソースに対するメソッド (GET) を作成します。
  • 認証の設定でuser poolを設定したAuthorizerを設定します。
  • Lambda 関数を GET メソッドの送信先に設定します。
  • prodステージにAPI をデプロイします。
  • API Gateway が Lambda 関数を呼び出すためのアクセス権限を付与します。ステージごとにアクセスを絞りたい場合は*をprodに変更します。
$ aws apigateway put-method --rest-api-id ${API} --resource-id ${RESOURCE} --http-method GET --authorization-type COGNITO_USER_POOLS --authorizer-id ${AUTHORIZER} --no-api-key-required
$ aws apigateway put-integration --rest-api-id ${API} --resource-id ${RESOURCE} --http-method GET --integration-http-method POST --type AWS_PROXY --uri "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${GET_ALL_EMAILS}/invocations" --content-handling CONVERT_TO_TEXT
$ aws apigateway put-integration-response --rest-api-id ${API} --resource-id ${RESOURCE} --http-method GET --status-code 200 --response-templates '{"application/json": ""}'
$ aws apigateway put-method-response --rest-api-id ${API} --resource-id ${RESOURCE} --http-method GET --status-code 200 --response-models '{"application/json": "Empty"}'
$ aws apigateway create-deployment --rest-api-id ${API} --stage-name prod
$ aws lambda add-permission --function-name GetAllEmails --statement-id prod --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn "arn:aws:execute-api:us-east-1:${ACCOUNT}:${API}/*/GET/emails"

ワークショップ用に用意されたlab3のファイルをS3にsync

  • アプリコードは用意されたものを使います。
  • userPoolIdとuserPoolClientId、apiUrlを今回のものに書き換えてからsyncします。
  • /adminにアクセスしてログインします。
  • Cognito user poolを使って作った管理者でログインして、「View Emails」からDynamoDBから登録ユーザ一覧を取得して表示します。
$ cp lab2/scripts/config.js lab3/scripts
$ sed -i -e "s/userPoolId: \'\'/userPoolId: \'${USER_POOL}'/" lab3/scripts/config.js
$ sed -i -e "s/userPoolClientId: \'\'/userPoolClientId: \'${USER_POOL_CLIENT}'/" lab3/scripts/config.js
$ sed -i -e "s/apiUrl: \'\'/apiUrl: \'https:\/\/${API}.execute-api.us-east-1.amazonaws.com\/prod\'/" lab3/scripts/config.js
$ aws s3 sync lab3/ s3://${BUCKET_NAME} 
$ open https://$(cat cloudfront.json | jq -r '.Distribution.DomainName')/admin

最後に

CORSエラーの解消にけっこう時間を消費してしまいました。。
けっきょくLambda 関数を呼び出すためのアクセス権限が抜けていたのが原因でした。Lambda側の設定だったので見逃していました。

最後の1つも頑張ります。

【ソフトインストール不要】WMVファイルをiOSで再生できる形式(movファイル)に変換する方法

WMVファイルをiOSで再生しようとしたのですが、そもそもダウンロードできませんでした。
わざわざ変換ソフトとかは入れたくないので試行錯誤していたら、簡単にiOSで再生できたのでメモしておきます。

やること

Google DriveにあるWMVファイルを選択して、CloudConvertで変換するだけです。

Google Driveでファイルを選択

Google Driveにログイン → ファイルを選択して右クリック「Open with」 → 「CloudConvert」 を選択します。
f:id:yamano3201:20161221135730p:plain

CloudConvertで変換

変換後のファイル形式を選択して、「anything」 → 「video」 → 「mov」 を選択します。
「Save file to my Google Drive」にチェックが入っていることを確認して「Start Conversion」ボタンを押すと変換後のファイルがGoogle Driveに保存されます。
f:id:yamano3201:20161221141117p:plain

最後に

調べないでも触ってたらわかるというのは地味に素晴らしいですね。

今回はiOSで再生するユースケースでCloudConvertについて書いてますが、たくさんのファイル形式に対応しているので様々な場面で活躍できるサービスだと思います。

ファイル形式がたくさんあるだけでなく、直接CloudConvertにファイルアップロードできたり、APIがあったり、Dropbox連携ができたりと細かいところが作り込まれてて使えそうなサービスですね。

ふるさと納税でベビー用品を申し込み

今年もふるさと納税の申し込みをしたいと思います。

実質2000円負担で各自治体からお礼の品がもらえるのでやらないと損ですね。

ふるさとチョイスを使えば、自分がどれくらい使えるのか管理しながら購入まで簡単に行うことができます。
www.furusato-tax.jp

今年は子供が生まれたので0歳から1歳くらいまでで使えそうなものを中心に申し込みたいと思います。

基本的には2016年分は12/31までに申し込みが必要なので、まだの方は急いで申し込んでみてはどうでしょうか。

セーフティグッズ

これは買おうと思っていたので嬉しかったですね。
部屋の中に階段があるので、赤ちゃんが動き出す前に準備しておこうと思います。

絵本

絵本も欲しかったので嬉しいですね。

ワンストップ特例制度

確定申告の不要な給与所得者はワンストップ特例制度を使うと手続きも簡単です。
www.furusato-tax.jp

必要な書類と合わせて、送られてくる書類に記入して送り返すだけなので迷うことも少ないと思います。

ただし年収2,000万円以上の所得者や医療費控除のために確定申告が必要な場合や、
1年間の寄附先が6自治体以上になる場合は確定申告で寄附金控除を行う必要があります。

我が家は今年出産があり医療費控除のために確定申告が必要になるので、ワンストップ特例制度は使えないみたいですね。残念。

最後に

とてもありがたいことに、今年は親戚一同のふるさと納税を娘のために使わせていただきました。
当たり前ですが、私一人ではこんなに選べない。。

既に持っているのでベビーベッドやベビーカーなどは選びませんでしたが、他にもたくさんあるので探してみてはどうでしょうか。