OmniAICreator/Qiita-1.07M huggingface dataset:
ISLispにElixir風の拡張シンタックスマクロ

#はじめに
Elixirの言語設計に私は心酔しています。設計者のJoseさん、正しく天才です。その卓越した言語設計の才能を尊敬しております。この度、ISLISPにElixir風のパターンマッチングとパイプ演算子をライブラリとして追加整備しました。


#例
フィボナッチ数列の例です。

```
(import "elixir")

(defpattern fib
    (0 1)
    (1 1)
    (_n (+ (fib (- _n 1)) (fib (- _n 2)))))


```

defpattern はマクロです。defunに展開しています。

```
Easy-ISLisp Ver1.92
> (macroexpand-1 '(defpattern fib
        (0 1)
        (1 1)
        (_n (+ (fib (- _n 1)) (fib (- _n 2))))))

(DEFUN FIB (#:G2) 
  (LET ((_N NIL)) 
    (COND ((AND (= #:G2 0)) 1)
          ((AND (= #:G2 1)) 1)
          ((AND (SETQ _N #:G2)) (+ (FIB (- _N 1)) (FIB (- _N 2)))))))
> 

```
読みやすいように整形しています。

#実行速度
マクロで展開したときに効率の悪いコードになっていては意味がありません。計測したところフィボナッチに関してはほぼ同じです。速度も普通に出せています。

```
(defun fib* (n)
    (cond ((= n 0) 1)
          ((= n 1) 1)
          (t (+ (fib* (- n 1)) (fib* (- n 2))))))

> (load "tests/elixir-test.o")
T
> (time (fib 35))
Elapsed Time(second)=0.924024
<undef>
> (time (fib* 35))
Elapsed Time(second)=0.982285
<undef>
> 
```

#仕様
パターンマッチでは変数は_a,_zのように頭部にアンダーバーをつけます。ElixirやPrologと同様です。

:rest &rest は通常の関数と同様に剰余変数として機能します。

else　は常にマッチします。その他のケースを補足するのに使います。


```
(defpattern boo
    ((* (* _a _b) _c) (list _a _b _c))
    ((e 1 :rest _a) (list _a))
    (else 1))

> (boo '(e 1 2 3))
((2 3))
> (boo 3)
1
> 

```


#パイプ演算子
以前作ってあったものを今回のElixirライブラリに収録しました。

```
(defpattern foo
    ((a _a) (pipe _a |> (cos) |> (sin)))
    ((b _b) (pipe _b |> (tan) |> (abs))))

```

関数がネストしていく場合に可読性をあげることができます。


#Github
ver1.92から動作可能です。Githubにて公開しています。クローンを作ってお楽しみください。
https://github.com/sasagawa888/eisl
android studioで新規ファイル作成時にフリーズしてしまう

課題
android studioで新規でファイルを作成しようとする
→android stuioがフリーズしてします。強制終了しない限り抜け出せない
(PC:Mac)

解決法
macのシステム環境構築「一般」タブで赤線部を「しない」で選択


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1242186/e08990bc-a9bd-d87d-0638-90ee15c4a941.png)
アルゴリズムの難易度 P, NP, co-NP, EXP, R, NP-hard

## P, NP, co-NP

問題の区分として P, NP, co-NP の3つの集合を考えます。

* P
    * 多項式時間で解ける問題の集合
    * c を定数として、 $O(n^c)$ に属する問題の集合。
    * ハノイの塔($\Theta(2^n)$)はこの集合に属さない。
* NP
    * あるYESを出力するための入力が与えられた時に、その入力が本当にYESを出力するのか多項式時間で確認できる問題の集合
* co-NP
    * あるNOを出力するための入力が与えられた時に、その入力が本当にNOを出力するのか多項式時間で確認できる問題の集合

$ \textrm{P} \subset \textrm{NP} , P \subset \textrm{co-NP}$

* EXP
    * 指数時間で解ける問題の集合
    * c を定数として、 $O(2^{n^c})$ に属する問題の集合。
    * チェスはこの集合に属し、 P には属さない。 テトリスはこの集合に属し、Pに属すか否かはわかっていない。

* R
    * 有限時間で解ける問題の集合。
    * 停止問題(与えられたプログラムが停止するか動き続けるか)はこの集合にも属さない。

* NP-hard
    * ある問題AがNP-hardであるとは、任意のNP問題がチューリングリダクションによってAに帰着可能であることをいう


## Reduction

AをBにReduceするとは、Aを解くアルゴリズムを、Bを解くアルゴリズムがあるという前提で記述することである。

例）Aを解くアルゴリズムを、Bを解く関数を組み合わせて作る

## チューリングリダクション

チューリングマシンにて実行可能なリダクション


ある NP-hard の問題を 問題Aにreduceできれば、AはNP-hardであることがいえる。

## 問題の例

### Satisfiability, SAT

論理式が与えられた時に、その論理式を真にするようなリテラルの組み合わせは存在するかという問題。
入力が与えられたら、多項式時間で正しいか否かを判定できるので、 NP に含まれる問題。

これが NP-hard であることは、 全てのNPに属する問題が論理式で表されることにより証明された。

#### 2SAT

2SAT は Np-hard ではない

#### 3SAT

$(a+b+c)(d+e+f)$ のように、 ( ) の中が3つの項からなる論理式。

3SAT は NP-hard.
3SAT は SAT に帰着(reduce)可能。

#### Clique (最大クリーク問題)

クリークとは、グラフの一形態で、任意の2頂点の間に枝がある頂点の集合です。
問題としての Clique は、 あるグラフの中にある最大のクリークを見つける問題です。

* NP-hard
    * Clique
* NP-complete
    * 3SAT
IBM Cloud: CIS(Cloud Internet Service)のアクセス元の都道府県と市レベルの住所が分かるAPIを試してみた

#1. はじめに

PublicKeyで[アクセス元の都道府県と市レベルの住所が分かるAPI、Cloudflareがエッジ上のCloudflare Workersで提供へ](https://www.publickey1.jp/blog/21/apicloudflarecloudflare_workers.html)という記事が紹介されていたので、IBM CloudのCIS(Cloud Internet Service)で実行できるか確認してみた。
※Cloudflare Workersは、CISではEdge Functionsと呼ばれている。

- CloudflareのBlog記事は[こちら](https://blog.cloudflare.com/location-based-personalization-using-workers/)
- Source Codeのサンプルは[こちら](https://developers.cloudflare.com/workers/examples/geolocation-hello-world)
- ただし、上記のSource Codeサンプルをコピペすると（私の環境だと）改行が崩れたので、[GitHub上の元ソース](https://github.com/cloudflare/cloudflare-docs/blob/production/products/workers/src/content/examples/geolocation-hello-world.md)を参照した。


#2. Edge Functionsの設定

- Edge FunctionsのActionsタブにて、`Create`を選択。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/1983c157-8fd3-cad5-3e39-3a5c0bdac721.png)
- 関数名に適当な名称を入力（今回は`geolocationhelloworld`とした）し、上記のsource codeを貼り付けて保管。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/4cc3db62-1f6b-8424-a825-f8aec3707629.png)
- Trigger列で、どういうFQDNにアクセスした際に上記のEdge Functionsが呼び出されるかを登録する。今回は自分のドメインが、`example.com`だったとしたら、`hello.example.com`でこのEdge Functionsが呼び出させるように構成したいので、Trigger URLに`hello.<自分のドメイン>`と登録し、Actions欄に上記で作成したEdge Functionsを登録する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/d8cae03b-9b99-54ae-0a35-ed679ddd8f12.png)
- Reliability -> DNSで`hello.<自分のドメイン>`が名前解決できるようにレコードを登録する。この際、解決先のIPアドレスは何でもいいので、Proxyを有効化してクライアントからのリクエストがEdgeに転送されるように`Proxy`を有効化する。本来は、EdgeがReverse Proxyと作動してこのDNSに登録されたIPアドレス宛にEdgeからリクエストが飛ぶはずだが、Edge FunctionsでHTMLを返すように構成しているので、このDNSに登録するIPは使われない（なので必ずしもAレコードである必要もないが、今回はシンプルなのでAレコードを利用し、`8.8.8.8`を登録）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/8a46c734-8bce-a566-11e1-fdc0c36b8f75.png)




