OmniAICreator/Qiita-1.07M huggingface dataset:
VRChatのログイン監視体制を作る②

##概要
以下の記事を参照

https://qiita.com/nimani/items/cd51b7d7881a032388c3

##本記事について
上記記事にてフレンドのログインを監視するところまで作成しているので、
本記事では通知の種類やサンプルコードを記載します。

##メール通知
1つめはメールにて通知を行う方法を紹介します。
今回使用するシステムはSendGridです

https://sendgrid.kke.co.jp/?utm_source=google&utm_medium=cpc&utm_content=text&utm_campaign=dsa&gclid=Cj0KCQjwnueFBhChARIsAPu3YkTuwwbbUaoBzYPPfYPhpu4tPS-NdK1lvBYSi_sO0JRL5bhPt1y5fc0aAntDEALw_wcB

こちら、クラウドタイプのメール配信サービスで初回会員登録に承認が必要ですが、
無料プランでもある程度の件数のメールを送ることができるサービスです。

今回記載するスクリプトは以下環境にて動作させています。
----環境----
OS　：　Linux
Apacheバージョン　：　2.4.6
PHP　　　　　　  ：　7.4.13

今回はcURLを使用してapiをpostする方法でメールを送ります。
※SendGrid公式ライブラリを使用する場合の方法はSendGrid公式に記載されています


```sendmail.php
<?php
$url = 'https://api.sendgrid.com/';
$sendgrid_apikey =SendGridのAPIキー;
$mail_address = "送信先のメールアドレス";
$FILE = 'tmp_players.txt';
$BOARD = json_decode(file_get_contents($FILE));

$params = array(
    'Authorization: Bearer'  => $sendgrid_apikey ,
    'to'        => $mail_address,
    'subject'   => "監視対象ログイン通知",
    'html'      => "
	以下お友達がログインしました
	<br /> ".$BOARD.
	"早く会いに行きましょう",
    'from'      => 'vrclogintest@monitoring.jp',
  );

$request =  $url.'api/mail.send.json';
if (!defined('CURL_SSLVERSION_TLSv1_2')){
define('CURL_SSLVERSION_TLSv1_2', 6);
}

// カールリクエストを生成する
$session = curl_init($request);
// SSLv3を使用しないようにPHPに指示します（代わりにTLSを選択します）
curl_setopt($session, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
curl_setopt($session, CURLOPT_HTTPHEADER, array('Authorization: Bearer ' . $sendgrid_apikey));
// CurlにHTTP POSTを使用するように指示します
curl_setopt ($session, CURLOPT_POST, true);

// これがPOSTの本文であることをcurlに伝えます
curl_setopt ($session, CURLOPT_POSTFIELDS, $params);
// Curlにヘッダーを返さないように指示しますが、応答を返します
curl_setopt($session, CURLOPT_HEADER, false);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
// レスポンスを得る
$response = curl_exec($session);
curl_close($session);
?>
```

これで、以下メールが送信されます
![mail2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187924/6bccdc77-3a40-e808-2f78-b735d3d503dc.png)

通知メールが来ることでログインしたことが分かるので**早く会いに行きましょう**

##デスクトップ通知
上記メールでの通知ですが、常に監視するためのLinuxサーバーが必要です。
PCを起動していないとログインの通知が来てもすぐにログインはできないので、
常にPCを起動しておく場合はデスクトップに通知を飛ばしたほうがいいですよね。

ということで、次にデスクトップに通知を飛ばす方法を以下にて解説します。
今回はplyerモジュールを使用します。

https://pypi.org/project/plyer/

今回記載するスクリプトは以下環境にて動作させています。
----環境----
OS　：　Windows
Python　：　3.8.8
Anaconda version : 4.10.1
plyer　：　2.0.0

```notification.py
from plyer import notification

user_file = open("tmp_players.txt", mode='r',encoding='utf-8')
user_data = user_file.read()
user_file.close()

notification.notify(
    title = "監視対象ログイン通知",
    message=user_data + "\nがログインしています\n\n早く会いに行きましょう",
    timeout=5
    )
```

上記を実行することで以下通知が飛んできます
![tuutita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187924/0650cace-6002-3261-3160-b6de90babe0a.png)

こちらを一定時間ごとに自動実行することで常にログイン動向を確認することができるので
ログイン通知が飛んで来たら**早く会いに行きましょう**

##終わりに
これは友達を**監視**ではなく**見守る**のための技術紹介記事なので
変なことに使用しないようにしましょう

あくまで友達を**見守りたい**人向けです...
Vuexで初期値をセットする

# Vuexで初期値をセットする方法

Vuexで初期値をサーバーから取得してセットする方法を記述します。

## 環境

Vue 2.5.17
Vuex 3.6.2

## 参考サイト

https://bernar.do/vuex-store-with-normalized-data-using-a-laravel-backend

## 実装例

Vuexのインスタンスに初期化用のメソッドを作成します。
例では`init`と命名していますが名前は任意です。Ajaxでデータを取得しセットします。

```javascript
const store = new Vuex.Store({
    state: {
        userId: "",
        userName: ""
    },

    // ...

    actions: {
        init() {
            // ajaxで初期値を取得し、stateにセットします。
            axios.post("/api/vuexInit").then(response => {
                this.state.userId = response.data.user_id;
                this.state.userName = response.data.user_name;
            }).catch(error => {
                console.error(error);
            });
        },
    }
});
```

上記で定義したメソッドをVueコンポーネントの`created`などで呼び出すことで初期値をセットできます。

```javascript
  created: function () {
      this.$store.dispatch("init");
  },
```
fetchなどでダブルクオーテーション囲みの数値が入ってきた場合の対処方法

# 問題
fetchで返されるレスポンスに`"123"`などのダブルクオーテーションが付いた数値が帰ってくる。
APIドキュメント上は、数値と定義されているが、””囲みなので実際の演算時や.toFixedしたい場合などに文字型となりエラーとなる。

数値であることはAPIドキュメント上、保証されているとき、どうすれば簡単に数値型へ変えられるか。

# 対応
[単項プラス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Unary_plus)を使う。

```typescript
const numericString = "10";
const numericValue = 10;

// 通常は文字列結合
console.log(`numericString + numericValue: ${numericString + numericValue}`);

// 単項プラスをあらかじめすることで
console.log(`+numericString + numericValue: ${+numericString + numericValue}`);
```

```
[LOG]: "numericString + numericValue: 1010" 
[LOG]: "+numericString + numericValue: 20" 
```
An error occurred while installing mysql2 (0.5.3), and Bundler cannot

# 概要
Rails6でMySQLを使おうとして、bundle install して、失敗したときの解決方法です。
誰かの参考になれば嬉しいです！

## 前提条件
Node v12.17.0
Ruby v3.0.0
Rails v6.0.3.7
macOS Big Sur

# 手順
1. openssl対応
2. ｍｙSQLをダウンロード
3. zshrcに保存
3. readline導入


## 1. openssl対応
OpenSSLとは、SSLプロトコル・TLSプロトコルの、オープンソースで開発・提供されるソフトウェアである。
mysqlにSSLアクセスできるように設定しましょう。

``` 
bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib --with-cppflags=-I/usr/local/opt/openssl@1.1/includ\n'
bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib --with-cppflags=-I/usr/local/opt/openssl@1.1/includ"
``` 


## 2. MｙSQLをダウンロード
``` 
brew install mysql@5.7
echo 'export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"' >> ~/.zshrc
sudo chown -R `whoami`:admin /usr/local/bin

``` 

## 3. zshrcに保存
macOS Catalina から、Mac は zsh をデフォルトのログインシェルおよびインタラクティブシェルとして使うようになりました。こちらは、Catalina　以上の人の処理になります。

``` 
echo 'eval "$(rbenv init -)"' >> ~/.zshrc
source ~/.zshrc
 
``` 

