Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all 8818 articles
Browse latest View live

リングフィットアドベンチャーをガチるためにサーバレスアプリケーションを作る

$
0
0

TL;DR

リングフィットアドベンチャーの称号をコンプするための進捗管理を、以下の技術要素を詰め込んで自動で行えるようにしたお話です。

  • serverless framework
  • AWS Lambda
  • Amazon S3
  • Amazon DynamoDB
  • Amazon API Gateway
  • Google Cloud Vision
  • Twitter API
  • Googleスプレッドシート
  • Glide

ご注意

  • エモ多め、技術の詳細少なめ
  • 画像が多いです(ここを読んでる時点で手遅れだと思いますが)
  • 掲載しているコードは実運用しているものとは異なり、参考程度の内容に編集しています
  • 記事内のリングフィットアドベンチャーに関する画像は、任天堂公式より転載、またはゲーム画面のスクリーンショットを用いています

リングフィットアドベンチャー is 何

慢性的な運動不足に陥るか、筋肉だけは裏切らないと狂信しているかの二極化しがちなITエンジニアの方々はご存知だと思いますが、リングフィットアドベンチャーは任天堂が生み出したSwitch向けの家庭用フィットネスゲームです。

image.png

ゲームの雰囲気についてはガッキーの公式動画を見ていただければ伝わると思うのでここでは割愛しますが以下のようなゲームだと思ってください。

  • ゆるい運動を
  • 長期間に渡って
  • 手軽に楽しく行える

(※ただしゆるいかどうかは人と遊び方による)

スキルについて

リングフィットアドベンチャーでは、戦闘パートにてフィットネススキル(以下スキル)という、特定の運動を一定回数行うことで敵にダメージを与える(あるいは自身のダメージを回復する)ことができる、本ゲームのメインとなる要素が存在します。

image.png
(引用元)

スキルには、特定条件下のみで発動するもの(ラッシュスキル)などもありますが、本記事では便宜上、「戦闘中に使用でき、称号(後述)のコンプリートに必要な43種類」のことを「スキル」と呼びます

対象となる43種類のスキルが以下になります。

アームツイスト アゲサゲコンボ アシパカパカ ウシロプッシュ カタニプッシュ グルグルアーム サゲテプッシュ スクワット ステップアップ スワイショウ チョウツガイのポーズ トライセプス ニートゥーチェスト ねじり体側のポーズ ハサミレッグ バタバタレッグ バンザイコシフリ バンザイサイドベンド バンザイスクワット バンザイツイスト バンザイプッシュ バンザイモーニング ヒップリフト プランク ベントオーバー マウンテンクライマー マエニプッシュ モモアゲアゲ モモアゲコンボ モモデプッシュ リングアゲサゲ リングアロー レッグレイズ ロシアンツイスト ワイドスクワット 椅子のポーズ 英雄1のポーズ 英雄2のポーズ 英雄3のポーズ 舟のポーズ 折りたたむポーズ 扇のポーズ 立木のポーズ

皆さんのお気に入りのスキルも入っているでしょうか?ちなみに私のお気に入りはステップアップやロシアンツイスト、舟のポーズあたりです。

称号とは

本記事でメインとして取り上げる 称号ですが、これはトロフィー実績などと表記すると、他ハードのゲームをされる方にはピンと来ると思います。

リングフィットアドベンチャーにおける称号もそれらと同様で、「ゲーム内で何らかの基準を達成した場合に取得できるが、ゲーム本編には影響を与えない要素」のことです。

image.png

例えば上記画像では、折りたたむポーズというスキルを一定回数ゲーム中で実施すると、回数に応じて 折りたたむポーズに目覚めし者折りたたむポーズに愛されし者折りたたむポーズを極めしものといった称号が取得できます。2000回まで達すると、折りたたむポーズ関係の最後の称号が解禁できそうですが、まだそこまで達していないという状況です。

この称号は、それをプロフィール上で名乗れるというだけで、ゲームを有利にすすめるような要素は一切ありません。

こんなん、埋めたくならないわけがないですよね??埋めましょうよ。

称号コンプ上の問題点

※ リングフィットアドベンチャーの称号は全部で250種類ぐらいありますが、そのほとんどが 〇〇(スキル名)を行った回数が累計N回以上となったが解禁要件になるので、本記事ではそれについてのみ着目します。

それぞれのスキルを、あとどれぐらいやれば該当の称号が手に入るのか。それを確認するには以下のような手順を取る必要があります。

1. 称号メニューから、該当の称号の要件を確認する
image.png

ふむふむ、2000回が目標か…。今は何回目なんだろう image.png

2. プロフィールメニューから、該当のスキルの累計回数を確認する
スクリーンショット 2020-04-26 2.24.13.png

ほうほう、いまは820回ね。

3. 差分から残りの回数を算出して絶望する

あと1180回か image.png

以上の手順を、確認したいスキルの数だけ行わなければならず、スキルを累計N回使った / 称号取得まであとN回やるの全体進捗が把握しづらいという大きな問題があります。

しかし私達は筋肉を愛するものである前に、ITエンジニアだ。テックの力で解決しようじゃないか。

進捗をスプレッドーシートで管理する

「テックの力」とか言いながら、まずはGoogleスプレッドシートで進捗を管理するための基本となるシートを手作業で作成します。

image.png
(当時のは残ってないので、完成形を元にしたイメージ)

  • スキルの基本情報
  • 実施回数
  • 目標回数
  • 実施回数と目標回数から決定する進捗関係

以上の列を用意し、実施回数を自動で更新できるような仕組みを目指します。

リザルト画面をOCRする

リングフィットアドベンチャーでは、一日の活動を終了すると、本日の運動結果という形で、その日行ったスキル及びこれまでの累計回数が一覧で表示されます。

image.png

本記事では、この画面のスクリーンショットを撮影し、OCRにかけることで累計回数を抽出しようと試みます。

今回はGCPのCloud Vision APIを使ってみることにします。

image.png
(引用元)

Cloud Vision APIは、上記のように画像の中からテキスト情報とメタデータ取得できる上、その精度の高さと、無料枠でも充分収まるリーズナブルさを兼ね備えていたので採用しました。

では実際にCloud Vision APIに対して、リングフィットアドベンチャーのスクリーンショットを安直に投げてみましょう。

image.png

惜しい!!

テキスト自体は認識できていますが、その区切りがガバガバで、どのスキルが何回なのかの関連付けができそうにはありません。また、「本日の運動結果」や、画面を撮影するといった、本来の目的には不要なノイズまで混じってしまっています。

  • 必要な部分だけOCRさせるようにする
  • レイアウトの区切りがわかりやすいようにする

までは、こちら側でお膳立てしてからCloud Vision APIにお願いして上げる必要がありそうです。

では以下のように、スクリーンショットから不要な部分を削ぎ落とし、3分割して、それぞれをOCRにかけるのはどうでしょうか。
image.png

分割後のスクリーンショットを投げてみると...

image.png

素晴らしい!!

スキル名、回数(累計回数)の順に解析され、多少のノイズはアレど充分に活用できることがわかりました。

Switchからスクリーンショットをツイートする

さて、OCRからは一度離れて、まずSwitchからスクリーンショットを投稿し、それをAWS Lamdaで処理する下準備をしていきます。

Switchでスクリーンショットを手っ取り早く共有するには、TwitterやFacebookと言った、SNS連携を使うのが一番です。Switchで撮影したスクショをTwitterで共有すると、以下のようにハッシュタグ付きのツイートが投稿されます。

image.png

これをTwitter APIを用いて取得しましょう。ご丁寧にハッシュタグがついているので容易に絞り込めそうです。