#3. テスト
`https://hello.<自分のドメイン>`にアクセスすることで、無事表示された！
[Publickeyでの記事](https://www.publickey1.jp/blog/21/apicloudflarecloudflare_workers.html)中に記載のある通り、住所の正確性は郵便番号は前3桁のみ正しく、後ろ4桁は間違っているし、携帯電話を利用している時は正しい場所を取得できてないが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62127/59f11970-2735-90b7-aa07-b566cbcd2623.png)
SQL　JOIN(複数テーブルの結合)

SQLの結合に関して学びましたが、わかりにくいものやあやふやなものがあったため、脳内整理＆備忘録として残します。

<b>●複数テーブルの結合

　<b>・まず,なぜ結合が必要となるのか</b>
　　　　①本格的にDB活用する場合、<b>安全・確実・高速に取り扱うため</b>、データは複数のテーブルにわけて格納する。


　<b>○テーブルの結合</b>
　　　　例：テーブルAとBの結合
SELECT　[選択列リスト]
　　FROM　[テーブルA]
　　JOIN　[テーブルB]
　　ON　【両テーブルの結合条件】

　　・解説
　　　　①まず、3行目の<b>JOIN句</b>によってテーブルAにテーブルBが結合される。
　　　　②<b>ON句の結合条件</b>で、テーブルAとBのどの行を繋ぐかを指定している。
　　　　③結合後、列の絞込み(選択列リストの指示)や行の絞込み(WHERE句の指定)を行う。

　　　　※注意点：結合はテーブルA・Bが共に対等の関係ではなく、FROM句で指定したテーブル(左表)が主役。主役に対して、JOIN句で指定したテーブル(右表)の内容を、必要に応じて繋いでいく。


　　<b>○結合テーブルが複数行の場合</b>
　　　　・繋ぐべき右表の行が複数あるとき、DBMSは<b>左表の行を複製して結合する</b>。
　　　　　そのため、結果表の行数は、元の左表の行数より増える。

　　<b>○結合相手の行が存在しない または　NULLだった場合</b>
　　　　　・右表に結合相手の行がない場合や、左表の結合条件の列がNULLの場合、結合結果から<b>消滅</b>する。

　　　　　　※しかし、結合相手がなかったりNULLだからと勝手に消滅してしまうのは問題がある場合がある。その際に活躍するのが以下の<b>左外部結合</b>である。
.


　　<b>○左外部結合</b>
　　　　　・DBMSに対して、「左表については結合相手が見つからなくても、NULLであっても必ず出力せよ」という指示を出す。
　　　　　・方法としては、<b>JOINをLEFT　JOIN</b>　にするだけ。
　　例：テーブルAとBの結合
　　　　SELECT　[選択列リスト]
　　　　FROM　[テーブルA]
　　　　<b>LEFT　JOIN</b>　[テーブルB]
　　　　ON　[両テーブルの結合条件]

　　<b>○３テーブル以上の結合</b>
　　　　　・「JOIN～ON～」を繰り返すことで、３つ以上のテーブルを結合することも出来る。この場合、一度に３つのテーブルが結合されるわけではなく、前のJOIN　ONから順に結合処理が行われる。

　　<b>○副問い合わせの結果との結合</b>
　　　　　・JOIN句の後ろに、<b>「表形式でデータに化ける副問い合わせ」</b>も記述できる。ただし、選択列リストや結合条件の指定のために、<b>副問い合わせに別名を指定すること</b>が必要となる。
【初心者向け】Bog of wordsでテキストデータのベクトル化しよう

##はじめに
今回はテキストデータの前処理を行いたいと思います。
最初はベーシックな手法であるBag of Words(BoW)を紹介します。

###Q.そもそもなぜ前処理が必要か？
これは簡単で機械学習などでテキストデータを学習させたい時に、そのままでは使えないからです。

機械学習モデルは文章を学習することを前提としていないので、文字列を数字に置き換える必要があります。

##環境
今回はGoogle Colaboratory上で動かしたいと思います。

実際のコードは[こちらのGoogle Colabのノート](https://colab.research.google.com/drive/1tCnlVvlXb_aK3KbYiHc5nlmx9bibggrV?authuser=1#scrollTo=p9BlKI1Rfwez)を参照してください。

##英文をBag of Wordsで表現してみよう

###Bag of Wordsとは？
Bag of Wordsは文で登場した単語の回数を数えるための手法です。

今回は次の3文をBag of Wordsで表現してみます。

- This movie is very scary and long(この映画は怖くて長い)
- This movie is not scary and  slow(この映画は怖くなくて、ゆっくり)
- This movie is spooky and good(この映画は不気味で、良い)

**まずは３つの文をpandasのDataFrameに入れましょう**

```
import pandas as pd

df = pd.DataFrame({
    'text':[
        'This movie is very scary and long',
        'This movie is not scary and  slow',
        'This movie is spooky and good'
    ]
})
df
```

**次にscikit-learnのCountVectorizerと正規表現で文章をベクトル化しましょう**

```
from sklearn.feature_extraction.text import CountVectorizer

vectorizer = CountVectorizer(token_pattern=u'(?u)\\b\\w+\\b')
bag = vectorizer.fit_transform(df['text'])
bag.toarray()
```
**最後に各indexに対応している単語を確認しましょう**
print(vectorizer.vocaburary_)
論文概要: POI Atmosphere Categorization Using Web Search Session Behavior

#初めに
この記事は自分用の論文まとめです。
またPOIの論文を読むのが初めてなのでわからない単語そのままです。
#論文
タイトル : POI Atmosphere Categorization Using Web Search Session Behavior(Web検索セッションの動作を使用したPOI雰囲気の分類)
URL : http://hayatokobayashi.com/paper/SIGSPATIAL2020_Tsubouchi_preprint.pdf
発表 : SIGSPATIAL '20: Proceedings of the 28th International Conference on Advances in Geographic Information Systems

#前提用語
POI : Point Of Interest の略、興味を持たれている特定の場所。つまり、ただの特定の場所という意味？
https://www.esrij.com/gis-guide/gis-other/point-of-interest/
DSSM : 検索クエリと検索ドキュメントの関連度を計算する教師ありDeep Learningのモデル
https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/cikm2013_DSSM_fullversion.pdf
LSTM : long-short-term-memoryの略、自然言語処理における深層学習のモデルの1つ



#0.概要
POIの雰囲気、つまり特定の場所の雰囲気によってカテゴリ分類するのは物件検索サービス等の商用サービスに便利である。
そこでPOIの雰囲気を捉える新しい分類方法を提案する。

#1.イントロ
同じ公園でもサラリーマンが多い公園と子供が多い公園では雰囲気は別物なので、その差を表したい。
POIに関連する検索をする人はその公園に関する予備知識を持っている場合が多い。POIの検索クエリと一緒に検索されるクエリにはその場所の雰囲気が含まれると考える。
検索クエリとクリックされた文章との関連度を計算するDSSMというモデルを使用する。ここではPOIに関連する検索クエリとその次に検索されたクエリは関連すると考え、その多数のペアを用いてDSSMをトレーニングする。

#2.提案手法
## 2.2データ
同一人物の検索履歴を取得する。その履歴の中で一定時間以内の間隔で検索された内容を1つの組とする。その組の単語群のペアを全通り取得し、それをデータとして用いる。
## 2.3DSSM訓練
3層のLSTMを用いてクエリ$Q$をエンコードする。それを$f(Q)$とする。これはいうならば、クエリの座標となる。
これを用いて2つのクエリ間の距離を計算する。これにはコサイン類似度を用いる。
$R(Q,Q')=\frac{f(Q)^Tf(Q')}{||f(Q)|| ||f(Q')||}$
そしてこの距離を用いて、あるクエリ$Q$が与えられた後にクエリ$Q_0$がくる確率を以下に示す。
$p(Q_0|Q)=\frac{exp(\beta R(Q,Q_0))}{\sum^K_{k=0} exp(\beta R(Q,Q_0))}$

また損失関数は以下のように計算する。
クエリ$Q$の後に実際に検索されたクエリを$Q_0'$としたときの$p(Q_0'|Q)$が最大化すればよく、つまりクロスエントロピーロスを用いる。
$\sum -\log{p(Q_0'|Q)}$
この損失関数を最小化する。

#3実験
訓練したDSSMを使って、検索クエリのマッピングを行い、そのマッピング値を使って結果を調べる。
##3.2 クエリエンコーダの特徴
コサイン類似度をクエリ間の類似スコアと考える。
『新宿』と『横浜』のスコアが0.7で高い！
『熱海』と『湯布院』のスコアが0.77で高い!
『富士山』と『富士通』のスコアが0.25で同じ単語がクエリ内に含まれていても低い！
『美しが丘公園』と綴りミスの『美しくしがおかこうえん』のスコアは0.79と高い！
単語の雰囲気が取れてそうなことが分かる。

##3.3公園およびその他のPOIの分類 
公園、建物、レストラン街をマッピングすると、既存手法ではうまく分かれてくれないが、新しい手法だとかなり綺麗に分かれる。
渋谷ヒカリエは建物なのにレストラン街に近いマッピングになってしまってるが、渋谷ヒカリエにはレストランが多く入っているので直感的には理解できるマッピングとなっている。
（論文内の図５）

##3.5公園の雰囲気を現実の世界につなぐ
実際の公園の例を見ると、雰囲気が取れてる！すごい！

#5結論
検索クエリを使って、POIの雰囲気をつかんだ。
検索クエリは地理情報処理にも使える！
地理リソースも使えばより発展できそう。

#私的なまとめ
今までのPOIの分類法
地理におけるユーザーの行動、地理の空間的特徴
→これでは場所の雰囲気を捉えられない

場所を検索した次の検索にはその場所の情報を含まれる？
→その検索クエリを利用してその場所の雰囲気を捉える。

DSSM
3層LSTMによってクエリをマッピングする。
マッピングからコサイン類似度、事後確率を計算する。
真のクエリペアの事後確率をクロスエントロピーロスを損失関数として用いて最大化
→マッピングを学習

学習したDSSMを使ってクエリをマッピングして比較。
→直感的な雰囲気の理解ができてそう。

検索クエリは自然言語処理以外にも地理情報処理の有用！

自然言語処理と地理情報処理の架け橋的になった？
vuforia どこでもドアの作り方

1, vuforiaをインポート、ライセンスキーまで設定する
ARcameraやplaneも実装する

２、Shaderをインポートし、マテリアルを作成する
![6A6DF5D7-7E48-4B7E-AA9B-5D0E5D5D04C1_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/b1f380ed-18d2-f92f-857e-1794593fb2d5.jpeg)
![09422CC7-939B-44AB-AC6E-9DF504778BF4_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/e5c48249-a2b1-e668-c84f-35bd49dc833e.jpeg)

３、マテリアルのShaderをCustomのMask、値を１９９９にする
![C8C0293E-0736-4E27-959E-D3271EC97733_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/c92c1cf9-3683-32a3-64f9-7501c33db07c.jpeg)

４、Cubeを設置し、SkinnedMeshRendererをコンポーネントする
![A85EF01B-18A5-48FC-9A97-F92858461132.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/0f81bde6-e3e4-3ad4-3650-41f36dd1e9e2.jpeg)

５、Cubeにマテリアルをアタッチする
![A9453E51-4BDE-44CA-9FE3-E7D9D819D9FA.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/41bfe875-5c71-2b5d-af07-f59c69f4da34.jpeg)

６、Cubeを平らにしてサイズを調整する
![E08C0758-D8F3-4903-B927-769E533ABAD2_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/7eb858d6-96b0-a7b2-c4d2-0033eabaf7b1.jpeg)

７、オブジェクトを配置して隠したい部分にあてる
![CFF1EF0D-369E-477F-9BC0-41B737D6BDFB_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/e6cd3d90-aa83-2ff6-cf90-d5acc0d676c4.jpeg)

８、Cubeをコピーして複数作成し、隠す部分に当てる
![8E555F6F-4A98-4410-B8F1-DC49723A1CC6_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/4021343e-1da5-9faf-21e7-e0777aca085c.jpeg)
![E955AD84-7FE0-4EFF-80FB-43AFC3719180_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/99906afa-c0b8-91c5-537e-1dff56bddf42.jpeg)
![C06F85C0-8918-4AC1-8A24-C8F6C673CCEA_4_5005_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/940521/140da997-4e0d-caad-9b20-fd2d7fe34215.jpeg)
駐輪場代と電車定期代どっちが安いのか収支計算EXCEL

コロナのご時世、電車通勤が怖いという方、
自転車通勤を始めてみませんか？

駐輪場代と定期代どっちが安いのか、シュミレーションや収支計算にご活用ください。

![excel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50308/a3def707-4e13-36f2-6a84-7345be3add94.png)

ダウンロードはこちらから

https://github.com/torogurio/bicycle-parking-fee/commit/219e83213992d9777a02c375b6657fb5e4c55cea
herokuで動かしている俺のRailsアプリがこんなにメモリを食うわけがない

# 発端

2021/04/18

ふと気がつくとherokuで運用中のrailsアプリが亡くなっていました。

原因探るの面倒だったので再起動しました。

その後も割と頻繁に死亡していたので、herokuのダッシュボードを確認しました。

すると...

### **🧟Memory Usage 100%🧟**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307103/371464a7-de5c-d0e8-daa4-3b42d12a6367.png)

なんかメモリが爆上げしているご様子

そして多数のapp crashのログがちらほら

# 環境

heroku
web: Free Dynos
worker: Free Dynos
Ruby: 2.7.3
Rails: 5.2.5


# 対応したこと

herokuがrubyでのメモリ爆上げ状態の対策をまとめてくださったので、そちらを参考に対応しました。

https://devcenter.heroku.com/ja/articles/ruby-memory-use

ありがとうheroku、いいプラットフォームです。

調べてみるとSidekiqで非同期処理を動かしていたのが怪しいみたいな感じでした。

### 起動時の Worker 数の超過

起動時のWorkerを1にしました。

```ruby
# config/puma.rb
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
```
```bash
# CLI
$ heroku config:set WEB_CONCURRENCY=1
```

引用すると

> 2 つの Puma Worker が原因で、​standard-1x​ dyno が提供できる量を超える RAM が使用されます。これが発生した場合でも、スレッドを使用して、スループットを増大させることができます。または、​dyno サイズをアップグレード​して、実行する Worker の数を増やすことができます。

2つで死が近づくっぽいですね

### 経過に伴うWorker数の超過

メモリが増加して上限を迎える場合（今回の私の感じで）Puma Worker Killerでプロセスを再起動することでメモリの増加を抑制できます。

```ruby
gem "puma_worker_killer"
```

```ruby
PumaWorkerKiller.enable_rolling_restart
```

> Worker が再起動すると、数秒間リクエストに応答できないので、繰り返しの再起動がトリガーされると、エンドユーザーは、アプリケーション全体のスループットが低下したときに減速を経験することがあります。再起動すると、スループットは通常に戻ります。

このアプリケーションは非同期処理ではリアルタイム性を特に求めてなかったのでプロセスには容赦なく消えていただきました。
Puma Worker Killerはgemで、指定した条件になったらWorkerプロセスを切るしてくれるイイやつです。
Unicornにも似たようなことができるgemがあったと思います。

### 環境変数MALLOC_ARENA_MAX=2を指定する

https://qiita.com/kazutosato/items/4ab561bf5cc03da75e72
↑こちらの記事に自分と全く同じ状況の方がいたので参考にさせていただきました。

> Herokuでは、上記の2の環境変数MALLOC_ARENA_MAX=2はデフォルトになりました。ただし、2019年9月24日より前に作られたアプリケーションでは自分で設定する必要があります。

らしいです。私のアプリケーションこれより前に作ってた気がしています。

### 起動時のメモリの超過

こちらは調査で終わったやつですが一応。
derailedというベンチマークのgemで起動時のメモリ使用量をチェックしました。


```ruby
gem 'derailed', group: :development
```

```bash
$ bundle exec derailed bundle:mem
```

これでボトルネックとなりそうなgemを消すという対策です

が、Hobby Dynosの512MBを食いつぶすようなものは見つからず...

```
TOP: 67.2734 MiB
```

### jemallocでのビルド

なんか公式のものよりメモリに優しいアロケータらしい

https://elements.heroku.com/buildpacks/gaffneyc/heroku-buildpack-jemalloc

```bash
$ heroku buildpacks:add --index 1 https://github.com/gaffneyc/heroku-buildpack-jemalloc.git
$ git push heroku master
$ heroku config:set JEMALLOC_ENABLED=true
```

# 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307103/f02fabb1-4c30-b23a-3bda-b0f136b78b9c.png)

↑の右の方のダウン（メモリ消費が0になった）の後に対応しました

増え続けていはいない気がするけど、なんか期待してたのと違う

とりあえず要経過観察です

# オチ

### unicorn起動してたwwwwwwwwwww

Procfileでガッツリunicorn起動していました...

なんの為に私はpumaの設定をせっせと書き換えていたのだろうか....

unicornのgemもけしました

無事に平和な感じになってそうです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307103/d781f107-3111-a3b0-c6f8-273ad21eb639.png)
ADOを使ってExcelテンプレートへ差し込み一斉出力するシステムを作ってみた

Excelで作られたフォーマットへ差し込み出力する話は
Qiitaでも他のサイトでも既出だとは思いますが、
（なぜか）ADOを使ったものは見かけなかったのと、
まあまあ汎用的な感じのシステムにうまいことなったので、投稿します。

#### ADOを使うメリット
- コードがすっきり書けます。
- 動作も速めです。
- リストを色々なファイルやデータベースから引っ張れます。

#### ADOを使うデメリット
- リストはデータベースのテーブルとして（型などが）整理されている必要があります。

### 作ったシステム
![1-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340299/7f53a659-0026-db18-344d-541e63759a22.png)
こんな感じで、リストとひな型をそれぞれ読み込んで、
また別のExcelファイルに件数分のシートをダダダダダと出力していく仕組みです。
セルの名付け方さえわかれば誰でも、ひな型を作ってシステムを利用できます。
PowerPointで作ったひな型への出力にも不完全ながら対応しています。

動かしているところを動画にもしていますのでよければご覧になってください。

https://www.youtube.com/watch?v=KZ51lmuO13I

コードは分量が多くてここに書ききれませんので、
私のホームページからダウンロードできる実物を見ていただけたらと思います。
https://unmebakka.web.fc2.com/
コードだけ読みたい方はマクロ無効にしたままどうぞ。

### 技術的なポイント
Excel VBAでの開発は、手軽で初心者向きである反面、
コードの読みやすさや保守性が失われがちです。
なるべく抽象的に書くことを考えると良いと思います。

まずは、ユーザーインターフェースで入力させるセルに名前をつけることから始めましょう。
これにより、インターフェースのデザインが多少変わっても
コードをいじるためにエディタを立ち上げる必要がなくなります。

表は素のままにしないでテーブル（ListObject）としておくと、
VLOOKUP関数やドロップダウンリスト、VBAで利用したいときに
テーブル名と列名を使って抽象的に表現できます。

また今回は、入力させた情報を一旦自作オブジェクトに持たせることで
取り回しが楽になり、コードもすっきり書けました。

エラーの報告のさせ方を丁寧に考えることは、開発をスムーズにしてくれます。
参考：https://qiita.com/oedkty/items/d6d2e86d689c9a267f11

ADOの部分については基本的な使い方しかしていませんので
既にたくさん出ている情報にあたっていただきつつ
コードを読んでいただくと良いかと思います。

### 作った動機
以前勤めていた職場がExcelをよく使うところで、
皆が膨大な時間をコピペに費やしていました。
自分はそれが面倒だったのでVBAを覚え、一斉出力するコードを
あちこちのExcelファイルに書き込んだりしていました。

その職場はもう退職してしまったのですが、
ひな型のセルの名前とリストのフィールド名が一致するかどうか見る
というアイデアが、ふと（なぜか今さら）思い浮かんだので
VBAの復習がてら作ってみた次第です。

何かの参考になれば幸いです。
画像やタイトルなどいろいろな要素を全て同じリンクをさせる


##Controllers

```app/controllers/item_controller.rb
class ItemController < ApplicationController
  def index
    @items = Article.all
  end
end
```



```ruby:app/views/item/index.html.erb
<% @items.each do |item| %>
   <ul> 
      <li>
        <%= link_to item_path(item), class: 'hoge' do %>
          <% if item.image? %>
            <%= image_tag item.image.to_s %>
          <% else %>
            <%= image_tag 'no_image.png' %>
          <% end %>
 
          <h4><%= item.title %></h4>
          <p><%= item.sentence %></p>
        <% end %>
      </li>
    </ul>
<% end %>
```

基礎１:ヘルパーメソッド
-

railsはcrfの対策で下のようにコンパイルされる
「前」

```ruby:app/views
<%= image_tag 'test.jpg', class: 'hoge' %>
```
「後」

```ruby:app/views
<img src="/assets/test.jpg" class="hoge">
```

基礎２:link_to
-


|メソッド|第一引数|第二引数|オプション|
|--|--|--|--|
|<%= link_to|“Topページへ”,|“root_path” |method: :delete%>|

*第一引数は表示テキスト
＊第二引数はリンク先指定
*オプションのデフォルトはGET

基礎３:HTML要素などにリンク付け
-

**<%= link_to root_path do %>**
(html要素)＊特に画像・アイコンなど
**<% end %>**

基礎4:1つずつ取り出して
-

@のついたインスタンス変数には通常複数のデータがハッシュで入っています。
１つずつ取り出すメソッドがeachです。

**＠A.each do |A|**
 処理
**end**
で間の処理を繰り返します。

3+4
-

```html
<% @A.each do |A| %>
  <%= link_to do %>
  <% end %>
<% end %>
```

リンクのついたくさんのHTML要素が出来上がります。
Laravelのログフォーマットを変更したらスタックトレースが出力されなくなった

#環境
- PHP 7.4.16
- Laravel 8.34.0

#何が起きたか
Laravelでログのフォーマットを変更するために`app/Logging/CustomizeFormatter.php`を以下のように設定しました

```php
class CustomizeFormatter
{
    /**
     * @param  \Illuminate\Log\Logger  $logger
     * @return void
     */
    public function __invoke($logger)
    {
        foreach ($logger->getHandlers() as $handler) {
            $handler->setFormatter(new LineFormatter(
                "%level_name%[%datetime%] url:%extra.url% http_method:%extra.http_method% context:%context% class:%extra.class% function:%extra.function% message:%message% \n",
                'Y-m-d H:i:s',
                true
            ));
            $handler->pushProcessor(new WebProcessor);
            $handler->pushProcessor(new IntrospectionProcessor(Logger::ERROR, ['Illuminate\\']));
        }
    }
}
```

これによってログのフォーマットの変更と追加情報の出力には成功したのですが、
**エラー時にスタックトレースが出力されなくなってしまいました**。

#解決

`LineFormatter`クラスは以下のようにスタックトレースを含むか否かを定めるメソッドが存在することがわかりました

```php
public function includeStacktraces(bool $include = true)
    {
        $this->includeStacktraces = $include;
        if ($this->includeStacktraces) {
            $this->allowInlineLineBreaks = true;
        }
    }
```

なんだ！メソッド呼んだらいいんじゃん！！ということでコードを以下のように書き換えて修正完了です

```php
public function __invoke($logger)
    {
        $format = new LineFormatter(
            "%level_name%[%datetime%] url:%extra.url% http_method:%extra.http_method% context:%context% class:%extra.class% function:%extra.function% message:%message% \n",
            'Y-m-d H:i:s',
            true
        );

        $format->includeStacktraces(true);

        foreach ($logger->getHandlers() as $handler) {
            $handler->setFormatter($format);
            $handler->pushProcessor(new WebProcessor);
            $handler->pushProcessor(new IntrospectionProcessor(Logger::DEBUG, ['Illuminate\\']));
        }
    }
```

無事にエラー時にはスタックトレースがログに出力されるようになりました。
再Vue.jsディレクティブ学習

Vue.jsを薄く学んでいた際、`v-bind`、`v-if`、`v-show`、`v-for`などはよく使っていました。
しかし、しっかり勉強しようとした際、知らないディレクティブが結構あったので、メモとして残します。

## v-once
最初の一度だけテンプレートを評価し、その後は静的なコンテンツとする。

#### 例
`v-once`が設定されているpタグは、ボタンを押しても`hoge`と表示されたままとなる。

```js
data() {
  return {
    message: 'hoge'
  }
},
methods: {
  onClick: function() {
    this.message = 'click';
  }
}
```
```html
<p>{{ message }}</p>
<p v-once>{{ message }}</p>
<button v-on:click="onClick">Click</button>
```

#### 主な用途
更新不要な部分を評価させず、描画更新のパフォーマンスを上げる。

#### 注意点
ノード内の全てのバインディングに影響するが、子孫ノードには適用されず、評価＆更新される。

## v-pre
ノードと子孫ノードのコンパイルをスキップする。

#### 例
`v-pre`が設定されているpタグは、`{{ message }}`がそのまま表示される。

```js
data() {
  return {
    message: 'hoge'
  }
}
```
```html
<p>{{ message }}</p>
<p v-pre>{{ message }}</p>
```

#### 主な用途
ディレクティブが存在しないノードを評価させず、描画のパフォーマンスを上げる。
XSS対策。

## v-cloak
関連づけられたviewModelのコンパイルが完了するまで、ノードにプロパティが残る。

#### 例
コンパイル完了まで`<p v-cloak>`となり、完了後は`<p>`となる。
`v-cloak`プロパティが残存する間、cssの`[v-cloak]`が効いているため、pタグは表示されない。

```js
data() {
  return {
    message: 'hoge'
  }
}
```
```html
<p v-cloak>{{ message }}</p>
```
```css
[v-cloak] {
  display: none;
}
```

#### 主な用途
コンパイルに時間がかかる場合のチラつき防止など。

## v-text
ノードのtextContentに指定したデータで更新する。
=> マスタッシュ構文と同じことをする。

本家にも
> 内部的には、{{ Mustache }} 挿入も textNode 上の v-text ディレクティブとしてコンパイルされます。

と書いてある。

#### 例
`v-text`で指定した`hoge`がマスタッシュ構文の場合と同様に表示される。

```html
<p v-text="message"></p>
{{ message }}
```

#### 主な用途
あまりわからず、、

## v-html
ノードのinnterHTMLを更新する。
=> html形式の文字列をテキストではなく、プレーンなhtmlとして評価する。

#### 例
pタグのinnterHTMLにデータオブジェクトの`html`を設定している。

```js
data() {
  return {
    html: '<span style="color: blue;">blue</span><br/><span style="color: red;">red</span>'
  }
}
```
```html
<p v-html="html"></p>
```

#### 主な用途
サーバーサイドからのレスポンス（html形式の）をそのまま表示する場合など。

#### 注意点
XSSの危険性があるため、信頼できるデータソースからのデータのみに使用する。
入力フォームなどに使うのはNG。
GoogleAppsScriptの挙動・動作



[GoogleAppsScriptを起動時/編集時に動かす](https://googleappsscript.info/2017-07-23/setting_onopen_onedit.html)

```js
onEdit(e)
```

[Event Objects  |  Apps Script  |  Google Developers](https://developers.google.com/apps-script/guides/triggers/events)

```js
let value = e.source.getActiveSheet().getRange("A1").getValue();
```

source使うことも多くなりそうだなと。
SpreadSheetオブジェクトが返ってくるので色々できそう。

[複数列にまたがるデータ一覧から検索条件に一致する値を取り出す方法 - Qiita](https://qiita.com/AquaMeria/items/a17591715a40f9c0c2ea)

複数行データから見出しを検索する必要があったので非常に参考になりました。
SUMPRODUCT関数のこういう使い方があることを初めて知りました。
数学の配列の授業まともに受けとけば良かったとしみじみ。

[Googleスプレッドシート初心者脱出！SUMPRODUCT関数を使ってみよう ｜ SiTest (サイテスト) ブログ](https://sitest.jp/blog/?p=7871)

___COUNTIF関数で日付比較するとき___

```
=COUNTIF(A1:A10, "<=2013/9/1")
```
yyyy/m/dを文字列として比較しちゃって良いみたい。
[COUNTIF関数で特定の日付の以前・以降をカウントするには:Excel(エクセル)の関数・数式の使い方/統計](https://www.relief.jp/docs/excel-countif-date-less-greater-than.html)
GCE上でFlask+uWSGI+Nginxの簡易webアプリ：メモ

今回はGCE上でflaskを動かしてみることを試したので、その手順をメモに残す。
## GCEでVMインスタンス作成
GCEにログインしてComputeEngineでVMインスタンスを作成を選択。
イメージはubuntu18.04を使用。
ファイアウォールでHTTP トラフィックを許可する、HTTPS トラフィックを許可するに設定。

作成後、VPCネットワーク、外部IPアドレスから固定のIPアドレスを予約する。
これで事前の準備は完了!

## Flaskのインストール
まず、Flaskインストールのために必要なpythonとpipをインストールし、その後にflaskをインストール。

```bash
$ apt update #パッケージリストの更新
$ apt upgrade #インストールされてるパッケージの更新
$ apt install python3 #python3のインストール
$ apt install python3-pip #pipのインストール
$ pip3 install flask #flaskのインストール
```

## 簡易なFlaskアプリの準備
今回はhomeフォルダの下にflaskというフォルダを作成し、その下にapp.pyを作った。

```bash
$ cd /home
$ sudo touch flask
$ cd /home/flask
```

hello worldと表示するだけの簡易なwebアプリ。

```python:app.py
from flask import Flask

app = Flask(__name__)

@app.route("/") #このpathにアクセスがきたときに実行する処理
def index():
    return "hello world"

if __name__ == "__main__":
    app.run(host="0.0.0.0",port=80)
```

flaskだけの簡易なサーバーを実行

```bash
$ sudo python3 app.py 
```
「http://xxxxx:80」　
（xxxはGCEで設定したIPアドレス）で「hello world」と表示されていることを確認

## Nginx・uWSGIインストール

```bash
$ apt install nginx    #nginxのインストール
$ pip3 install uwsgi   #uwsgiのインストール
```

その他、必要なパッケージをインストール

```bash
$ sudo apt-get install uwsgi-plugin-python
$ sudo apt install uwsgi-plugin-python
$ sudo apt-get install libpcre3 libpcre3-dev
```


## Nginxの設定

/etc/nginx/下に設定を作成する
ubuntuだとsites-available下にファイルをおき、sites-enabledにそのショートカットを作っておく

```bash
$ cd /etc/nginx/sites-available #移動
$ sudo touch uwsgi #名前は自由
$ sudo vi uwsgi
```

設定ファイルの中身
nginxにきたアクセスはuwsgiに任せるというような指示

```bash:uwsgi
server {
    listen       80;

    location / {
        include uwsgi_params;
        uwsgi_pass unix:///tmp/uwsgi.sock;
    }
}
```

```bash
#ショートカットの作成
$ ln -s /etc/nginx/sites-available/uwsgi /etc/nginx/sites-enabled/uwsgi 

#defaultの削除
$ cd  /etc/nginx/sites-enabled
$ rm default
```

あとはnginxを再起動して問題がないか確認をする

```bash
$ sudo systemctl restart nginx.service #nginx再起動
$ sudo nginx -t #nginx自体に問題ないか確認
```

## uWSGIの設定
最後にuWSGIの設定を行う。
uwsgiの設定 uwsgi自体はパラメータをまとめてかいた設定ファイルを用意しておき、以下を実行して起動することができる

```bash
uwsgi (設定ファイル読み込み)
```

設定ファイルはflaskのプロジェクトフォルダに作る(今回の場合だと/home/flask/)

```bash
$ cd /home/flask #移動
$ sudo touch flaskapp.ini #ファイルの名前自由
$ sudo vi flaskapp.ini
```

ファイルの内容

```:flaskapp.ini
[uwsgi]
plugins = python3
module = app
callable = app
master = true
processes = 1
socket = /tmp/uwsgi.sock
chmod-socket = 666
vacuum = true
die-on-term = true
```

## uWSGIの起動

sshでの接続が切れても、serverを立ち上げたままにするためにnohupというコマンドを使用する

```
$ cd /var/log
$ touch uwsgi.log
$ nohup uwsgi --ini flaskapp.ini --logto /var/log/uwsgi.log &
```
Django のモデル定義を一瞬で SQLAlchemy に変換する魔法のような方法

魔法、それは聖なる力🌞 (元ネタはしりません)

Qiitaに書くのは初めてなのですごく緊張しています🙄
そんなに長くないので最後まで読んでいただけるとうれしいです。

対象読者は以下のような方を想定しています😺

- Djangoと一緒にSQLAlchemyを使いたいが、モデルを定義するのがめんどくさい方😡
- Djangoから他のフレームワークに移行してORMにSQLALchemyを使いたい方🥺

以前も同じような記事を自分のブログで書いたんですが、今回は一味違います。(ハードルを上げていくスタイル)

こちらのライブラリを使います👇

https://pypi.org/project/d2a/

当然かもしれませんが Django と SQLAlchemy がインストールされている必要があります。Django は 2.2以上、SQLAlchemy は 1.1以上であれば動作するはずです。

# 基本的な使い方

使い方はかんたん。インストールしてコマンド実行するだけです🍄

pip やらでインストールして、

```shell
$ pip install d2a -U
```

settings.INSTALLED_APPS に追加して、

```python
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # :
    # :
    'd2a',
]
```

コード実行 (完)

```shell
$ ./manage.py sqla_codegen
```

実際にコード生成されたものが[こちら](https://github.com/walkframe/d2a/blob/master/project_postgresql/models_sqla_example.py)です。(指定したオプションは少し違いますが...)

さて、このコード生成というのは `d2a` の3系でリリースされたもので、2系までは変換したものはインメモリで保持していました🧠
しかしインメモリで保持するとエディタの補完も効かないし実際に何が行われているのかわからないという大きなデメリットがあります。しかもこんなスターの少ないライブラリを本番のランタイムで動かすなんて不安だ。そう思われてしまっても仕方ありません😵

でもコード生成なら出力されたファイルを確かめられるし、もし間違っていても自分の手で修正できるわけです🤝
生成されたファイルはほぼ `SQLAlchemy` にしか依存していないというのが地味に注目ポイントです。
Columnのdefault引数については Django のモデルを参照していますが、これは関数等のコーラブルなオブジェクトが指定された場合に文字列に戻すことができないため苦肉の策です。

Djangoを使っている方は定期的にコマンド実行して出力されたファイルをリポジトリに格納すると良いでしょう。自動生成系のファイルはリポジトリに入れないという考えの人がいるかも知れませんがこれは入れてください。

他のFWに移行する方は後述する設定ファイルにてdefaultにNoneなどを指定して出力すればDjangoへの依存も全くなくなります👌

# 少し進んだ使い方

## コマンドオプション

コマンドのオプションは現状３つだけです💅

- `--path`: 生成先のファイルパス
- `--template-path`: テンプレートのパス(`settings.TEMPLATES` からの相対パス)。パス指定されたテンプレートによって生成コードを自由に変更できる
  - 現在のテンプレートは[こちら](https://github.com/walkframe/d2a/blob/v3.0.1/project_postgresql/original_template.tmpl)
- `--db-type`: データベースのタイプ。settingsから自動的に判断するため基本は指定しなくてOK。

https://docs.walkframe.com/products/d2a/features/codegen.html

## 設定ファイル

`settings.D2A_CONFIG` を設定することで細かい生成ルールやカスタムフィールドの扱いをハンドリングできます🍏

https://docs.walkframe.com/products/d2a/config.html


## ショートカット
せっかくDjangoを使っているのにSQLALchemyを使うためにDBの接続情報を二重で定義したくありませんよね。

d2aで用意してあるショートカット関数を使うことで Django の接続情報を使ってクエリを発行できます。是非試してみてください。

https://docs.walkframe.com/products/d2a/features/shortcut.html

# おわりに
このライブラリも初回にリリースしてから3年ほど経ったようです🤓
最初は全然使えなかったんですが、少しずつ機能拡張をするうちに段々とライブラリらしくなってきたようで嬉しく思っています。

もし少しでも興味を持った方がいたらスターしてもらえるとうれしいです😭
モチベーションになります！

https://github.com/walkframe/d2a

ブログもあるんですが、過疎化しているので紹介系の記事は利用者の多いプラットフォームに書いてます🐸
勉強した内容とかはブログ👇に書くので興味ある方はこちらもよろしくおねがいします👻

https://note.crohaco.net/
AWS LambdaでPillow-SIMDを使用した際に起きたエラーの解決方法

# はまったエラー
Lambda上でPillow-SIMDを使用した際に下記のエラーが発生した。
```Unable to import module 'app': libjpeg.so.8: cannot open shared object file: No such file or directory```
エラー内容はPillow-SIMDを使用する際に依存モジュールであるlibjpegが存在しないよというもの

# 解決方法
##1.libjpeg.soなど必要な依存モジュールをまとめたzipを作成する
##2.右上のレイヤーの作成をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699070/49a8a2fe-e6ba-c7e9-d469-c83c78edb74f.png)
##3.名前に任意の名称を入力し、1で作成したzipをアップロードし作成をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699070/40563ab1-26da-3367-45e6-3ea6b8924c4c.png)
##4.レイヤーが作成されるのでarnをコピーしておく
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699070/c22b8fe8-b650-893a-d41e-a96c72d3e2a1.png)
##5.コピーしたarnを下記のページを参考にconfig.jsonに設定する。

```config.json
      "automatic_layer": true,
      "layers": [
        "4でコピーしたarn"
      ]
```

## 参考URL
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html
https://qiita.com/t-kigi/items/0b4dd6bd15313faa3d73
MySQL操作で使う基本コマンド

#MySQLの基本コマンド

###rootユーザーでのログイン
下記コマンド入力後にパスワード入力を求められるため、入力しEnter
※ただしパスワードは入力しても文字数すら表示されないため、気をつけて入力する

```terminal:rootユーザーでのログイン(パスワード有)
mysql -u root -p
```

###ログアウト
```terminal:ログアウト
exit
```


##データベースに対する操作

###データベース一覧表示

```terminal:データベース一覧表示
show databases;
```


###データベースの作成
「testdb」というデータベース名のデータベースを作成する

```terminal:データベースの作成
create database testdb;
```
作成されたかどうかの確認は「データベース一覧表示」コマンド


###使用するデータベースを選択する
「testdb」というデーターベースを使用する

```terminal:使用するデータベースを選択する
use testdb;
```

##テーブルに対する操作

###テーブル一覧表示
デフォルトで作成されているテーブルは存在しないため、０件表示になる
※エラーにはならない

```terminal:テーブル一覧表示
show tables;
```


###テーブルの作成
1. 「testtb」というテーブルを作成する。<br>

1. テーブルには数字型の「id」と文字列型の「name」という列(カラム)を持たせる。
   数字型は特殊な使い方をしない場合は、**int型**を使用する。
   文字列型は**varchar型**と**char型**の2種類があるが、char型の場合は文字数が固定となり、追加した値の文字数が少ない場合には空白で文字うめをした状態でデータが格納される。使用用途によって使い分ける。また、varchar型の後ろの数字はバイト数を表す、**日本語の場合は1文字あたり3byte**になるため、その点を考慮して余裕を持たせて設定する。

1. 「not null」を設定し、「name」と「subtesttb_id」を必須項目に設定。
　 ※主キーの「id」はprimary keyに設定した時点で「必須項目」となっているため設定不要

1. idを主キーを設定。subtesttb_idを外部キーに設定(参照先はsubtesttbテーブルのid列)。
　 ※subtesttbテーブルを作成してから実行しないと、エラーになります。

```terminal:テーブルの作成
create table testtb(
  id int primary key,
  name varchar(40) not null,
  subtesttb_id int not null,
  foreign key (subtesttb_id) references subtesttb (id)
);
```
作成されたかどうかの確認は、「テーブル一覧表示」コマンド


###テーブル設定情報の確認
testtbテーブルの設定情報を見ることができます。

```terminal:テーブルの設定情報の確認
show columns from testtb;
```

##テーブル内の要素に対する操作

###テーブル内のデータ一覧表示
testtbテーブル内のデーター一覧表示をします。

```terminal:テーブル内の要素の取得
select * from testtb;
```

###テーブルに要素を追加
testtbテーブルに下記要素を追加します
>id:1
name:taro
subtesttb_id:1

```terminal:テーブルに要素の追加
insert into testtb(
  id,
  name,
  subtesttb_id
) values (
  1,
  'taro',
  1
);
```
追加できたかどうかの確認は「テーブル内のデータ一覧表示」コマンド

###テーブル内の要素の更新
testtbテーブルの下記要素を更新します。
※要素をwhereで指定しない場合、テーブル内の全件更新になるので注意
>id:1
name:taro→jiro
subtesttb_id:1

```terminal:テーブル内の要素の更新
update
  testtb
set
  name = 'jiro'
where
  id = 1;
```
更新できたかどうかの確認は「テーブル内のデータ一覧表示」コマンド


###テーブル内の要素の削除
testtbテーブルの下記要素を削除します。
※要素をwhereで指定しない場合、テーブル内の全件削除になるので注意

>id:1
name:jiro
subtesttb_id:1

```terminal:テーブル内の要素の削除
delete from
  testtb
where
  id = 1;
```
削除できたかどうかの確認は「テーブル内のデータ一覧表示」コマンド
Railsチュートリアルまとめ 第1章

# Railsチュートリアル
以前少しチュートリアルをやったことはあるが、こういったqiitaのように他人に伝わりやすい形でアウトプットできていたかと言われればできていなかったかもしれない。
今回はチュートリアルをもう一度やり直してなるべく分かりやすく、かつシンプルにまとめていこうと思う。

# 目次
[1.railsアプリの作成](#1-railsアプリの作成)
[2.Bundler, Gemfile](#2-Bundler, Gemfile)
[3.MVCアーキテクチャの説明](#3-MVCアーキテクチャの説明)
[4.簡単なルーティングとアクション](#4-簡単なルーティングとアクション)
[5.gitの使い方](#5-gitの使い方)
[6.herokuにデプロイ](#6-herokuにデプロイ)

#1. railsアプリの作成
railsでアプリケーションを作成する際はまず作成したいディレクトリに移動する。
そして`rails _バージョン_ new アプリ名`コマンド実行でアプリケーションを作成できる。

#2. Bundler, Gemfile
Bunderとはgemのバージョンや依存関係を管理するもの。gemはRubyのライブラリ。
`bundle install`コマンドでgemのインストールを行う。

gemのバージョンを指定する主な方法は２種類ある。
①gem 'capybara', '>=2.15'
->最新バージョンのgemがインストールされる。（2.15以上のバージョンならインストールされる）
②gem 'rails', '~>6.0.3'
->gemのバージョンが6.0.3以上で6.1よりも小さい場合にインストールされる。(マイナーバージョンの部分に相当するアップデート済のgemをインストール）

### bundle installとbundle updateの違い
* bundle install
bundle installはgemfile.lockを元にgemのインストールを行うが、gemfile.lockに記述されていない、gemfileに記述されているgemがある場合はそのgemをインストール。その後gemfile.lockを更新する。

*bundle update
bundle updateはgemfileを元にgemのインストールを行い、gemfile.lockを更新する。

bundle updateは本番環境ではgemのバージョンのズレが起こり、アプリがクラッシュしてしまう可能性があるので基本的にはbundle installを使い、ローカルでのみbundle updateを使うべき。

#3. MVCアーキテクチャの説明
* model ... データベースとのやりとり
* view ... 表示処理をする
* controller ... リクエストを処理する
Railsアプリの通信の流れはブラウザからリクエストを送り、コントローラに渡されて必要に応じてビューを生成しHTMLをブラウザに送り返すといったようになっている。また、データベースからデータを引き出す必要がある際はコントローラはモデルを呼び出し、モデルはデータベースとやりとりをする。

#4. 簡単なルーティングとアクション
config/routes.rbに
root 'コントローラ名#アクション名'
を書くと一番最初のページを指定できる。(ルートに接続する時にどのコントローラのどのアクションに繋がるかを設定できる)

app/controllers/application_controller.rbには
def アクション名
  処理内容
end
というように書く。

#5. gitの使い方
gitをインストールしたばかりであれば、初めに`git config --global user.name "名前"`と`git config --global user.email メールアドレス`で名前とメールアドレスを設定する。
gitを使いたい場合はgithubでリポジトリを作成して
①`git init`コマンドを実行して.gitを作成。
②`git add -A` （ファイルをステージング）
③`git commit -m "Initialize repository"`
④`git remote add リポジトリのURL`
⑤`git push origin master`(-uオプションをつけるとgit pushのみでmasterにpushできるようになる)

よく使うコマンド
* git branch ブランチ名 ... ブランチを作成(-dオプションをつけるとマージされている指定したブランチを削除、-Dオプションならマージされてなくても削除)
* git checkout ブランチ名 ... ブランチを切り替える(-bオプションをつければ新規にブランチを作成してそのブランチに移動)
* git status ... ステージングの状態を表示する
* git log ... コミットメッセージの履歴を参照する

ちなみにgit commitメッセージは**現在形**で**命令形**で書くようにすること。

#6. herokuにデプロイ
heroku createでherokuアプリを作成。同時にgit remoteにもherokuが追加される。（git remote -vでリモートを一覧表示）
git push heroku masterでデプロイ。

herokuはデフォルトがpostgresqlなのでrailsのデフォルトと違うことに注意。（railsはsqlite3）
gemfileに開発環境、テスト環境はsqlite3で本番環境はpgを使うように書く。

## herokuでデプロイ時にエラー
heroku openでエラーになってしまった。
エラーをみてみるとapp crachedになっているが原因わからず。
[こちら](https://jyu2log.com/rails-no1-heroku-deploy/#SQlite3)を参考にしてheroku run consoleを実行してみると、どうやらherokuでsqliteを使おうとしてしまっていることが分かった。
そこでconfig/database.ymlのproductionの設定を
`adapter: postgresql`
`database: db/production.pg`
に変更。

これでコンソールが動いたので再びheroku openでデプロイ成功。


## 参考文献
以下の記事を参考にさせていただきました。
[bundle installとbundle updateの違いについて](https://qiita.com/lasershow/items/1a048d03ddaaba98171e)
[Railsチュートリアル1章でHerokuにデプロイできない時の対処方法](https://jyu2log.com/rails-no1-heroku-deploy/#SQlite3)
[Qiitaの投稿記事内でページ内リンクや目次リンクを行う方法](https://qiita.com/tsunasandot/items/d0972fb3bfc0d4156b34#5-%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB)
AWSセッションマネージャーでEC2にSSH接続する

# 概要
AWS EC2に対してSSHでのログインを行う際に、踏み台サーバからのログイン・直接SSH接続などのオンプレライクな接続方法が今更ながらイケてないなと感じ、セッションマネージャー（SSM）を用いたインスタンスへのログインを試してみました。

他の先人の方々の記事を参考に試してみたという自分用メモですので特に目新しい記事にはなっておりません。

# そもそもセッションマネージャーとは
セッションマネージャーとはなんぞやというあたり、またその利点については詳しく書いてあるリンク貼っておきます。

[AWS Systems Manager (SSM) を やってみよう](https://blog.serverworks.co.jp/tech/2020/04/16/systems_manager_yattemiyou/)
[セッションマネージャー越しにSSHアクセスすると何が嬉しいのか](https://dev.classmethod.jp/articles/ssh-through-session-manager/)

要するに、SSMの機能の一部の「セッションマネージャー」とやらを使うと、以下のような利点がありますよと言うことです。（と理解しています）

- 踏み台サーバが不要
- IAMで認証・認可できる
- SSH用のインバウンド設定する必要無い

# 設定手順
手順についても他の方の記事等参考にさせていただきました。

[初めてのAWS Session Manager（SSM）](https://qiita.com/comefigo/items/b705325d082018ab2348)
[EC2インスタンスにWindowsとMacからセッションマネージャーを利用して接続してみた](https://dev.classmethod.jp/articles/ec2-login-with-session-manager/)

## IAMロール作成
SSMを利用するためのIAMロールを作成します。

1. 「IAMロール」 > 「ロールの作成」
![1png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340134/e2c1f7a3-841d-df70-2bd2-f6f0ff642f04.png)

2. 「AmazonEC2RoleforSSM」を選択 > ロール名等指定して作成
![2png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340134/72c5f617-347b-dd05-c40d-9bfb00445a47.png)



## インスタンス作成
SSH接続対象のインスタンスを作成します。

1. 「EC2」 > 「インスタンスを起動」 > 先程作成したIAMロールを付与
![３png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340134/108c6dec-901e-2389-4a64-112bcf9f8c81.png)

## クライアント端末（Mac）の設定
aws-cli はインストール済み、また設定も完了していることを前提とします。ここでは Session Manager plugin のインストール方法のみ記載します。（cli の設定等は [設定手順](#設定手順)に貼ったリンク参照）

```bash:bash
$ cd /tmp
$ curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip" -o "sessionmanager-bundle.zip"
$ unzip sessionmanager-bundle.zip
$ sudo ./sessionmanager-bundle/install -i /usr/local/sessionmanagerplugin -b /usr/local/bin/session-manager-plugin
```
## 接続
aws-cli を用いてセッションマネージャー経由で作成したインスタンスにログインを行います。

```bash:bash
$ aws ssm start-session --target <インスタンスID>
```

# 感想
踏み台とか余計な設定とかなくなってラッキー:star:
セッション履歴をS3に保存できるみたいでそういった管理もうまくできそう。
以下の点が未検証なので確認したいと思っています。

- [x] インスタンス作成時に登録した認証鍵を持っていないユーザでも適切なIAMさえあればログイン可能なのか
    - [AWS公式ドキュメント](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager.html) に書いてありました。そもそも鍵の管理をしなくても接続できるということも利点の一つですね。
- [x] グローバルIPのないEC2(プライベートサブネット内のEC2)に対してのセッションマネージャーを用いたSSH方法
    - [こちらの記事](https://dev.classmethod.jp/articles/ssm-session-manager-private/) にあるようにplivatelinkを用いた方法で実現できるようです
ActionCableでのメッセージ機能について

# ActionCableについて
ActionCableとは、通常のRailsアプリケーションと同様の記述で、即時更新機能を実装できるフレームワークです。例えば、メッセージやコメントを即時表示させたい場合に使用します

#実装について

まずは以下のコマンドをターミナルで打ち込んでください

```terminal
rails g channel message
```

このようになれば成功です。

```terminal
Running via Spring preloader in process 11084
      invoke  test_unit
      create  test/channels/message_channel_test.rb
      create  app/channels/message_channel.rb
   identical  app/javascript/channels/index.js
   identical  app/javascript/channels/consumer.js
      create  app/javascript/channels/message_channel.js
```

今回の実装では以下の2つのファイルについて理解する必要があります。

message_channel.rb
クライアントとサーバーを結びつけるためのファイルです。

message_channel.jsの役割
サーバーから送られてきたデータをクライアントの画面に描画するためのファイルです

<br>

では、さっそくコードを書いていきます。
まずは、サーバーとクライアントを結び付けます。

```app/channels/message_channel.rb
class MessageChannel < ApplicationCable::Channel
  def subscribed
    stream_from "message_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end
end
```

このとき出てくるstream_fromは、ActionCableで用意されているメソッドでサーバとクライアントを関連づけます。この関連づけられたことで作られるデータの経路をboradcast(ブロードキャスト)と言います。

次にコントローラの編集をしましょう

```app/controller/messages_controller.rb
class MessagesController < ApplicationController
  def new
    @messages = Message.all
    @message = Message.new
  end

  def create
    @message = Message.new(text: params[:message][:text])
    if @message.save
      ActionCable.server.broadcast 'message_channel', content: @message
    end
  end
end
```

下から四行目に着目してください。
broadcastを通して、'message_channel'に向けて@messageを送信するという意味です。content:@messageの指定ミスに注意してください。

さて、いよいよjsファイルを編集します。

```app/javascript/channels/message_channel.js
import consumer from "./consumer"

consumer.subscriptions.create("MessageChannel", {
  connected() {
    // Called when the subscription is ready for use on the server
  },

  disconnected() {
    // Called when the subscription has been terminated by the server
  },

  received(data) {
    const html = `<p>${data.content.text}</p>`;
    const messages = document.getElementById('messages');
    const newMessage = document.getElementById('message_text');
    messages.insertAdjacentHTML('afterbegin', html);
    newMessage.value='';
  }
});
```

ここで出てくるdataは送られてくる情報を受け取っています。
data.contentで,createアクションで指定したインスタンス（@message）を取り出しています。

あとは、通常のJavascriptと同様です。なお、newMessage.value="";としているのはメッセージ入力・送信後は入力フォームに文字を残しておきたく泣いためです。

あとはビューファイルを作って終わりです。お疲れ様でした！

```new.html.erb
<%= form_with model: @message do |f| %>
  <%= f.text_field :text %>
  <%= f.submit '送信' %>
<% end %>
<div id='messages'>
  <% @messages.reverse_each do |message| %>
    <p><%= message.text %></p>
  <% end %>
</div>
```

# 終わりに
ActionCableの他にAjaxなどの似たような技術もあるので、そこについてはまた今度執筆します！！！
【AWS】EC2とは？【初心者】

# 概要

AWSのEC2について学習して理解した内容をまとめた。

# EC2

## EC2とは

仮想サーバーを作る機能を提供するアンマネージドサービス
仮想サーバーのことを**EC2インスタンス**という

## インスタンスタイプ

AWSではさまざまな種類のEC2のインスタンスを使うことができる。
EC2インスタンスの種類は用途別に大きく分けられており、これを**インスタンスタイプ**という
いろいろなインスタンスタイプがあるが、一般的にサーバー用途としてよく使われるのは`T2`と`M5`らしい。

## EBS

EC2インスタンスには1台以上のディスクが必要
EC2インスタンスで一般的に扱うのは**EBS**という機能で作られたボリューム

## 料金

**EC2の料金**=`インスタンス使用量`＋`EBSの費用`＋`通信費用`＋`その他のオプション`

### インスタンス使用量

稼働している秒単位での課金

### EBSの費用

EC2インスタンスで利用するEBSの費用
確保した容量単位の課金

### 通信費用

EC2インスタンスとの通信費用
インターネットからEC2インスタンスに向けた通信は無料で、EC2インスタンスからインターネットに向けた通信のみ費用がかかる。

### その他のオプション

EC2にはさまざまなオプションが追加でき、そうしたオプションを使う場合は費用がかかる。
デリゲートとプロトコル

#始めに
　この記事を書く１週間ほど前から僕はSwiftの勉強を始めたわけですが、学ぶ中で出てきたデリゲートとプロトコルについて簡単に説明します。

#デリゲートとプロトコルの意味
　デリゲートは英語で人に任せるという意味を持っている、プロトコルを用いたデザインパターンのことです。ちなみにプロトコルとはメソッドの書いてある仕様書のことです。
　デリゲートを用いると、他のクラスで定義されたメソッドなどを、自分のクラスで簡単に使用することができます。すなわちデリゲートという操作を行って、プロトコルに書いてある自分の使いたいメソッドを利用するということです。お分かりいただけたでしょうか？

##1.プロトコル
   依頼する処理をメソッドとして定義します。
##2.処理を依頼するクラス
デリゲートメソッドを使用し、プロトコルを適用したクラスから処理の流れを記述します。
##3.処理を依頼されるクラス
プロトコルで定義されたデリゲートメソッドを実装します。

#デリゲートを使う理由
イベント発生を検知する処理と検知した後にする処理を分けることで、コードはわかりやすくなり、処理を任せる側は実際に処理をするクラスやどんな処理をするのかを考えなくていいためだと僕は理解しました。

#終わりに
コードの書き方などは自分自身で０からデリゲートを用いて、コードを書けるようになったときに説明しようと思います。
Ubuntuにpythonをインストールして仮想環境を構築する

# 環境
- 端末：[NVIDIA JETSON AGX XAVIER](https://www.nvidia.com/ja-jp/autonomous-machines/jetson-agx-xavier/)
- os：Ubuntu 18.04 LTS
- インストール対象のpythonのバージョン：3.8

# 背景
Pythonを使用して複数のアプリケーションを同時に開発する場合、
アプリケーション毎に使用するライブラリのバージョンが異なるケースに遭遇するかと思います。
仮想環境を構築することで、同一の端末内に複数の実行環境が構築できます。

# 手順
1. [pythonのインストール](#pythonのインストール)
1. [バージョン確認](#バージョン確認)
1. [venvのインストールとactivate](#venvのインストールとactivate)
1. [pipのアップグレード](#pipのアップグレード)

### pythonのインストール
pythonをインストールします。
ここではpython3.8を対象とします。

```
sudo apt-get install python3.8
```

### バージョン確認
インストールできたことを確認するため、下記コマンドを実行します。

```
python3.8 -V
```

### venvのインストールとactivate
仮想環境を構築するためにvenvをインストールします。

```
sudo apt install python3.8-venv
```

仮想環境を構築します。
下記コマンドを実行することで、指定したディレクトリ配下に仮想環境名のディレクトリが作成され、
配下にモジュールが配備されます。

```
mkdir <仮想環境を構築するディレクトリ>
cd <仮想環境を構築するディレクトリ>
python3.8 -m venv <仮想環境名>
```
仮想環境をactivateします。

```
cd <仮想環境を構築するディレクトリ>
source <仮想環境名>/bin/activate
```
例）<仮想環境名>=venv001、ユーザー名=test001の場合、ターミナルが下記のように表示されます
(venv01) test01:~/dev$ 


### pipのアップグレード
ライブラリのインストールが上手くいかない可能性があるのでpipを最新化します。（これを忘れるとこの後のinstallで結構はまります）
仮想環境をactivateした状態で下記コマンドを実行します。

```
python -m pip install --upgrade pip
```

これで、仮想環境の構築は完了です。
仮想環境をactivate後にpipを使用してライブラリのインストールことで、任意の開発環境が構築可能です。
なお、ここで作成した仮想環境はvscodeからも指定可能です。
dockerでmysqlを立ち上げ、外部から接続できるようにする

開発PCにmysqlをインストールをしていなかったのですが、dbを使った技術検証をするのに不便だったので、dockerでmysqlコンテナを立てることにしてみました。

ディレクトリ構成は下記になります。

```
// ディレクトリ構造
─db
    └─conf
        └─mysqld.conf.d
                my.cnf
```

mysqlの設定として、簡単に以下のファイルを用意しました。

```configuration:my.cnf
[client]
default-character-set=utf8mb4

[mysql]
default-character-set=utf8mb4

[mysqld]
character-set-server=utf8mb4
explicit_defaults_for_timestamp=on

```

下記のコマンドでdockerコンテナ立ち上げます。

```
docker run -v ${pwd}/db/conf/mysqld.conf.d:/etc/mysql/conf.d --name mysql -e MYSQL_ROOT_PASSWORD=root -e BIND-ADDRESS=0.0.0.0 -p 3306:3306 -d mysql:5.7
```

コンテナの状況を確認すると、ちゃんと起動できていることが確認できました。

```
docker ps
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS                               NAMES
0580fa7597c2   mysql:5.7   "docker-entrypoint.s…"   4 seconds ago   Up 3 seconds   0.0.0.0:3306->3306/tcp, 33060/tcp   mysql
```

この状況であれば、ホスト側のPCからlocalhostのポート:3306でmysqlに接続することができます。今回はホスト側にmysqlクライアントがインストールされていないので、dockerコンテナを用意してこのコンテナ内から先ほど立ち上げたmysqlコンテナに接続してみます。

```
> docker run -it --rm mysql:5.7 /bin/bash
root@e24782850c58:/# mysql -u root -p -h host.docker.internal
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 5.7.33 MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
```

無事に接続することができました。設定が反映されているかも確認してみます。

```
mysql> show global variables like 'explicit_defaults_for_timestamp';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| explicit_defaults_for_timestamp | ON    |
+---------------------------------+-------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE "char%";
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)

mysql>
```

設定ファイルも無事に反映されていることが確認できました。

ちなみに今回立ち上げたmysqlコンテナはデータを永続化させる設定ではないので、コンテナを削除したらデータが消えてしまうので注意してください。
【AWS】S3とは？【初心者】

# 概要

AWSのS3について学習して理解した内容をまとめた。

# S3

## S3とは

ストレージサービスを提供するマネージドサービス
簡単にいうと`ファイル置き場`
ファイル置き場のことを**S3バケット**と呼ぶ。
S3バケットはPCのドライブに相当するものというイメージ

## Static website hosting

**Static website hosting**という機能を有効にするとWebServerとして使えるようになる。
ただしプログラムの実行ができないのであくまで静的サイトのホスティングしかできない。

## 料金

保存している`容量`と`転送量(ダウンロード等)`に基づいた従量課金制
ちなみにデータのアップロード時には課金はされない。

## メリット

マネージドサービスのためストレージを自動的に拡張・縮小してくれる。
あとは高い耐久性、安価、データ量無制限、他のAWSサービスとの連携などがある。
rootOnNVMeを使っている人はパッケージアップグレードする時注意！

先日、職場で使っているJetson AGX XAvierのデスクトップが正常起動しなくなるという、
とてもヒヤッとした出来事がありました。

色々と調べてなんとか解決したので、備忘録と、同じ現象になることがある人も多分いると思うので何が問題だったのかと、解決方法をまとめて置きたいと思います。

## この問題が発生しうる人

下記に該当する方は同じ問題が起こっている可能性があります。

* [rootOnNVMe](https://github.com/jetsonhacks/rootOnNVMe)で、ルートパスをSSDに切り替えている
* `apt upgrade`等、パッケージをアップグレードするようなコマンドを実行して再起動した

## 症状

Jetson起動時にデスクトップがが表示されず、黒い画面が一定間隔で点滅して表示されます。黒い画面にはエラーメッセージが表示されています(カメラで写真取るなどしないとエラー内容の確認が難しいです)。

なお、デスクトップは起動しませんでしたが、SSHでCUIに接続することはできました。
ただし、CUDAが使えない、シャットダウンが遅い等、正常に動いている状態ではありませんでした。

## 原因はなんだったのか？

原因は[rootOnNVMe](https://github.com/jetsonhacks/rootOnNVMe)を使ってルートパスを内蔵SDカードからSSDに変更した状態で`apt upgrade`を実行したことが原因でした。

rootOnNVMeは、[data/setssdroot.sh](https://github.com/jetsonhacks/rootOnNVMe/blob/master/data/setssdroot.sh)という「ルートパスをSSDに切り替えるシェエルスクリプト」を起動直後に呼び出すことでSSDにパスを変更しているようです。

ちなみに、パスの切り替えは下記の箇所です。

```shell:data/setssdroot.sh
cd ${CHROOT_PATH}
/bin/systemctl --no-block switch-root ${CHROOT_PATH}
```

デスクトップが起動しなくなる問題が発生した直前、私は`apt upgrade`を実行してパッケージをアップグレードしました。このとき、L4TやLinuxカーネルが更新されたようでした。このとき更新された各種ファイルは当然、SSDに保存されます。

rootOnNVMeは「起動してすぐにSSDに切り替える」というものなので、Jetson起動時に使われるブートローダーやLinuxカーネルは内臓SDカードに入っている古いブートローダーとLinuxカーネルで起動します。このせいでJetsonのシステムに不整合が発生してデスクトップが起動しなくなっってしまったというのが真相のようです。

## 解決方法

よく見ると、READMEに注意書きがありました。ちゃんとREADME読まないとですね；

> Once this service is installed, the rootfs will be on the SSD. If you upgrade to a newer version of L4T using OTA updates (using the NVIDIA .deb repository), you will need to also apply those changes to the SD card that you are booting from.
> 
> Typically this involves copying the /boot* directory and /lib/modules/<kernel name>/ from  the SSD to the SD card. If they are different, then modules load will be 'tainted', that is, the modules version will not match the kernel version.

READMEに書いてあるとおり、SSDの`/boot`と`/lib/modules`をSDカードの同じパスに設置すれば元通り動きました。

そのときに作業したコマンドログです(実行は自己責任でお願いします)
SSHを使ってJetsonに入って実行してください。

```bash
$ sudo su -                 # ルートユーザになる
# mount /dev/mmcblk0p1 /mnt # Jetson内臓のSDカードを/mntにマウント
# cd /mnt
# mv boot boot_org          # もともとあったbooyを念の為バックアップ
# cp -rpf /boot /mnt/boot   # SSDのbootディレクトリをSDカードの方にコピー
# cd /mnt/lib
# mv modules modules_org    # もともとあったmodulesを念の為バックアップ
# cp -rpf /lib/modules /mnt/lib/modules # SSDのカーネルをSDカードの方にコピー
#### 上記コマンドを実行後、システム再起動 ####
```