## 4. readlineを導入
こちらを導入することでRailsがうまく動作します。
readlineとは、1度に1行ずつデータを読み取るためのインターフェースを提供します(Node: https://nodejs.org/api/readline.html )

``` 
brew install readline
brew link readline --force
``` 
## 5. bundle installを実行
で成功します！( sudoが必要できたら追加してください。)


# 最後に
3年ぶりのRails環境構築で少し苦労しました。
一回やっていると仕組みが固まっているから、スルスル書き始められました！
みなさんもよい開発ライフを〜
E資格　応用数学

# はじめに
本記事は、日本ディープラーニング協会のDeep Learning資格試験（E資格）の受験に必要な、協会認定の講座プログラムのひとつである[ラビットチャレンジ](https://ai999.careers/rabbit/)のレポート記事（応用数学編）となります。

# 線形代数
- スカラーとベクトル<br>
スカラーはいわゆる普通の数、ベクトルは「大きさ」と「向き」を持ち、スカラーのセットで表現される。

- 行列<br>
スカラーを表にしたもの、ベクトルを並べたもの。ベクトルの変換に利用される。<br>
行列の積は少々不思議な計算方法となっているが、これは連立方程式の研究から生まれたとのこと。

- 固有値と固有ベクトル<br>
ある行列Aに対して、以下のような式が成り立つような、特殊なベクトル$\vec{x}$と、右辺の係数λがある。
$$A\vec{x} = λ\vec{x}$$
行列Aとその特殊なベクトル$\vec{x}$の積は、ただのスカラーの数λとその特殊なベクトル$\vec{x}$との積と同じ値になる。
この特殊なベクトル$\vec{x}$とその係数λを、行列Aに対する固有ベクトル、固有値という。

- 固有値分解<br>
ある実数を正方形にならべて作られた行列A（Aは正方行列）が固有値と固有ベクトルを持つとする。この固有値を対角線上に並べた行列Λ（Λは対角行列：対角線上以外の成分は0）

```math
Λ = 
\begin{pmatrix}
λ_1 & \\
& λ_2 \\
& & \ddots
\end{pmatrix}
```
と、それに対応する固有ベクトルを並べた行列V（Vは正則行列：掛け合わせると単位行列になる）

```math
V = 
\begin{pmatrix}
\vec{v_1} & \vec{v_1} & \cdots
\end{pmatrix}
```
を用意した時、それらは
$$AV = VΛ$$
と関係付けられる。したがって
$$A = VΛV^{-1}$$
と変形できる。このように正方形の行列を3つの行列の積に変換することを固有値分解という。（固有値分解のメリットは後述。）

- 特異値分解<br>
固有値分解と似た分解手法に、特異値分解がある。特異値分解を述べるにあたり、固有値分解の制限に関して分かりやすく説明していた記事があったため紹介する。

>それは「Aが正方行列でないと適用できない」という制限です。この制限は結構強いです。なぜでしょう。それは正方形の行列は中々手に入らないからです。エクセルのデータが正方であることはほとんどないですよね。行と列の数が揃っているというのは結構珍しいのです。
参考：[分解すると見える世界 ー特異値分解ー](https://thinkit.co.jp/article/16884)

上記記事で述べられている通り、仕事をしていく中でエクセルでデータを扱うことは多々あるが、行数と列数が一致していることはあまりないなと感覚的に理解できた。<br>
さて、本題に戻るが、特異値分解とは以下のような特殊な単位ベクトルが存在する場合に、分解を行うことができるというものだ。
$$A = USV^{-1}$$
なお、Aは任意のm×n行列、U、Vはそれぞれm×m、n×nの直交行列、Sはm×nの対角行列。

- 固有値分解・特異値分解のメリット<br>
固有値分解・特異値分解を行った結果、ある行列Aは、固有値の数分の足し算で表現できることが分かった。つまり、元データから値の小さい固有値成分を取り除いていくことで、データ量を削減できる。これが分解のメリットだと推察する。

# 確率・統計
- 条件付き確率・ベイズの定理<br>
ある事象が与えられたもとでの確率を条件付き確率といい、以下のベイズの定理が成り立つ。

```math
P(A|B) = \frac{P(B|A)P(A)}{P(B)}
```

- 確率変数/確率分布/期待値<br>
確率変数は、事象と結び付けられた数値。確率分布は、事象の発生する確率の分布。 期待値は、その分布における確率変数の平均値または「ありえそうな値」を指す。

- 分散と共分散<br>
分散は、データの散らばり具合。共分散は、2つのデータ系統の傾向の違い。それぞれ以下の式で表せる。

```math
分散Var(f) = E((f_{(X=x)}-E_{(f)})^2) = E(f^2_{(X=x)}) - (E_{(f)})^2
```
```math
共分散Cov(f,g) = E((f_{(X=x)}-E_{(f)})(g_{(Y=y)}-E(g)) = E(fg) - E(f)E(g)
```
- 様々な確率分布<br>
ベルヌーイ分布やマルチヌーイ（カテゴリカル）分布などがある。

# 情報理論
自己情報量は、以下の式で表せる。対数の底が2のとき、単位はbit、対数の底がネイピア数のとき、単位はnat。

```math
I(x) = -log(P(x))
```
自己情報量の期待値をシャノンエントロピーという。また、同じ事象・確率変数における異なる確率分布の違いを表した式をKLダイバージェンス、その一部を取り出したものを交差エントロピーという。

# おわりに
はじめての投稿となります。記載や内容の誤り等ございましたらご指摘いただけますと幸いです。
Gitの概要　<基本のコマンド>

#Gitの基本的な概念

##Gitの構造

・Gitはワークツリー、ステージ、リポジトリの３つで成り立っている
→ワークツリーでは、自分のローカルPC上のファイルを編集するような物
→ステージトは、ワークツリーで編集などをしたファイルをリポジトリにあげる（コミット）する準備をする場所
→リポジトリとは、ステージにおいたファイルを置く場所
→つまり、ワークツリーとステージはあくまでも、ローカルの作業（個人のファイル）
→リポジトリーは、各個人のワークツリーとステージを統合するような場所

##Gitのデータ構造

・Gitは「圧縮」、「ツリー」、「コミット」、この３つのファイル
→まず、ワークツリーからステージの時にあげるファイルに対して一つの圧縮ファイルが作られる
→その後、コミットを行うと、ステージからリポジトリへと新たにファイルが追加される
（この時のファイルは、コミットを行なった時点での圧縮ファイル情報が含まれている）

##Gitのコマンド

1.git init
→このコマンドを使用することにより、ローカルリポジトリを作成することができる
→.gitのファイルが作成させれる（.gitなので隠しファイル)

2.git clone <リポジトリ名>
→リモートリポジトリに存在するファイルを、ローカルリポジトリへとコピーすることができる

3.git add <ファイル名、ディレクトリ名>
→ワークツリーからステージへと変更を追加することができる

4.git commit -m "<メッセージ>", git commit -v
→ステージに追加したファイルなどをリポジトリに登録する

5.git status
→ワークツリーとステージ間、ステージとリポジトリ間で変更があったファイルを表示することができる

6.git diff --staged
→git diff <ファイル名>はaddする前の変更差分を見ることができる
(ワークツリーとステージ間の差分を確認する時に使用する)
→--stageオプションを使用することでgit addした後の差分を見ることができる
(ステージとリポジトリ間の差分を確認する)

7.git log
→今までのコミットの履歴を確認することができる

8.git rm <ファイル名>
→ファイルを削除するコマンド
→ワークツリーからも自分のローカルリポジトリからも削除されてしまう
→もし、ローカルから消えるのが嫌なのであれば、ファイル名の前に --cachedのオプションをつける

9,git mv<前のファイル名><新ファイル名>
→ファイル名を変更する時に使用する

10,git remote add origin http::~
→originという名前で、指定したURLでリモートリポジトリ(Git Hub)にアップすることができる

11.git config (--global) alias. (a) (b)
→aにはエイリアス（別名）を入力して、bには本来の名前を入力することで、今後はエイリアスを入力するとそのコマンドを使用することができる
→globalオプションを使用することで、グローバルで使用することができるエイリアスにする

12.git checkout
→ワークツリーないの変更を取り消すことができる
（ステージと同じ状態にする）

13.git reset HEAD <ファイル名>
→ステージした追加した変更を取り消す
→ローカルそのものもファイルには影響を及ぼさない

14.git commit --amend
→直前にコミットした内容を修正することができる

15.git remote
→リモートリポジトリの名前が表示される
ITプロジェクトでなぜドキュメントを書くのか？

## ITプロジェクトでなぜドキュメントを書くのか？

ITプロジェクトでの発注者と受注者の関係は以下である。

**【発注者はお金を払って物を作ってもらう人、受注者はお金をもらって物を開発する人】**

その場合、発注者の意図を正しく理解でき、製造物が正しく動作するとした場合ドキュメントは不要となるはずである。
フリーランスが受注するケースなどはこれに該当すると思う。

ところが、開発の規模が大きくなったり、システム化する業務が複雑であったりする場合、口頭だけでやりたい事を伝えるのは困難となってくる。
また、口頭のみでやり取りした場合、発注者が伝えた通りの物ができているのかを確認する方法もなくなってしまう。
そこで、契約から納品までを円滑に進めるために合意形成をするため、合意形成をした証拠品としてドキュメントを作成することになったと考える。


## 合意形成

ITプロジェクトのドキュメンテーションについては、IPAによる[機能要件の合意形成ガイド](https://www.ipa.go.jp/sec/softwareengineering/reports/20100331.html
)というガイドラインが存在するが、2010年のもので少々古く読まれている方も少ないと思う。

また、手に馴染んでない細かいルールは実践できない事が多く、結局のところは属人的なルールが蔓延し、実際には会社に存在する過去のドキュメントをベースにプロジェクト毎で、およそ以下のドキュメントを作成することにしていると思う。

- 要件定義書
- 外部設計書
- 詳細設計書
- 試験項目書

※話を簡単にするためインフラや運用等は除外している


## 詳細設計書を省略

合意形成とその証拠品としてのドキュメントとした場合、外部設計を行う人間とプログラム製造を行う人間が同一人物の場合「詳細設計書」は不要となる。同一人物であれば合意形成は不要だからだ。

低予算、短納期の案件に対応するためには大幅なコストダウンを余儀なくされるため「外部設計と実装を出来る人間」がその様な案件に対応し、低予算で案件を受注する事が常態化してくる。

実は、自分が担当する工程以外の工程を学ぶ教育的側面として大きな役割を担っていたが、その点については考慮されず、[コモンズの悲劇](https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%A2%E3%83%B3%E3%82%BA%E3%81%AE%E6%82%B2%E5%8A%87)が発生してしまったと考察する。


## 上級SEとPG

ウォーターフォール開発と呼ばれていた頃には、**上級SEが設計**を行い、**PGが実装**を行っていた。
しかし、上記の様に詳細設計の工程を飛ばすと、**PGができる仕事がない**状態となる。

それまでは顧客の案件予算内でエンジニアの育成をできていたが、それができない状態となる。

予算が増えない限り、工程の数は増やせない。
むしろ予算は減る事はあっても増えることはない。
さて、どうするべきだろう？


## A1. オフショア

製造工程を安価に抑えて、詳細設計の工程を復活させる。
上級SEを多く抱えている企業であれば、**直近は**可能であろう。
新たな上級SEをどの様に育成するかが次の課題となると推察する。


## A2. ポイントを記載したドキュメント / レビュー

詳細に記載した詳細設計書をメンテナンスするのはコストにしかならない。
『設計者がポイントを記載、実装者が理解を記載するドキュメント』ならどうだろうか？
レビューして指摘することで設計手法を伝える事はできないだろうか？


## まとめ

抜けもれない手順書を与えると、与えられた側の人間は思考を停止する。思考する必要がないからだ。
設計ができる上級SEは、プログラムが上手いプログラマーではなく、問題を解決できる開発者だと思う。

思考して問題を解決できた事を確認できるドキュメント、すなわち **上級SE、問題解決できる開発者を育成するためのドキュメント**を作成するのがITプロジェクトのドキュメントではないかと考える。
シリアルコンソールケーブル

中古の電話機から取り出した部品と電話線とレベルコンバータでシリアルコンソールケーブル作ってみました。

![IMG_20210605_145929.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/f2e65911-86f6-18ce-21ad-d86036e1ec0f.jpeg)

部品はamazonで買った安い半田ごてセットの半田吸い取りで外しました。

スルーホール用の一本ずつのワイヤーは外れやすく、この部品はまとまっていて外れにくく良いです。半田付けはしてません。

電話線のワイヤーは半田付けには向いてないので、注意して扱わないと切れそうです。

D-SUBのコネクタはネジ(インチ #4-40)を外してあり、金属の枠が外れるので、穴のところを細い針金で結わえました。
PowerApps Microsoft Dataverse で、参照型つかわないほうがいいだなんてとんでもない！

とある記事で、参照型は使うべきじゃないっていうことが書いてあったので、急遽書きました。
結論いうと、参照型はとても有用なので、ぜひ使いましょう。

# とりあえず、テーブルを作ってみる。

記事に合わせてテーブルを作ってみます。
※こっちは会社にしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/94d068e6-3121-04b1-189f-78ef29ebc4e9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/d0b2a3a6-069b-0a15-0d78-6f12056fe7f4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/d07bb0fa-a8da-3b4c-605c-e6ee2f4d9a6b.png)


# アプリを作ってみる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/f81e4fff-2f6e-4096-9170-7cf5e660aa64.png)

## 問題のボタンを押したときの処理

記事に合わせて以下のように設定します。

```
Collect(社員,{苗字:TextInput1.Text,名前:TextInput1_1.Text,会社:Dropdown1.SelectedText.Value,保護者:TextInput2_1.Text}
```

でた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/c0a71036-2b5c-fb52-9db2-749a8086cee2.png)

# なんでこんなことなるの？

参照列に追加可能な DataEntity 型は、Lookupしないと取れません。
※だってデータ型が参照型(Lookup)なんだもん。

## 会社のLookup
この場合は、Dropdown1 で選択されていますので、以下の関数で取れます。

```
Dropdown1.Selected
```

## 保護者のLookup
保護者は、同一画面で新規登録していますので、登録した結果を変数に入れてあげることで取得することができます。
なので、こんな感じですね。

```
Set(ParentPostData,Collect(保護者,{苗字:TextInput1_2.Text,名前:TextInput1_3.Text,メールアドレス:TextInput2_1.Text}));
```

ただし、入れたデータはテーブル型となっているので、レコードを取得する必要があります。

```
Last(ParentPostData)
```


# ボタンに入れるべき処理はこんな感じ

```
Set(ParentPostData,Collect(保護者,{苗字:TextInput1_2.Text,名前:TextInput1_3.Text,メールアドレス:TextInput2_1.Text}));
Collect(社員,{苗字:TextInput1.Text,名前:TextInput1_1.Text,部署:TextInput2.Text,会社:Dropdown1.Selected,保護者:Last(ParentPostData)})
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/29c8d175-fd3c-02d3-45f3-63c39dea09e9.png)

これで、一応登録することができるようになります。


![2021-06-05_15h15_34.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269159/ced67fe9-cd73-aa0e-5350-4797406600ad.gif)
Jetson nanoをRemote Desktopでアクセスする

# 目的
JetbotでROS環境で使っていくのにモニターをつなぎたくないので、Macからアクセスできるようにする。

# 環境
- Host PC
    - Macbook air 2013

- Target
    - Jetson nano
    - Jetpack 4.4
    - Ubuntu 18.04

# 手順
### Jetson nano側の準備
#### IPアドレスの確認
Jetson nanoでterminalを開いて、ifconfigでJetson nanoのIPアドレスを確認。

#### TigerVNCのインストール
Jetson nanoでterminalを開いて、下記コマンドを実行。vncpasswdはパスワードを設定した後、view-only passwdをy/nで聞いてくるので、nを打ち込む。

```
sudo apt update
sudo apt install tigervnc-common tigervnc-standalone-server tigervnc-scraping-server
vncpasswd #接続用パスワード設定

x0vncserver -display :0 -passwordfile ~/.vnc/passwd
```
最期のコマンドでうまく行かない場合、以下を打ち込んでみる。Displayが1とあったので、上のコマンドでDisplayを1にするとVNCが起動できた。
```
env | grep DISPLAY
DISPLAY=:1

x0vncserver -display :１ -passwordfile ~/.vnc/passwd
```

###Macbook側の設定
まずVNC viewerを以下からDownloadしてインストール。
https://www.realvnc.com/en/connect/download/viewer/

VNC viewerを起動し、タブ上のnew connectionから設定画面を開き、VNC ServerにJetson nanoのIPアドレスを設定。
![screenshot_466.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1503757/bd3ee020-699b-c578-c29e-9d8d39c64e8b.jpeg)

パスワードを聞いてくるので、上で設定したvncのパスワードを打ち込むと、無事接続完了。
![screenshot_467.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1503757/f06dd691-7396-ca54-2212-2a3fe8d5c545.jpeg)

###起動時に自動設定
起動時に自動的に設定されるようにしてみる。

```
sudo vi /etc/systemd/system/x0vncserver.service
```
viを起動して、下記内容を記載。

```
[Unit]
Description=Remote desktop service (VNC)
After=syslog.target
After=network.target remote-fs.target nss-lookup.target
After=x11-common.service 

[Service]
Type=forking
User=xxxx
Group=xxxx
WorkingDirectory=/home/xxxx
ExecStart=/bin/sh -c 'sleep 10 && /usr/bin/x0vncserver -display :0  -rfbport 5900 -passwordfile /home/xxxx/.vnc/passwd &'

[Install]
WantedBy=multi-user.target
```

上記スクリプトで設定した内容の動作確認をしてみる。

```
sudo systemctl start x0vncserver.service
```
"vncserver failed to determine group credentials"というエラーが発生。。。GroupをUserと分けていたのかダメだったのか、変更するとうまくいった。

有効化して再起動。

```
sudo systemctl enable x0vncserver.service
sudo reboot yes
```
###解像度の設定
起動時にJetson nanoにモニターを繋げてないと、Remote DesktopでVGAで出力されてしまうので、下記ファイルを編集。

```
sudo vi /etc/X11/xorg.conf
```
viを起動して、下記内容を下に追記すると、VNCで解像度が変わってアクセスできた。

```
Section "Monitor"
   Identifier "DSI-0"
   Option    "Ignore"
EndSection

Section "Screen"
   Identifier    "Default Screen"
   Monitor        "Configured Monitor"
   Device        "Default Device"
   SubSection "Display"
       Depth    24
       Virtual 1280 800
   EndSubSection
EndSection
```
###キーボード
無事Remote Desktopで入れるようになったが、Macbookからのキーボード操作で、":"が入力できない。ブラウザ上でのURLのベタ打ちや、viで保存するときの":wq!"が入力できなくて不便。色々と調べたけど、有効打を見出せず。当面、viで保存するときは、大文字ZZで我慢するしかないか。。。

#参考
下記は非常に参考になりました。
https://qiita.com/iwatake2222/items/a3bd8d0527dec431ef0f
【Git】GitHubリポジトリの移行手順

GitHubリポジトリの移行手順について、調べた事を纏めます。

# 作業手順
<b>「--mirrorオプションで実施する方法」</b>と<b>「1つずつリポジトリを移行後にpushする方法」</b>
の2つに分別できるかと思います。
※移行前と移行後のgitに関しては、本書では「移行前.git」と「移行後.git」という形で表現します。


## --mirrorオプションで実施する方法
以下の--mirrorオプションを付ければ、それで完結する模様。
これがおススメ。

```
# git clone --mirror 移行前.git
# cd 移行前ディレクトリ
# git push --mirror 移行後.git
```

## 1つずつリポジトリを移行後にpushする方法
移行前リポジトリをfetch（ダウンロード）して、１つずつ移行していくといった形です。




① 移行後のgitをcloneしておく。
 
```
# git clone 移行後.git
# cd 移行後ディレクトリ
```

② 移行前リポジトリをremoteとして追加する。
 
```
# git remote add ikoumae_origin 移行前.git
# git remote -v
ikoumae_origin 移行前.git (fetch)
ikoumae_origin 移行前.git (push)
origin 移行後.git (fetch)
origin 移行後.git (push)
```

③ 移行前リポジトリをfetchする。

```
# git fetch ikoumae_origin
```

④ 移行前リポジトリから対象ブランチをチェックアウトする。
（※ここでは例として、"feature/test"というブランチ名を取る。

```
# git checkout ikoumae_origin/feature/test
```

⑤ ローカルブランチ作成

```
# git branch feature/test
```

⑥ 移行後ブランチにpushする

```
# git push origin feature/test
```

※※ 後はリポジトリの数分、上記の作業を繰り返して完了。 ※※

# 終わり
gitの移行手順なんて、ググれば沢山出てくるような情報ですが、
普段作業をしていると、単純なgitのコマンドを忘れたりする事もあるので、
それらも含めて、備忘録として活用してもらえればいいかなと思います。
Googleデータポータルの知っておくて便利な使用方法


#Googleデータポータルの概要
![名称未設定のデザイン.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1180499/9db83818-f7f6-4e9a-8f4f-b49b18c7d1ec.jpeg)


##概要
Googleにより提供されるBI（ビジネスインテリジェンス）ツール
- 無料で使用可能である
- Googleアカウントが必要である


##データ連携
データポータルにはGoogle AnalyticsとGoogle Search Consoleのコネクタだけではなく、Bigqueryやスプレッドシート、CSVデータ等様々連携可能です。


##使用方法
大きな流れ
データソースを接続して準備
→ INT型,STRING型など変換が必要な内容があれば変換を実施
→ 複数のデータソースがあり結合させる
ここまでできれば、あとは「ディメンション」と「メジャー」を指定すれば様々なグラフが作成可能

###データ接続
データを追加 > 各データソースが羅列されているので選択
※YouTubeデータ,CSV,BIgquery,Googleアナリティクスなど様々なデータへコネクト可能

###型変換
それぞれを使用したいように型変換する

上部リソース > 追加済データソースの管理 > 対象データソースにて編集


###複数データの統合
混合データの作成方法
混合データを管理 > 新規の混合データ作成　> キー（各データをつなげる役割）データを指定

参考資料：https://dekiru.net/article/19570/

##まとめ
＜データポータルの資料は少ない＞
教材本には実際のグラフを作成する方法までは記載されていない。
個人の見解として、よりビジュアライズした視差を見たいのであればtableauを推奨する。

ただし有料である。

この部分に大きな違いがある。

コスパよく同じようなグラフを毎回作成するのであれば
必要データのグラフを瞬時に把握できるダッシュボードを開発するという点で
データポータルは便利に活用できる。

ダッシュボード構築が進めば
データアナリスト/マーケター/営業マンが分析の為に必要なデータを取得して提供する
データエンジニアの「データ集計係」が不要となる。
完全に不要となることはないだろうが、間違いなく業務量は削減する。

比較的、駆け出しや若手のデータエンジニアが集計係を務めることも多く、当方も経験した役割である。

当時、自らの集計業務をダッシュボード化して「自らの業務が不要になる」ということを肌で感じ恐怖を覚えた。

ただ、「プロとは仕事を手放せること」なのではないだろうかと考察した。

自らが存在しなくても上手く回るようなシステムを策定することが
ITの最大の「仕事」である。

より効率化した業務の推進や新たな業務に「人員」を割くことができる。

ITに携わる者として恐れず実践していきたい。
plunkerでvue その48

#概要

plunkerでvueやってみた。
練習問題、やってみた。

#練習問題

chatを実装せよ。

#参考にしたページ

https://qiita.com/donraku/items/fa03f0bfed30db6c656f

#バックエンド

enebular

#サンプルコード

```
const MSG_START = "start";

new Vue({
  el: "#app",
  components: {},
  data: () => ({
    name: "名無し",
    message: "おはようございます。",
    connection: null,
    messages: [],
    ws_key: 0,
    avatar_color: "",
  }),
  created: function() {
    this.connection = new WebSocket("wss://ohiapp0.herokuapp.com/pub");
    let random_color = "#";
    for (var i = 0; i < 6; i++) 
    {
      random_color += "0123456789abcdef"[(16 * Math.random()) | 0];
    }
    this.avatar_color = random_color;
    const vm = this;
    this.connection.onopen = function() {
      vm.sendMessageData(vm.avatar_color, MSG_START, vm.name);
    };
    this.connection.onmessage = function(event) {
      const msg_json = JSON.parse(event.data);
      vm.messages.push({
        ws_key: 1,
        avatar_color: msg_json.avatar_color,
        message: msg_json.message,
        name: msg_json.name,
      });
    };
  },
  updated: function() {
    this.scrollToEnd();
  },
  methods: {
    send_onClick: function() {
      if (this.message == "") 
        return;
      this.sendMessageData(this.avatar_color, this.message, this.name);
      this.message = "";
    },
    sendMessageData: function(avatar_color, message, name) {
      const msg_json = {
        avatar_color,
        message,
        name,
      };
      this.connection.send(JSON.stringify(msg_json));
    },
    scrollToEnd() {
      this.$nextTick(() => {
        const chatLog = this.$refs.scrollTarget;
        if (!chatLog) 
          return;
        chatLog.scrollTop = chatLog.scrollHeight;
      });
    },
  },
})




```

#成果物

https://embed.plnkr.co/plunk/oTdz54hBrOkW5hu7

以上。
M1 macでHeroku CLIをインストールする方法

#問題
M1 macでHeroku CLIをインストールしようとすると

```ターミナル
Error: Cannot install in Homebrew on ARM processor in Intel default prefix (/usr/local)!
Please create a new installation in /opt/homebrew using one of the
"Alternative Installs" from:
  https://docs.brew.sh/Installation
You can migrate your previously installed formula list with:
  brew bundle dump
```
とエラーが出る。
おそらくhomebrewを、localディレクトリではなくてoptディレクトリにインストールするように言われている。

#解決
まずはoptディレクトリの中を確認してみる。

```ターミナル
$ ls /opt
homebrew
```
どうやら、optディレクトリにはhomebrewはインストールされていたので、パスが通っていないことが原因だと考えられる。
パスを通すために、~/.zshrcファイルに以下のコードを追加する。

```~/.zshrc
export PATH=/opt/homebrew/bin:/usr/local/bin:$PATH
```
最後に

```ターミナル
$ brew tap heroku/brew && brew install heroku
```
を入力してインストールできました！

#参考記事
https://shiro-changelife.com/error-cannot-install-in-homebrew/

もし、optディレクトリにhomebrewがインストールされていなかった場合は下記を参考にしてみてください！
https://www.teamxeppet.com/macbook-m1-homebrew-install/

#最後に
初心者ながら、自分がわかる範囲で記事を書かせていただきました。
間違っているところがあれば、ご指摘いただきたいです。
皆さんの参考になれば、嬉しいです。
VS Code 1.46 の新機能 - リストとツリーのスクロールをスムーズにする

https://code.visualstudio.com/updates/v1_46#_smooth-scrolling-for-lists-and-trees

Windowsのマウスホイールなどでリストやツリーをスクロールする際にスクロールをスムーズにする機能が追加された。

設定の **Workbench > List: Smooth Scrolling** をオンにするとスムーズになる。

![smooth_scroll.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181011/a5f6921c-9137-ecdd-bcdf-c8a325ecdafe.gif)

アニメGIFだとイマイチ違いが分かりづらいが、実際にやってみるともうちょっと違って見える。
AccessVBA　大量データ処理時のパフォーマンス改善

某システムのデータをSQL-Serverへ移行するにあたり、数万件レベルのデータをAccessで加工して移行データとする案件で。
よくあるインデックス付与etc.に加え、パフォーマンスに大きな効果のあった施策について記します。

***
**1. アーリー・バインディング**

外部ExcelファイルをAccessのテーブルに取り込むにあたり、インポート機能を使わずVBAでデータ加工しながら取り込もうとするとき、よくネットなどに記されているのは

```VB
　　Dim xls As Object
　　Set xls = CreateObject("Excel.Application")
　　・・・
```
という、いわゆる**「レイト・バインディング」**。
ただ、該当処理で約1.2万件のデータを取り込むのに、さすがに53分はかかり過ぎやと業を煮やして！:pouting_cat:

いろいろ調べた結果、
・Excelアプリケーションのオブジェクトを、VBA「参照設定」に設定しておく
・VBA内では、直接設定したExcelアプリケーションのオブジェクトを参照する
という方法（**アーリー・バインディング**）で処理効率が向上するそうで。
※図はあくまでイメージであり、実際の画面とは異なります![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170624/48959f35-cfd6-53cd-8137-4d3c88b8c072.png)

```VB
　　Dim xls As Excel.Application
　　Set xls = New Excel.Application
　　・・・
```
これと、後述するWith記法の採用とで、11,575件のExcelデータ取り込み処理が
　**53分　⇒　16.5分**
へと大幅改善しました（約220%のパフォーマンス向上）。
***
**2. 参照先オブジェクトのオプション指定**

上記1.で指定したExcelアプリケーションオブジェクトについて、
・画面表示：なし
・再計算：手動
・画面更新：なし
という設定を加えると、さらに処理効率はアップするそうで。
（ExcelVBAを単体で動かす時も同じらしいですが）

```VB
　　Dim xls As Excel.Application
　　Set xls = New Excel.Application
　　・・・
　　xls.Visible = False　　　　　　　　　　　　' 画面表示：なし
　　xls.Calculation = xlCalculationManual 　' 計算方法：手動
　　xls.ScreenUpdating = false　　　　　　　　' 画面表示：なし
　　・・・
```
このケースでは、データ読み込みに当たり、
　**4,232件：6分18秒　⇒　4分19秒**（約46%）
　**24,301件：40秒　⇒　26秒**（約54%)
と、それぞれ大幅なパフォーマンス向上が実現できました。
***
**3. With記法**

いちおう知ってはいましたが、それまでせいぜい数千件レベルを扱うアプリしか作ってこなかった立場としては、そこまで大切やとは思ってませんで・・・
ともあれ、処理相手（＝この場合、Excelのワークシート）がデカければデカいほど、With記法やと処理効率が良くなるらしいです。

```VB
　　Dim xls As Excel.Application
　　Set xls = New Excel.Application
　　・・・
　　With xls
　　　　.Visible = False　　　　　　　　　　　　' 画面表示：なし
　　　　.Calculation = xlCalculationManual 　' 計算方法：手動
　　　　.ScreenUpdating = false　　　　　　　　' 画面表示：なし
　　・・・
　　　　.Close
　　End With
```
ArduinoのSerialモニタから２桁以上の数値を受け取るテンプレート

#概要
タイトル通り
あると便利だが、ネットに便利なテンプレートが見当たらなかったので

参考：https://qiita.com/hikoalpha/items/633c677f5cd12d536dcc

#使用上の注意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405484/0fec7791-29b9-dd05-315e-af6744875010.png)

において改行を”LF"のみにしてください。
LFは10進で"10"です。

注意：4桁以上になるとpow関数の誤差が大きくなるので
int(pow(10,3))=999

#コード

```C
byte NUMs[100];    //データ保存用
int digit_inv=0;   //保存桁番号逆順

void setup() {
  Serial.begin(250000);
  
}

void loop() {
  
  if(Serial.available()>0){

    byte data = Serial.read();
    
    if(data != 10){                    //改行で分岐
      if(data >=48 and data<=57){      //受け取ったのが整数なら保存
        digit_inv++;
        NUMs[digit_inv]=data-48;
      }
    }else{
      //整数化
      int hoge = 0;
      int digit_all = digit_inv;
      while(true){
        hoge += NUMs[digit_inv]*int(pow(10,digit_all - digit_inv));
        digit_inv --;
        if(digit_inv < 0){
          break;
        }
      }


      //hoge に結果が保管されている
      Serial.println(hoge);
    }
  }
```

追記、一応動きますが
digit_invの動きがちょっとおかしいかもしれません
NUMs[０]使ってません

#サーボを使うのに使用した例
数値入力だけでなく、
"a"で+10
"s"で+1
"d"で-1
"f"で-10
の機能を追加した結果


```C
#include <Servo.h>
Servo myservo;

#define sw_s A0
#define servo 10

byte NUMs[100];    //データ保存用
int digit_inv = 0; //保存桁番号逆順
int result = 0;
boolean shortcut_flag = false;  //ショートカットキーを使った後ならLFを無視する

int angle;

void setup() {
  pinMode(sw_s, INPUT);
  pinMode(servo, OUTPUT);
  myservo.attach(servo);
  Serial.begin(250000);
  angle = 90;
}

void loop() {

  if (Serial.available() > 0) {

    byte data = Serial.read();

    if (data != 10) {                  //改行で分岐
      if (data >= 48 and data <= 57) { //受け取ったのが整数なら保存
        NUMs[digit_inv] = data - 48;
        digit_inv++;
        shortcut_flag = false;

      } else if (data == 97) {          // a
        result += 10;
        shortcut_flag = true;
        
      } else if (data == 115) {          // s
        result += 1;
        shortcut_flag = true;
        
      } else if (data == 100) {          // d
        result -= 1;
        shortcut_flag = true;
        
      } else if (data == 102) {          // f
        result -= 10;
        shortcut_flag = true;
      }
    } else {
      if (shortcut_flag == false) {
        //整数化
        int hoge = 0;
        digit_inv --;
        int digit_all = digit_inv ;
        while (true) {
          hoge += NUMs[digit_inv] * int(pow(10, digit_all - digit_inv));
          digit_inv --;
          if (digit_inv < 0) {
            digit_inv = 0;
            break;
          }
        }
        result = hoge;

      } else {
        digit_inv = 0;                  //とりあえず初期化
      }
    }
  }

  angle = result;
  if (angle < 0) {
    angle = 0;
  } else if (angle > 180) {
    angle = 180;
  }
  myservo.write(angle);
  Serial.print(result);
  Serial.print(" ");
  Serial.println(angle);
  delay(50);

}

```
serveしたときの「http://localhost:5000」と「http://192.168.1.37:5000」は同じではない。

パソコンのカメラ映像を表示するJavaScriptをChromeで表示させるとConsoleにこんなエラーが出ました。
![0605-thermo-1424.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1289676/96dc333c-5a32-9ea2-59db-c2bcac2bcf5e.png)
で、調べてみると以下とのこと。

https://dianxnao.com/getusermedia-is-not-a-function/



>Chromeなどのブラウザは、内蔵マイクによる録音や録画などのプログラムをブラウザ上で動作させる際は、SSL化されたサイトでないとパソコンやスマホに内蔵されたカメラやマイク等にアクセスできない仕様となっている


ふむ。じゃあSSLしたサイトに乗せて・・・いや、作ってる途中までは問題なくカメラの映像取ってきた動作してましたやん？

ここで怪しいなと思ったのがこれ。serveしたときのURL。
![0605-thermo-1426.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1289676/746b2e39-35c1-0bd2-7b8e-eef97af91990.png)

特に違いを意識してなかったのですが、「http://localhost:5000 」だとカメラ映像は問題なく映って、**「http://192.168.1.37:5000 」だと上記のエラーが出てカメラ映像が出ませんでした。** 

「Local」と「On YourNetwork」と書かれているので、後者はネットワーク越し扱いで上述のChromeのSSL必須条件でエラーになると推測。

こういうのにハマるのは初心者だけかもしれませんが、お気をつけください・・・。
JavaScript 半角数字が入力されたことを正規表現で確認


## したいこと
入力された値がすべて半角数字であることを、
正規表現を使って確認したい。

## 結論
数値である入力値を一度文字列に変換し、match()で比較する。

## 以下は失敗例と成功例

### 使用する値

半角数字のみであることを確認する正規表現：`/^\d+$/`　
　（行頭から行末まで半角数字のみであるということ）


### 1. 失敗1 正規表現はイコールでの比較ができない。

```.javascript
// 比較する関数（入力値が半角数字である場合1, それ以外の場合は0を返す）
function sample(value){
    if(value == /^\d+$/){return 1}else{return 0}
}

// `1234`を入力してチェック
sample(1234)
```

入力値は半角数字のみだが、返ってくる値は0。
一致しているとみなされていない。


### 2. 失敗2 数値はmatch()で比較することができない

```.javascript
// 比較する関数（入力値が半角数字である場合1, それ以外の場合は0を返す）
function sample(value){
    if(value.match(/^\d+$/)){return 1}else{return 0}
}

// `1234`を入力してチェック
sample(1234)
```

`Uncaught TypeError: value.match is not a function`というエラーが発生。
※今回の入力値は数値なのでエラーが出たが、入力値が文字列の場合はこの書き方でOK。


### 3. 成功　数値は文字列に変換してからmatchで比較する

```.javascript
// 比較する関数（入力値が半角数字である場合1, それ以外の場合は0を返す）
function sample(value){
    if(String(value).match(/^\d+$/)){return 1}else{return 0}
}

// `1234`を入力してチェック
sample(1234)
```

返ってくる値は1。比較ができた。
three.jsで隕石を飛ばしてみる

# 概要

three.jsで隕石（っぽい球体）が飛んでいくところを表現してみました。

# 隕石の簡単な飛ばし方

簡単なベクトルの計算で隕石を飛ばせます。ベクトルの計算もthree.jsが用意してくれているので非常に楽です。

## 手順1

隕石のstart位置とend位置を決めます。（画像はthree.jsの空間を真上から見下ろした図になります。）

```javascript
// 隕石の開始位置
var startMeteorVector = new THREE.Vector3(-100, 500, -9000);
// 隕石の終了位置
var endMeteorVector = new THREE.Vector3(250, -400, 10000);
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305269/2cc778ac-abc4-9745-58ef-51de7e8c1df4.png" width=60%>

## 手順2
隕石の開始位置と終了位置から隕石の軌道を求めます。

```javascript
// 隕石の軌道ベクトル
var meteorVector = endMeteorVector.sub(startMeteorVector);
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305269/2c3283da-3e02-6ab2-06ee-b1edf403e6b6.png" width=60%>!


## 手順3
隕石の移動単位（単位ベクトル）を求めます。

```javascript
  // 隕石移動の基本となる単位ベクトル
  var unitMeteorVector = meteorVector.normalize();
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/305269/bb205ed6-7511-4cef-f66b-5e71ffac4dbc.png" width=60%>

## 手順4
単位ベクトルだと移動が遅すぎるので、隕石が高速で飛んでくるように単位ベクトルを適度にスカラー倍します。

```javascript
// 隕石の速度
var fastMeteorVector = unitMeteorVector.clone().multiplyScalar(200);
var slowMeteorVector = unitMeteorVector.clone().multiplyScalar(1);
```

## 手順5

算出した移動速度を毎フレームごとに加算します。

```javascript
meteor.position.x += fastMeteorVector.x;
meteor.position.y += fastMeteorVector.y;
meteor.position.z += fastMeteorVector.z;
```


# 隕石が飛んでくる動作のサンプル

遠くの方に見えている小さい黒い丸が隕石です。画面のどこかをクリックしたら隕石が高速で飛んできます。小技として、隕石がカメラの周辺に近づいたら一瞬動きがスローモーションになるようにしています。

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="tosizo" data-slug-hash="XWMzJEz" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="three.js meteor">
  <span>See the Pen <a href="https://codepen.io/tosizo/pen/XWMzJEz">
  three.js meteor</a> by tosi (<a href="https://codepen.io/tosizo">@tosizo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
AWS上でのアプリログ・メトリクスの外部サービス連携について

アプリの監視について、調査する機会があったので備忘録としてまとめます。

### コンテナアプリの監視について
例えば、ECS上で稼働するアプリケーションの場合、監視用エージェントをサイドカーで同梱して、
外部サービスにログ・メトリクスを連携することが多いと思います。

サイドカーパターンを採用する理由としては以下などがあるかと思います。
・メインコンテナに優先的にリソースを割り当て、低レイテンシで応答させることができる
・ログのルーティング設定を変更する際にアプリに手を加える必要がなくなる

この時、同梱した監視用エージェントが頻繁に外部サービスにログ・メトリクスを送信していると、
リソースを食いつぶしてしまって、メインの機能に影響が出る可能性があります。
そのため、多くの場合、アプリコンテナから送信されたログ・メトリクスをエージェントが
バッファリングしてまとめて外部サービスに送信するといった手法をとります。

例えば、Datadogを使用する場合は、[Datadogが提供するコンテナイメージ](https://docs.datadoghq.com/ja/agent/docker/?tab=)を利用することで
手軽にコンテナ監視を実現することができます。

![0605.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684883/613f6a47-e308-ce02-316c-a3a2c855df64.png)


### Lambdaの監視について
Lambdaの場合はECSのように、実行環境に好きなコンテナを同梱することができません。Lambdaの場合、
Lambda Extensionsを用いるのがよいと考えられます。Lambda Extensionsを用いることで
関数とは別のプロセスとしてモニタリング用エージェントなどの配置などが可能になります。
Lambda Extensionsについては[こちらの記事](https://dev.classmethod.jp/articles/lambda-extensions/)が非常に分かりやすく参考になりました。

例えば、Datadogの場合、[Datadog Lambda 拡張機能](https://docs.datadoghq.com/ja/serverless/datadog_lambda_library/extension/)というものが提供されています。
これをアプリが動くLambdaに対して、Lambdaレイヤーとして追加することで
関数実行中のカスタムメトリクスおよびログの同期的送信が可能になります。

なおもう一つ似たものとして[Datadog Lambdaライブラリ](https://docs.datadoghq.com/ja/serverless/datadog_lambda_library/)がありますが、
こちらはライブラリとしてプログラムの中にインポートすることで、カスタムメトリクスの送信を
可能にするもので、ログの送信には対応していないようです。
現状、ログの送信に対応しているDatadog Lambda 拡張機能の方が使い勝手が良さそうですね。
Googleアドセンスをトップページに導入する際のサイトスピード改善方法

自ブログにgoogleアドセンスを使う際、どうしてもサイトスピードが低下する問題があった。
しかし、もろもろ調べた結果、遅延読込機能を使うと、スピードが改善されることが分かった。

自ブログの記事にて備忘録用として手順をまとめた。

参考記事→https://kairi-life-blog.com/adsense-lazyload/
VS Code 1.46 の新機能 - サイドバー・パネルのビューのレイアウト変更機能

https://code.visualstudio.com/updates/v1_46#_flexible-layout

サイドバーやパネルにあるビューをドラッグ＆ドロップで移動してレイアウト変更できるようになった。
コマンド **表示: ビューの移動(View: Move View)** を使っても移動できる。
元に戻すにはコマンド **表示: ビューの位置をリセットする(View: Reset View Locations)** を使用する。

![move_view.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/181011/a7c3cad3-4695-5953-70d7-0df24ce29821.gif)

サイドバー←→パネル間だけではなく、サイドバー内でのビューのレイアウト変更もでき、よく使うビューを独立したアイコンにしたり、ビューのグループ構成を変更したりできる。

自分の使いやすいビュー配置にすることで作業効率が上がりそう。
スケーラビリティという幻想・ソフトウェア開発はスケールしない

# この文章で言いたいこと
この文章では**ソフトウェア開発組織のスケーラビリティを「ソフトウェア開発組織メンバを増やせる」と定義**する。また**ソフトウェア開発組織とは企業体のことではなく、「あるプロジェクト、プロダクトに関係する組織」と定義**づける。

**結論から言うとソフトウェア開発組織はスケールしない**。ソフトウェア開発組織をスケールさせるという発想は幻想である。あなたはソフトウェア開発組織はスケールしないことを前提に計画を立てる必要がある。

# なぜスケールさせる必要があるのか
例えば経営者の構想、例えば他社が追従できない高機能などで大規模なソフトウェアを開発をする動機があるから。**大規模なソフトウェアを開発するには大規模なソフトウェア開発組織が必要**となり、それにはソフトウェア開発組織をスケールさせる必要がある。

まーこの時点で何でそんな大規模なソフトウェアを開発しないといけないの？という根源的な疑問はあるものの、会社の偉い人がやりたくてやることなので仕方ない。

ここで問題なのは**ソフトウェア開発組織のスケーラビリティは指数関数である**こと。2倍の規模のソフトウェア開発をする場合、かかるリソースの量は2倍以上になる。これがソフトウェア開発の本質であり、ソフトウェア開発組織のスケーラビリティと大きな関係がある。（察しのいい人はこの時点で何が言いたいかわかるよね？）

# リソースという限界
ソフトウェア開発組織をスケールさせる際に限界となるのはリソースの問題である。スケーラビリティは指数関数で効いてくるため、簡単にリソースの限界に到達する。

一般的な企業でよくあるのはプロジェクトの予算の枯渇だろう。開発組織をスケールさせる形で大規模なソフトウェア開発をしようとすれば、システムの規模に対して指数関数で予算が増えていく。このような状況では簡単に予算が枯渇するのはわかりきっているだろう。ただ実は問題なのは次に上げる事例の限界の到達の仕方である。

2019年7月、みずほ銀行の新しい勘定系システムの「MINORI」が稼働された。開発期間20年、総工数35万人月、総工費4000億円の世界最大のプロジェクトである。**このプロジェクトの歴史的快挙は、人類のソフトウェア開発のスケーラビリティの物理的限界に到達したことである**。断言してもよいがこれ以上大きな開発組織のソフトウェア開発は不可能であり、今後も現れない。現れたとしても指数関数で規模が大きなものはないだろう。

みずほ銀行の「MINORI」が示したのは、これ以上大きくしようとしても人類のエンジニア人口の限界があるため、これ以上規模が大きくできないデッドラインがあるということである。総工費4000億円を10兆円にしたところでスケールしない。

「MINORI」の場合は最終的に集める開発人員の質は目をつぶったと考えられるが、人類で流通しているエンジニアのリソースには意外と低い限界があり、特にモダンな開発がしたい場合については、その何十分の一程度しかエンジニアはいない。たとえ大企業でも先進的な技術が扱えるエンジニアは思ったほどとれないだろう。これはソフトウェアエンジニアの能力が適正に強力に依存するため、人類の何％がソフトウェア開発できるかは最初から決まっているためである。

**誰にとっても優秀な開発チームはたくさん作れない、これが現実である**。

札束で殴れば解決するという甘い考えは捨て、保有するリソースで指数関数と戦わなければならないのがソフトウェア開発である。指数関数との戦いには資本の大小は関係がない。これらのスケーラビリティの限界は小資本には関係ないと思われがちだが、指数関数の世界なので**小資本もこれらのスケーラビリティの限界とは隣り合わせ**である（指数関数では予算が4000億円なのと100億円なのはそれほど大きな差ではない）。

# スケールが不要な世界
ソフトウェア開発組織がスケールしないという現実があるなら、ソフトウェア開発の大企業は存在しない、またはスケールできずに崩壊状態であると考えられるが、それも事実ではない。ソフトウェア開発の大企業の中でもひとつのプロダクト、サブプロダクトのサイズには限界があり、それは「**分割統治**」されている。

いわゆるGAFAであっても「MINORI」の事案で示されたソフトウェア開発のスケールの限界の壁をこえたプロダクトはないはずである。企業の開発するソフトウェアは単独では適正なサイズに収め、分割する。大規模なソフトウェア開発は諦める。これが認めないといけない現実である。

都市銀行の勘定系システムと双璧をなす大規模ソフトウェア開発と言えば「車載ソフトウェア」である。トヨタのレクサスだと車載ソフトウェアの規模は「MINORI」と同規模の1億SLOC（ソースコードの行数）である。ミッションクリティカル性についても差はない。それでも恐らくトヨタはレクサスのソフトウェア開発に4000億円もかけていないだろう（そんなことしたら倒産する）。これだけ巨大なソフトウェアにもかわわらずうまくいっているのは車載システムが100～150個と言われるECUに分割され、分割統治されているからである。

とはいえ車載ソフトウェアが「MINORI」と同規模の1億SLOCというのはマジックナンバーになっており、ここが車載ソフトウェアも限界だと思われる。これ以上の大規模化は不可能と判断し、新しいアーキテクチャに移行、規模を縮小する必要があると思われる。

# 余計な心配はするな
人海戦術が発達してるソフトウェア開発の現場では「このやり方ではソフトウェア開発組織がスケールしない」という発想の人が多いように見受けられるが、余計な心配なのでしなくてよい。一番ベストなやり方をすれば良い。

**それより重要なのはソフトウェア開発組織がスケールしないことを前提に、そんな大規模なソフトウェア開発を最初から考えないことだ**。

もともとソフトウェア開発組織はスケールしないのだ。
既存のプロジェクトにBootstrap5を導入する手順

## 環境

- Ruby 2.6.3
- Rails 6.0.3
- MacOS 11.2.3

## 自分の環境で動作した手順

[https://medium.com/nerd-for-tech/rails-6-bootstrap-5-3492b7c0a626](https://medium.com/nerd-for-tech/rails-6-bootstrap-5-3492b7c0a626)

## 自分の環境で動作しなかった手順

私の環境で動作しなかっただけかもしれません。

[https://dev.to/yarotheslav/install-bootstrap-5-with-ruby-on-rails-6-replace-bootstrap-4-2bf9](https://dev.to/yarotheslav/install-bootstrap-5-with-ruby-on-rails-6-replace-bootstrap-4-2bf9)

[https://www.srockstyle.com/develop/programming/ruby/3905/](https://www.srockstyle.com/develop/programming/ruby/3905/)

[https://qiita.com/Ekkunlab/items/940be50230390748309b](https://qiita.com/Ekkunlab/items/940be50230390748309b)

## この投稿の意図

他記事を紹介するだけの投稿になってしまいましたが、動作させるために参考する手順の判断が難しく時間がかかってしまったため、同じように悩んでいる方のために投稿させていただきました。
FastAPI: GET の引数の処理

FastAPI で GET の引数の受け取り方です。

## サーバープログラム

```py:get01.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/sum/")
async def create_item(aa: float = 0.0,bb: float = 0.0):
	rvalue = {}
	rvalue["wa"] = aa + bb
	return rvalue

@app.get("/diff/")
async def create_item(aa: float = 0.0,bb: float = 0.0):
	rvalue = {}
	rvalue["sa"] = aa - bb
	return rvalue
```

## サーバーの起動

```bash
uvicorn get01:app --reload
```

## クライアントでアクセス

```text
$ http http://127.0.0.1:8000/sum/ aa==12.1 bb==34.5
HTTP/1.1 200 OK
content-length: 11
content-type: application/json
date: Sat, 05 Jun 2021 05:06:31 GMT
server: uvicorn

{
    "wa": 46.6
}
```

```text
$ http http://127.0.0.1:8000/diff/ aa==12.1 bb==34.5
HTTP/1.1 200 OK
content-length: 12
content-type: application/json
date: Sat, 05 Jun 2021 05:06:50 GMT
server: uvicorn

{
    "sa": -22.4
}
```

## 確認したバージョン

```text
$ python
Python 3.12.7 (main, Feb  4 2025, 14:46:03) [GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import fastapi
>>> fastapi.__version__
'0.110.3'
```
ヘッドホン・ハック編


ブランド・ヘッドホンなど
もはやマネタイするほどの性能なのかどうかもわからないくらいなレベルである

ヘッドホンのドライバが壊れることは、分解したり変なことをしない限り
ほぼないような気がする。
基本変えかえるタイミングは、たぶん
1 筐体の破損
2 ケーブルの断線
上記２つだろうと思われる。

とくに筐体の破損が８０％を占めるのではないだろうか
お高いウッズ筐体も、ヒビが入ったり、パッカーンと割れたりと
お高い割には、はやすぎないか？というレベル。

まだ全然使えるドライバもいっしょにゴミ箱にとか
ほんと裕福層はちがいますね。

ケーブル断線なんて、半田にぎり、ものの３分もしないうちに修復するのに
それも、みんなしないで捨てたりと。

高級だからといって、強靭にできているかというと、それもなく。
ほんとに、どんな殿様商売だぁ〜と言いたくなるレベルのときも。

と、そんなあるとき
筐体とかめっちゃ頑丈なのがあーるではないか？とおもいついた。

作業用イナーパフである。
外使用なで、水分、ほこりさらには衝撃　さまざまな耐久性をもつ
そして、かなりおやすい。。

高級ヘッドホンへの挑戦状みたいなのりで
現在、イナーパフに　以前高級ヘッドホンのなかに収まっていたドライバを
組み込み、おきまりのホットボンドでとめ〜の。

オープンヘッドの場合は、ドリルで数箇所穴を開けたりして。

かなり、再利用可したような気分です。
Dockerとは何なのか？それについて学びつつ、学んでみる。その1

現場でDockerを使う現場で作業したことはあるが仕組みが曖昧で、完全に理解したわけではないので参考書を読みつつ、初心に戻り、まとめてみることにしました。

<h2>本来のシステムや機能の仕組み</h2>
本来、システムや機能は、以下のようにサーバー内にいろんなフレームワークだったり、様々なプログラムやソフトウェアが存在していて、動いています。

![スクリーンショット 2021-06-05 12.39.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/bba91060-0fe5-eeae-f705-254506fa0bb0.png)

そして、それらはそれらを動かすための実行環境だったり、他のプログラムを元に動いていたりすることがあるのです。

![Apache MySQL Nuxt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/de445ccf-1af3-52aa-0119-bab150ffc3c1.png)

また、システムやソフトウェアは共通の実行環境だったり、ライブラリを使用していることだって少なくありません。
そして各々のシステムが作動するversionが決まっていることもあり、共通のプログラムがそれに対応していないと、一部のシステムが動かなくなってしまいます。

![Apache MySQL Nuxt (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/69f35bee-b278-a6e1-7c64-739a4a351fdb.png)

<h2>Dockerは一つのサーバーに複数の実行環境を構築するもの</h2>
こういった問題を解決するものとして、Dockerというものがあります。

Dockerとは、サーバー内の様々なシステムやプログラムの実行環境をシステム・プログラムごとに作成できるシステムです。

つまり、一つのサーバーに
○Laravelなら、PHPの実行環境
○Nuxtなら、Nodeの実行環境
を構築することができ、システムにあった環境を用意することができます。

そして、その実行環境のことを「コンテナ」と言います。

![Apache MySQL Nuxt (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/6b5eee99-1969-7d9a-70fc-d57f148d86dd.png)

そして、そのコンテナの種類のことを「イメージ」といい、コンテンはイメージをもとに作成されます。
![Apache MySQL Nuxt (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/caf831a6-c207-5ff3-a367-c2646f62ab9a.png)


<h2>DockerはLinuxで動く</h2>
DockerはLinuxで動くので、Dockerの操作をするとき(Dockerを起動する、Docker内のコンテナを移す、削除するetc...)はLinuxのコマンドで操作したりします。

<h2>そもそもサーバとは</h2>
そもそもサーバって何なのかも合わせて調べてみました。

サーバとは英語で書くと、「Server」と書き、Serve(割り当てる、給仕する)という動詞から成り立っている言葉であり、これの名詞型になるとサービス(Service)となります。

つまり、サーバとは何かを提供するものということです。
○「Webサーバ」と言えば、Web関係の機能が格納されたサーバ
○「メールサーバ」と言えば、メール関係の機能が格納されたサーバ
というように。

そして、サーバは大きく分けて、
○総合的なサーバ
○部分的なサーナ
の2つに分けることができます。

![Apache MySQL Nuxt (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/bbd7d81e-fb4c-da7e-f8b2-874b4e9c6123.png)

<h2>Dockerの構造</h2>
まずは復習として、Dockerは大体以下のような構造になっています。
![Apache MySQL Nuxt (7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1182751/c32aa109-d759-9606-36b6-12af31caac30.png)

もともと使用しているサーバーOSがあり、そのサーバーOSはLinux　OSで作動し、さらにその上でDockerがあるのです。

そして、Dockerのコンテナの中には、コンテナごとのそのコンテナ専用のLinux OSが存在しています。

ちなみに、OSとは「Operating System(オペレーティング・システム)」の略で、ユーザの命令をシステムや機械に伝えるものです。

世の中の機械やシステムは単純であり、人間のように思考回路があるわけではないので、人間のしたいことを伝えてもそのままでは、機械は理解できません。

つまり、OSとは、人間の言葉を機械に変換するためのものなのです。

以上、まずはDockerがどんなものかをまとめてみました。
JUnit でテスト用のデータを使用する（@Sqlアノテーション ）

### 概要

実行時点によって、データが変わってしまうので、
ユニットテストは、テスト用のデータで実行したいという場合、
`@Sql`アノテーション を使用する。

### 1. テスト用のsqlを作成

src/main/resources 配下に、以下のようなsqlを作成する。

```sample.sql
INSERT INTO sample (id, name)
VALUES(20, 'サンプル');
```

### 2.テストを作成

```test.java
// @Sql()の中には`src/main/resources`以下のパスを書く
@Test
@Sql({"/newsRoutingTest.sql"})
public void sampleTest(){
  // テスト内容
}

```
Redmineで、カスタムフィールドの情報をプロジェクト毎に表示／非表示させる方法

〇Redmineは汎用的に利用できる多機能なソフトウェアですが、実際に運用しようとすると出来るはずなのにやり方が良くわからない（あるいは分かり辛い）事がよくあると思うので私個人の事ですがその事例を公開します。
※閲覧注意事項：
　技術的な内容は一切なく、5分もあれば解決する類の問題？ですが、暖かい目で見守って下さい。

■やりたいこと
　カスタムフィールドの情報をプロジェクト毎に表示／非表示させたい。

■準備
適当にプロジェクトを作成
※今回は会社の部署毎の運用を想定して、人事、経理、設計、営業、製造を準備
　「新しいプロジェクト」より作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651745/460f27cd-e780-98a4-f839-06298cc6710d.png)

■カスタムフィールド作成
　以下操作で適当に関してカスタムフィールドを作成
「管理」→「カスタムフィールド」→「新しいカスタムフィールド」を作成
※「今回カスタムフィールドテスト１」を作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651745/a0babda2-4a89-cbf7-eed6-254434deceba.png)

■作成したカスタムフィールドテストの設定
　今回は「プロジェクト」→「人事」のみ表示設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651745/6cf34e23-c349-088f-9f7b-d687fbbbdc8f.png)

■デバッグ
　人事のプロジェクトでは、カスタムフィールドテスト１が表示されているが、経理では表示されていないことを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651745/e665a3a2-beeb-ddda-794a-325ed922071b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651745/7c3418b2-493f-9455-d786-b9624668f2f0.png)
《おしまい。お疲れ様でした！》
FastAPI: POST の引数の処理

FastAPI で POST の引数の受け取り方です。

## サーバープログラム

```py:post01.py
from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
	aa: float
	bb: float

app = FastAPI()

@app.post("/sum/")
async def create_item(item: Item):
	rvalue = {}
	rvalue["wa"] = item.aa + item.bb
	return rvalue


@app.post("/diff/")
async def create_item(item: Item):
	rvalue = {}
	rvalue["sa"] = item.aa - item.bb
	return rvalue
```

## サーバーの起動

```bash
uvicorn post01:app --reload
```

## クライアントからアクセス

```text
$ http POST http://127.0.0.1:8000/sum/ aa=12.1 bb=34.5
HTTP/1.1 200 OK
content-length: 11
content-type: application/json
date: Sat, 05 Jun 2021 04:49:11 GMT
server: uvicorn

{
    "wa": 46.6
}
```

```text
$ http POST http://127.0.0.1:8000/diff/ aa=12.1 bb=34.5
HTTP/1.1 200 OK
content-length: 12
content-type: application/json
date: Sat, 05 Jun 2021 04:49:37 GMT
server: uvicorn

{
    "sa": -22.4
}
```

## 確認したバージョン

```text
$ python
Python 3.12.7 (main, Feb  4 2025, 14:46:03) [GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import fastapi
>>> fastapi.__version__
'0.110.3'
```
rbenv install 2.6.7 を実行しエラーが発生した場合の解決方法

## エラー内容

```console
% rbenv install 2.6.7
Downloading openssl-1.1.1k.tar.gz...
-> https://dqw8nmjcqpjn7.cloudfront.net/892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5
Installing openssl-1.1.1k...
Installed openssl-1.1.1k to /Users/Username/.rbenv/versions/2.6.7

Downloading ruby-2.6.7.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.7.tar.bz2
Installing ruby-2.6.7...
ruby-build: using readline from homebrew

BUILD FAILED (macOS 11.2.1 using ruby-build 20210423)

Inspect or clean up the working tree at /var/folders/21/ntlh79kd1yvfz2gwv8n79f4c0000gn/T/ruby-build.20210427115224.72475.T0ZRPY
Results logged to /var/folders/21/ntlh79kd1yvfz2gwv8n79f4c0000gn/T/ruby-build.20210427115224.72475.log

Last 10 log lines:
compiling dmyenc.c
vm.c:2489:34: warning: expression does not compute the number of elements in this array; element type is 'const int', not 'VALUE' (aka 'unsigned long') [-Wsizeof-array-div]
                             sizeof(ec->machine.regs) / sizeof(VALUE));
                                    ~~~~~~~~~~~~~~~~  ^
vm.c:2489:34: note: place parentheses around the 'sizeof(VALUE)' expression to silence this warning
3 warnings and 1 error generated.
make: *** [vm.o] Error 1
make: *** Waiting for unfinished jobs....
1 warning generated.
1 warning generated.

```


## 解決方法

`CFLAGS="-Wno-error=implicit-function-declaration" rbenv install 2.6.7` を実行することで解決できます。

引用:[https://github.com/rbenv/ruby-build/issues/1747](https://github.com/rbenv/ruby-build/issues/1747)
M1 macにpython仮想環境を作りTensorFlowを導入

# はじめに

M1 macbookProを会社から貸与いただいたので、pythonの仮想環境を作ってみました。
ところがtensorflowモジュールがpipで入らなくて、それを解決できたので記事にします。

# pythonの仮想環境を作る
今回仮想環境は、machineLearningという名前で作ってます。まずpythonの仮想環境を作ります。

```
${your_name}@MacBook-Pro> python3 -m venv machineLearning
```

# 仮想環境にモジュールをインストール
sourceコマンドで仮想環境を起動すれば、その環境に入れる。

```
${your_name}@MacBook-Pro> source ./machineLeaning/bin/activate
(machineLearning)${your_name}@MacBook-Pro>
```



その仮想環境にnumpyモジュールをインストールする

```
(machineLearning) ${your_name}@MacBook-Pro ~ % pip install numpy
Collecting numpy
  Downloading numpy-1.20.3-cp38-cp38-macosx_10_9_x86_64.whl (16.0 MB)
     |████████████████████████████████| 16.0 MB 5.9 MB/s 
Installing collected packages: numpy
Successfully installed numpy-1.20.3
```
# TensorFlowが入らない
次にtensorflowをインストール。次のように公式サイトどおりにpipするも、失敗してしまう。適当なバージョン指定しても同じ。M1（ARM版）用のtensorflow見つからないと言っている。仮想環境に見合ったモジュールのバージョンが見つからない、ということのようだ。

```
${your_name}@MacBook-Pro>　pip install --upgrade tensorflow

Could not find a version that satisfies the requirement tensorflow (from versions: ) No matching distribution found for tensorflow
```


# M1用のTensorFlowモジュールを発見

そこで、

[*Mac-optimized version of TensorFlow 2.4*](https://note.com/npaka/n/n7f2dcf8b316d"note.comへ行きます")


を拝見すると、M1 MAC用のパッケージがあるようである。しかもこっちの方が、実行スピードが格段に速い。実測だと4倍以上のようだ。
![MacBook Pro 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/554997/c3f72218-d0cb-9c2d-03cd-29b59c064e49.png)
[*tensorflowのブログ から引用*](https://blog.tensorflow.org/2020/11/accelerating-tensorflow-performance-on-mac.html "tensorflow　blogへ行きます")

将来的にはマスターブランチにマージされるようである。

# TensorFlowモジュールのインストール

これをインストールするため、　[*github 公式apple*](https://github.com/apple/tensorflow_macos "githubへ行きます")　のINSTALLATION にあるように、次のscriptを実行。

```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/apple/tensorflow_macos/master/scripts/download_and_install.sh)"
```
無事インストールできました。M1　MAC用に作られたモジュールはまだまだ少ないようです。M1MACに対応して性能を生かせるようになるまで、しばらくかかるのではないかと思います。