constTwitter=require('twitter')asyncfunctionfetchImageUrls(){constclient=newTwitter({consumer_key:process.env.TWITTER_CONSUMER_KEY,consumer_secret:process.env.TWITTER_CONSUMER_SECRET,access_token_key:process.env.TWITTER_ACCESS_TOKEN,access_token_secret:process.env.TWITTER_ACCESS_SECRET})consttweets=awaitclient.get('statuses/user_timeline',{count:200})// 自身の直近のツイートのうち、対象となるハッシュタグが付いているものを絞り込み、// そこから添付画像のURLを抽出するreturntweets.filter((tweet)=>tweet.text.includes('#RingFitAdventure')).map((tweet)=>tweet.entities.media[0].media_url_https+'?format=jpg&name=large')}

上記コードでは、直近200件のツイートを対象としているため、取得したツイートが既に解析済みかどうかを把握する必要があります。コードは省略しますが、ここではDynamoDBを用いて、解析済みの画像URLにはチェックを入れ、初出の画像URLの場合は次の処理に進むという構成になっています。

スクリーンショット 2020-04-26 3.09.55.png

抽出された画像ファイルの3分割処理は、次のLambdaに委譲されます。

画像ファイルの分割処理

画像の3分割は、nodeを用いて、jimpという画像編集ライブラリを用いて、以下のように行いました。

imageCreator.js
constJimp=require('jimp')constAWS=require('aws-sdk')constS3=newAWS.S3()// 元のスクショから必要な部分だけ3分割するための座標情報// スクショが3カラム構成になっていることを前提とするconstWIDTH=321constHEIGHT=462constY=132constX1=150constX2=502constX3=857asyncfunctionuploadToS3(image,key){constimageBuffer=awaitimage.getBufferAsync(Jimp.MIME_JPEG)returnS3.putObject({ACL:"public-read",Body:imageBuffer,Bucket:"bucket-name",ContentType:"image/jpeg",Key:key}).promise()}module.exports.index=asyncevent=>{constimageUrl='hoge'constdirName='fuga'constorigin=awaitJimp.read(imageUrl)awaituploadToS3(origin.clone().crop(X1,Y,WIDTH,HEIGHT),`${dirName}/1.jpeg`)awaituploadToS3(origin.clone().crop(X2,Y,WIDTH,HEIGHT),`${dirName}/2.jpeg`)awaituploadToS3(origin.clone().crop(X3,Y,WIDTH,HEIGHT),`${dirName}/3.jpeg`)};

上記コードでは、3分割した画像それぞれをS3にアップロードして、このLambdaのお仕事は終了です。

image.png

OCRを実行する

S3にファイルがアップロードされたことをトリガに次のLambdaを実行します。このLambdaは、S3から受け取ったイベントに含まれている、分割後の画像をCloud Vision APIに投げ、その結果をさらに次のLambdaに委譲します。

constaxios=require('axios')module.exports.index=asyncevent=>{constTOKEN=process.env.TOKENconstENDPOINT=`https://vision.googleapis.com/v1/images:annotate?key=${TOKEN}`constIMAGE_URL=event.imageUrlconstimageResponse=awaitaxios.get(IMAGE_URL,{responseType:'arraybuffer'})constimageBase64=Buffer.from(imageResponse.data,'binary').toString('base64')constpostData={requests:[{image:{content:imageBase64},features:[{type:'DOCUMENT_TEXT_DETECTION',// これがOCRをやるぞっていう指令maxResults:1}]}]}constresponse=awaitaxios.post(ENDPOINT,postData).catch((e)=>{console.log(e)})// OCRのレスポンス内容見て成否を戻す

image.png
(正確にはCloud Vision APIのレスポンスをハンドリングして、エラー処理したり次のLambdaを呼んだりするLambdaが別にいるけど割愛)

OCR結果を整形して永続化する

Cloud Vision APIの精度が高いとはいえ、Switchのスクリーンショットの画質が低かったり、レイアウトがギリギリを攻めすぎてることもあって、ノイズが入ることが多々あります。

まずノイズを正規表現で殴ります。

text=text.split(/\n/)text=text.filter((line)=>line)text=text.map((line)=>{returnline.replace('','').replace('','').replace('','').replace('','').replace('バタバタレック','バタバタレッグ').replace('ラッシュバンザイコシフリー','ラッシュバンザイコシフリ').replace('ラッシュモモデプッシュ|','ラッシュモモデプッシュ').replace(/(\d+)(\D)(\d+)(\D)\)$/,'$1$2($3$4)')// 171回1990回) → 171回(1990回).replace(/(\d+)(\D)(\d+)(\D)$/,'$1$2($3$4)')// 1042m17253m → 1042m(17253m).replace(/(\D+)(\d+)(\D)(\d+)\D?/,'$1$2$3($4$3)')// 引っぱりバンザイサイドベンド1081秒117999) → 引っ張りバンザイサイドベンド1081秒(117999秒).replace(/^(\d{7,}).+$/,'0回(0回)')// 22139142650円) → 0回(0回) 不正データのため.replace(/^(\d+)(\D)\((\d+)(\D)$/,'$1$2($3$4)')// 602m(136893m → 602m(136893m).replace(/^(\d+)(\D)\/(\d+)(\D)\)$/,'$1$2($3$4)')// 1694m/19577m) → 1694m(19577m).replace(/^(\d+)(\D)\/(\d+)(\D)】$/,'$1$2($3$4)')// 1回(21回】→ 1回(21回)})

ノイズを除外すると、概ね スキル名\n回数(累計回数)\nの繰り返しパターンが出来上がっているので、これを良い感じにオブジェクトに変換します。
その辺りのコードは闇が深いので割愛しますが、最終的には以下のような、スキル別の累計回数と最終実行日だけが永続化されるように、DynamoDBを更新します。

"results":{"舟のポーズ":{"updatedAt":"2020-04-21T17:20:24.362Z","value":1722},"英雄1のポーズ":{"updatedAt":"2020-04-25T16:20:24.095Z","value":1357},"英雄2のポーズ":{"updatedAt":"2020-04-25T16:20:24.197Z","value":1213},"英雄3のポーズ":{"updatedAt":"2020-04-25T16:20:24.197Z","value":1555}}

updatedAtは本処理実行時点の時刻で、DynamoDBが持っている現在の記録を元に、OCR結果をマージした新しい記録で更新します。

constaws=require('aws-sdk')constdynamoClient=newaws.DynamoDB.DocumentClient({region:'ap-northeast-1'})// これまでの累計記録と、今回OCRされた結果をマージするfunctionmergeResults({currentResults,newResults}){constmergedResults={}Object.keys(currentResults).forEach((key)=>{// まれにここでもノイズが入るので、最新記録のほうが高い数値の場合のみ更新するif(newResults[key]&&newResults[key].value>=currentResults[key].value){mergedResults[key]=newResults[key]}})returnmergedResults}// 現在の記録をDynamoから取得asyncfunctionfetchCurrentResult({userName}){constparams={TableName:'rfa-logs',Key:{'hogehoge'}}constcurrentDoc=awaitdynamoClient.get(params).promise()if(currentDoc.hasOwnProperty('Item')){returncurrentDoc.Item.results}}// これまでの累計記録と、今回OCRされた結果をマージして更新するasyncfunctionupdateResult(newResults){constcurrentResults=awaitfetchCurrentResult()constmergedResults=mergeResults({currentResults,newResults})constnewDocawaitdynamoClient.update({TableName:'rfa-logs',Key:{'hogehoge'},UpdateExpression:'set results = :r',ExpressionAttributeValues:{':r':{...currentResults,...mergedResults}},ReturnValues:'UPDATED_NEW'}).promise()returnnewDoc}

ここまでで、常に最新の進捗がDynamoDBに反映される状態に!

image.png

進捗を取得できるAPIを用意する

データが出来上がっちまえばこっちのもんです。
API Gatewayと、DynamoDBを参照するだけのLambdaを用意して、最新のデータを取得するWebAPIを提供します。

constaws=require('aws-sdk')constdynamoClient=newaws.DynamoDB.DocumentClient({region:'ap-northeast-1'})constDYNAMO_TABLE_NAME='rfa-logs'asyncfunctionfetchCurrentResult(){constparams={TableName:DYNAMO_TABLE_NAME,Key:{'hogehoge'}}constcurrentDoc=awaitdynamoClient.get(params).promise()if(currentDoc.hasOwnProperty('Item')){returncurrentDoc.Item.results}}module.exports.index=async(event,context,callback)=>{constresults=awaitfetchCurrentResult()callback(null,{statusCode:200,body:JSON.stringify({results})})}

API Gatewayは新しい公開エンドポイントを生成し、上記のLambdaに接続することで、特定URLを叩くだけで以下のようなJSONを取得できるようになります。

"results":{"舟のポーズ":{"updatedAt":"2020-04-21T17:20:24.362Z","value":1722},"英雄1のポーズ":{"updatedAt":"2020-04-25T16:20:24.095Z","value":1357},"英雄2のポーズ":{"updatedAt":"2020-04-25T16:20:24.197Z","value":1213},"英雄3のポーズ":{"updatedAt":"2020-04-25T16:20:24.197Z","value":1555}}

image.png

スプレッドシートでAPIを叩いて更新する

さぁ、いよいよスプレッドシートに戻ってきました。
以下のスプレッドシートがあるとき、今度はGASの力で前述のAPIを叩いて、レスポンスの内容に応じてシートを更新します。

image.png

GASは非常に簡単にAPIを叩けます。レスポンスのJSON文字列をパースしてシートの更新に使いましょう。

functionfetchCurrentResults(){varurl='https://hogehogehoge.execute-api.ap-northeast-1.amazonaws.com/dev'varresponse=UrlFetchApp.fetch(url);varcontent=response.getContentText("UTF-8")returnJSON.parse(content).results;}
functionupdateResults(){varresults=fetchCurrentResults()// APIから最新の進捗を取得Object.keys(results).forEach(function(key){varname=key;vartotal=results[key].value;varupdatedAt=newDate(results[key].updatedAt);varrow=searchRow(name)// スキル名から、該当行を特定するif(row){sheet.getRange(row,COL_TOTAL).setValue(total);// 累計回数列を更新sheet.getRange(row,COL_UPDATED).setValue(updatedAt);// 最終実施日を更新}})}

上記のようなコードを実行すると、シュバババっとシートが自動で埋められていきます。実施回数カラムが埋まれば他のカラムも遷移的に決まっていくので、これで進捗が管理できるようになりました。

スクリーンショット 2020-04-26 4.13.17.png
(画像はイメージです)

さらに、Google Apps Script で毎日決まった時刻にスクリプトを実行するトリガー設定を参考に、このスクリプトを毎時実行することによって、こちらは何もしなくても(正確にはTwitterにスクショをアップロードするだけで) 進捗が管理できるようになります。

スクリーンショット 2020-04-26 4.19.49.png

Glideでスマホアプリ化

以上でスプレッドシート上でリングフィットアドベンチャーの進捗を自動管理できるようになりましたが、スプレッドシートはパソコンで開かないと使いづらいし、そもそも現状だと情報量が多くて視認性が少し悪い!!

ということで、本当に知りたい最低限の進捗のみを、スマホアプリで確認できるようにします。

といっても、整形されたスプレッドシートが用意されてる時点で、あとはGlideという、スプレッドシートを元にPWAなアプリを自動生成できるサービスを活用します。

これを用いることで、まるでネイティブアプリかのようにホーム画面にアイコンを配置し、ネイティブアプリ化のようなUI/UXで進捗を確認できるようになります。

image.png

まとめ

以上で全てのシステムが完成し、最終的には以下のような構成になりました。

技術的な好奇心も強かったため、必要以上に冗長な構成になってしまったようにも思えますが、AWS関係のリソースはserverless frameworkを使って構成管理したため、デプロイはもちろん、IAMの付与やAPIGatewayの設置なども非常に簡単に出来、管理も容易に行うことができました。

スクリーンショット 2020-04-26 4.24.22.png

ちなみに実運用しているスプレッドシートは特に意味もなく公開しています。見ての通り、現在(2020/04/26時点)でも、まだまだコンプが遠い状態なので毎日頑張ってます。

長々とお付き合いいただきありがとうございました。良いリングフィットアドベンチャーライフを!


Dockerでの環境構築(Rails)超入門

$
0
0

はじめに

Ruby on Rails初心者です。今回はDockerを使ったRailsの環境構築の初歩を勉強のために備忘録として残したいと思います。

前提

DockerでRailsの開発環境を行う
※あくまで開発環境を構築するためだけの超入門であるため、DBや細かい設定等は次回以降投稿する

手順

Dockerはインストールしていることが前提
1. Dockerfile, docker-compose.yamlの作成
2. Dockerのコンテナを起動
3. Railsの設定
4. 4. Node.jsの設定
5. Yarnのインストール

実践

  1. Dockerfile, docker-compose.yamlの作成

・ディレクトリを作成(今回はDocker/practice)

$  cd Desktop
$ mkdir docker
$ mkdir practice
$ cd practice

・Docker hubで「ruby」を検索し、バージョンを確認

・Dockerfile作成

FROM ruby:2.6.6-stretch

・docker-compose.yaml作成

version: '3'
services:
  app:
    build: .
    volumes:
      - ".:/app"
    ports:
      - "3000:3000"
    tty: true
  1. Dockerのコンテナを起動
$ docker-compose up

 下記が表示されればOK!

(省略)
Creating practice_app_1 ...  done
Attaching to practice_app_1
(省略)

・practice_app_1の中に入る

$ docker exec -it practice_app_1 /bin/bash

# Appがローカルになっているので
/# cd app/

3.Railsの設定

/# gem install rails

/# rails new

# ローカルに接続
/# rails s -b 0.0.0.0

4.Node.jsの設定

・3でローカルに接続したら下記のエラーが出た

# エラー「Please run rails webpacker:install」
/#  rails webpacker:install

# エラー 
Webpacker requires Node.js >= 6.14.4 and you are using 4.9.1
Please upgrade Node.js https://nodejs.org/en/download/

・そのためNode.jsをアップデートする

# Node.jsのバージョン管理ツールnvmをclone
$ git clone git://github.com/creationix/nvm.git ~/.nvm
$ echo . ~/.nvm/nvm.sh >> ~/.bashrc
$ . ~/.bashrc

# nvmバージョン確認
$ nvm --version
0.35.3


# 最新の安定版をインストール
$ nvm install stable

# バージョン確認
$ node -v
v14.0.0

# 再度試す
$ rails webpacker:install 
Yarn not installed. Please download and install Yarn from https://yarnpkg.com/lang/en/docs/install/

↑Yarnのインストールが必要とのこと、、

5.Yarnのインストール
・node.jsをインストールするとnpmが入っているはずなので以下のコマンドを実行する

# node.jsのバージョンを確認
node -v
# npmのバージョンを確認
npm -v


# npm 経由でyarnをインストール
npm install -g yarn
# yarnのバージョンを確認
yarn -v

/app# yarn install

/app# rails webpacker:install

# 成功
Webpacker successfully installed 🎉 🍰

# ローカルに接続
/app# rails s -b 0.0.0.0

# エラー
error Couldn't find an integrity file
error Found 1 errors.


========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================

↑言われた通りコマンドを実行

/app# yarn install --check-files

# 再度接続
/app# rails s -b 0.0.0.0

・下記の画面が出ればOK!

スクリーンショット 2020-04-25 12.37.24.png

Herokuを使ってみた

$
0
0

はじめに

適当にJSとかwebアプリケーションを勉強している学生が記録するために使っているので,あまり内容は期待しないでください。とりあえず今回はHTTPサーバをHerokuを使って公開してみます。

1.Herokuとは

webサービスを動かせるプラットフォームを提供してるサービスらしい。小規模なら無料で使えるとのこと。

2.Herokuのアカウント作成

とりあえずアカウント作成
https://jp.heroku.com/
でいろいろ個人情報を流出してきます。

ここで開発言語を選択するらしいですがまぁJS程度しかやってないのでNode.js一択ですね。

ドラえもんが引っかかってしまう私はロボットではありませんチャレンジをクリアしてメールアドレス認証。パスワード設定したら登録完了です。いやぁ非常にスムーズ,毎回どこかでつまづくんじゃないかと冷や冷やしながら登録してます。

3.Heroku CLIをインストール

順番がゴチャゴチャしてきましたがherokuコマンドを利用しなきゃと思ったらHeroku CLIが必要らしい。まぁあるあるというか常識なのだろう。今回はUbuntuにインストールしちゃうのでiTerm2で仮装環境を起動するよ。

起動したところで
1.Virtual Box(バーチャルボックス)
2.Vagrant(ベイグラント)
という2つのソフトウェアを使った仮装環境でUbuntuを使用します。
cd ~/vagrant/ubuntu64_18
vagrant up
vagrant ssh

Ubuntuがインストールされたディレクトリに移動。vagrant upは仮装的なPCにインストールされたUbuntuを起動するコマンドで,vagrant sshはVagrantの仮想マシンがセットされている状態でSSHに接続します。

仮装環境を起動して以下のコマンドを実行。

sudo snap install --classic heroku

sudoは管理者として実行するコマンド。
snap install --classicはsnapパッケージのコマンドで,snappyというUbuntu向けに開発されたパッケージ管理システムの一部らしい。Snapには、ソフトウェアを隔離してセキュリティを高めるサンドボックス機能があるが,この制限をかけると使い勝手が悪くなるパッケージがあるので、 そのリスクを承知してインストールをするために –classic オプションを追加してます。

まぁそんなこんなでHeroku CLIがインストールされましたね。

4.Heroku CLIからHerokuにログイン

というわけでHeroku CLI から Heroku にログイン。

heroku login -i

コンソールで以上を記入してログインします。

5.Herokuで実際にデプロイしてみる(失敗)

とりあえずコンソールで使用したいファイルのディレクトリに移動します。
cd node-js-http-3016
そして以下のコマンドでHeroku 上で動かすための設定ファイルを作成します。
echo "web: node index.js" > Procfile

echoは文字をそのまま出力するコマンド。ProcfileはHerokuがアプリを動作する時Herokuのプラットフォーム上にあるWebアプリがどのようなコマンドで実行されるのかを記述するファイルのこと。Webアプリを動かす指示書みたいなものらしい。いろいろ書き方があるみたいだけどとりあえず割愛。

はいここで問題発生

Herokuではサーバー上へソースコードを配置するためにGitを利用している!!!
そのため、Heroku での実行前にGitのリポジトリにコミットすることが必要!!!

......まぁやりますよ、知らなかった自分が悪い

いろいろ調べた結果gitとリポジトリを保存しているgithubを連携する必要があるらしい。今回はSSHを使うのでsshを追加した後,新しい公開鍵情報をコンソールに表示させ,それをコピー。githubの右上アイコンからsettingという項目を表示し,SSH and GPG keysを選択してnew ssh keyでssh keyを追加。この設定の時に先ほどの公開鍵情報が必要。
まぁそんなこんなで追加が無事終了し,これでGitHubとマシンがSSHを利用した暗号化通信ができるらしい。もうなんか細かいことはわからなくなってきた。

6.試しにGithubからクローンをしてみる

作ってきたリポジトリのclone or downloadの欄をクリックしSSHのリンクをコピー
コンソールに
git clone SSHのリンク

を記述。これでなんとかgithubからgitにクローンできた様子。さすがです
git pull origin gh-pages

を行ったところエラーなども表示せず,Already up-to-dateという感じでできてるっぽい。

今度こそ実際にデプロイ!!

heroku create

これでサーバを用意して
git push heroku master-2020:master

以上でデプロイを実行!!
remote: Verifying deploy.... done.

実行後にデプロイが完了したというお知らせ。まぁこれでなんとかデプロイできました。

実際のアプリケーションはというとなんか知らないけど問題がありそう。まぁそれについては今後考えます...とりあえずはお疲れ様でした

おまけ1 : iTerm2とは

Terminal.appより簡単に便利な機能が使えるという噂のアプリ。実際のところTerminal.appすらまともに扱ったことがないので便利かどうかは不明。

おまけ3 : Ubuntuとは

狭義ではカーネルに属すLinuxのOSとしての一つがUbuntu(Linuxディストリビュージョン)。PCとして使えたりする初心者におすすめしやすいものらしい(確証はないです)。

おまけ2 : SSHとは

よく高校で使われるスーパーなんちゃらじゃない。どうやらSSHは一種の通信プロトコルらしい。

Node.jsでお天気を取得してみよう

$
0
0

はじめに

OpenWeatherMap APIからお天気情報を取得しようという試みです。
色々な方が、さまざまな言語で同様の記事を上げています。
私は、勉強真っ最中のNode.jsでやってみようと思いました。
(Node.jsの導入はこちら)

環境

wslの環境です。

Editor: VSCode
Shell : bash version 4.4.20
Ubuntu: 18.04.4 LTS
node  : v10.14.2

1.APIの取得

OpenWeatherMapの公式サイトで無料アカウントを作成後、
表示されるAPIキーを控えておいてください。
APIキー取得後は少し時間をおいてか試したほうがいいと思います。
公式もそういってますし。

2.プロジェクトを作成

1.任意の位置(緯度経度)のお天気情報を取得

とりあえず福岡市にしてみました。

app.js
'use strict';consthttp=require('http');constMY_WEATHER_APIKEY={YOUR_API_KEY};constLAT=33.60639;//緯度constLON=130.41806;//経度constreq='http://api.openweathermap.org/data/2.5/weather?lat='+LAT+'&lon='+LON+'&appid='+MY_WEATHER_APIKEY;http.get(req,res=>{varbody='';res.setEncoding('utf8');res.on('data',(chunk)=>{body+=chunk;});res.on('end',()=>{res=JSON.parse(body);console.log(res);});}).on('error',e=>{console.error(e.message);});

{YOUR_API_KEY}に控えておいたAPIキーを入れてください。

実行結果

$ node scripts/app.js 
{ coord: { lon: 130.42, lat: 33.61 },
  weather:
   [{id: 803,
       main: 'Clouds',
       description: 'broken clouds',
       icon: '04n'}],
  base: 'stations',
  main:
   { temp: 286.85,
     feels_like: 284.37,
     temp_min: 285.93,
     temp_max: 287.15,
     pressure: 1018,
     humidity: 58 },
  visibility: 10000,
  wind: { speed: 2.1, deg: 300 },
  clouds: { all: 75 },
  dt: 1587901760,
  sys:
   {type: 1,
     id: 7998,
     country: 'JP',
     sunrise: 1587846896,
     sunset: 1587895019 },
  timezone: 32400,
  id: 1863967,
  name: 'Fukuoka',
  cod: 200 }

この結果をいろいろ触って特定の情報を抜き出せます。

weather:
[ { id: 803,
main: 'Clouds',
description: 'broken clouds',
icon: '04n' } ]

が欲しければ、console.log(res.weather);

main: 'Clouds'

が欲しければ、console.log(res.weather[0].main);
という風にすればいいですね。
おぉ、いま福岡の方は曇りなんですね。

2.モジュール化

うまくいったので、モジュール化しました。
のちのちモジュール化しておいたほうが使いまわしやすいと思います。

app.js
'use strict';constweather=require('./weatherFunc');constMY_WEATHER_APIKEY={YOUR_API_KEY};weather.clweather(MY_WEATHER_APIKEY);
weatherFunc.js
'use strict';consthttp=require('http');functionclweather(api){constLAT=33.60639;//緯度constLON=130.41806;//経度constreq='http://api.openweathermap.org/data/2.5/weather?lat='+LAT+'&lon='+LON+'&appid='+api;http.get(req,res=>{letbody='';res.setEncoding('utf8');res.on('data',(chunk)=>{body=body.concat(chunk);});res.on('end',()=>{res=JSON.parse(body);console.log(res);});}).on('error',e=>{console.error(e.message);});}module.exports={clweather}

さいごに

今後の展望としては、現在地の自動取得とか取り入れていけば、
経度、緯度指定にしていることが活きてきて、
もう少し実用的になると思います。

拙い文章でしたしょうが、お付き合いありがとうございました。

さよなら:wave:

関連記事

参考

Herokuへのアップロードでつまづいた時の対処法 Node.js + MongoDB

$
0
0

自分の経験をここに記述します。

【経緯】先日、EJS, CSS, JavaScript, MongoDB, Nodeを使って作成したWebsiteをHerokuにアップロードしようと試みた時、正常にアップロードできず、丸2日間の時間を犠牲にした上でようやく問題解決までに至りました。ここで記載することがいつかこれを見た困っている人の手助けになればと思います。

【方法】ステップに分けて説明していきます。MongoDBを使用している場合には、別の記事でその追加で必要な方法を記述します。

1:Command Line(Hyper Terminal)がアップロードしようとしているファイルのパスを正しく選択しているか確認する。

2:Command Line(Hyper Terminal)からHerokuへとログインする。コマンド:$heroku login 

3:GitをInitializeし、add、commitする。コマンド:$git init → コマンド:$git add . → コマンド:$git commit -m "sample message"

4:HerokuでURLを作成する。 コマンド(urlが何でもいい場合):$heroku create  コマンド(自分のオリジナルを作成する場合):$heroku create ここに半角英数でタイプする。但し他ユーザーがすでに使用している場合は、そのurlは使えない。

5:Gitにpushをする。 コマンド:$git push heroku master

6:現状では正しくHerokuへとアップロードはされません。ほぼ100%エラーの表示がでます。これからそのエラーを直していきましょう。

7:自分のファイル内にprocfileが作成しているか、確認する。procfileが何か分からない場合はこの記事を参考にしてみてください。https://creepfablic.site/2019/06/15/heroku-procfile-matome/

8:procfileの中身が正しく記載されているか確認する。私の場合、web: node app.js、app.jsはあくまでも私がよく使うファイル名のためindex.jsや他のファイル名の場合はそちらに書き換えてください。

9:app.listen(process.env.PORT || 3000, function( ){

console.log("The server 3000 is now up and runnning")

});

私の場合、app.jsの中にローカルサーバーを立ち上げるためのapp.listenを入力しているので、そこにprocess.env.PORTと追加されているか確認する。

10:再度、Command Line(Hyper Terminal)の画面に戻る。そして自分のファイルへのパスが選択されている状態で、次のコマンドを入力する。コマンド:$heroku buildpacks

そのコマンドを入力した時にheroku/nodejsと表示されていれば特に何もしなくて良い。しかし、何も表示されない、もしくは別のものが表示された場合には次のコマンドを入力する。コマンド:$heroku buildpacks:set heroku/nodejs

11:もう一度、コマンド:$heroku buildpacksを入力して正しくheroku/nodejsと表示されるか確認する。

12:自分のパソコンにインストールされているNodeとNpmが最新版であるか確認する。どこでインストールするか分からない場合は👉https://nodejs.org/ja/で推奨版をダウンロードする。左のバージョン。

コマンド:$node --version  

コマンド: $npm --version

13:自分のファイルの中にpackage-lock.jsonというファイルが作られているか確認する。作成されていない場合は次のコマンドを入力する。コマンド:$npm install

14:package-lock.jsonの中に以下のプログラムが記載されているか確認する。されていない場合は順番はどこでもいいのでファイル内に付け加える。NodeとNpmのバージョンは2020/04時点のものなので、最新かどうかはhttps://nodejs.org/ja/で確認する。右側の最新版のバージョンをnodeに記述する。最後のxの部分は変更しなくて大丈夫。scriptsのapp.jsはあくまでも私が使用しているファイル名なので、これは各個人のファイル名に直す。

"engines": {
"node": "^14.0.x",
"npm": "6.14.x"
}

"scripts": {
"start": "node app.js"
}

15:.gitignoreファイルが作成しているか、確認する。まず次のコマンドを入力する。

コマンド:$git ls-files | grep node_modules

もしも、上記のコマンドを入力した際にリストがズラーーーっと表示された場合は以下のコマンドを順々に入力する。表示されなかった場合は多分.gitignoreが作成されていると思う。

コマンド:$echo "node_modules" >> .gitignore
コマンド:$git rm -r --cached node_modules
コマンド:$git commit -am 'untracked node_modules'

16:再度、.gitignoreが作成されているか、コマンド:$git ls-files | grep node_modules、を入力して確認する。自分のファイル内で.gitignoreというファイルが作成されているのを確認できればおっけい。

17:.gitignoreの中にnode_modulesと記載されていると思うので、その下に以下のコマンドを入力する。

/lib  ←この4文字を記述する。

18:これであとは再度Herokuへのアップロードを試みる。以下の順でCommand Line(Hyper Terminal)内でコマンドを実行する。

コマンド:$heroku login

コマンド:$git init

コマンド:$git add .

コマンド:$git commit -m "whatever you want to type"

コマンド:$git push heroku master

これで正しくHerokuへとアップロードが完了するはずです。

19:最後に、冒頭にも書きましたが、MongoDBを使用している場合はもうワンステップ必要な作業がありますので次回のストーリーを参考にしてみてください。

Puppeteer on Lambda (Node.js 12.x) で日本語ページのキャプチャを取る方法 簡単

$
0
0

やりたいこと

Lambda上でPuppeteerを動かしてキャプチャを取るとき、日本語フォントを正しく表示させる。
(デフォルトではLambdaに日本語フォントが入っていないため、何もしないと日本語がすべて豆腐になってしまうのだ。)

環境

  • AWS Lambda
    • Node.js 12.x
  • ローカル
    • Windows10
    • Node.js v12.16.2
    • npm 6.14.4

やり方(ざっくり)

  • Lambda Layerに日本語フォントをzip化してアップロードする。
  • Lambda関数にそのLayerを追加する。
  • Lambda関数内でLayerのフォントファイルを参照できるようにindex.jsでprocess.env['HOME'] = "/opt";を定義する。

やり方(詳細)

ローカルのディレクトリ構成
puppeteer_sample
├─ modules # Layerに登録するnpmモジュール群│   ├─ node_modules
│   └─ package-lock.json
├─ .fonts  # Layerに登録する日本語フォント置き場│   ├─ ipag.ttf
│   ├─ ipagp.ttf
│   ├─ NotoSansCJKjp-Bold.otf
│   └─ NotoSansCJKjp-Regular.otf
└─ lambda  # Lambda本体のコード群└─ index.js

Lambda上でpuppeteerを動作させる

こちらの記事が非常に分かりやすく、参考になりました。
参考記事は、LambdaのランタイムにNode.js 8.10を選択できる時代の記事ですが、Node.js 12.xと読み替えても通用します。

参考記事とほぼ同じですが、僕のやった手順を簡単にメモしておきます。

Lambda Layerに登録するモジュールの作成

cmd
$ cd modules
$ npm i chrome-aws-lambda puppeteer-core

modulesを丸ごとzipしてmodules.zipを作成

コメント 2020-04-26 233309.png

Lambda Layer作成

このステップはほぼ参考記事のまんまです。

AWSコンソールからLambda Layerを開く

コメント 2020-04-26 233955.png

レイヤー作成(npmモジュール群)

コメント 2020-04-26 233955-2.png

image.png

  • 名前:任意
  • .zipファイルをアップロード:先ほど作成したmodules.zipを選択
  • 互換性のあるランタイム:Node.js 12.x
  • 作成ボタン押下

日本語フォントを登録する

Lambda Layerに登録するための日本語フォントをローカルにダウンロードします。
僕の場合は、以前取得していた日本語フォントファイルが手元にあったので、詳細な手順は割愛します。
IPAのサイトからダウンロードしたり、適当な記事を参考に各自調達してください。

取得したフォントファイルを.fonts配下に格納し、エクスプローラから.fontsフォルダごとzipして.fonts.zipを作成します。
image.png

レイヤー作成(日本語フォント)

再びAWSコンソールからレイヤー作成を行います。
コメント 2020-04-26 233955-2.png

image.png

  • 名前:任意
  • zipファイルをアップロード:先ほど作成した.fonts.zipを選択
  • 互換性のあるランタイム:Node.js 12.x

Lambda関数作成

このステップもほぼ参考記事のまんまです。

AWSコンソールからLambda 関数を開く

image.png

関数作成

image.png
image.png

  • 関数名:任意
  • ランタイム:Node.js 12.x
  • 実行ロール:後で編集するので、作成時は適当に。
  • 「関数の作成」を押下
レイヤー登録

デザイナービューでLayersを選択する
image.png

「レイヤーの追加」ボタンを押下
image.png

レイヤーを追加する
image.png

追加したいレイヤーとバージョンを選択し、「追加」ボタンを押下する。
この手順を繰り返して、先ほど作成した2つのレイヤーを追加する。

index.jsの編集

デザイナービューでLambda関数を選択し、メイン処理を記述する。
image.png

index.js
/* 日本語フォントが入っている.fontsを読み込ませるためにHOMEを設定する */process.env['HOME']="/opt";// Layerの内容は/optにあるconstAWS=require('aws-sdk');constchromium=require('chrome-aws-lambda');constpuppeteer=require('puppeteer-core');// パラメータ定義constSAVE_BUCKET_NAME='キャプチャ保存先のバケット名'constoperations=[{method:'goto',args:['https://www.yahoo.co.jp/']},{method:'waitFor',args:[1000]}]/* ユーティリティ関数 */// operationsに従ってブラウザ操作。clickやwaitFor時にキャプチャを取得constexecOperations=asyncfunction(page,operations,result,jpgBuf){for(constopofoperations){console.log(`${op.method} (${op.args[0]}${op.args.length>1?" ,"+op.args[1]:""})`)if(op.method==='click'){jpgBuf.push(awaitpage.screenshot({fullPage:true,type:'jpeg'}));}awaitpage[op.method](...op.args)if(op.method==='waitFor'){jpgBuf.push(awaitpage.screenshot({fullPage:true,type:'jpeg'}));}}}// S3にキャプチャを保存constsaveJpg=async(jpgBuf)=>{consts3=newAWS.S3();constnow=newDate();now.setHours(now.getHours()+9);constnowYMD=now.getFullYear()+(now.getMonth()+1+'').padStart(2,'0')+(now.getDate()+'').padStart(2,'0')constnowHMS=(now.getHours()+'').padStart(2,'0')+(now.getMinutes()+'').padStart(2,'0')+(now.getSeconds()+'').padStart(2,'0');for(constidxinjpgBuf){constfileName='screenshots/'+nowYMD+'/'+nowHMS+'_'+('0000'+idx).slice(-4)+'.jpg';lets3Param={Bucket:SAVE_BUCKET_NAME,Key:fileName,Body:jpgBuf[idx]};awaits3.putObject(s3Param).promise();}}// メイン処理exports.handler=async(event,context)=>{letbrowser=null;constresult={}constjpgBuf=[]try{// 初期処理browser=awaitpuppeteer.launch({args:chromium.args.concat(['--lang=ja']),defaultViewport:chromium.defaultViewport,executablePath:awaitchromium.executablePath,headless:chromium.headless,});letpage=awaitbrowser.newPage();awaitpage.setExtraHTTPHeaders({'Accept-Language':'ja-JP'});// ブラウザ操作awaitexecOperations(page,operations,result,jpgBuf)// 取得したキャプチャをS3に保存awaitsaveJpg(jpgBuf)}catch(error){returncontext.fail(error);}finally{if(browser!==null){awaitbrowser.close();}}returncontext.succeed(result);};
Lambdaの設定を編集する

メモリとタイムアウトはデフォルトだと少なすぎる/短すぎるので、適当に増やす。
image.png

Lambda関数にアタッチされているIAMロールにS3書き込み権限を付与する

Lambda関数の基本設定の「編集」ボタンを押下してLambdaにアタッチされているIAMロールを確認する。
image.png
「IAMコンソールでxxxxxロールを表示します」のリンクからIAMロールを編集し、S3書き込み権限を付与する。
image.png

S3バケットを作成する

キャプチャ保存用のS3バケットを作成する。
Lambda関数のindex.js の SAVE_BUCKET_NAME に作成したバケット名を設定する。

Lambda関数の実行

Lambda関数の「テスト」を押下する。(初回はテストオブジェクトの定義が必要だが、適当でOK。)
image.png

結果

日本語を含むページのキャプチャが文字化けすることなく取得できました。
image.png

How to start to write out a program first.

$
0
0

Talk about writing out a program.

If you've been doing the program lately, and you think
The first program I touched when I was a junior high school student
was the N80-BASIC.
I still remember it, but the following sentence was completely in my head.

N88-BASIC

WIDTH 80,25.
CONSOLE 0,25,0,1
LOCATE 0,0
PRINT "HELLO WORLD"

Of course, back then, I'd just struck this code.
The interpreter only shows an inorganic cursor.
I can't find any help.

So to speak, writing out a program is
It's still the same today, he's a really inorganic guy.

Well, that's today's topic.
It starts with a new programming language, a development environment
So, Mr. Program, as if to say hello.
The greeting is important.

Not just in the programming world, but in the real world as well.
If a single greeting is understood, the person will talk to you in some way.

Even if you just walked up to them without knowing what was going on.
That's what you get, a puzzled look on your face or a
In the worst case, they just send you back to go away.

Past storiesd, digress a little bit...

When I first went on my college graduation trip, I was in transit at an American airport.
I left the tickets in my caster case.
And I managed to explain the crisis to the black woman at the airport counter.
No tickets! No Ride!
I still remember the time I was really turned away for saying, "I don't want to do this.

After that, I went to the help desk at the airport to get a
The old man came over and took me to the baggage claim area.

I had a bag that was almost silver in color, so I
"Gold," he managed to pull the bag back.
I was able to get my ticket.

The horror of it all, and the fact that my friend who went with me was laughing at me.
I still remember this episode of my first trip abroad.
(The nostalgic video became a hot topic at the reunion, and it's still on YOUTUBE.)
https://www.youtube.com/watch?v=joamkkQdKQw

The main point of this topics.

I mean, the guy who says programming languages, what do you write in the first place?
This rule has not changed since the beginning of time
If you don't know this, you can't do anything at all.

In the meantime, the chatbot side of the house will be able to
"What should I write, sir? 
Can't you kindly tell me how to start the code?

When AI comes out, at least, we'll be able to solve this engineer shortage in earnest.
The gap in communication with computers.
I am hoping that they will fill it in.

That's why today's topic is the one I've been learning recently
The starting point of the programming language is explained in a way that even beginners can understand
I'm going to try to put it together in my own way.

python ---> import

 In the case of python, it's an import statement.
 This could not be more wrong.

C# ---> using

 In the case of C#, it is a using clause.
It's not the start of an enka song.

C ---> #include < >

Let me add to that because I remembered it a long time ago.
C++ might be basically the same, though.

node.js ---> require()

Dare I mention JavaScript, which is plunged into HTML?

VB.NET ---> Imports

Unfortunately, there are no such conventions in VBA, so
This is written in the case of VB.
 

JAVA ---> import

 I've never used JAVA personally, so I'll write it out as knowledge.

the others

Typescript
RUBY
PHP
GO

I guess there's a lot of program languages, but I don't know any more.

Like a greeting

Of course it's necessary, you say "hello" to your neibor naturally.
But also it need to catch a glimpse of other people's conversations,
when you read the cord written by other people, such as GITHUB, etc.

Let's start with this opening salutation
Because it's the beginning of everything.
We're going to have to unravel it from here.
The program is completely incomprehensible.

This greeting is very important.
For example, the manners of the other country and
The book is packed with general knowledge of the arts and sciences.

Especially nowadays, with all the namespaces and such.
You don't even have to name the namespace.
In the first place, this is just a tree structure with a directory
It's a name, and I'd like it to be said that way.

In addition, PYTHON is using ENV and so on, such as virtual space.
It will be made, but once this too is done, it will be
It's just the name of a temporarily created folder.
(It's really difficult for this IT engineer to say difficult things.
It's a nasty routine, and that's why it goes around so much.
(It's a rather disgusting culture that doesn't accept first-time students.

And these days, object thinking...
In the old days, a single craftsman, who started his own business
And then they hired more and more people to work in an organized way.
It's like building more and more departments.

It's not like there's any real-world rules or
Common sense, rules, and regulations are plunged into the storage area of your computer.
That's just the story, but somehow they don't accept first-time students.
It has a unique atmosphere.

Therefore, I believe that the more the world becomes an IT society, the more
These advanced engineers, your engineers, look like they own the place.
I want to make a hole in the world that is so prevalent.

Translated with www.DeepL.com/Translator (free version)

如何先开始写出一个程序

$
0
0

谈谈写出一个方案。

如果你最近一直在做程序,而你认为
我在初中时接触的第一个节目,是我在初中时接触的第一个节目
是N80-BASIC。
我还记得,但下面这句话完全在我的脑海里。

N88-BASIC

WIDTH 80,25.
CONSOLE 0,25,0,1
LOCATE 0,0
PRINT "HELLO WORLD"
宽80,25

当然,那时,我只是打出了这样的代码。
解释器只显示了一个无机游标。
我找不到任何帮助。

可以这么说,写出一个程序是
今天还是这个样子,他真的是个无精打采的家伙。

那么,这就是今天的话题。
这要从一种新的编程语言、开发环境说起。
所以,节目先生,好像是在问候。
问候是很重要的。

不仅仅是在编程世界,在现实世界中也是如此。
如果一个问候语被理解了,对方就会以某种方式和你交谈。

哪怕你只是在不了解情况的情况下走到他们面前,也是如此。
那你会得到的,是一脸疑惑的表情,或者是一种
最坏的情况下,他们只是送你回去走人。

过去的故事D,扯远了一点

我第一次去大学毕业旅行的时候,在美国的机场转机。
我把车票放在了我的行李箱里。
我设法向机场柜台的黑人女士解释了危机。
没有车票!没有车票!
我还记得有一次真的被拒绝了,因为我说:"我不想这样做。"我真的被拒绝了。

之后,我去机场的服务台拿了一个
老人走了过来,把我带到了行李提取区。

我拿着一个几乎是银色的包包,所以我
"金子,"他勉强把袋子拉了回来。
我的车票也被我抢到了。

这一切的恐怖,让和我一起去的朋友都笑了起来。
我还记得我第一次出国时的这段插曲。
(这段怀旧视频在同学会上成为了热门话题,现在还在YOUTUBE上流传着)。
https://www.youtube.com/watch?v=joamkkQdKQw

这个题目的重点

我的意思是说,说编程语言的人,一开始你写什么?
这个规律从古至今都没有改变过
如果你不知道这个道理,那你根本就不能做任何事情。

在这段时间里,聊天机器人那边就能
"先生,我该怎么写呢? 
你就不能好心告诉我怎么开始写代码吗?

等人工智能出来后,至少我们就能真正解决这个工程师短缺的问题。
与计算机交流的缺口。
我是希望他们能够填补这个空缺。

所以今天的话题是我最近一直在学习的话题
以连初学者都能理解的方式来讲解编程语言的出发点
我想用我自己的方式来拼凑一下。

python ----> import

 在python的情况下,它是一个导入语句。
 这是不可能再错了。

C# ----> using 句

 在C#的情况下,它是一个使用子句。
它不是恩卡之歌的开头。

C ----> #include < >

让我补充一下,因为我很早就想起来了。
不过C++可能基本上也是一样的。

node.js ----> require()

敢不敢提一下陷入HTML中的JavaScript?

VB.NET----->导入

不幸的是,VBA中没有这样的约定,所以
这是用VB的情况下写的。
 

JAVA ----> import

 我个人没有用过JAVA,所以就当做知识来写吧。

其他的
Typescript
RUBY
PHP
GO

我想,程序语言有很多,但我不知道更多。

比如说问候语

当然这是必要的,你和你的neibor自然而然的打招呼。
但它也需要捕捉到别人的谈话的一瞥。
当你看了别人写的绳索,如GITHUB等。

先说说这个开场白吧
因为它是一切的开始。
我们要从这里开始解开它。
这个程序是完全无法理解的。

这个问候是非常重要的。
比如说,对方国家的礼仪和
书中有很多文理科的常识。

尤其是现在这个时代,名字空间什么的都有了。
命名空间都不需要命名。
首先,这只是一个树状结构,有了目录
这是个名字,我也想这么说。

另外,PYTHON在使用ENV之类的虚拟空间等。
会做,但一旦这个也做出来了,就会是
只是临时创建的文件夹的名字而已。
(这个IT工程师真的很难说难听的话。
这是一个很讨厌的套路,所以才会流传这么多。
(这是一种相当恶心的文化,不接受初入职场的学生,这是个相当恶心的文化。

而这年头,对象思维......
以前的时候,一个独身手艺人,自己创业的时候
然后,他们雇佣的人越来越多,工作也越来越有条理。
就好像是建立了越来越多的部门。

这并不像有什么现实世界的规则或
常识、规则、规章制度都陷入了你的电脑存储区。
这只是故事,但不知为何他们不接受初入职场的学生。

通过www.DeepL.com/Translator(免费版)翻译


【Node】nodebrewでnodeのバージョンを瞬時に切り替え!

$
0
0

インストール

  1. curl -L git.io/nodebrew | perl - setup
  2. shell に export PATH=$HOME/.nodebrew/current/bin:$PATHを設定
  3. source ~/.bashrc

nodebrew を使う

nodebrew ls

nodebrew経由でインストールしている nodeのバージョンを表示してくれます。

nodebrew ls-remote

インストール可能なバージョンを表示してくれます。

nodebrew install [インストールしたいnodeのバージョン]

インストールします。

nodebrew use [インストールしたバージョン]

インストールしたものでなにを使用するか決定します。

参考にした記事

GitHub - hokaccha/nodebrew: Node.js version manager
Macでnodeのバージョン切り替え -nodebrew の使い方- - Qiita
Node.jsのバージョンを自動で切り替えられるnodenvが超便利 - Qiita

遭遇したエラー

nodebrewでrequired brew_dirというエラーになる - Qiita

【Node.js】nvmの導入

$
0
0

nvmとは?

Node.jsのバージョン管理ツールです。
Node.jsのバージョンによっては互換性がなかったりする為、nvmで管理する。

環境

  • macOS Catalina
  • zsh

インストール

公式ドキュメントに従いながらインストールする。
以下のコマンドを実行する。

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

.zshrcに以下の文を追記しターミナルを再起動すると、nvmコマンドが使えるようになる。

export NVM_DIR="$HOME/.nvm"[-s"$NVM_DIR/nvm.sh"]&&."$NVM_DIR/nvm.sh"# This loads nvm

バージョンを確認してみる。

$ nvm --version
0.35.3

Node.jsをインストール

インストールできるバージョン一覧を確認する。

$ nvm ls-remote
v0.1.14
...
v14.0.0

v10.19.0をインストールする。

$ nvm install v10.19.0

Node.jsのバージョンを確認してみる。

$ node -v
v10.19.0

Node.jsのバージョン切替

nvmでインストールされたNode.js一覧を確認する。

$ nvm ls
->     v10.19.0
       v12.16.2

バージョンを切り替え、Node.jsのバージョンを確認してみる。

$ nvm use v12.16.2
$ node -v
v12.16.2

Dockerでの環境構築(Rails)超入門 2~Dockerfileの設定~

$
0
0

前回

Dockerでの環境構築(Rails)超入門1

はじめに

Ruby on Rails初心者です。今回はDockerを使ったRailsの環境構築の初歩を勉強のために備忘録として残したいと思います。
※あくまで開発環境を構築するためだけの超入門です。

やること

前回はコマンドでrailsやNde,jsのインストールを行なっていた
今回はdockerfileに記述することでいちいちコマンドを打たなくて済むようにする

手順

  1. railsのインストールをdockerfileに記述
  2. apt-get update, Node.jsのインストールもdockerfileに記述
  3. 再度コンテナを起動、この時buildする
  4. Rails を起動

実践

1) railsのインストールをdockerfileに記述

RUN gem rails install

2) apt-get update, Node.jsのインストールもdockerfileに記述

RUN apt-get update && \
    apt-get install -y node.js

\ は複数行記述する際に使う。
Node.jsはインストール時にiyes/noを聞かれるので -y を記述

3) 再度コンテナを起動、この時buildする

$ docker -compose up --build

(Build,,,, 動いていたコンテナを破棄して新しくdockerfileを実行)

4) Rails を起動

$ docker exec -it practice/bin/bash

/# cd app/

/# rails s -b 0.0.0.0

#bunde installを要求される

/# bundle install

#再度実行
/# rails s -b 0.0.0.0

Dockerfileに書く理由

書いた状態でGithubにcommitしておけばコマンドが実行された状態でDockerが起動してくれる

【メモ】Raspberry Pi に node をインストール

$
0
0
  • Raspberry Pi Model B Plus Rev 1.2

tj/n をインストール

$ curl -L https://git.io/n-install | bash

amazon-qldb-driver-nodejsからQLDBを使う②(書き込み、検索編)

$
0
0

前回の記事はこちらです
https://qiita.com/shushutochako/items/bbb3ec5f721c57949ea7

概要

今回はテーブルへのデータの追加、更新と検索を試してみたいと思います。
AWSの認証などについては前回の記事を参考にして下さい。

また、本記事は公式チュートリアルの内容を参考にしています。
https://docs.aws.amazon.com/qldb/latest/developerguide/getting-started.nodejs.tutorial.html

moduleのバージョン

今回使用した「amazon-qldb-driver-nodejs」自体や他に必要なモジュールのバージョンは以下のとおりです。
前回の記事の時点ではpreviewでしたが、2020/4のはじめにPre-release版がリリースされたようですね!
正式なリリースも近いのではないでしょうか。

  • amazon-qldb-driver-nodejs
    • v1.0.0-rc.1
  • aws-sdk
    • 2.663.0
  • ion-js
    • 4.0.0
  • typescript
    • 3.7.5
  • jsbi
    • 3.1.1

前提

事前にAWSのコンソールから台帳に任意の名前でテーブルを作成しておいてください。
クエリエディタで以下を実行するとテーブルを作成できます。

CREATE TABLE {Your Table Name}

QLDBはドキュメント指向のデータモデルを採用しているため、事前に列定義をする必要はありません。

データの追加

それではテーブルへのデータの追加を試していきます。
※「{Your Table Name}」となっている部分は作成したテーブルに合わせて修正して下さい

awaitqldbDriver.executeLambda(async(txn)=>{constresults=awaittxn.execute('INSERT INTO {Your Table Name} ?',[{id:1,name:'TestRecord',createdAt:newDate()},{id:2,name:'TestRecord2',createdAt:newDate()},{id:3,name:'TestRecord3',category:'A',createdAt:newDate()}]);results.getResultList().forEach(element=>{// 各データ採番されたdocumentIdを表示console.log(element.get('documentId').stringValue());});});

生成したPooledQldbDriverのインスタンスからexecuteLambdaを呼び出します。
以前のバージョンではsessionを取得してexecuteをする必要がありましたが、driverから直接実行出来るようになりました。

excuteLambdaを実行すると関数にTransactionExecutorが渡されます。
TransactionExecutorのexcute関数にプレースホルダを含むPartiQL文とパラメータを渡して呼び出します。
excute関数の第二引数は可変長になっており、プレースホルダに渡す値を順に指定します。
excuteLambdaを使用すると暗黙的にトランザクションの開始とコミットが行われるようです。
追加した各データにはdocumentIdが自動で採番されます。

データの変更

先ほど追加したデータの内容を変更します。以下の例ではidをキーにnameを更新しています。
普段SQLに慣れ親しんだ方であれば、特に困るところもなさそうです。

awaitqldbDriver.executeLambda(async(txn)=>{awaitexecute(txn,'UPDATE TestTable AS t SET t.name = ? WHERE t.id = ?','NewTestRecord1',1);});

ロールバック

もし追加内容をロールバックしたい場合はTransactionExecutorのabortを呼び出します。
これによりロールバックされ「LambdaAbortedError」がthrowされます。

constresults=awaittxn.execute('INSERT INTO {Your Table Name} ?',[ ・ ・ ・]);awaittxn.abort();

データの取得

続いて、データを取得してみます。
こちらも基本的にはinsertやupdateと変わりません。

awaitqldbDriver.executeLambda(async(txn)=>{constresults=awaittxn.execute('SELECT * FROM TestTable WHERE id = ?',10);results.getResultList().forEach(element=>{if(element.get('name').getType().name==='string'){// 各データのnameを取得console.log(element.get('name').stringValue());}});});

QLDBではAmazon Ionの形式でデータを取り扱います。
以下のコードではdocument内のnameプロパティについて型を確認したのち実際の値を取得しています。

if(element.get('name').getType().name==='string'){// 各データのnameを取得console.log(element.get('name').stringValue());}

Amazon IonはJsonのスーパーセットで、厳格な数値の定義など色々と拡張されているようです。
https://docs.aws.amazon.com/ja_jp/qldb/latest/developerguide/ion.html#ion.json-compatible

コード全文

今回実装したコードの全文は以下のとおりです。

import{PooledQldbDriver}from"amazon-qldb-driver-nodejs";constAWS=require("aws-sdk");AWS.config.loadFromPath("./credentials.json");(async()=>{consttestServiceConfigOptions={region:"{Your Region}"};constqldbDriver:PooledQldbDriver=newPooledQldbDriver("{Your Ledger}",testServiceConfigOptions);// insertawaitqldbDriver.executeLambda(async(txn)=>{constresults=awaittxn.execute('INSERT INTO {Your Table Name} ?',[{id:1,name:'TestRecord',createdAt:newDate()},{id:2,name:'TestRecord2',createdAt:newDate()},{id:3,name:'TestRecord3',category:'A',createdAt:newDate()}]);results.getResultList().forEach(element=>{// 各データ採番されたdocumentIdを表示console.log(element.get('documentId').stringValue());});});// updateawaitqldbDriver.executeLambda(async(txn)=>{awaittxn.execute('UPDATE {Your Table Name} AS t SET t.name = ? WHERE t.id = ?','NewTestRecord3',10);});// selectawaitqldbDriver.executeLambda(async(txn)=>{constresults=awaittxn.execute('SELECT * FROM {Your Table Name} WHERE id = ?',10);results.getResultList().forEach(element=>{if(element.get('name').getType().name==='string'){// 各データのnameを取得console.log(element.get('name').stringValue());}});});})().catch(err=>{console.error(err);});

さいごに

PartiQLベースで操作できることで、SQLに慣れている人であれば直感的に使用できそうですね!
今回はシンプルな「追加」「更新」「検索」などを試してみました。
しかし、「ORDER BY」句が現状は使用できなかったり、完全にSQLの感覚で考えていると困る点がいくつかあるように感じました。
QLDB Streamingなるもののも出てきたようで、検索の柔軟性に関しては他のサービスに任せるなど役割分担を考えていくことが必要そうだと感じました。
https://dev.classmethod.jp/articles/update_qldb_streaming/

ZEROBILLBANKでは一緒に働く仲間を募集中です。
ZEROBILLBANK JAPAN Inc.

knexでdistinct onする方法

$
0
0

特定のカラムだけdistinctしてーーー!
そしてdistinctしたカラム以外も取得してーーーー!

って時、極稀にありますよね。
RDBに多少でも触れる人生なら一生に3回くらいは遭遇するはずです。

エンジニア歴10年超えにしてやっと実運用ProductでPostgresデビューした私にも、人生で3回遭遇するうちの第一回目が来ました。

knexのドキュメント見てもですね。
「distinct on」サポートしてないんですよ。

http://knexjs.org/

distinct on なにそれ?おいしいの?くらいの勢いでカレーにスルーされてるんです。
Postgresの方言らしいので仕方ないのかな。。

もうこういったRDB固有の方言は、raw使うしか無いようですロー

knexでdistinct on するには"raw"を使う

knex.select(knex.raw('DISTINCT ON (target_colum) target_colum1, other_colum2, other_colum2)

こうすると、target_columでdistinctしつつ、other_colum1とother_colum2も取得できます。

orderも組み合わせる

knex.select(knex.raw('DISTINCT ON (target_colum) target_colum1, other_colum2, other_colum2).orderBy([target_colum, {target_colum1: 'desc'}])

orderByの1つ目は必ずdistinct onで指定したやつに。

2つ目に指定したカラムでソートして一番最初に出る行が残されて取得できるよ

Herokuへのアップロードでつまづいた時の対処法 その② Node.js + MongoDB

$
0
0

先日記述した「Herokuへのアップロードでつまづいた時の対処法」の後編になります。なお、タイトル通りMongoDBを使っていない場合には、この後編を参考にする必要はありません。前編に引き続き、これを見た未来の困っている人たちの手助けになれば嬉しいです。それでは順を追って説明していきます。

前編で記述したprocfileの作成方法や.gitignoreの作成方法をすでに行っている前提で話していきます。

1:HerokuでMongoDBのアドオンを使用するためには、Herokuでクレジットカード情報を登録する必要があります。ただし、お金は一切かかりませんし、メルマガなどの勧誘もありません。登録方法はこちらの方の記事を参考にしてみてください。👉https://wp.developapp.net/?p=5250
大体4-5分でできます。

2:登録が完了したらHeroku上の自分のアプリケーション画面に移動します。👉https://dashboard.heroku.com/apps

3:今回Herokuへアップロードするアプリを選択しクリックする。

4:画面の上部に表示されている”Resources”をクリックする。

5:Find more add-onsをクリックする。

6:Heroku Add-onsと表示され、多数のアドオンが表示されるので、その中の”mLab MongoDB”を選択する。クリックするとそのアドオンのリンク先に飛ぶ。

7:スクロールダウンすると"install mLab MongoDB"のボタンがあるのでクリックする。

8:App to provision toのsearchボックスの中に自分のHerokuアプリ名を入力し、"Provision add-on"をクリックする。これでアプリとアドオンの紐付けが完了。

9:次にアドオンのアドレス情報を登録するので、今のHerokuの画面上に表示されている"mLab MongoDB"(名前部分)をクリックする。

10:画面中央のUsersを選択すると、右側に"Add database user"が表示されるので、クリックする。

11:Database UsernameとDatabase Passwordは後々必要になるが、ここでは以下のように例として設定する。※パスワードは英数6文字以上、チェックボックスをチェックする必要はなし。

Database Username: user

Database Password: 123qwe

12:作成したら自分の画面に表示されている以下の部分をコピーする。下のはあくまでもサンプル例。これでHeroku上での設定は終わりです。次のステップからファイルとRobo 3Tを使用していきます。

mongodb://:@ds151508.mlab.com:51508/heroku_mxzlxdnp

13:mongoose.connectを書いているファイルを開き、先ほどコピーしたURIを以下のように貼り付けます。そして、process.env.MONGODB_URIも以下の通りに追記します。

mongoose.connect(process.env.MONGODB_URI || "mongodb://:@ds151508.mlab.com:51508/heroku_mxzlxdnp", {
useNewUrlParser: true
});

14:コピーして貼り付けたURIの中に:と書かれているので、私の場合、先ほどuserと123qweと設定して作ったため、ここをそれぞれuser:123qweと書き換えます。以下完成文。これでファイルの中身の設定は終わりです。

mongoose.connect(process.env.MONGODB_URI || "mongodb://user:123qwe@ds151508.mlab.com:51508/heroku_mxzlxdnp", { useNewUrlParser: true });

15:Robo 3Tを使って接続を確立させるので、Robo 3Tを開いてください。Robo 3Tをダウンロードしていない方はここからダウンロードしてください。※今後作業する時もRobo 3T使うと結構便利です。👉https://robomongo.org/

16:Robo 3Tの画面上で、"Create"をクリックする。わからない場合は、左上の"FIle"を選択し"Connect"を選ぶと"Create"を選べる画面が表示される。

17:Connection Settingで、まず、接続名を入力する。

18:とりあえず先ほどコピーしたURIをAddressに貼る。”localhost”の文字は消す。

Address: mongodb://user:123qwe@ds151508.mlab.com:51508/heroku_mxzlxdnp

19:ここから以下のように変更する。

Address:  ds151508.mlab.com

20:次に、隣の5桁の数字を消して、自分のURI内に書かれてある5桁の数字を代わりに入力する。

ds151508.mlab.com:51508/heroku_mxzlxdnp

51508 👈ds151508.mlab.com:と/heroku_mxzlxdnpの間の数字

従って、最終的には以下のようになる。※私の場合

Address:  ds151508.mlab.com  :51508

21:Connectionの隣にあるAuthenticationをクリックする。

22:Perform authenticationにチェックを入れると、他の部分の入力が可能になる。

23:Database: の部分には自分のURIの最後のherokuから始まる部分を入力する。以下参考にしてください。

mongodb://user:123qwe@ds151508.mlab.com:51508/👉👉heroku_mxzlxdnp👈👈これこれ

従って以下のようになる。

Database: heroku_mxzlxdnp

24:UsernameとPasswordには自分が設定したものを入力する。私の場合、userと123qwe、なので以下のようになる。

Username: user

Password: 123qwe

25:最後に左下の"Test"をクリックし、どちらもグリーンになれば全ての設定が完了。

26:Command Line(Hyper Terminal)を起動し、Herokuへとアップロードするファイルを選択。

27:次のコマンドを順々に実行する。

コマンド:$heroku login

コマンド:$git init

コマンド:$git add

コマンド:$git commit -m "random message"

コマンド:$git push heroku master
※冒頭でも伝えたように、procfileや.gitignore、その他の作業はすでに実行済の想定で書いています。

28:長くなりましたが、これで終了です。DBも全て反映されるようになります。

日本語で正解のドキュメントを探すのも一苦労のプログラミング世界ですが、試行錯誤を重ねに重ねて、さらに重ねまくった上で実装できた時は嬉しいですね笑

1歩1歩頑張っていきましょう。


Herokuを使ってみた

$
0
0

はじめに

適当にJSとかwebアプリケーションを勉強している学生が記録するために使っているので,あまり内容は期待しないでください。とりあえず今回はHTTPサーバをHerokuを使って公開してみます。

1.Herokuとは

webサービスを動かせるプラットフォームを提供してるサービスらしい。小規模なら無料で使えるとのこと。

2.Herokuのアカウント作成

とりあえずアカウント作成
https://jp.heroku.com/
でいろいろ個人情報を流出してきます。

ここで開発言語を選択するらしいですがまぁJS程度しかやってないのでNode.js一択ですね。

ドラえもんが引っかかってしまう私はロボットではありませんチャレンジをクリアしてメールアドレス認証。パスワード設定したら登録完了です。いやぁ非常にスムーズ,毎回どこかでつまづくんじゃないかと冷や冷やしながら登録してます。

3.Heroku CLIをインストール

順番がゴチャゴチャしてきましたがherokuコマンドを利用しなきゃと思ったらHeroku CLIが必要らしい。まぁあるあるというか常識なのだろう。今回はUbuntuにインストールしちゃうのでiTerm2で仮想環境を起動するよ。

起動したところで
1.Virtual Box(バーチャルボックス)
2.Vagrant(ベイグラント)
という2つのソフトウェアを使った仮想環境でUbuntuを使用します。
cd ~/vagrant/ubuntu
vagrant up
vagrant ssh

Ubuntuがインストールされたディレクトリに移動。vagrant upは仮想的なPCにインストールされたUbuntuを起動するコマンドで,vagrant sshはVagrantの仮想マシンがセットされている状態でSSHに接続します。

仮装環境を起動して以下のコマンドを実行。

sudo snap install --classic heroku

sudoは管理者として実行するコマンド。
snap install --classicはsnapパッケージのコマンドで,snappyというUbuntu向けに開発されたパッケージ管理システムの一部らしい。Snapには、ソフトウェアを隔離してセキュリティを高めるサンドボックス機能があるが,この制限をかけると使い勝手が悪くなるパッケージがあるので、 そのリスクを承知してインストールをするために –classic オプションを追加してます。

まぁそんなこんなでHeroku CLIがインストールされましたね。

4.Heroku CLIからHerokuにログイン

というわけでHeroku CLI から Heroku にログイン。

heroku login -i

コンソールで以上を記入してログインします。

5.Herokuで実際にデプロイしてみる(失敗)

とりあえずコンソールで使用したいファイルのディレクトリに移動します。
cd node-js-http-3016
そして以下のコマンドでHeroku 上で動かすための設定ファイルを作成します。
echo "web: node index.js" > Procfile

echoは文字をそのまま出力するコマンド。ProcfileはHerokuがアプリを動作する時Herokuのプラットフォーム上にあるWebアプリがどのようなコマンドで実行されるのかを記述するファイルのこと。Webアプリを動かす指示書みたいなものらしい。いろいろ書き方があるみたいだけどとりあえず割愛。

はいここで問題発生

Herokuではサーバー上へソースコードを配置するためにGitを利用している!!!
そのため、Heroku での実行前にGitのリポジトリにコミットすることが必要!!!

......まぁやりますよ、知らなかった自分が悪い

いろいろ調べた結果gitとリポジトリを保存しているgithubを連携する必要があるらしい。今回はSSHを使うのでsshを追加した後,新しい公開鍵情報をコンソールに表示させ,それをコピー。githubの右上アイコンからsettingという項目を表示し,SSH and GPG keysを選択してnew ssh keyでssh keyを追加。この設定の時に先ほどの公開鍵情報が必要。
まぁそんなこんなで追加が無事終了し,これでGitHubとマシンがSSHを利用した暗号化通信ができるらしい。もうなんか細かいことはわからなくなってきた。

6.試しにGithubからクローンをしてみる

作ってきたリポジトリのclone or downloadの欄をクリックしSSHのリンクをコピー
コンソールに
git clone SSHのリンク

を記述。これでなんとかgithubからgitにクローンできた様子。さすがです
git pull origin gh-pages

を行ったところエラーなども表示せず,Already up-to-dateという感じでできてるっぽい。

今度こそ実際にデプロイ!!

heroku create

これでサーバを用意して
git push heroku master-2020:master

以上でデプロイを実行!!
remote: Verifying deploy.... done.

実行後にデプロイが完了したというお知らせ。まぁこれでなんとかデプロイできました。

実際のアプリケーションはというとなんか知らないけど問題がありそう。まぁそれについては今後考えます...とりあえずはお疲れ様でした

おまけ1 : iTerm2とは

Terminal.appより簡単に便利な機能が使えるという噂のアプリ。実際のところTerminal.appすらまともに扱ったことがないので便利かどうかは不明。

おまけ3 : Ubuntuとは

狭義ではカーネルに属すLinuxのOSとしての一つがUbuntu(Linuxディストリビュージョン)。PCとして使えたりする初心者におすすめしやすいものらしい(確証はないです)。

おまけ2 : SSHとは

よく高校で使われるスーパーなんちゃらじゃない。どうやらSSHは一種の通信プロトコルらしい。

仮想環境でNode.jsを始めた

$
0
0

はじめに

この記事はなんとなくJSとかを勉強している学生がメモ代わりに記録しているものです。内容は期待しないでください。

仮想環境でコンソールを起動する

今回はUbuntuで行うのでiTerm2で仮想環境を起動するよ。

起動したところで
1.Virtual Box(バーチャルボックス)
2.Vagrant(ベイグラント)
という2つのソフトウェアを使った仮想環境でUbuntuを使用します。
cd ~/vagrant/ubuntu
vagrant up
vagrant ssh

Ubuntuがインストールされたディレクトリに移動。vagrant upは仮想的なPCにインストールされたUbuntuを起動するコマンドで,vagrant sshはVagrantの仮想マシンがセットされている状態でSSHに接続します。

Node.jsを使ってみる

コンソールに
node

と入力すると,コンソールがjsを受け付ける状態になります。これはREPLという状態です。
今回実装するディレクトリに保存しているnode.jsのファイルを以下に記述します。
'use strict';
const n = process.argv[2] || 0;
let sum = 0;
for (let i = 1; i <= n; i++) {
s = s + i;
}
console.log(s);

1行目はJSをstrictモードで利用するための記述で,2行目はnという変数にprocess.argv[2] || 0
以上のような値が代入されます。process.argvはNode.js プログラムから、コマンドライン引数を取得します。argv[0] には node 実行ファイル (node.exe) のフルパス、argv[1] にはスクリプトファイル (.js) のフルパスが格納されているため,格納できるのはargv[2]からです。||はJSの論理演算子のORで左側をtrueと見ることができる場合は、左側を返します。そうでない場合は右側を返します。真偽値と共に使われた場合演算対象のどちらかが true ならば、|| は、true を返し、両方とも false の場合は、false を返します。
3行目はsという変数を指定し4行目以降はfor文を使ったループを書いています。ループはiがコマンドライン引数の値になるまで続きます。
最後にコンソールにsの値を表示して終了です。

仮想環境のコンソールに以下を記述して値が表示されていれば成功です。お疲れ様でした!!!
node ファイル名 コマンドライン引数

REPLとは

REPLにおいてユーザーが1つ以上の式を入力すると、インタプリタがそれを評価し結果をコンソールに表示する。静的型付け言語のREPLでは、型安全性を維持したまま、動的型付け言語の手軽さを享受することができるが、統合開発環境に搭載されているREPLの中には、コードエディター上で動作するものと同様の本格的なコード補完が機能するものもある。

コマンドライン引数とは

コマンドラインはキーボードだけで操作する画面,引数はプログラムや関数に渡す値です。つまりコマンドライン引数と言った場合はプログラムに渡す値だと解釈してください。

node v12でのnode-gyp rebuildでのエラー

$
0
0

環境

macOS Catalina(10.15.4)
node.js v12.16.2

発生した問題

gatsby newをしようとしたところ以下のようなエラーが発生。

error /Users/gedyra/blog/node_modules/sharp: Command failed.
Exit code: 1
Command: (node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)
Arguments:
Directory: /Users/gedyra/blog/node_modules/sharp
Output:
info sharp Using cached /Users/gedyra/.npm/_libvips/libvips-8.7.0-darwin-x64.tar.gz
(中略)
In file included from ../../nan/nan_converters.h:67:
../../nan/nan_converters_43_inl.h:22:1: warning: 'ToBoolean' is deprecated: ToBoolean can never throw. Use Local version. [-Wdeprecated-declarations]
X(Boolean)
(省略)
/Users/gedyra/Library/Caches/node-gyp/12.16.2/include/node/v8.h:2663:3: note: 'ToBoolean' has been explicitly marked deprecated here
  V8_DEPRECATED(\"ToBoolean can never throw. Use Local version.\",
(省略)

解決策

どうやらnode v12では、すでにdeprecatedだったいくつかの関数が削除された模様。
https://kokufu.blogspot.com/2019/11/node-ffi-node-12.html

nvm use lts/dubniumなどでnode v10以下を使えば解決しました。
https://github.com/nodejs/node-gyp/issues/1941

Raspberry Pi に東京都の新型コロナウイルス感染症対策サイトをインストール

$
0
0

東京都の新型コロナウイルス感染症対策サイトを Raspberry Pi にインストールする方法です。

必要なソフトのインストール

Node.js

sudo curl -sL https://deb.nodesource.com/setup_12.x | bash -
sudo apt install-y nodejs

インストールされたバージョン

$ node --version
v12.16.2

yarn

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo"deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt update
sudo apt install yarn

インストールされたバージョン

$ yarn --version
1.22.4

ソースコードのクローン

git clone https://github.com/tokyo-metropolitan-gov/covid19.git

依存関係のインストール

cd covid19
yarn install

実行

yarn dev

http://localhost:3000にアクセス
tokyo_apr28.png

Node.js を使ってファイルからデータを読み取ってみた。

$
0
0

はじめに

この記事はなんとなくJSとかを勉強している学生がメモ代わりに記録しているものです。内容は期待しないでください。

仮想環境を開く

今回はUbuntuで行うのでiTerm2で仮想環境を起動する。

起動したところで
1.Virtual Box(バーチャルボックス)
2.Vagrant(ベイグラント)
という2つのソフトウェアを使った仮想環境でUbuntuを使用します。
cd ~/vagrant/ubuntu
vagrant up
vagrant ssh

Ubuntuがインストールされたディレクトリに移動。vagrant upは仮想的なPCにインストールされたUbuntuを起動するコマンドで,vagrant sshはVagrantの仮想マシンがセットされている状態でSSHに接続します。

1.ファイルから読み取るプログラムを書く

'use strict';constfilesystem=require('fs');constreadline=require('readline');constrs=fs.createReadStream('ファイル名');constrl=readline.createInterface({input:rs,output:{}});constprefectureDataMap=newMap();rl.on('line',lines=>{console.log(lines);});

1行目はJSをstrictモードで利用するための記述です。

2,3行目はNode.js内のモジュールをrequireで呼び出しています。requireとは,拡張機能を使用することができるnpm(Node Package Manager)モジュールです。以下の記述でモジュールを変数に代入してJS内で使用することができます。
const 変数名 = require('モジュール名')

今回呼び出したモジュールはファイルを扱うためのfs(filesystem)とファイルを1行ずつ読み込むreadlineです。

4行目はストリームを使用してファイルを読み込み,rsという変数に代入しています。この他にもfsモジュールにはfs.readFileSyncなどの同期的にデータを読み込む関数も存在します。

5行目はストリームを行ごとに読み込むことができるモジュール(readline)を使用して以下のように設定しています。
//インターフェースの設定
const rl = readline.createInterface({
//読み込みたいストリームの設定
input: rs,
//書き出したいストリームの設定
output: {}
});

6行目はキーと値を組み合わせて扱うためMapオブジェクトを使用しています。ここでは変数にMapオブジェクトを代入するとともに,新しくMapオブジェクトを初期化しています。

7行目はrlというオブジェクトでlineというイベントが起きた時に以下の関数を発火させています。今回はlinesという引数をコンソールに表示しています。

2.6行目の関数を変更する

6行目のonメソッドに渡されている関数を以下に変更しました。
rl.on('line', lines => {
const cutline = lines.split(',');
const year = parseInt(cutline[0]);
const prefecture = cutline[1];
const popu = parseInt(cutline[3]);
if (year === 2010 || year === 2015) {
let vofmap = prefectureDataMap.get(prefecture);
if (!vofmap) {
vofmap = {
p10: 0,
p15: 0,
change: null
};
}
if (year === 2010) {
vofmap.p10 = popu;
}
if (year === 2015) {
vofmao.p15 = popu;
}
prefectureDataMap.set(prefecture, value);
}
});

2行目のsplit()メソッドは、Stringを指定した区切り文字列で分割することにより、文字列の配列に分割します。メソッドの使い方は以下のように使います。
文字列.sprit(指定した区切り)

3行目からは文字列から作られた配列の一部を変数に代入しています。parseInt()は文字列の引数を解析し,指定された基数 (数学的記数法の底) の整数値を返します。簡単にいうと文字列の値だったものを数字(整数値)に変更し,扱いやすくしています。

6行目からはif文を使用して指定した値を変数が持っている場合のみ以下のプログラムを動かしています。

7行目はマップにキーを指定しながらキーの値を取り出しています。記述の仕方は以下参照
マップ名.get(キー名);

8行目はキー名に指定された値がない場合,初めてキー名に当たる値を代入しています。

9行目以降のこの部分について解説します。
if (year === 2010) {
vofmap.p10 = popu;
}
if (year === 2015) {
vofmao.p15 = popu;
}
prefectureDataMap.set(prefecture, value);
}
});

ここでは先ほどMapオブジェクトで作成したキー名に当たる値の各オブジェクトに代入しています。その後キーと値のセットを先ほどのマップに登録しています。記述の仕方は以下参照
```javascript

マップ名.set(キー名,値)
```

3.closeで発火させる関数を記述する

以下の内容を最後に記述します。
rl.on('close', () => {
for (let [key, vofmap] of prefectureDataMap) {
vofmap.change = vofmap.popu15 / vofmap.popu10;
}
const rankingArray = Array.from(prefectureDataMap).sort((pair1, pair2) => {
return pair2[1].change - pair1[1].change;
});
const rankingStrings = rankingArray.map(([key, value]) => {
return (
key +
': ' +
value.popu10 +
':' +
value.popu15 +
':'+
value.change
);
});
console.log(rankingStrings);
});

1行目は先ほどと同じでrlというオブジェクトでcloseというイベントが起きた時に以下の関数を発火させています。

2~4行目はfor~of構文でprefectureDataMapというマップに対してキー名とそれに当たる値のループを行っています。その後に新たにchangeというオブジェクトをマップ内に作り当てはまる値を代入しています。

5行目は関数を行った後に配列に変換しています。今回はsortを使ってコールバック関数の値の大きさによって順番を変更しています。記述方法は以下参照。
Array.from(変換対象,関数{})

9行目はmap関数を使っています。先ほどのキー名などを使うものとは別物です。map関数は、 Array の要素それぞれを,与えられた関数を適用した内容に変換します。今回は全てを文字列として変換しています。

node JSファイル名

以上を実行してREPLでエラー等が発生しなければ成功です。お疲れ様でした!!

ストリームとは

サイズが非常に大きなデータを取り扱う際などには,データの全てを一度にメモリに読み込んでしまうとメモリが逼迫し,プログラムのパフォーマンスを低下させてしまう可能性があります。
そのような場合にはストリームを使用します。ストリームとはデータを徐々に読み込んだり,書き込んだり、変換したりすることができるものです。

Viewing all 8818 articles
Browse latest View live