OmniAICreator/Qiita-1.07M huggingface dataset:
回帰分析 - 「レンタル自転車の利用者予測」を題材に

# 目的
SIGNATEさんの練習問題として公開されている[「レンタル自転車の利用者予測」](https://signate.jp/competitions/114) に挑戦します。レンタル自転車の利用者数を予測します。

# 目的変数と説明変数を選択する
[「データを理解する - データを解析する前にすること」](https://qiita.com/Ambition_TY/private/4229065704815f0cb031)でデータの特徴や傾向を表やグラフを作りながら確認しました。

利用者数を予測するコンペですので、説明変数は自動的に利用者数('cnt')になります。

説明変数は、利用者数('cnt')と相関や関係がありそうな変数を選びます。時間('hr'),温度('temp'),体感温度('atemp')が利用者数('cnt')と相関や傾向がありそうでした。それに加えて、天気('weathersit')も追加します。天気('weathersit')はカテゴリーデータなので相関関係を確認していませんが、関係あると思って投入します。

目的変数・・・利用者('cnt')
説明変数・・・時間('hr')、温度('temp')、体感温度('atemp')、天気('weathersit')
で回帰分析を実施します。

# カテゴリーデータの天気('weathersit')をダミー変数に変換する
天気('weathersit')は
1=晴,やや曇り
2=薄い霧+曇り,霧+千切れ曇,霧+やや曇り,薄い霧
3=小雪,小雨+雷雨+千切れ曇,小雨+千切れ曇
4=大雨+凍雨+雷雨+霧,雪+濃い霧
というデータ構成になっています。データ形式は整数(int)ですが、そのまま投入しても意味がありません。1から4をそれぞれゼロイチ(0,1)の2値にしてダミー変数にします。

One-Hot Encodingというのを使います。

```python
df_one_hot_encoded = pd.get_dummies(df,columns=['weathersit'])
```
こんなイメージです。weathersit_1からweathersit_4まで作られました。
![output_table_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688182/de16174a-846e-9e68-9b91-44c357bb6c58.png)

もし0,1に分かれているか確認したければ、value_counts()をやってみましょう。
```python
df_one_hot_encoded[['weathersit_2']].value_counts()
```
weathersit_2は0が6427件、1が2218件あります。合計が8645ですので、train dataの件数と合致します。

# 回帰分析
いよいよ回帰分析です。

回帰分析で使うモジュールをインストールします。
```python
from sklearn.linear_model import LinearRegression as LR
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
```
説明変数(X)と目的変数(y)を用意します。使うデータはダミーデータを作ったdf_one_hot_encodedを使います。
```python
X = df_one_hot_encoded[['hr','temp','atemp','weathersit_1','weathersit_2','weathersit_3','weathersit_4']]
y = df_one_hot_encoded['cnt']
```
角括弧に使用する変数名を入れます。Xには複数の変数を投入しているので、重回帰分析を行うことになります。

```python
# train dataをtrain dataとtest dataに分けます。
train_X, test_X, train_y, test_y = train_test_split(X, y, random_state=42, shuffle=False)

# 線形回帰モデルを作成する（実はこれは機械学習です）
model = LR()

# trainの説明変数('train_X')と目的変数('train_y')をモデルに投入します。
model.fit(train_X, train_y)

# モデルの精度を確認します。
model.score(test_X, test_y)
```
0.3493 ん...あまり高くないですね。

test dataもtrain dataと同じフォーマットにします。つまり天気の'weathersit'をダミー変数に変換します。

```python
df_one_hot_encoded_t = pd.get_dummies(df_test,columns=['weathersit'])
```
test dataにモデルを適用します。

```python
X_test = df_one_hot_encoded_t[['hr','temp','atemp','weathersit_1','weathersit_2','weathersit_3','weathersit_4']] 
X_test_pred = model.predict(X_test)
```
# 予測結果をcsvに保存する

予測された利用者数はX_test_predに反映されています。これを提出用のフォーマットに保存して投稿します。

```python
sample = pd.read_csv('パスをコピペします/sample_submit.csv', header=None)
sample[1] = X_test_pred
sample.to_csv('保存したい場所のパスをコピペします/ファイル名.csv',index=None, header=None)
```

# 結果と考察
暫定評価は198でした。精度が良い結果を得られませんでした。うまく学習できていないようですので、[Deep learning](https://qiita.com/Ambition_TY/items/73b3b00915d21bba5350)を試したいと思います。
データを理解する - データを解析する前にすること

# 目的
SIGNATEさんの練習問題として公開されている[「レンタル自転車の利用者予測」](https://signate.jp/competitions/114) に挑戦します。レンタル自転車の利用者数を予測するコンペです。

予測する手段として、回帰分析やDeep learning、XBBoostをやってみようと思いますが、その前に、教師データ(train data)の中身を確認します。データ数の確認や基本統計量、グラフなどを出力してデータの特徴や傾向を探ります。

# 使用するデータ
データはコンペのサイトにある[データ](https://signate.jp/competitions/114/data)で入手します。学習用データ(train.tsv)、評価用データ(test.tsv)そして提出用のフォーマットとして応募用のサンプルファイル(sample_submit.csv)が提供されています。tsvはダウンロードした時に、csvに保存し直しました。

# データを読み込む
train dataを読み込みます。いつもnumpy、pandas、matplotlib.pyplotもインストールしています。

```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
```
そしてtrain dataを読み込みます。
```python
df = pd.read_csv("データの保存先のパスをコピペ/train.csv")
```
# 基本的な確認
まずはhead()でデータの頭出し。最初の5つの行が表示されます。
```python
df.head()
```
下から5つの行を出したかったら、```df.tail() ```を使います。尻尾ですね。

コンペのページでデータについて説明されています。文字列なのか、整数なのか書かれていますが、書かれていない時は

```python
df.dtypes
```
で確認しましょう。丸括弧()は不要です。

そして基本統計量を出力します。
```python
df.describe()
```
データ数(count)、平均(mean)、標準偏差(std)、最小値(min)、最大値(max)、第1から第3四分位数を確認する事ができます。

個別に基本統計量を見たい時、例えば最大値だけ見たい時は
```python
df.describe.loc['max']
```
と書きます。

# 相関関係
このコンペは利用者数を予測することが目的です。利用者数('cnt')と他の変数の相関関係を調べて、相関がありそうであれば、説明変数に含めることを検討します。

コードはとてもシンプルです。
```python
df.corr()
```
ただ、これだと全ての変数に対して相関関係を出力してきます。変数名が多いと左右にスクロールする手間が発生します。今回は利用者数に対して相関関係を見たいので、

```python
df.corr()[['cnt']]
```
を実行します。

![output_table_1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688182/a080e825-8e0c-9354-d1b8-180a3983d4b7.png)

シンプルな出力になりました。0.4を超えているのが時間('hr')、温度('temp')、体感温度('atemp')で、季節('seanson')は0.2を超えています。季節('season')や曜日('weekday')はカテゴリーデータなので、この表を見て、相関の有無を判断することはしない方が良いと思います。カテゴリーデータはクロス集計などを作って特徴あるデータかどうか判断しても良いでしょう。


# クロス集計
時間('hr')と利用者数に相関がありそうです。曜日ごとに何か特徴があるかもしれません。そこで、利用者数を時間('hr') x 曜日('weekday')でクロス集計を作りたいと思います。

```python
p_table2 = pd.pivot_table(data=df.loc[:,['cnt','weekday','hr']], index = 'hr', columns = 'weekday', aggfunc='mean')
p_table2.columns=['Sun.','Mon.','Tue.','Wed.','Thr.','Fri.','Sat.']
p_table2
```
曜日('weekday') x 時間('hr')で表したければindexを'weekday'にして、columnsを'hr'にします。

```python
p_table3 = pd.pivot_table(data=df.loc[:,['cnt','weekday','hr']], index = 'weekday', columns = 'hr', aggfunc='mean')
p_table3.index=['Sun.','Mon.','Tue.','Wed.','Thr.','Fri.','Sat.']
p_table3
```
でコードを書きます。

どちらの表もaggfunc='mean'なので平均値で出力しています。

# グラフ
グラフを描く事で、データの特徴や傾向をビジュアルで理解できるようになります。上で出力したクロス集計表をグラフで示すともっとわかりやすくなります。

利用状況をグラフにしてみました。.plot()を最後に付け足すだけです。
```python
p_table2 = pd.pivot_table(data=df.loc[:,['cnt','weekday','hr']], index = 'hr', columns = 'weekday', aggfunc='mean')
p_table2.columns=['Sun.','Mon.','Tue.','Wed.','Thr.','Fri.','Sat.']
p_table2.plot
```
やはり、グラフにした方がわかりやすいですね。
![output_graph_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688182/7908edaf-ddbb-be85-81f6-fb0d39d88e0f.png)

土日と平日で傾向がはっきり分かれていますね。

曜日('weekday')はカテゴリーデータです。pivot_tableを実行してグラフにしましたので、このようにグラフを描く事ができました。pivot_tableを実行しないで、そのまま変数を投入すると期待しているグラフが出力されません。カテゴリーデータでグラフを描くにはひと工夫必要です。詳しくは[「生データ(raw data)のカテゴリーデータからグラフを作る - グルーピング」](https://qiita.com/Ambition_TY/items/77918cd2ed9a6dcd6283)をご覧ください。グルーピングという作業が必要です。
ノーコードを使ってみて

### はじめに
ノーコードと言われるツールが、ここ近年好調のようで、わりとユーザー数を伸ばしているようです。ノーコードとは、コードを書かずにWebシステムが構築できるツールのことです。コードを書かないため、非エンジニアでもシステムが構築できてしまいます。これが一番の大きな特徴です。ノーコードによって、既存のエンジニアの仕事が奪われるのではと囁かれていますが、実際のところどうなのでしょうか。未来の事は誰にも分かりませんが、現時点での、ノーコードを触った自分の印象を書いてみます。

### 感想
ラクスが出している楽楽販売というノーコードツールを使ったことがあります。テレビＣＭも行っているため、聞いたことがある人はそこそこ多いでしょう。ノーコードツールの中では有名な部類に入ると思います。このツールを使った感想はと言えば、一言で率直に言って、「確かに便利！」です。簡単な業務管理系のWebシステムなら、ノーコードツールを使えば簡単に構築できてしまいます。サーバーはノーコードを開発しているベンダーが運営、管理をしています。よって、ノーコードツールを触る上で、インフラの知識は一切不要です。既に出来上がっているシステムを使っているような感じです。デプロイといった作業も発生しません。ユーザーは、サーバーOSが何であろうが、ストレージが何であろうが、言語が何であろうが、一切気にする必要はありません。

エンジニアがノーコードツールを積極的に使いたいとは思うことは、まずないでしょう。エンジニアはコードを書いてなんぼだからです。ノーコードツールは単純な処理であれば、簡単に実装できます。しかし、少し複雑な処理を行いたいとなると、途端に実装できなくなります。ツールそのものがパッケージ化されているため、カスタマイズできる範囲に大きな制限がかかることになります。痒いところに手を届かすことはできません。

### 何ができるのか
ノーコードツールを使うと、簡単なCRUD機能を持つWebアプリをサクッと作ることができます。ノーコードツールで作れるのは、本当に単純な機能だけです。多少語弊はあるかも分かりませんが、ノーコードツールで作れるアプリは、RailsのScaffoldで作られるようなWebアプリといっていいでしょう。ノーコードツールを使って、一番便利だと感じたことは、簡単にテーブル設計ができるところです。テーブルの作成、削除がワンクリックで行えます。CUIでCreate tableとか、Drop tableといったSQL文を実行することはありません。SQL文の知識も、ストレージの知識も不要です。カラムの追加や削除もGUIの操作だけで行えます。カラムの位置の移動が、マウスのドラック操作だけで行えます。この便利さには流石に「おーっ」と唸り声が上がりました。カラムの数値型、テキスト型などのデータ型は、プルダウンメニューからの選択で設定することができます。外部キーの設定もGUIの操作で、付け外しが自由自在に行えます。「折角設定したのに、後から仕様変更かよ、めんどくせー」といったことが一切発生しません。それくらいの自由度合です。開発の前段階で作成したテーブルを、開発途中にメンテナンスすることが、本当に一瞬です。この辺りの便利さは、本当に素晴らしいの一言です。エンジニアとしては、寧ろ、RDBのクライアントツールとして提供してもらいたいくらいです。入力画面、一覧画面といった、フロントエンドの作成も、マウスの操作だけで簡単に作成することができます。

### すぐに使えるようになるのか

ノーコードツールは、エンジニアであれば、短時間でマスターできるようになります。ただし、最初は、使い方に慣れる必要があるため、ある程度のトレーニングは必要になります。非エンジニアであれば、トレーニングに多少時間を要することになります。しかし、マスターすることは、さほど難しい話ではありません。ノーコードツールをマスターするために、エンジニア程の知識は必要ありませんが、データベースの簡単な概念は理解しておく必要があります。内部結合、外部結合の概念は理解する必要があります。SQLの文法までは知る必要はありません。他にも、クエリ―、ユニーク制約、ユーザー管理、ロール管理、システム権限など、データベースを学習する時に出てくる、基本的な概念は理解している必要があります。非エンジニアでも使えるとは言ったが、基本的なIT知識は持っていないと、流石に使えるようになるの難しいとはいえるでしょう。テーブル設計の他に、GUIの操作だけでバッチ処理を構築することができます。条件分岐（If文、Swich文）、データ検索（AndとOrの違い）をGUIを使って作成し、処理が流れる順番を設定することができす。この辺りは、基本的なプログラミングの文法だけは知っておくことに越したことはないと言えます。

### 将来性
ノーコードはまだ出てきたばかりです。現時点のノーコードの機能だけでは、エンジニアにとって脅威感は殆どゼロです。ノーコードの機能の性能が飛躍的に向上して、複雑なことがノーコードだけで実現できるようになれば、多少は脅威感は出てくるかも分かりません。ただし、ノーコードの機能が向上することとと、非エンジニアがノーコードを使えるようになることは諸刃の剣とも言えます。システム音痴でも、圧倒的な低工数で、優秀なエンジニアが作成したWebアプリと同程度のものが作成できる日がくれば、それは確かに脅威でしょう。しかし、忘れてはいけないことは、どんなツールであっても、使うのはあくまでも人だということです。システム音痴が音痴のままでいる限り、ITリテラシーの低い人が、ITに何の興味、関心も抱かないままでいる限り、どのような高性能のツールが出てきたところで、エンジニアには何の脅威にもならないと思います。










----------------------------------------------------------------------
Pythonでsnscrapeを用いたツイート抽出

snscrapeは個人のAPIキーがなくても自由にSNSをスクレイピングできます。
詳しくはこちら：https://github.com/JustAnotherArchivist/snscrape

今回はsnscrapeを使って、Twitterから時間、キーワード、いいね数、ツイートの個数を指定して、スクレイピングしてみました。

# 開発環境
* M1 Mac
* python3.8
* pandas

# snscrapeのインストール
```python
pip3 install snscrape
```

# 実装
```python
# 必要なライブラリをインポート
import snscrape.modules.twitter as sntwitter
import pandas as pd

# ツイートの個数設定
maxTweets = 1000
# ツイート検索するキーワード
keyword = '新年'

df=[]
cols=pd.DataFrame([['id','date','tweet','likeCount']])
cols.to_csv('tweet.csv',index=False,header=False)

# 2022年1月1日の「新年」を含むツイート
for i, tweet in enumerate(sntwitter.TwitterSearchScraper(keyword + ' since:2022-01-01 until:2022-01-02 lang:ja -filter:links -filter:replies').get_items()):
        # いいね数20以上、文字数20以上のツイートを取得
        if tweet.likeCount >= 20 and len(tweet.content) >= 20:
            # 改行を削除 
            t = tweet.content
            text = t.replace('\n', '')

            df.append([tweet.id, tweet.date, text, tweet.likeCount])
            df1=pd.DataFrame([[tweet.id, tweet.date, text, tweet.likeCount]])
            # csvファイルとして保存
            df1.to_csv('tweet.csv',index=False,mode='a+',header=False)
        elif len(df) == maxTweets:
            break
```

# 結果
```python
import pandas as pd
tweet = pd.read_csv('tweet.csv')
tweet
```
![截屏2022-08-06 23.16.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744275/98a7383e-5c97-2cb5-95ff-6796ec9801b9.png)

# 参考
https://github.com/JustAnotherArchivist/snscrape
Docker for MacからLimaへの移行メモ

開発環境をM1をスキップしてM2 Macbook Airに移行したので今更Appleシリコン環境への移行をしました。
Lima (version 0.11.3) は普通に使えたのでDocker for Macと比較した注意点だけメモ。

* Docker for MacはMac OSが直接Dockerホストになっていたけど、LimaではDocker的にはLima VMがDockerのホストになる。
* Docker SwarmでpublishしたポートにMac OSからアクセスする場合、service作成時に
`--publish mode=host,target=8080,published=3000`
のように`mode=host`を指定する必要がある
* `mountType`がデフォルトだとsshfsになっているが、chownによるパーミッション絡みのエラーが出るので[9p](https://ja.wikipedia.org/wiki/9P)を使用した
```yaml
mountType: 9p
```
Bootstrap4のprimaryやinfoの色を変更する

Bootstrap4の
- primary
- info
- warning
- danger

の色を力技で変更する場合、かなり面倒くさい。

https://lingtalfi.com/bootstrap4-color-generator#

ここのサイトで簡単に実現できる。

クラス名とカラーコードを入力してGenerateボタンをクリックで、CSSが生成される。

後はコピペしてbootstrap4のCSSを読み込んだ後に読み込むようにする
![スクリーンショット 2022-08-05 15.24.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282328/757473ff-a0eb-7aca-e0c7-a71c6a8e614d.png)
PowerPoint（パワポ）における数式入力のメモ

# はじめに
- 数式入力を頻繁に行わないなら[挿入]タブ > [記号と特殊文字] > [数式]で数式を挿入し、[数式]タブから適宜必要なフォーマットを挿入・編集すればよい。
数式を入力する機会が多くなると、上記のGUI操作は煩雑となる。

- パワポで簡単に（キーボード入力で）数式を記述する際の入力方法として、LaTeX記法とMS系独自の記法がある。

    - LaTeX記法を使う場合は数式オートコレクションによる[事前の設定](https://mathphysnote.com/msoffice/powerpoint-tex/#:~:text=%E3%81%BE%E3%81%9A%20%E6%8C%BF%E5%85%A5%E2%86%92%E8%A8%98%E5%8F%B7%E3%81%A8,%E2%93%89%E3%82%92%E5%85%A5%E3%82%8C%E3%80%81%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%E3%80%82)が必要となる。
    （WordだとLaTeXに切り替えるボタンが標準でついているが、PowerPointだとそれがないのでひと手間かかる。）
    - [ワードやパワポ独自の記法](https://qiita.com/eqs/items/01a18c499bacebbd7aff)はLaTeX記法とは少し異なるので使うなら覚える必要がある。
- それらの入力例および気づいた注意点をメモする。

# 動作環境
- Windows10 64bit
- PowerPoint® for Microsoft 365 MSO (バージョン 2207)

# 数式入力
## 注意点
- パワポにおける数式挿入のショートカットはテキストカーソルを表示させた状態で`Alt`+`;`。覚えておくと便利。
- パワポコードをそのまま貼り付けても表示されない。どこにスペースを入力するかが重要になる。
    - 貼り付けるなら数式入力欄にプレーンテキストとして貼り付け。
    - \コマンドの後ろにスペースを入力（`\matrix`の直後とか）。
    - 数式入力欄の最後にスペースを入力。
- `()`などはパワポの数式フォーマットとして自動認識されてしまうとうまくいかない（見た目だけではわかりにくい）

## 上付き・下付き文字
```math
e^{x}
```
```LaTeX:LaTeX
e^{x}
```
```:PowerPoint
e^(x) 
```

```math
x_{i}
```
```LaTeX:LaTeX
x_{i}
```
```:PowerPoint
x_(i) 
```

## 分数
```math
\frac{1}{x}
```
```LaTeX:LaTeX
\frac{1}{x}
```
```:PowerPoint
1/x 
```

## 根
```math
\sqrt[n]{x}
```
```LaTeX:LaTeX
\sqrt[n]{x}
```
```:PowerPoint
\sqrt(n&x) 
```

## 総和
```math
\sum_{i=1}^N x_i
```
```LaTeX:LaTeX
\sum_{i=1}^N x_i
```
```:PowerPoint
\sum_(i=1)^N x_i
```

## 行列①
```math
M = \begin{pmatrix}
1 & 0 \\
0 & 1
\end{pmatrix}
```
```LaTeX:LaTeX
M = \begin{pmatrix}
1 & 0 \\
0 & 1
\end{pmatrix}
```
```:PowerPoint
M = (\matrix(1&0@0&1))
```

## 行列②
```math
M = \begin{pmatrix}
1 & \cdots & 0 \\
\vdots & \ddots & \vdots \\
0 & \cdots & 1
\end{pmatrix}
```
```LaTeX:LaTeX
M = \begin{pmatrix}
1 & \cdots & 0 \\
\vdots & \ddots & \vdots \\
0 & \cdots & 1
\end{pmatrix}
```
```:PowerPoint
M = (\matrix(1&\cdots&0@\vdots&\ddots&\vdots@0&\cdots&1))
```

## 極限
```math
\lim_{n \to \infty}\frac{1}{n}
```
```LaTeX:LaTeX
\lim_{n \to \infty}\frac{1}{n}
```
```:PowerPoint
lim_(n\to\infty)1/n 
```

## 微分・積分
```math
\frac{dx}{dt} = v(t)
```
```LaTeX:LaTeX
\frac{dx}{dt} = v(t)
```
```:PowerPoint
dx/dt = v(t) 
```
```math
\int_0^\infty f(x) \;dx
```
```LaTeX:LaTeX
\int_0^\infty f(x) \;dx
```
```:PowerPoint
\int_0^\infty f(x) dx 
```

# おわりに
MS系独自の記法はやや直感的に書けるように感じるが、必ずしも万全ではなさそうなので、やはり複雑な数式の場合LaTeX記法に頼るほかなさそう。

# 参考文献
https://qiita.com/eqs/items/01a18c499bacebbd7aff

https://mathphysnote.com/msoffice/powerpoint-tex/#:~:text=%E3%81%BE%E3%81%9A%20%E6%8C%BF%E5%85%A5%E2%86%92%E8%A8%98%E5%8F%B7%E3%81%A8,%E2%93%89%E3%82%92%E5%85%A5%E3%82%8C%E3%80%81%E8%BF%BD%E5%8A%A0%E3%81%99%E3%82%8B%E3%80%82

https://www.itc.u-toyama.ac.jp/el/word102/linear_format.htm#sum
【Ruby, Ruby on Rails】Active Storageで１つの投稿に複数の画像をアップする

## 初めに
プログラミングスクールでは、Active Storageを使って１つの投稿に１枚の写真を保存する方法を学びました。今回、ポートフォリオ制作時に複数枚保存できるといいな、と思って色々調べて実装したのでここにまとめておきます。

## 完成形
- 新規投稿ボタンを押下すると、フォイル選択のフォルダが出てくる。
- Shitキーを押しながら複数枚画像を選択し、アップロードボタンを押下すると、複数枚の画像が投稿フォームに反映される。
- 投稿ボタンを押下すると、上記で詮索した画像とともに投稿される。

## 実装
それでは、実装していきます！
（画像の単数枚投稿が既に頭に入っているという前提で実装方法を説明していきます）

### 下準備(チェックリスト)
##### ✅　以下のgemをbundle install してますか？
```ruby
gem "image_processing", ">= 1.2"
```
##### ✅　投稿を保存するモデル、テーブル、カラムを作っていますか？
※モデル、テーブル、カラムを作成するときに、画像を保存するためのカラムは必要ありません。
※ここではPostモデルとします。

##### ✅　コントローラ、ビューは準備できていますか？
- controller:いつものように新規投稿をするときの記述です。
```ruby
#例）今回はこの記述を使っていきます。
@post = Post.new

def post_params
  params.require(:post).permit(:caption, :user_id)
end
```
- view: form_withを使って投稿フォームを作成していきます。 

### 1. モデルの記述
post.rbに以下のように記述します。
```ruby
has_many_attached :images　
#画像複数枚投稿
```
（参考）以下の記述は、画像単数投稿の際の記述です👇
```ruby
has_one_attached :image
#画像単数枚投稿
```
【単数枚投稿との相違点】
①oneがmanyになっている
②imageがimagesになっている

### 2. コントローラの記述
```ruby
def post_params
  params.require(:post).permit(:caption, :user_id, post_images: [])
end
```
（参考）以下の記述は、画像単数投稿の際の記述です👇
```ruby
def post_params
  params.require(:post).permit(:caption, :user_id, :image)
end
```
【単数枚投稿との相違点】
・ストロングパラメータで受け取る値が、配列になっている

### 3. ビューの記述
```ruby
<%= form_with model: @post do |f| %>
  <%= f.file_field :images, multiple: true, class: 'form-control' %>
<% end %>
#画像複数枚投稿
```
（参考）以下の記述は、画像単数投稿の際の記述です👇
```ruby
<%= form_with model: @post do |f| %>
  <%= f.file_field :image, class: 'form-control' %>
<% end %>
#画像単数枚投稿
```
【単数枚投稿との相違点】
①imageがimagesになっている
②form_withの記述に、multiple: true が追加されている

### 4. 完成！！でも問題点が...
これで機能は実装されました！
しかし、１つの投稿に画像を複数枚保存できるようになったことで問題点が生まれました。
##### サイトの動作がめっちゃ重くなった！！
この問題に関して、少しでも改善するように記述を変更したりしたので、後ほど記事にしてまとめておきます🤗

## まとめ
参考資料はこちらです。
https://railsguides.jp/active_storage_overview.html
何か間違いや改善すべきところがあればご指摘ください！！
php-gdがインストールされていないエラーの解決

## エラーメッセージ
```
Unable to generate image: please check if the GD extension 
is enabled and configured correctly
```

## php-gdがインストールされていない事を確認
```
php -r 'phpinfo();' | grep gd
（何も表示されない）
```

## インストール可能なphp-gdのバージョンを確認
```
yum list | grep gd
```

## 現在のphpバージョンに一致するものをインストール
```
yum install php74-php-gd.x86_64
```

## インストールされた事を確認
```
php -r 'phpinfo();' | grep gd
# 実行結果
/etc/opt/remi/php74/php.d/20-gd.ini,
gd
gd.jpeg_ignore_warning => 1 => 1
```
Swiftの特殊リテラル（#xxx）

◎引用元
Expressions — The Swift Programming Language (Swift 5.7)
https://docs.swift.org/swift-book/ReferenceManual/Expressions.html

◎リテラル式
リテラル式は、通常のリテラル（文字列や数値など）、配列または辞書リテラル、プレイグラウンドリテラル、または次の特殊リテラルから構成されます。

◎特殊リテラル
|リテラル |タイプ |値 |
|---|---|---|
|#file 　　　|String |表示されているファイルへのパス。|
|#fileID 　　|String |表示されているファイル名とモジュール名。|
|#filePath   |String |出現するファイルへのパス。|
|#line 　　  |Int |表示される行番号。|
|#column 　  |Int |その文字が始まる列番号。|
|#function   |String 　　　　　|この関数が含まれる宣言の名前。|
|#dsohandle  |UnsafeRawPointer |出現した場所で使用されている動的共有オブジェクト(DSO)ハンドル。|

◎参考
SwiftでC/C++の組み込みマクロ__FILE__ __LINE__ の書き方 | by Swiftでアプリな日々🐟 | Medium
https://medium.com/@bj1024/swift4-special-literal-de20ab86cf0b

>__FILE__ __LINE__ のような組み込みマクロは C/C++言語ではプリプロセッサによって、ソースファイルパスやソース行数に変換されます。

>Swiftでも__FILE__ __LINE__ と同等の書き方ができます。

◎ただの作者メモ（qiitaでのテーブル作成方法）
Qiitaのテーブルの書き方についてまとめた - Qiita
https://qiita.com/zakuroishikuro/items/f33929eab9d55c5bd073
WASMのゲームをブラウザで拡大表示する方法

　golangとebitengineでwasmなゲームを作っていて。動いたのですが。ブラウザで拡大表示するのに少し苦労しました

```html:index.html
<!DOCTYPE html>
<head>
<style type="text/css">
html, body, iframe {
	width: 100%; height: 100%;
}
body, iframe {
	margin: 0;
	padding: 0;
	border: 0;
	overflow: hidden;
}
</style>
</head>
<body>
<iframe id="Game" src="main.html" scrolling="no"></iframe>
<script><!--
window.addEventListener('load',screenResize,false);
window.addEventListener('resize',screenResize,false);

let retimer;
function screenResize(event) {
	clearTimeout(retimer)
	retimer = window.setTimeout(function(){
		
		let scaleX = window.innerWidth / 1280; // ゲーム画面の横幅（px.）
		let scaleY = window.innerHeight / 720; // ゲーム画面の縦幅（px.）
		let scale = Math.min(scaleX, scaleY);
		
		document.getElementById('Game').width = window.innerWidth * scale;
		document.getElementById('Game').height = window.innerHeight * scale;

	}, 100);
}
//--></script>
</body>
</html>
```
　pixi.jsなどで良く使われている画面拡大ルーチンをiframeへ対応したのですが。CSSの設定が難しい。とりあえず動いてはいますが。想定の動作とは少し違っているので改善の余地はあります

（main.htmlは、ebitengineのwasm読み込みhtmlファイルです）

　メモを置いておきます

### 付記：簡単な方法

```html:indexhtml
<!DOCTYPE html>
<head>
<style type="text/css">
html, body, iframe {
	width: 100%; height: 100%;
}
body, iframe {
	margin: 0;
	padding: 0;
	border: 0;
	overflow: hidden;
}
</style>
</head>
<body>
<iframe id="Game" src="main.html" scrolling="no" allow="autoplay; fullscreen;"></iframe>
</body>
</html>
```
　でも、iframeの全面表示化と、ebitengineの補正機能で、普通で全画面表示が可能でした

　でも、自分はiframeを画面へ合わせて拡大表示して、余白へバックグラウンド画像を表示するんだ…

### 付記：その後
```html:indexhtml
<!DOCTYPE html>
<head>
<style type="text/css">
html, body {
	width: 100%; height: 100%;

	margin: 0;
	padding: 0;
	border: 0;
	overflow: hidden;
	
	-ms-overflow-style: none;
	scrollbar-width: none;
}
body::-webkit-scrollbar {
    display: none;
}
</style>
</head>
<body>
<script src="wasm_exec.js"></script>
<script>
// Polyfill
if (!WebAssembly.instantiateStreaming) {
  WebAssembly.instantiateStreaming = async (resp, importObject) => {
    const source = await (await resp).arrayBuffer();
    return await WebAssembly.instantiate(source, importObject);
  };
}

const go = new Go();
WebAssembly.instantiateStreaming(fetch("wasm.php"), go.importObject).then(result => {
  go.run(result.instance);
});
</script>
</body>
</html>
```
　全画面表示する分には、iframeがいらなかったってオチです…　凄く、面白い。これなので、プログラミングは辞められない…
PHP 7.4以降で型宣言ができることを初めて知った

はいさい！ちゅらデータぬオースティンやいびーん！

# 概要
昨日、ふとしたことで、PHPでも型宣言（Type Declaration）ができることを知ったので、それを共有したいと思います！

筆者はPHPに精通していないので、型があることを初めて知って嬉しく思いました。

https://www.php.net/manual/ja/language.types.declarations.php

# 例
以下のように、関数の引数と返す値の型を指定することができます。

`int`の定義をすると、実行時に`int`以外の型、例えば文字列などを渡したら、エラーが出ます。
```php
<?php
function sum(int $a, int $b): int {
  return $a + $b;
}

$result = sum(1, 2); // OK
$result = sum("a", "b"); // Fatal error: Uncaught TypeError
?>
```
## 関数に説明を添えることもできる
筆者はJavaScriptではよくやっていますが、PHPでも同じ構文で関数・クラスを説明するドキュメントを書くことができます。
```php
<?php
/**
 * Adds two integers.
 * @param int $a First number
 * @param int $b Second number
 * @return int
 */
function sum(int $a, int $b): int {
  return $a + $b;
}
?>
```
VSCodeのIntellisenseと併用すると、その関数の説明を、マウスのカーサをかざすだけで読むことができます。
![スクリーンショット 2022-08-05 12.33.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2344956/53fbac50-d3ab-91ac-5437-d406a4b1018d.png)

# まとめ
短い記事ですが、PHPにもとても便利な機能をご紹介しました！

PHPも、JavaScriptと同じようにWebを意識した言語で、筆者は使い勝手が良くて、しっかりできている言語だと思います。（くそRuby、お前は違うぞ！）
環境変数の意義とは

<h1>結論</h1>
環境変数の意義は、環境変数を設定することによって、本来アクセスできなかった値にコマンドをアクセスできるようにする。<br>
というのが結論である。

<h1>そもそも環境変数とは</h1>
「環境変数とはパソコン内で使える変数の様なもの」という内容をよく見るが、<br>
あまり的を得たかいとうではないな、、というのが本音である。

<h1>環境変数はどこに使われるのか</h1>
それはシェルコマンドである。ここがかなり重要な内容であるがシェルコマンドには2種類のコマンドがある。<br>
・外部コマンド<br>
・組み込みコマンド</n>
<br>
外部コマンドか内部コマンドか判断するには、「type <コマンド名>」をターミナルで打ち込めばよい。<br>

```ruby:ターミナル
$ type cp (外部コマンド)
cp is /usr/bin/cp
$ type cd (内部コマンド)
cd is a shell builtin
```
通常、外部変数はシェル変数($PATHなど)の値を参照できない。</n>
だが環境変数を用いることによって外部コマンドでも変数を使用することができる。

冒頭でもお伝えした通り、(環境変数を用いることで)本来アクセスできなかった値(シェル変数)に
コマンドからアクセスできるようにする。というのが意義にあたる。
UbuntuでPythonを使う前にやること

OS: Ubuntu18.04
Python: 3.8.13

# Make Install Media
Netbooter is better

# インストール
インストールは日本語で使いたい場合であっても英語で行う.
フォルダ名をつけ直す手間が省ける.

## ※サブディスプレイが表示されない場合
```
sudo apt update
sudo apt upgrade
```
Nvidia公式から自分のコンピュータ搭載されているGPUを選択し、バージョンをメモする
https://www.nvidia.com/download/index.aspx

e.g: Geforce2070Superは Version:515.65.01 のなので515, これをメモする
```
sudo apt install nvidia-cuda-toolkit nvidia-driver-515
sudo reboot
```
以下のサイトを参考にした

https://qiita.com/Ginom/items/edd2a65166d6d6787e46

## ※サブディスプレイの色がおかしい場合
lightdmのインストールで解決する場合がある.
```
sudo apt update 
sudo apt install lightdm 
```
以下のサイトを参考にした

https://tecadmin.net/installing-lightdm-on-ubuntu/

# ソフトウエア
Chrome VSCodeなど必要なソフトウエアをインストールする.

https://www.google.com/chrome/
https://code.visualstudio.com/

# 作業ディレクトリの作成
任意の場所に作成する
pyenvで設定する際に用いる

# Pythonのインストール
pipのインストール
```
sudo apt-get -y install python3-pip
```

今回はPyenv+Pipenvで環境整理を行う
pyenvのインストール
https://qiita.com/neruoneru/items/1107bcdca7fa43de673d

必要なバージョンのPythonをインストールしておく.
上記サイトの後に
```
cd /$自分の作成した作業ディレクトリのパス
pyenv local 3.8.6
python3 --version
cd 
python3 --version
```
これを行い, 一度目のpython3 --versionではpyenv local 3.8.6で選択したバージョンのPython, 二度目のpython3 --versionではシステムの規定のPythonになっていることを確認するとよい.

もしpipenvがインストールできない場合は
以下のコマンド
```
pip --version 
pip3 --version
python -m pip --version
python3 -m pip --version
```
でバージョンが同じになっているか確認する.

pipenvのインストール
```
python3 -m pip install pipenv
```
https://qiita.com/y-tsutsu/items/54c10e0b2c6b565c887a


# SSH key
SSHKeyの発行
```
cd ~/.ssh/
ssh-keygen -t rsa -f _rsa
```
パスワードは任意
.pubかついているものをアップロードする.

# 躓いた点まとめ
pip, pip3, python -m pip, python3 -m pip
これらは異なるバージョンのPythonと異なるバージョンのpipを参照する場合がある.
面倒ならばすべて同じバージョンに揃えると良い.

Ubuntuではシステムが使っているPythonがかんたんに消せる.
必ずpyenvなどを用いてバージョンを分ける.
[C#] VSCodeでコードコメント(///)の自動補完を有効化する

VSCodeの設定で `Editor: Format On Type`を`true`にすると、`///`を入力したときにコードコメントが補完される。

```json
{
    "editor.formatOnType": true
}
```

https://github.com/OmniSharp/omnisharp-vscode/pull/4261
【Django】ページをPDF出力する【Python】

# 初めに
本記事はDjangoで作成されたWebアプリケーションのページを、pdfkitというライブラリで出力する記事の目次です。
一番簡単な出力方法からオプションの指定、障害発生とその対策までいくつかの記事にまとめています。
これらを参考にしてページをpdf化させましょう！

# 環境
|名称  |バージョン  |
|---|---|
|Python  |3.10.4  |
|Django  |4.0.6 |
|pdfkit  |1.0.0 |

# 基本編
[【Django】ページをPDF出力する(基本)【Python】](https://qiita.com/nagisa_O/items/3eaaa18d68468e8de7e5)

# 応用編
[【Django】ページをPDF出力する(オプション)【Python】](https://qiita.com/nagisa_O/items/59be49e513cac1c2546d)

# セッション編
[【Django】ページをPDF出力する(セッション)【Python】](https://qiita.com/nagisa_O/items/9cdd82b8313a0fbb0400)

# 障害対応編
[【Django】ページをPDF出力する(障害対応)【Python】](https://qiita.com/nagisa_O/items/4ffd8777f716664affca)

# 追加検証編
※上記全てを読んでいただいた上で後日談的なものとしてお読みください。

障害対応の中で、セッションに格納した値を出力して確認しました。
実は以下のような確認方法も試しました。
```php:views.py
def to_pdf_alone(request):
    # idを受け取る
    id = request.POST.get('id')

    # idをセッションにセットする
    request.session['id'] = id

    # セッションを保存する
    # request.session.save()

    url = 'http://127.0.0.1:8000/test_app/detail/'
    cookie_list = request.COOKIES
    options = {
            'cookie': [
                ('sessionid', cookie_list['sessionid']),
            ]
        }

    print(f'セッションにセットした値: {(id)}')  #セッションの値を確認
    
    session_id = request.session.get('id')
    print(f'セッションからすぐ取り出した値: {(session_id)}')  #セッションの値を確認

    pdfkit.from_url(url, 'sample.pdf', options=options)
    return redirect('test_app:index')

def detail(request):
    # idをセッションから受け取る
    id = request.session.get('id')
    
    print(f'セッションから取り出した値: {id}')  #セッションの値を確認

    # idをキーにDBアクセス
    person = Person.objects.filter(id=id)

    context = {'item': {'id': person[0].id, 'first_name': person[0].first_name, 'last_name': person[0].last_name}}
    return render(request, 'test_app/detail.html', context)
```
自身でセッションに値を格納後、すぐに取り出して中身を確認します。
当然pdfkitと同じ出力結果になると思いましたが、障害対応編の2回目のユーザ操作を実施すると以下のようになりました。
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1225075/59f2f57c-b673-2da7-621d-5c5e7a272ceb.jpeg)
セッション格納後直後に取り出すと値は更新されています。
その後pdfkitがセッションから取得した値は更新前の値となります。

# 考察
まず、自身が取得した値はDB由来でないことは間違いなく、pdfkitとは参照場所は違うはずです。
参照場所はメモリとかでしょうか？

自身がセッションに格納した値を、同関数内で取得することを想定した仕様のように見えますが、
そのような処理が必要な場面があるのでしょうか。あまり想像できません。
何か理由を知っている方がいたらご教授ください。

# まとめ
セッションやcookie周りはWebアプリケーションに欠かせない要素なので、このような検証、
という名の遊びを通して学ぶのも良いかと思います。
SharePoint OnlineでREST Getメソッドを使ってリストアイテムを取得する

SharePointOnline(以下SPO)で作成したリストに対してJavaScriptからデータの取得操作を行った時の覚え書きです。

# はじめに
SPOではREST APIを使用してリスト上のアイテムの取得/登録/更新/削除を行う機能が含まれています。  
本記事ではデータの取得を行うGETメソッドについてまとめました。

# REST要求の送信

SPOにおけるjQueryおよびAjaxを使用したREST GETリクエストのベースは以下のようになります。

```javascript
$.ajax({
  contentType: "application/json;odata=verbose",
  headers: {
    "accept": "application/json;odata=verbose"
  },
  method: "GET",
  url: "https://xxx", // SharePointリソースにアクセスするためのREST URL(後述)
  success: (data => {
    // ここに成功したときの処理を記載する
  }),
  error: (error => {
    // ここにエラーが発生したときの処理を記載する
  })
})
```

## SharePointリソースにアクセスするためのREST URL

ベースとなるURL構成は以下です。
```
https://{サイトURL}/_api/web/lists/GetByTitle('リスト名')
```

# GETメソッドによるデータ取得

今回は以下のような状態を想定してコードを記載しています。
- サイトURL: (ドメイン名)/sites/FruitPortal
- リスト名: Apple

## 条件を指定して特定のアイテムだけを取得する

特定のプロパティに対して条件を設定する場合は、以下のサンプルコードのようにURLにフィルタークエリ(ODataクエリ)を追記してから、続けて条件式を入力します。


```javascript
// Titleプロパティが'example'と一致するアイテムを取得する
$.ajax({
  contentType: "application/json;odata=verbose",
  headers: {
    "accept": "application/json;odata=verbose"
  },
  method: "GET",
  // URLに使用できない文字はURLエンコードした文字に置き換える
  // $ -> %24
  // 半角スペース -> %20
  url: "https://(ドメイン名)/sites/FruitPortal/_api/web/lists/GetByTitle('Apple')/items%24filter=Title%20eq%20'example'",
  success: (data => {
    data = data.d.results;
  }),
  error: (error => {
    console.log(JSON.stringify(error));
  })
})
```  
[OData要求についてはこちらを参照してください。](https://docs.microsoft.com/ja-jp/sharepoint/dev/sp-add-ins/use-odata-query-operations-in-sharepoint-rest-requests)
[URLエンコードの対応についてはこちらを参照してください。](https://www.seil.jp/doc/index.html#tool/url-encode.html)


以下に主要な演算子とよく利用する検索条件についてまとめました。

| 演算子 | 意味 |
|:-:|:-:|
| eq | 等価 |
| ne | 等価でない |
| gt | より大きい |
| ge | 以上 |
| lt | より小さい |
| le | 以下 |

- IDが一致するアイテムを取得する
```javascript
$filter=ID eq 2
```

- 特定のプロパティの数値が指定の数より大きいアイテムを取得する
```javascript
// Countプロパティの値が10より大きいアイテムを取得
$filter=Count gt 10
```

- 指定した日時以降に作成したアイテムを取得する
```javascript
$filter=Modified ge DateTime'2022-08-05T09:00:00'
```

# 終わりに

今回はSPOでREST APIを用いたデータの取得方法についてまとめました。
残りのPOST/PUT/DELETEメソッドも順次公開していきたいと思います。

# 参考ページ

https://docs.microsoft.com/ja-jp/sharepoint/dev/sp-add-ins/complete-basic-operations-using-sharepoint-rest-endpoints

https://docs.microsoft.com/ja-jp/sharepoint/dev/sp-add-ins/working-with-lists-and-list-items-with-rest

https://learntutorials.net/ja/sharepoint/topic/3045/rest%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9
Accessでタブコントロール作成前に存在していたオブジェクトをタブコントロール内へ移動

# やり方

1. 移動させたいオブジェクトに紐づいているイベント一覧を確認しておく。
1. ```Ctrl + X``` で移動させたいオブジェクト切り取る。
1. タブコントロールのページ選択。
1. ```Ctrl + V``` でオブジェクト貼り付け。
1. 下記のような形でイベントを再度紐づけ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/0967fabe-67ba-0f67-98d2-cd9160509eb5.png)


切り取ると **イベントの紐づけが切れる** ので、貼り付け後に再設定が必要なので注意。
（※_Click()のような関数自体は消えないので紐づけのみ行えばOK）

# 参考サイトさん

https://okwave.jp/qa/q498883.html

# バージョン

Windows 10 Pro 21H2 OSビルド 19044.1865
Microsoft Access for Microsoft 365 MSO (バージョン 2206 ビルド 16.0.15330.20260) 32 ビット
日本企業「経験豊富な情シスが足りない」が約6割、だが約4割は「何もしていない」――IIJ調査　を読んで思ったこと


[日本企業「経験豊富な情シスが足りない」が約6割、だが約4割は「何もしていない」――IIJ調査](https://atmarkit.itmedia.co.jp/ait/articles/2208/02/news038.html)

**現在の情報システム部門の人員、人材に関する課題**
現在の情報システム部門の人員や人材に関する課題を見ると、人員や人材が不足している現状が見て取れた。具体的には、「豊富な経験を持った人材が足りない」と回答した人の割合が58.4％（複数回答）、「若手の人材が足りない」が42.1％、「人員が足りない」が37.9％だった。

# 読んだ感想
読んでみると、ふーんって感じ。いや、ずっと前から分かっていたことと思う。まぁ、何もしていないということだけど、企業としてはやる気はないでしょうね。外注すれば済む、金で解決したらいいと思っている経営者が多いと思う。だって解決策は分かってないでしょうからね。でも、これはシステム分野だけの問題でないと思います。

ここ何十年の間に景気が低迷して何でもコストをカットしてきたせいで　色んなことに余裕が無くなったのが一番の原因と思っています。

私自身は何故日本は生産性が低いのかということと同じだと思っています。コストをカットするあまりおそらくワンオペ（管理者もプレーイングマネージャー）が常態化しているので組織としての暗黙知が共有できないことが大きいのではないかと感じました。

所詮一人で経験できる範囲はしれています。他の人、仲間と情報を共有することで疑似的な経験を積むことができると思います。
しかし経験を少しでも多く積むためには時間的、精神的、金銭的余裕がまずは必要だと思います。余裕がないと現状を維持するので精いっぱいでしょう。

私自身は転職して今の会社に入って時間的な余裕は出来ました。（一応管理職相当ですが、部下はいません。役員さん直属です。部下がいないため自分のために全ての時間を使えます。かなり時間的には余裕ができました。）

ただ小さい会社なので情報システムの経験を共有できるメンバーは少ないです。そのため疑似的な経験を積むために英語のコミュニティで回答を続けています。ここで質問に答えるために調べものをしたり、考えたりすることで疑似的な経験をかなり積むことができていると思います。ただ英語なのでストレスが半端でないです。全てWEB翻訳を使っていますがそれでもアルファベットを見るのは辛いですね。やる気が失せます。

# そこで回答していて思ったこと。

日本に限らず海外の質問者さんには　みなさんが良く知っているであろう有名な会社の社員さんも多く見受けられます。私からすればコミュニティで質問しなくても周りに詳しい専門家さんはいっぱいいるでしょうと思ってしまいます。　周りに聴けない雰囲気なのかなって心配になりますね。行き過ぎた成果主義のため周りは競争相手だから教えないのかなぁって思ったりもします。

今の会社では人が少ないので周りに聴くことはできませんが、私は前職でもそういえば周りに聞かなかったですね。とこれは競争とか雰囲気が悪いとかでなくて誰もやってない事ばかりを担当していたので聴く相手がいなかったし、また誰も私に質問するような人もいなかったことが原因ですが...　（しかし前職の会社の雰囲気は良くは無かったなぁ。何でもできて当たり前で、出来なかったら処罰の対象だったから、新しいことはみんな挑戦したがらなかったです。何もしない方が持ち点が減らず結果的には評価が高くなったから...良くできたことは忘れ去られますが、失敗したことはよく覚えられていたと思います。）

また、実際の仕事ではミスを許さない風潮が強いと思います。（まぁ、当然ではありますが...）それでも私が新入社員の頃は周りは温かい目で見てくれていた（ハズ）と思います。お勉強中の丁稚さんなので失敗しながら成長する機会をいただけました。しかし今ではそんな余裕ないですよね。新人でも普通に成果を求められているんじゃないでしょうか？　またいろんな人が時間を取って教えてくれたようにも思います。組織にも余裕があったと思いますね。

もしベンダーさんにお願いして技術者をアサインしてもらった場合に新人さんだったら...今の私は許容できるかな？営業さんを呼んででチェンジしてもらうだろうか？　しかし呼べるだけの予算がないなぁ。仕方ない自分で作ります。

# 人材、人員獲得のために実施している施策 を見た結果

**ただし、待遇や条件の改善には至っていない企業が多いようだ。人員／人材の獲得の施策について聞くと、「何もしていない」と回答した人の割合が最も高く、44.2％だった。**

そもそもやる気はないんだろうなぁって思えますね。所詮サラリーマン経営者でしょう。自分がやっている時だけどうにかなれば後は関係ないでしょうから。結局外から人を取ってくればいいという発想ですね。人を育てる気はさらさらない。　

そうそう、私が前職を辞めた一番の理由はこれですよ。今いる社員を育てるとか、学習するチャンスを与えるとかは全くしないで、すぐに外から人を取ってこようとする姿勢。それを見続けてきたので先はないなぁって思って去ったのが実情です。

せっかくの調査でしたが、何か良くなるとは思えないです。このままなんだろうって感じますね。

まぁ、よその会社さんで経験豊富な情シスが足りてないかには関係なく、自分自身は経験値を上げておきたいと思います。やる気さえあれば、今は時間が自由に使えるので...
【Flutter】WidgetTestでレイアウトを実機やシミュレーターで表示して確認する方法

![rakugo_shimote.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228439/2242f86b-5b5a-e397-6f22-d6b16e464794.jpeg)


一度でいいから見てみたい、

Widget Testのレイアウトが表示されるところ、

どうも個人でアプリ開発をしているYuKiOです。

さて、Flutterの自動テストには「**Unit Test**」、「**Widget Test**」、「**Integration Test**」と３つありますが、

その中で「Widget Test」は、主にアプリのUIを確認するために用いられると思います。

そこで、こんな問題に遭遇したことありませんか？

## WidgetTestで困ること
「テストは通過しているけれど、これ本当に正常に表示されている？」
「タップ処理をしているけれど、Widgetが見つからないでエラーになる。あれ？Widgetが表示されているはずなんだけど・・・Keyが違うのかな？」

のように、WidgetTestはUIをチェックするテストですが、実際レイアウトされた画面が表示されるわけでなく、

**しっかりとテストできているのか？**
**テスト自体が間違っていないのか？**

ちょっと**疑心暗鬼**になることがありました。

「山田君〜。UI見せて」と気軽に解決できればいいですが、残念ながらWidget Testは笑点ではありません。

シミュレーターや実機にビルドしてUIをチェックしてもいいですが、条件を作成したり、分岐などを個々にチェックするのはちょっと大変ですよね。

そこで、**Widget Testでレイアウトを実機やシミュレーターで表示する方法**を紹介します。

## WidgetTestのレイアウトを実際に表示する
とはいえ、大したことはしないのですが、調べてもさっと出てこなかったので記録しておきます。

解決方法は「**WidgetTestのRun**」です。(ちなみにKing of Runといえば応仁の乱ですが、1467年に起きました。)

Flutter runの後に所定のWidget Testファイルを指定すると・・・(test/widget_test/dialog_test.dartの部分を適宜変えてください。)
``` 
flutter run test/widget_test/dialog_test.dart
```

![ダイアログビュー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228439/558845dc-1b65-e1b4-ba3c-7cfeef2238cb.jpeg)


こんな形でチェックできます。テスト中はインテグレーションテストのように動きます。

## 注意点-親のサイズ
ただし、下記のように日付のセレクトのように、親Widgetにサイズが調整されているChildの場合、サイズが自由気ままな感じになるので、SizeBoxなどで、擬似的に枠を作るなどの対策が必要だと思います。

![日付ビュー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228439/58fc0ed1-b848-3476-dfce-5e49cb57b8b3.jpeg)


Widget Testで困っている人の助けになったら、幸いです。

いろんなアプリ作っています。興味があったら見てみてください。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">HackerMemoを大幅にアップデートしたので、<br><br>海外向けのPVを作ってみました😆<br><br>夜なべして頑張って作ったので、拡散頂けたら泣いて喜びます😭🙏<br><br>音有りがオススメです！<br><br>元ネタわかる人いるかな〜🤔<br><br>アプリはこちら🔽<br>■iPhoneの方<a href="https://t.co/6T10L94Ld1">https://t.co/6T10L94Ld1</a><br><br>■Androidの方<a href="https://t.co/uBevCXrNw2">https://t.co/uBevCXrNw2</a> <a href="https://t.co/wiGLv46kaG">pic.twitter.com/wiGLv46kaG</a></p>&mdash; YuKiO｜アプリ個人開発｜Flutter × Firebase (@oo_forward) <a href="https://twitter.com/oo_forward/status/1348103082769453056?ref_src=twsrc%5Etfw">January 10, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
GASでJIRA Cloud REST APIを呼び出す


## 目次
[1.JIRAトークンの発行](#1jiraトークンの発行)
[2.API呼び出しのための情報をスクリプトプロパティに設定](#2api呼び出しのための情報をスクリプトプロパティに設定)
[3.GASでリクエストを投げる](#3gasでリクエストを投げる)

## 1.JIRAトークンの発行
Atlassian アカウントページからAPI TOKENを発行
Atlassian アカウント→セキュリティー→API トークンの作成と管理　から作成可能。

https://id.atlassian.com/manage-profile/security/api-tokens

APIトークンを作成するを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615368/3e43b527-b423-5b45-d5c3-67f961f744f6.png)

何に使用しているトークンかわかるようなラベルを設定し作成ボタン押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615368/28151757-551c-6aaa-40f0-aa1388c28cac.png)

トークンが発行されるのでコピペでどこかに控えておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615368/b5755dfc-3876-a50d-a765-80c25147fc67.png)

## 2.API呼び出しのための情報をスクリプトプロパティに設定
以下項目をプロジェクトのスクリプトプロパティに設定する。

| プロパティ | 設定値 |設定例|
|:-:|:-:|:-:|
|JIRA_BASE_URL|JIRAワークスペースのURL| https://your-domain.atlassian.net/
|JIRA_USER_NAME|ログイン時に使用しているアドレスもしくはユーザー名|user@mail.com| 
|JIRA_API_TOKEN|JIRAAPIトークンの値|| 

:::note info
個人的な好みでスクリプトプロパティを使っているので、
ハードコーディングしたりしても問題ないです。
:::

## 3.GASでリクエストを投げる
例を参考に実装し、APIをコール。
以下例ではissue/createmeta/を呼び出している。
[JIRA REST APIリファレンス](https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro)を参考に使用したい物の情報に適宜書き換えを行う。

https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro

```javascript:GAS
function main(){
  // スクリプトプロパティの読み込み
  const scriptProperties = PropertiesService.getScriptProperties();
  const props = scriptProperties.getProperties();   

  // 呼び出し先のAPIのURLを設定
  var url=props["JIRA_BASE_URL"]+"rest/api/3/issue/createmeta/";

  // ヘッダーを設定
  var headers = {
    "Accept": "application/json",
    "Authorization": "Basic "+Utilities.base64Encode(props["JIRA_USER_NAME"] +":"+props["JIRA_API_TOKEN"], Utilities.Charset.UTF_8)
  }

  // パラメータの設定
  var options =
  {
    "method" : "get",
    "headers":headers
  };

  // APIをコール
  var result = UrlFetchApp.fetch(url, options).getContentText('UTF-8');

  // うまく呼び出せれば結果がログ出力される
  Logger.log(result);
}

```
Prettier の設定をする

備忘録

## Prettier とは
Prettier とはコードフォーマッタです。
ソースコードを整形してくれるやつです。

以下に対応しているらしい
>JavaScript
JSX
Flow
TypeScript
JSON
HTML
Vue
Angular
Ember / Handlebars
CSS
Less
SCSS
styled-components 💅
styled-jsx
GraphQL
Markdown
YAML

## インストールする

![_prettierrc_—_parser-mizumoni.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687433/e156c1d4-56bd-705a-1eff-88c54c46d030.png)


## 設定してみる

セミロコンつけてくださいてきなやつ
お好みでどうぞ

```js:.prettierrc
{
  "semi": true,
  "arrowParens": "always",
  "bracketSpacing": true,
  "singleQuote": true,
  "endOfLine": "auto"
}
```

## どうやって使うの？

### コマンドを走らせる

` "format": "prettier --write './src/**/*.ts'"`
を追加する

```json:package.json
{
  "name": "app_name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "npm run json2ts && tsc --build tsconfig.json",
    "main": "node dist/app.js",
    "dev": "nodemon --watch src --exec ts-node --compiler-options '{\"noUnusedLocals\": false}' src/app.ts",
    "format": "prettier --write './src/**/*.ts'"
  },

  省略
```

### ディレクトリ保存時に適応させる

![package_json_—_parser-mizumoni.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687433/a2445ed7-6438-4e2a-e1d9-5acf01314c40.png)

![スクリーンショット_2022-08-05_12_54_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687433/05f671f6-0de9-12a3-794a-c8b6868ec9b4.png)

![Menubar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687433/522fcdf2-f01a-7765-4c88-659d04503b69.png)


※他の設定も入ってます

```json:settings.json
{
    "editor.tabCompletion": "on",
    "editor.tabSize": 2,
    "files.trimTrailingWhitespace": true,
    "files.insertFinalNewline": true,
    "[json]": {
      "editor.defaultFormatter": "vscode.json-language-features"
    },
    "editor.codeActionsOnSave": {
      "source.fixAll.eslint": true
    },
    "editor.formatOnSave": true,
    "[javascript]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[typescript]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "cSpell.enabledLanguageIds": [
      "html",
      "css",
      "ruby",
      "javascript",
      "typescript",
      "markdown"
    ],
}


```

### `.prettierrc` に基づく
```json
{
    "workbench.startupEditor": "none",
    "editor.tabSize": 2,
    "[json]": {
        "editor.defaultFormatter": "vscode.json-language-features"
    },
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
    },
    "editor.formatOnSave": true,
    "[javascript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "[typescript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "prettier.requireConfig": true,
    "prettier.configPath": "./.prettierrc",
}
```
【夏休み企画】#IT用語一問一答【毎朝投稿2日目】DHCP

# この記事を読むと、、
- 「関連用語」を使って「DHCP」を説明できるようになる
- 「DHCP」がもっと好きになる(多分)

# 関連用語
DHCP server / DHCP client / IP address lease time / DORA

[**復習用**] 記事の内容を見る前に上記の言葉でDHCPを説明してみよう！

# 企画説明
- クラウドって何？って人に聞かれて説明してるけど俺もよく知らないや、、
- ドキュメント読んでみてるけど半分くらい何言ってるか分かんない、、
- 今日の夕飯はナスの炒めものにしよっかな〜、あれ、NASってなんだっけ？

みたいなことが結構あったので、知ったかしていたIT用語を毎日一個ずつちゃんと学んでいこうっていう企画です！

昨日の記事はこちら↓

https://qiita.com/acta/items/5622dfd06285ec4fde2f

# DHCPとは
DHCP = Dynamic Host Configuration Protocol = IPネットワーク上でIPアドレスなどの接続に必要な情報を自動で割り当てる仕組み

IPアドレスを割り当てるホスト = **DHCP server**
IPアドレスを割り当てられるホスト = **DHCP client**


**DORA**と呼ばれる4つの手順で接続を確立する
1. Discover
    DHCP clientが「この設定で接続したい」というリクエストを投げる
    - ブロードキャストで通信

    この際送る情報は
    - 自分のMACアドレス
    - 割り当てられたいIPアドレス

1. Offer
    DHCP serverが「じゃあこの設定でどう？」という提案をする
    - ユニキャスト(またはブロードキャスト)で通信

    この際送る情報は
    - クライアントID ≒ クライアントのMACアドレス
    - 割当予定のIPアドレス
    - 自分のIPアドレス

1. Request
    DHCP clientがOfferで提案された設定での接続をリクエストする
    - ブロードキャストで通信
    - 複数のDHCP serverから提案されていたら一つだけ選ぶことになる
    - リクエスト前にARPでIPアドレスが被っていないか確認する

    この際送る情報は
    - 自分のIPアドレス
    - 選んだDHCP serverのIPアドレス

1. Ack
    Requestで選ばれたDHCP serverは各種設定をDHCP clientにおくり、DHCP clientがそれに応じれば、接続が確立される
    - ユニキャスト(またはブロードキャスト)で通信

上では省略したけどIPアドレスの他に
- ルーターのIPアドレス
- **IP address lease time** = DHCP serverがIPアドレスをDHCP clientに割り当てる時間
- DNS serverのIPアドレス

などなどの設定も通信されている

# 調べている時にでてきたなにこれ用語(おまけ)
- Client-Server Model = クライアントとサーバーに役割を分けて通信するアーキテクチャ
    - メインフレームからダウンサイジングしたモデル
    - 他のモデルには例えばP2P networkがある
- ARP = Address Resolution Protocol = 特定のIPアドレスが割り当てられているホストのMACアドレスを取得するプロトコル
    - ブロードキャストのARPリクエストとユニキャストのARPリプライの2種類のパケットがある

# 参考資料
- https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol
- https://www.infraexpert.com/study/tcpip2.html
- https://en.wikipedia.org/wiki/Default_gateway
【Laravel】Featureテストを実行すると、factoryメソッドが実行できずエラーとなる。

# 環境
MacOS 11.5.2(Big Sur)
Laravel 9.17.0
php 8.1.2

# 困ったこと
LaravelのFeatureテストにて、データベーステストを実施しようとすると、ターミナルにて下記のエラーが表示された。
```Call to undefined method App\Models\Person::factory()```

# 解決方法
モデルクラスPersonを定義しているPerson.phpに、```use HasFactory;```を追記する。
これを追記しないと、Personクラスの静的メソッドとしてfactoryメソッドを使用できないみたい。


# 参考記事
https://stackoverflow.com/questions/68606726/call-to-undefined-method-app-models-categoryfactory-laravel
Autonomous Databaseのリフレッシュ可能クローンの静止点を計測してみた

# はじめに
Oracle Autonomous Database(以下ADB)には、ソースの更新内容をクローンに反映するリフレッシュという機能を持つ、リフレッシュ可能クローンがあります。
これはOracle Multitenantの一機能でもありますが、今回はAutonomous Databaseのリフレッシュ可能クローンに限定します。

リフレッシュ可能クローンのクローン作成時・リフレッシュ時にトランザクションを発生させ、その前後の静止点のずれがどのくらいか計測してみました。

# 事前準備
Autonomous Transaction Processing(ATP)インスタンス **ATPtest**を作成します。
**ATPtest** に接続し、以下のSQL文で検証に使用する表sampleとシーケンス**serial**を作成した時点から検証を開始します。

```sql
create table sample(ID number primary key, time timestamp);
```

```sql
create sequence serial maxvalue 10000;
```

# クローン作成時の静止点
以下のシェルスクリプトを作成します。
1秒ごとに1行sample表にIDとSYSTIMESTAMPを追加します。

```check.sh
#!/bin/bash

sql_flg=/tmp/sql.flg
touch $sql_flg


(
while [ -a ${sql_flg} ]
do
 echo "insert into sample values(serial.nextval, systimestamp);"
 echo "commit;"
 sleep 1
done

echo "exit"

)|sqlplus  -s  admin/Welcome12345#@ATPtest_tp

exit
```

このスクリプトを実行している状態、つまりソースDB側にトランザクションが発生している状態で、OCIコンソール画面からリフレッシュ可能クローンの作成を行います。
その際、作成されたクローン側はどの時点のデータが最新になっているのか確認します。

ADBの詳細画面から、[他のアクション]→[クローンの作成]をクリックします。

![スクリーンショット 2022-08-05 105144.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1930162/b45833d6-3fcf-5e72-ec34-3adce348a882.png)

[クローン・タイプの選択]で**リフレッシュ可能クローン**を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1930162/e4473c1a-66c2-b698-98b1-84a8348b0266.png)

check.shを実行している状態で、上記の手順でコンソール画面からリフレッシュ可能クローンの作成を行います。


作成後、クローン側の作業リクエストを確認すると、**1:59:14**に作成開始、2:03:11に終了しています。

![スクリーンショット 2022-08-05 110537.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1930162/c95cbdf7-a647-8139-4042-1a5b231cd10d.png)

クローン側のsample表の最新レコードを参照します。
```sql
select * from sample where id = (select max(id) from sample);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1930162/1e3d43cd-9e3c-5a5d-0e79-6b5aeb35d261.png)

最新のレコードは**1:59:31**にINSERTされたレコードです。

このことから、クローン作成開始から数秒後のトランザクションまではクローン側に反映される、ということが分かりました。

クローン作成時は、データブロックのコピーと合わせて、複製元から複製先にREDOを転送、適用することで同期しながらクローンします。
REDOを転送、適用しながら複製するのである程度同期を保ったままコピーされますが、複製元にトランザクションが常に発生する限り、最終的には若干ずれることになります。

# リフレッシュ時の静止点
続いて今度は、リフレッシュ（ソースとクローンを同期する）時に指定したタイムスタンプと実際のデータのずれを計測します。
引き続きcheck.shを実行しておき、コンソールからリフレッシュで以下のようにタイムスタンプを指定し、リフレッシュをします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1930162/a0d60fe1-8690-bb0a-36fc-96de0375341d.png)
**2:40:34**を指定してリフレッシュします。
リフレッシュ後、先ほどと同様にクローン側のsample表の最新レコードを参照します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1930162/2d778764-cfd7-dd97-8acd-f22bdc963a64.png)
**2:40:33**のレコードが最新でした。

このことから、『リフレッシュ時に指定したタイムスタンプは正確にソースと同期する』ことが確認できました。

なお、リフレッシュ自体はREDOログをクローン側に転送・同期を行います。
指定するタイムスタンプが現在の時刻に近すぎると、このような表示になりリフレッシュできません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1930162/64649821-7da8-9166-9f21-450b08ed4c08.png)
最小で過去1分からリフレッシュできるようになるので、注意してください。

リフレッシュ可能クローンは、簡単に本番環境と同じ状態でテスト環境が作れるだけでなく、指定した静止点でバックアップとしてインスタンスを複製できますので、ぜひご活用ください。

# 参考資料
+ <a href="https://docs.oracle.com/ja-jp/iaas/adbrefreshableclone/autonomous-refreshable-clone.html" target="_blank" rel="noopener noreferrer">Autonomous Databaseでのリフレッシュ可能クローンの使用</a>
Red Hat Developer Subscription for Individualsを更新（再発行）する 

## 概要

RedHat Enterprise Linuxは開発用途で無料で使用できますが、そのDeveloper Subscriptionは1年で期限切れとなります。
期限切れ後、https://access.redhat.com/management/subscriptions で確認すると更新可能に見えますが、実はこの無料ライセンスは製品ライセンスとは異なり、**更新ができません**（更新リクエストは成功するがいつまでたっても何も起きない）。そのため、再発行する必要があります。

## 手順

1. http://developers.redhat.com/http://developers.redhat.com/ にアクセスし、RedHatのIDでログインする
1. 利用許諾に同意する
1. ログアウトする
1. http://access.redhat.com/management にアクセスする

これだけで再発行され、また1年使用可能になります。
[sphinx] WARNING Inline interpreted text or phrase reference start-string without end-string.

# 最初に

以下の環境で実施

|環境|詳細|
|---|---|
|OS|windows11|
|言語|python|
|sphinx|v5.1.1|

Pythonでの自作モジュールのdocを以下で作成
_dirは絶対パスを入れている

```
sphinx-apidoc -f -o source_dir module_dir
sphinx-build source_dir build_dir
```

# エラー

記事タイトルのエラーが発生。
```
WARNING Inline interpreted text or phrase reference start-string without end-string.
```

# 原因

原因は下記の記事を参照して推定した。
恐らく、rst記載の方法として、「``」で囲むべき文字列が適切でないと思われる。
apidocで自動生成しているので、rst自体は解読できないので確定できなかった。

https://techwriter.documatt.com/sphinx-errors/5-inline-literal-start-string-without-end-string.html

```
# Example1
[NG] Exit code of a process is stored in the ``RetValue variable.
[OK] Exit code of a process is stored in the ``RetValue`` variable.

# Example2
[NG] Python ``list``s use square bracket syntax.
[OK] Python ``list``\s use square bracket syntax.
```
# 解決

ソースコード内の以下の記載が原因と思われたので修正した。
```python
# NG
param = str
# OK
param = ''
```
特定のコマンドが存在しているか（インストールされているか）を確認できるコマンド

# 特定のコマンドが存在しているを確認できるコマンド

## 概要

Bashを書いていて、特定のコマンドがないと実行できない、特定のコマンドを使って、とある処理を実現するみたいなことがあるかと思います。
そのコマンドはデフォルトではインストールされていない、だとか、結構あるかと思います。
例えば`Homebrew`を実行して何かをインストールするだとか、`Homebrew`が存在しているか知りたい！
そんな時！
`Homebrew`は存在しているか！
していなければ、`Homebrew`をインストールできるハンドリングがあると便利、みたいなケース結構あるかと思います。
そんな時にどんなシェルを書いてそのコマンドがあるかを確認するか考えてみました。


## 結果

色々考えてみましたが、下記が最終形態になりました。

```bash
if [ -z `which hogehoge` ]; then
  echo "ご指定のコマンドは存在しません。"
fi
```
ご意見ある方、ご意見いただけると幸甚です。
Accessでオブジェクトを最前面（or 最背面） に移動

# やり方

ボタンとかのオブジェクトは右クリックで下記がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/e3b6e019-071e-d76f-dc26-262f5b8c33e7.png)

でも、 **タブオブジェクトは** 右クリックで『位置』が **出てこない** ので、下記。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706116/17c6fa46-8984-7e68-06fa-18641b318b7d.png)

# バージョン

Windows 10 Pro 21H2 OSビルド 19044.1889
Microsoft Access for Microsoft 365 MSO (バージョン 2207 ビルド 16.0.15427.20166) 32 ビット
TypeORMのEntityManagerをJestでMock化する方法

# はじめに
色々調べたけど「これ！」というのが見つからなかったので備忘録として。

# やりたいこと


https://www.tutorialspoint.com/typeorm/typeorm_transactions.htm

にあるような

```Typescript
import {getManager} from "typeorm";

await getManager().transaction(async transactionalEntityManager => { 
   await transactionalEntityManager.save(students); 
});
```

という使い方をしている場合に、 `transaction` をモック化したい。

# 実際の実装

こんな感じ

```Typescript
beforeAll(() => {
  const mockGetManager = jest.spyOn(typeorm, "getManager");
  const entityManager = {} as EntityManager;

  mockGetManager.mockImplementation(() => {
    async function mockTransaction(func: any) {
      entityManager.save = function save(entity: any): Promise<any> {
        return Promise.resolve(true);
      };

      entityManager.update = function update(entity: any, update: any): Promise<any> {
        return Promise.resolve(true);
      };

      entityManager.findOne = function findOne(query: any): Promise<any> {
        return Promise.resolve(true);
      };

      entityManager.find = function find(query?: any): Promise<Array<any>> {
        return Promise.resolve([]);
      };

      entityManager.delete = function del(query: any): Promise<any> {
        return Promise.resolve(true);
      };

      return await Promise.resolve(func(entityManager));
    }

    entityManager.transaction = jest.fn().mockImplementation(mockTransaction);
    return entityManager;
  });
});
```

# 参考
* [How mock a test for EntityManager.transaction() in TypeOrm?](https://stackoverflow.com/questions/64968445/how-mock-a-test-for-entitymanager-transaction-in-typeorm)
Amazon Linux2 上の nginxをcertbotを使ってSSL化


なんかスルッと行かなかったのでメモ。
nginxインストール直後の想定。

```
sudo yum-config-manager --enable epel*
sudo yum install certbot-nginx

# 重要：nginx.confのserver_nameのとこをドメイン名に修正

sudo certbot --nginx
```

以下は指示に従う。