OmniAICreator/Qiita-1.07M huggingface dataset:
【Chakra-UI】STack / HStack / VStack を使用すると、子要素の「:not(style)~*:not(style)」に「margin-inline-start: 0.5rem」が付与されて、意図しない「margin-left: 8px」 がある

個人的な備忘録です。

# 環境
- react: 17.0.2
- next: 11.1.3
- @chakra-ui/react: 1.8.5

# 事象
- HStack 内の **2つ目以降の子要素から** 意図しない *margin-left: 8px;*  が付与されて、デザインが崩れてしまう

```tsx
<HStack className={styles.list}>
	<div>hoge</div>
	{/* 2つ目以降の要素から意図しない margin-left: 8px; が付与されてしまう */}
	<div>hoge</div>
	<div>hoge</div>
	<div>hoge</div>
</HStack>
```

```scss
.list {
    justify-content: space-between;
	flex-wrap: wrap;
}
```

![Screen Shot 2022-08-16 at 16.43.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/f8f323fe-a397-06bb-0927-e6d39230f566.png)

![Screen Shot 2022-08-16 at 16.43.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/5d08bf65-eb26-8bca-13b3-30429694c610.png)

# 原因
- chakra-ui のコードを確認すると `node_modules/@chakra-ui/layout/src/stack.tsx` というファイルに `spacing = "0.5rem"` が記述されている
- HStack / VStack は、STack をラップしているだけなので、HStack で囲んだ子要素に、デフォルト値の *margin-left: 8px;* が付与されていた

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3339393631302f34633439373332362d623434652d663834622d643362372d3266376631323136616637662e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/e8056a90-dfed-3881-81a0-dce1fde743e5.png)
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3339393631302f61663133313433612d343062642d393332362d333636302d3337313966323464356630322e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399610/d11412c0-9ae8-af8d-4d51-7b0e1e733594.png)

# 解決策
## 1. `spacing="0"` を明記する

```tsx
<HStack className={styles.list} spacing="0">
	<div>hoge</div>
	<div>hoge</div>
	<div>hoge</div>
	<div>hoge</div>
</HStack>
```

## 2. STack / HStack / VStack をやめて Box などに変えてスタイルで調節する
```tsx
<Box className={styles.list}>
	<div>hoge</div>
	<div>hoge</div>
	<div>hoge</div>
	<div>hoge</div>
</Box>
```

```scss
.list {
    display: flex;
    justify-content: space-between;
	flex-wrap: wrap;
}
```

# 参考文献
https://github.com/chakra-ui/chakra-ui/issues/2578

https://qiita.com/nitaking/items/7ba69b06bbfbd0862794
【Rails】resourcesとは

# はじめに
この記事は、resourcesに関する基礎知識をまとめた記事である。（備忘録的な意味もあります…）
　・前提
　・resourcesとは
　・書き方
　・注意事項




## 前提
・Railsのルーティングを理解している

## resourcesとは
resourcesとは、特定のコントローラーに対する**ルーティングをまとめて設定してくれる**もの。


設定するルーティングは、データベース上での**CRUD操作**(Create/Read/Update/Delete)にそれぞれ対応できるようなルーティングを設定してくれる。


:::note info
index、new、create、show、edit、update、destroyアクションに対するルーティングを設定してくれる。
:::



## 書き方


### 基本
・書く場所：`config/routes.rb`
・書き方　：`resources :コントローラー名`


```rb:config/routes.rb
resources :コントローラー名
```

　
例：postsコントローラーのルーティングを設定する場合
```rb:config/routes.rb
resources :posts
```

作成されるルーティングの一覧
| HTTP verb | パス | Controller#Action |
|:-:|:-:|:-:|
|GET|/posts|posts#index|
|GET|/posts/new|posts#new|
|POST|/posts|posts#create|
|GET|/posts/:id|posts#show|
|GET|/posts/:id/edit|posts#edit|
|PATCH/PUT|/posts/:id|posts#update|
|DELETE|/posts/:id|posts#destroy|

### 複数書く方法
複数のコントローラーに対してresourcesを書く方法は複数ある

#### ①それぞれのコントローラー分書く
例：posts、commentコントローラーのルーティングを設定する場合
```rb:config/routes.rb
resources :posts
resources :comments
```

#### ②1行でまとめて書く(略記法)
例：posts、commentコントローラーのルーティングを設定する場合
```rb:config/routes.rb
resources :posts, :comments
```
　
ただし、②は①と完全に同一の意味を持つ



## 注意事項
:::note warn
ルーティングが読み込まれる順番（ファイルの上から下に読み込まれる）を考慮して記述する必要がある
:::

# まとめ
:::note info
・resourcesとは
index、new、create、show、edit、update、destroyアクションに対するルーティングを設定してくれる。
:::
リモートにQuorumノードを立ち上げてRemixと接続する

# 背景
(2020年4月頃に下書きを書いたまま公開できていなかったので、今は解消しているかもしれないですが投稿します）
Quorumをリモートで立ち上げ、RemixをChromeで接続しようとするとエラーでうまく接続できない。どうもjson-rpcポートに対してlocalhost以外ではHTTPSでの接続が必須の模様。
ApacheやNginxはHTTPS化は確立されて簡単だが、Quorumのjson-rpcポートのHTTPS化についての情報がなかなか見つけられない。
ちょっと無理矢理だけど、Quorumの外側でHTTPS/HTTP変換してつなげるようにしてみる。
今回はQuorumで確かめたがたぶんEthereum/Gethでも同じかな。
（もっといい方法があればご教授ください）

# 動作環境
### Quorumノード
今回はAzureのVM上にubuntuを立ち上げ、その上のdocker上でquorumを走らせているので、少しややこしい。下記のような構成となっている。

| stack | ポート関係 |
|:-:|:-:|
| quorum | json-rpc :8545  |
| docker | expose portで8545->22000  |
| ubuntu  | 上記の22000ポート  |
| azure vm  | nsgで22000を許可  　|

# StunnelでHTTPS化
### Stunnelとは
Stunnelはプロキシ的にクライアントとプログラムの間に介在してTLS暗号化/復号化するもの。ApacheやNginx、Squidなどでもできるだろうがよりシンプルにできそう。
参考：[Stunnlel](https://www.stunnel.org/)

これにより
`Browser(Remix)--HTTPS-->Stuunel--HTTP-->Quorum`
という構成でQuorumには変更を加えず、RemixからはHTTPSでJSON-RPCでやり取りが可能。
単純なLookMLだけで対処できなくなった時の簡易フローチャート

* 初心者向けにざっくり関係性を描写したものです。
* 下に行くほど手間がかかります。
```mermaid
flowchart TD
a["カラム同士の計算をしたい"]-->|yes|b["表計算"]
a-->|no|c["微調整したディメンションを使用したい"]
c-->|yes|d["カスタムディメンション"]
c-->|no|e["微調整したメジャーを使用したい"]
e-->|yes|f["カスタムメジャー"]
e-->|no|g["変更できないファイルに要素を付け足したい"]
g-->|yes|h["リファインメント"]
g-->|no|i["LookMLベースのクエリで表現できる"]
i-->|yes|j["ネイティブ派生テーブル"]
i-->|no|k["SQL派生テーブル"]
j-->l["既存のLookMLの要素を引き継ぎたい"]
k-->l
l-->|yes|m["エクステンド"]
l-->|no|n["クエリが重い"]
m-->n
n-->|yes|o["永続的な派生テーブル"]
n-->|no|p["一時的な派生テーブル"]
```
IBM Quantumの空いている無料（5qbit)マシンを検索する

API tokenを取得済みで既にQuantumに繋がっているなら、たくさんある世界のQuantumの中でどれが空いているか調べる小技を紹介します。

~~~rb:Jupyter Notebookに貼り付けて利用可能です。
# initialization
import matplotlib.pyplot as plt
import numpy as np

# importing Qiskit
from qiskit import IBMQ, Aer
from qiskit.providers.ibmq import least_busy
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, transpile, assemble

# import basic plot tools
from qiskit.visualization import plot_histogram


# Load our saved IBMQ accounts and get the least busy backend device with less than or equal to 5 qubits
IBMQ.load_account()
provider = IBMQ.get_provider(hub='ibm-q')
provider.backends()
backend = least_busy(provider.backends(filters=lambda x: x.configuration().n_qubits <= 5 and
                                   x.configuration().n_qubits >= 2 and
                                   not x.configuration().simulator and x.status().operational==True))
print("最も空いている実機: ", backend)
~~~
~~~rb:出力結果
最も空いている実機:  ibmq_belem
~~~

このように現時点で、最も空いているQuantumが表示されます。
Enterキーを押すとミュートキー動作もする（Keycodeの取得・変更方法）

# 何の記事か
あるときからWeb会議をしていても急に音が聞こえなくなったり、聞こえるようになったり...
よく観察すると、ワイヤレスキーボードのEnterキーを押すと同時にMuteボタンを押した動作になってしまうようになってしまっている。ググるとロジクールで同様の問題だと思われる事例はいくつかあるのですが、トラブルシュートに至っている事例が無かったので、調査・暫定対応方法について書きたいと思います。

# 環境
Keybord : Logicool K275（かなーり古いもの。バッテリー入れ替え済み）
OS : Kubuntu22.0.4.1

# まとめ
原因
そのままですが、「Enter」キーを押すと、同時に「Mute」キーのキーコードEventも上がっていました。（現象そのままなのですが明確に問題がわかった。）
対処
「Mute」のキーコードを書き換えて、何も設定されていないように修正。
Kubuntu側ではxmodmapで対応。他に使っているWin側はAHK(AutoHotKey)で対応。

# 実際の調査・対応方法
## 発行されるKeyイベントの調査
KubuntuなどXベースでGUIが立ち上がっている状態で、Xのeventを調べることができるxevを立ち上げる。
```
$ xev
```
この状態で、実際にEnterを押すと、ターミナルに以下のようにKeyイベントが出力される。（実際はKeyPress eventとKeyRelease event。以下はKeyRelease eventだけを抜きだしています。）
```
KeyRelease event, serial 40, synthetic NO, window 0x5a00001,
    root 0x7b6, subw 0x0, time 85080177, (524,569), root:(1850,644),
    state 0x0, keycode 36 (keysym 0xff0d, Return), same_screen YES,
"   XLookupString gives 1 bytes: (0d) "
    XFilterEvent returns: False

KeyRelease event, serial 40, synthetic NO, window 0x5a00001,
    root 0x7b6, subw 0x0, time 85080197, (524,569), root:(1850,644),
    state 0x0, keycode 121 (keysym 0x1008ff12, XF86AudioMute), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False
```
上記結果のkeycode部分。
うーん。確かに2種類のkeycode(36と121)でイベントが発生している。特に121の方は`keycode 121 (keysym 0x1008ff12, XF86AudioMute)`となっている！

## keycode割当の確認
以下のコマンドでX上で割り当てられているkeycodeが確認できるので、一応こちらでも確認しておく。
```
$ xmodmap -pke
```
実際にkeycode 36と121は
```
:
keycode  36 = Return NoSymbol Return
:
keycode 121 = XF86AudioMute NoSymbol XF86AudioMute
:
```
確かに「Return」と「Mute」に割り当たっている！
そりゃ、これは確かにEnterキーを押すとミュートになるわ！（でも、Web会議中にそうなるってことは、なんか横で別のことやっているっていうこと？！）

## 暫定対処
今回はたまたま同時に発行されるキーコードを無効にしても大きな問題にならないものだったので、単純にkeycode 121をMuteと認識しないようにした。
（これが普通のキーコードならこの対処はできないですね。）
```
$ xmodmap -e "keycode 121 ="
```
もちろん、これだけだと再起動後など戻るので~/.Xmodmapや.bash??などのファイルに書いてやる必要がある。

## 恒久対応
どうやらキーボード本体の問題のようなので、もちろん新しいキーボードを買いたい。Keychronを狙っている！
【AWS】Cognitoのユーザープール作成後にカスタム属性が消えたお話

概要
以前インフラエンジニアとして働いていた現場での出来事。アプリチームからの依頼でCognitoのユーザープールを作成。アプリチームに引き渡し、帰ったらゲームをしようと思いながら休んでいたら…

アプリチーム「ユーザープールのカスタム属性1つ足りなかったので追加してください」
自分「ごめんなさい、今すぐ追加しますorz」

こんな感じでユーザープール作成時にカスタム属性を1つ入れ忘れミスしちゃったーと思いつつ、心の中のもう1人の自分がこんな事を思っていた。

「いや、そのカスタム属性の設定した記憶があるぞ…」

思い立ったが吉日、Slackでそのカスタム属性を検索すると、、以前にも同じカスタム属性が足りないとアプリチームから指摘されている人を発見！
これは単なるヒューマンエラーじゃないと思い検証の結果、とある条件下においてCognitoのユーザープール作成後にカスタム属性が消える現象を確認したので以下に記す。

環境・条件
・AWS Console (CLIは試してないです)
・AWS Cognitoのユーザープール作成時
・標準属性として存在する属性をあえてカスタム属性として設定した時 (アプリチームからの依頼でそのようにしてました)
以上の条件下においてユーザープール作成後に設定したカスタム属性が消えます。

実践
AWS ConsoleにてCognitoの「ユーザープールを作成する」をクリック
![ユーザープール作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784264/bc666973-3e13-40f9-45e1-9b146d4036a4.png)
属性の追加画面にて、標準属性として存在する「locale」をカスタム属性として設定
![属性の設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784264/338dfeca-8f9e-f390-0aea-25037927038c.png)
ユーザープール作成前の最終確認画面ではカスタム属性「locale」は存在する
![確認画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784264/43f857b3-5a29-7c4d-d15d-59d57305758b.png)
ユーザープールは正常に作成されたらしいが…
![ユーザープール作成完了.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784264/a6e20573-0861-dad2-3cf3-ad46f965d333.png)
作成されたユーザープールを確認しにいくと「locale」の属性だけなくなっています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784264/0ebbafe8-1d26-061f-3e62-ed8be9d95858.png)
AWSサポートへの問い合わせ結果・対策
AWSサポートに以下を問い合わせを行った。
①ユーザープール作成時に設定したカスタム属性が消えたのは標準属性として存在する属性をカスタム属性にしたからで合ってる？
②ユーザープール作成後は「locale」をカスタム属性として追加できたのは何で？

遠回しに設定ミスなんじゃない？、みたいな一次回答が来たので検証環境の添付画像とともに再現性ある事象である旨説明。
後日担当者から返信がきて、以下のような説明だった。
・Amazon側でも上記の事象について確認できた
・①についてyes
・②についてユーザープール作成時と作成後の属性追加では使用しているAPIが違うから
という返答を頂きました。ご担当者さんありがとうございました。

対策は2通り。
1つ目は前述の通り、ユーザープール作成後にカスタム属性を追加すること。
2つ目は色々いじくっていたら発見した方法で、、

ユーザープール作成時の最終確認画面で「属性」をクリックして属性設定の画面に戻りましょう
※　現時点でカスタム属性が「test, locale」となっているのを覚えておいてください
![対策2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784264/2848bc89-9e07-5870-5349-8d61a4217c96.png)
属性の設定画面に戻ったら「確認」をクリックして、最終確認画面に戻りましょう(何をやってるんだと思われるかもしれませんがやりましょう(笑))
![対策2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784264/6584b18f-14cc-f833-dd7c-5faee3318544.png)
最終確認画面を確認すると…カスタム属性が「custom:test, custom:locale」に変わってますね！？
![対策2-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784264/7d457a96-c4f6-58d7-2e2d-1b640da096f8.png)
この状態で「ユーザープールの作成」をクリックすればカスタム属性が消えずにユーザープールを作成することができます。
Piniaで管理している状態の変化をコンポーネント側で検知する

# $onAction
https://pinia.vuejs.org/core-concepts/actions.html#subscribing-to-actions

actionが発火されるごとに呼ばれる。

```typescript
const unsubscribe = someStore.$onAction(
  ({
    name, // name of the action
    store, // store instance, same as `someStore`
    args, // array of parameters passed to the action
    after, // hook after the action returns or resolves
    onError, // hook if the action throws or rejects
  }) => {
    // a shared variable for this specific action call
    const startTime = Date.now()
    // this will trigger before an action on `store` is executed
    console.log(`Start "${name}" with params [${args.join(', ')}].`)

    // this will trigger if the action succeeds and after it has fully run.
    // it waits for any returned promised
    after((result) => {
      console.log(
        `Finished "${name}" after ${
          Date.now() - startTime
        }ms.\nResult: ${result}.`
      )
    })

    // this will trigger if the action throws or returns a promise that rejects
    onError((error) => {
      console.warn(
        `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`
      )
    })
  }
)
```

# $subscribe
https://pinia.vuejs.org/core-concepts/state.html#subscribing-to-the-state

stateの変更があるごとに呼ばれる。

```typescript
cartStore.$subscribe((mutation, state) => {
  // import { MutationType } from 'pinia'
  mutation.type // 'direct' | 'patch object' | 'patch function'
  // same as cartStore.$id
  mutation.storeId // 'cart'
  // only available with mutation.type === 'patch object'
  mutation.payload // patch object passed to cartStore.$patch()

  // persist the whole state to the local storage whenever it changes
  localStorage.setItem('cart', JSON.stringify(state))
})
```

# 考察
ケースによって使い分ければ良さそうだが、
stateが変わるのは原則actionが呼ばれたときなので、
そのactionを監視していた方がコントローラブルではないかなと思った。
WARN  Address localhost:8080 is already in use.の解決策

サーバー起動時に

```
 WARN  Address localhost:8080 is already in use.
```

と出た場合は、すでにそのポートが使用されています。

## 解決策

```
 lsof -i -P | grep 8080
```
でそのポートを使用していないか確認。

```
kill PID(プロセスID)
```
上記コマンドで消去できない場合は
```
kill -9 PID(プロセスID)
```
`-9`を使用して強制終了します。

https://amateur-engineer.com/port-process-kill/
Splunk MLTKのマクロ設定

Splunk MLTK (Machine Learning Toolkit)のhistogramを使おうとしたら、下記のようなエラーが出ることがある。

![splunk.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163445/016fd917-d7f4-0100-3a5b-728eaa7c1be8.png)

どうやら、histogramのパーミッション設定がおかしいらしい。
特に、パネルをダッシュボードに保存した際に、このようなエラーが出ることが多い。

検索してみた。

https://community.splunk.com/t5/Dashboards-Visualizations/Are-there-specific-permissions-needed-in-order-for-the-Machine/m-p/406336

Settings ->　Advanced search -> serch macro で辿っていくと、

X.X.X.X:8000/en-US/manager/Splunk_ML_Toolkit/data/macros

![splunk2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163445/3a20bdb8-906b-4781-1279-2c061cd36141.png)

このような行があるので、

![splunk3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163445/9aa2007a-f367-ac5f-d73e-c7c2c6d7110d.png)

↑上のように変更したら解決した。
iTerm2 でカーソルを単語単位で移動するショートカット


# 概要
iTerm2 でカーソルを単語単位で移動するショートカットを設定したい。
`Alt(Option)` + `矢印(→←)`でカーソルを移動させたい。

VSCode のターミナル上ではデフォルトの設定で移動できるが、iTerm2ではできなかったので、メモ


# 環境
- iTerm2
- zsh

```
$ echo $SHELL
/usr/local/bin/zsh
```

# 設定方法
iTerm2 -> Preference -> Profiles -> Keys -> +ボタンで設定追加

- 左矢印の設定を追加する。
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239544/b3cab2c8-7783-80dd-f5a2-b3c18e2d90a2.png">

- 右矢印の設定を追加する。
<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239544/1b01976b-d140-fedf-3f8c-2527e09b6bbc.png">








# 参考

- [iTerm2でカーソルを単語単位で移動する方法](https://www.karakaram.com/iterm2-move-caret-to-next-word/#:~:text=%E3%81%BE%E3%81%A8%E3%82%81,%E5%8D%98%E8%AA%9E%E3%81%AB%E7%A7%BB%E5%8B%95%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)
Reactでローディングアニメーションを実装

Reactでローディングアニメーションを実装をしました。

参考記事
https://almonta2021blog.com/%E3%80%90react%E3%80%91%E3%81%8A%E3%81%97%E3%82%83%E3%82%8C%E3%81%AAloading%E3%82%A2%E3%83%8B%E3%83%A1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3react-spinners/

https://deecode.net/?p=1891


まずは、_app.tsxに記載します。

アニメーションはreact-spinnersというライブラリを利用しており、ClipLoaderを利用しています。カスタマイズもしやすいため、おすすめのライブラリです。

```JavaScript
import Head from "next/head";
import "../styles/globals.css";
import "tailwindcss/tailwind.css";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import ClipLoader from "react-spinners/ClipLoader";
import { textAlign } from "@mui/system";

function MyApp({ Component, pageProps }) {
  const router = useRouter();
  const [pageLoading, setPageLoading] = useState(false);

  useEffect(() => {
    const handleStart = (url) => url !== router.asPath && setPageLoading(true);
　　　　　　　　//urlはbasepathが入る
    const handleComplete = () => setPageLoading(false);
    //読み込み完了するとローディングがfalseになる

    router.events.on("routeChangeStart", handleStart);
    //ページ移動すると発火する　 ルーティング開始はrouteChangeStart
    router.events.on("routeChangeComplete", handleComplete);
    //ページ移動すると発火する　 完了はrouteChangeComplete
    router.events.on("routeChangeError", handleComplete);
     //ページ移動すると発火する　 エラー時はrouteChangeError
    return () => {
      router.events.off("routeChangeStart", handleStart);
      router.events.off("routeChangeComplete", handleComplete);
      router.events.off("routeChangeError", handleComplete);
    };
  });

//中央揃えにする
  const style: React.CSSProperties = {
    fontSize: "20px",
    verticalAlign: "middle",
    margin: "auto",
    position: "absolute",
    top: "300px",
  };
//中央揃えにする
  const loadingbg: React.CSSProperties = {
    fontSize: "20px",
    position: "absolute",
    top: "0px",
    left: "0px",
    right: "0px",
    width: "100%",
    margin: "auto",
    backgroundColor: "white",
    height: "100%",
    zIndex: "200",
    textAlign: "center",
  };

  // TODO 正式なローディングコンポーネントにする
  const loadingComponent = (
    <div style={loadingbg}>
      <span style={style}>
        <ClipLoader color={"#FFBB7A"} size={80} />
      </span>
    </div>
  );

  return (
    <div>
      {pageLoading && loadingComponent}
      <Component {...pageProps} />
    </div>
  );
}

export default MyApp;


```
レンタルサーバーを借りてオンラインゲームのWikiサイトを作ってみる #3

## 前回の記事
https://qiita.com/Unirenkon/items/bb58b8b4228fcf845e6f

## 今回の作業
プロジェクトをGitHubにpushする

## 事前準備
前回の記事で書いたFTPソフトを使ってxserverからプロジェクトディレクトリをlocalにダウンロードしておく

## GitHubにレポジトリ作成
![スクリーンショット 2022-08-16 16.54.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296171/5831a964-7360-9c3b-1f1f-ccc58473a44b.png)

![スクリーンショット 2022-08-16 16.56.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296171/1995be2c-1c53-0389-f93b-8da18cc27253.png)

左上のコードを押してレポジトリのアドレスをコピー

![スクリーンショット 2022-08-16 16.57.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296171/f04a3146-b18a-9272-0a86-9923c5fc1e43.png)



## GitHubにプッシュする
準備でダウンロードしたlocalのプロジェクトディレクトリに移動

```git init
git remote add origin https://github.com/[username]/[repositoryname].git
//originの後は先ほどコピーしたレポジトリアドレスを貼る

git add .
git commit -m "First Commit"

//gitのデフォルトブランチがmasterからmainになっている
//（2020年10月以降変更されたようで、今回初めて知った）のでブランチ名を変更してからpushする

git branch -m "main"
git push origin main

```
## 参考にさせていただいたサイト
https://tech.amefure.com/web-git-laravel-vue-xserver
Python 標準入力

自分がatcoder などでpythonを使うときのためのメモ
# 二次元配列　数字 （スペースあり）
**入力例**

```
1 3 4 10
2 3 4 5
3 25 3 91
4 5 2 3
```

```Python
a = [list(map(int, input().split())) for _ in range(n)]
```
内包表記を使い、`list(map(int, input().split()))`をn回繰り返して入力している
〜細かく説明〜
`list(map(int, input().split()))` ・・・空白ありの数字を配列で標準入力する時のやつ
`input().split()`・・・split()の()の中にsplit(分裂)を決める文字を入れる。何も入れない時は(" ")これが自動で。(" ")は半角スペースでsplitさせるという意味。

# 二次元配列　数字 （スペースなし）
**入力例**
```
4783
1267
6532
9823
```
4784ではなく4 7 8 4 で二次元配列に格納したい時

```Python
a = [list(map(str, input())) for _ in range(n)]

結果
[['4', '7', '8', '3'], ['1', '2', '6', '7'], ['6', '5', '3', '2'], ['9', '8', '2', '3']]
```
str型で格納し、使うときは`int(a[0][0])`このように型変換して利用するのがベストかなと。
video.js の使い方

次のページを参考にしました。
[Getting Started](https://videojs.com/getting-started)

次のように動画を再生します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f4011eca-f74d-0c7b-c8b0-bcc109014708.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/6f7d32d9-ccca-dff2-7346-f4f1cf8dd594.png)


フォルダー構造

```text
$ tree
.
├── index.html
├── linux_logo.png
└── sample-5s.mp4
```

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<title>こんにちは</title>
<link href="https://vjs.zencdn.net/7.20.2/video-js.css" rel="stylesheet" />
</head>
<body>
<h1>こんにちは</h1>

<hr />
<video class="video-js" width="264" height="480" poster="linux_logo.png" data-setup={} controls >
<source src="./sample-5s.mp4" type="video/mp4">
</video>
<hr />
<p>/var/www/tmp/video/index.html</p>
<p>Aug/16/2022 PM 16:44</p>
<script src="https://vjs.zencdn.net/7.20.2/video.min.js"></script>
</body>
</html>
```
typescriptのプロパティで使われる「!」「?」

typescriptを利用したNuxtのコードリーディングをしている中で「!」「?」がプロパティで使われていたが、何を示しているのかがよくわからなかった。
「?」が引数として使われるときは省略可能オプションということはわかっていた。

例
```
private Data1!: Data1Output
private Data2?: Data2Output
private totalCount: number = 0
```
# 「!」「?」がない場合
```private totalCount: number = 0```
定義時にnull | undefindの状態(初期値が記述されていない)とエラーになる
→初期値をいれないならどちらかをプロパティのあとに書かないといけない。

# 「!」
```private Data1!: Data1Output```
「!」はプロパティで定義した時はnull | undefind だけど後で空ならず値が入って使う
→定義時にはプロパティの初期値がなくても問題ない。ただ、利用するときにはnull | undefindではエラーが出るので値を入れなければいけない
# 「?」
```private Data2?: Data2Output```
「?」はnull | undefind の場合もある
→定義時にプロパティの初期値がなくても問題ない。利用するときにも値がnull | undefiindで問題ない

# 結論
簡単に言うと、「!」「?」どちらもも定義した時点では初期値がない状態(null | undefind)、「!」はそのあとに何かいれないといけない、「?」は入れなくても大丈夫。
npm install vs npm ci ( vs npm i )

# 概要
環境構築時にnpmのモジュールを他の開発者と同じようにインストールするために下記のコマンドを使ってnodemoduleをインストールするは鉄則のようなものかと思います。
```npm install```, ```npm ci```, ```npm i```

ですが「。。。ん？そういえば環境構築のREADME.mdいつもコピペしてて、こんなのよく出てたけどこれらの違いってよくわからないな。。？」
ということで記事を書きます。

いまだに間違った理解をしている可能性も十分にあるので、その場合は訂正コメントをお願いします！

# npm install vs npm i
```npm install = npm i```
省略記法です。
**これからは```npm install```をnpm iと書き換えて説明します。**

# npm i vs npm ci  
## npm iは何をしているのか
**package.json**を基に、npmでパッケージをインストールする。

## package.jsonってなんだ
簡単に言うと何を**入れたいか**が書いてあります。
インストールすべきパッケージのバージョンの**範囲**が記載されています。

→**範囲**なので```git clone```して```npm i```しても、実際にインストールしたパッケージが他の開発者と異なる場合があります。

プロジェクト序盤で```npm init```をすることで、作成されます。

## npm ci は何をしているのか
**package-lock.json**を基に、npmでパッケージをインストールするコマンドです。

下記を実行しています
1. node_modules ディレクトリの削除
2. package-lock.json と package.json の整合性のチェック。違ったらエラーを吐く。
3. package-lock.json から node_modules を再現

ちなみに処理はいくつかの機能を省略するので、```npm install``` より圧倒的に高速な場合があります。

## package-lock.jsonってなんだ
簡単に言うと何を**実際に入れた**が書いてあります。
npmが依存関係など考慮して、実際にインストールしたパッケージのバージョンが記載されています。

## 大まかな流れ
```
npm init 
→package.json作成

↓

npm install <package>
→指定したパッケージをインストール
→インストールしたパッケージのバージョン範囲をpackage.jsonに自動で記述
→package-lock.json作成・実際にインストールしたバージョンを記述

↓

npm install
→他の開発者がpackage.jsonをもとにインストール

OR

npm ci
→他の開発者がpackage-lock.jsonをもとにインストール
```

## 結論
package.jsonは何をインストールするか、package-lock.jsonは何をインストールしたかが記載されています。
```npm ci```ではpackage-lock.jsonに基づいてパッケージをインストールします。
```npm i```ではpackage.jsonに基づいてパッケージをインストールします。

CI 実行時や git clone 後の動作確認の場合は```npm ci```
その他の場合は```npm i```で分ける感じかと思います。

環境構築時に```npm i```を使うと、他の開発者の環境とまったく同じではない環境ができる可能性があり、レポジトリをpushする際にも毎回差分を削除する必要などが出てくるため、今回のようなケースでは```npm ci```が推奨されています。インストールのスピードも速いです。

# reference
- [package-lock.json ってなに？](https://qiita.com/sugurutakahashi12345/items/1f6bb7a372b8263500e5)
- [「package.json」って何？って時に少し調べた時のノート](https://overworker.hatenablog.jp/entry/2020/09/27/232236)
- [【初心者向け】NPMとpackage.jsonを概念的に理解する](https://qiita.com/righteous/items/e5448cb2e7e11ab7d477)
- [Difference between npm i and npm ci in Node.js](https://www.geeksforgeeks.org/difference-between-npm-i-and-npm-ci-in-node-js/#:~:text=npm%20i%3A%20The%20npm%20i,json%20file.&text=npm%20ci%3A%20CI%20stands%20for,devDependencies%20from%20a%20package%2Dlock.)
唐突にダイスの期待値を計算するツールが欲しくなったから1週間で作ってリリースした part3

**この記事はpart3です！！part1の内容が前提になってるのでpart1を読んでからの方が楽しめると思います🥰**

▼ part1 ▼

https://qiita.com/cp20/items/b475b6f6757be814846f

※プロダクト開発っぽいタイトルですが、この記事の内容はかなりアルゴリズムっぽいです。若干エッセーっぽいのは許して。

## 完成品どーん (3回目)

https://dicespec.vercel.app/

## part1のあらすじ

- ダイスの期待値などを計算してくれるサービスを作った
- しかしダイスの期待値に正規分布の近似を使ってるから精度が微妙

今回は精度を改善していくお話です

## そもそも、元々どのぐらいの精度だったん？

正規分布というのは超ざっくり説明すると下の図のような分布のことです。それに対してダイスの出目というのは多項分布というものなので、強引に正規分布に近似すると精度が落ちちゃいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909155/0a0ab892-e6f7-0a98-7f18-1dda8f9fb866.png)
出典：http://ryo-kida.blog.jp/archives/54884972.html

じゃあどのくらい落ちるのかと言われると難しいのですが、例えば2d100の分布は次のような形をしています。

![chart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909155/cfc791b2-c86c-45e6-e7d1-3152b3f6515f.png)

似ていると言われれば似てるけど、ちょっと無理があるなぁってぐらいの精度ですね。

なので正規分布に近似せずにダイスの期待値を求めてみようというお話です。

## どうやって求めるのさ

**「それは私にもわからん」**

というのは半分冗談ですが、私には思いつかなかったのでTwitterで聞いてみました。

https://twitter.com/__cp20__/status/1539240976086089728

誰も答えてくれませんでした。世間は非情だね。

しょうがないので友達に聞いたら答えてくれました。持つべきものは友ってそれ一番(ry

友達から貰ったのがこのコード

```ts
const generate2DArray = (m: number, n: number, val = 0): number[][] => {
  return [...Array(m)].map((_) => Array(n).fill(val));
};

const dp = generate2DArray(n, m * m, 0.0);

for (let i = 0; i < m; i++) {
  dp[0][i] = 1.0 / m;
}
for (let i = 1; i < n; i++) {
  let sum = 0.0;
  for (let j = 0; j < n * m; j++) {
    if (j < m) {
      sum += dp[i - 1][j];
    } else {
      sum = sum - dp[i - 1][j - m] + dp[i - 1][j];
    }
    dp[i][j] += sum / m;
  }
}

for (let i = 0; i < ; i++) {
  console.log(`${n + i} : ${dp[n - 1][i]}`);
}
```

まず`n`×`n*m`の大きさの2次元配列を定義して、そこに値を埋めていく方式で計算していることがわかります。なので表を使って値が埋まる過程を追ってみましょう。

例として3D6 (n=3, m=6) の場合を考えます。この時二次元配列の大きさは3×18になります。

ループの外で値が少しいじられているので最初の配列は次の図のようになります。この表がどのように変化していくのか見ていきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909155/bc6e88c0-7029-d6f2-9653-152b483740da.png)

### 1ループ目

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909155/fccfeb27-0b18-336b-7a32-ad9f4b745124.png)

5列目まで（赤色の部分）は上のものを足してコピーという風に動いていましたが、6列目から（青色の部分）は6個前のものを引くという動作が加わるのでだんだん小さくなって11以降は0になっています。

### 2ループ目

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909155/00c2fc40-ca89-568f-3311-8803b07921a1.png)

2ループ目もやることは変わらず、5列目までと6列目以降にわけて処理を行っていきます。

するとあら不思議、3D6の確率分布が得られているではありませんか！

![chart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909155/98a0285f-5a18-7e2a-0b42-753909449e42.png)

グラフにするとこんな感じ。

このプログラムが何をしているのかをまとめると

- 最初にm面ダイスの確率分布を作る
- ループごとにダイスを増やしていく
- n-1回ループするとn個ダイスを振った確率分布が得られる

という感じです。さっきの具体例に当てはめてみるとこんな感じ。

- 最初に1d6の確率分布を作る
- 1ループ目では2d6、2ループ目では3d6の確率分布を作る
- 3d6の確率分布をGETだぜ！

計算量は $ O(n^2m) $ なので微妙に大きいですが、`1000D`のような馬鹿でかい値を入れなければあまり問題にならないです。

## 精度が上がると何が嬉しいの？

精度が上がって一番嬉しいのは


**めっちゃきれいな確率分布のグラフ(下図)が書ける！！！！！！！！**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909155/24ca83b1-2b5b-a3a9-fc21-3842929e3ca4.png)

濃くなってる部分が信頼区間です。これがやりたかったんだよこれが、、、

## さいごに

https://dicespec.vercel.app/expect

確率分布のグラフを見るぐらいの価値はあるはずなので覗いてやってください。
テックキャンプで学習を終えた感想

# テックキャンプで学習を終えた感想

最初に結果だけお伝えすると、`テックキャンプでの学習はとても良かったです。`

ただ、メリットデメリットはありますし、人によって合う合わないがあると思うので、
テックキャンプを卒業した自分からの目線で解説したいと思います。


## メリット
- 早く確実に就職できる
- 学習する習慣をつけることができる
- メンバーと一緒に切磋琢磨しながら学習できる

#### 早く確実に就職できる
まず最大のメリットは、なんと言っても、

<b>早く確実に就職できること</b>です。

私自身、学習期間中（9週目）で地方の自社開発企業から内定をいただきました！！

これは、テックキャンプで学習の進捗や困りごとを相談してくれるライフコーチ、

分からないことがあればすぐに聞けるメンター、

就職活動全般をサポートしてくれるキャリアアドバイザー、

そして一緒に学習を進めてきたメンバーのおかげです。

ここまで学習をサポートしてくれたテックキャンプには感謝の気持ちでいっぱいです。

#### 学習する習慣をつけることができる
テックキャンプでの学習は正直しんどいです笑

何がしんどいかと言うと、学習時間の長さだと思います。

ライフコーチからは週に55時間学習時間を確保できるように言われますが、

週に55時間だと平日10時間やって、土日のどちらかに5時間やればやっと達成できるという感じです。

正直毎週それが達成できていたわけではないですが、平日は大体10時間やっていて、結構しんどかったですが、

途中から慣れてきて学習する習慣をつけることができて良かったと思います。


#### メンバーと一緒に切磋琢磨しながら学習できる
テックキャンプでは5~7人くらい（自分調べ）のメンバーで学習を進めていきます。

1日に何度もアウトプットをするためにzoomを繋いでいくのですが、

最初は億劫だったアウトプットも途中から気分転換になったり、

なかなか解消できないエラーを解消する手伝いをするなど、

どんどんメンバーの仲が良くなっていくのを感じました。

ただこれに関しては、チームで動くのが嫌いだったり、コミュニケーション能力に自信がない方は

向いてないかも知れません。実際、あまりチームに馴染めない人もいます。

エンジニアになったら自分一人で仕事するよりもチームで仕事することが多いと思いますので、

コミュニケーションが苦手な方は修行だと思って取り組んでみるのもいいと思います。

## デメリット
- 高い
- オリジナルアプリでメンターに質問できない
- 東京以外で就職活動すると転職保証対象外

#### 高い
こちらはテックキャンプ受講を検討されている方にとって一番悩むポイントかと思います。

私も補助金が対象外だったため全額支払うことになり、とても高いと感じました。

しかし、独学で仕事しながら勉強するよりも確実に就職できますし、就職してから頑張れば

授業料もすぐ回収できると思っています。

これからどんどんプログラミングの需要、供給が増えていきスクールも値上がりしていくと思うので、

もし検討中の方は、できるだけ早めに決断した方がいいのではないかと個人的に思います。

#### オリジナルアプリでメンターに質問できない
これは知っていましたがやはり大変でした笑

私は8週間かかるカリキュラムを　４週間で終わらせたので、オリジナルアプリに4週間以上時間を取れたのですが、

何か分からないことがあってもメンターに質問できず、テックキャンプで学習している感じがしませんでした笑

それが自走力や検索力をつけるという意味ではいいのかも知れませんが、高いお金を払っているので、

早くカリキュラムが終わった人にも何かしらのサービスがあればいいなと思いました。

#### 東京以外で就職活動すると転職保証対象外
学習を終えた後、転職活動をして、結果内定が出なかった場合には受講料を全額返金する

というものがあるのですが、こちら利用規約を確認すると

東京以外で転職活動を１つでもすると転職保証が外れます

と書かれています。

そもそもそこまで内定が出ないということはないと思いますが、この転職保証があるからテックキャンプにしようと

思う人がいて、地方からの応募も多数あるなか、これを最初に確認していない点に関しては少し疑問に感じます。

ちなみに14日以内であれば全額返金というものに関しては、結構気軽に利用できそうな雰囲気だったので、

試しにやってみたいという人にはとてもいいと思いました。


## まとめ
今回メリット、デメリット書きましたが、個人的にテックキャンプでの学習はお勧めできます。
他のスクールを受けてないのであまり比較はできませんが、スクールを必死で調べていた時期に比べた結果、やはり大手で実績があり、短期集中で基本的な技術習得ができるという点において他のスクールよりも良いのではないかと思います。逆に、時間かかっても良いから授業料を抑えたいのであれば、他にも選択肢があります。
みなさんが自分に合った選択をしてくれることを願っております。
SQLでWHERE NOT INする時はカラム値がNULLの場合の考慮抜けに注意

# MariaDB

NULLの場合も検索結果に上がってほしい場合は、COALESCE()かます必要あり。

```sql:test_valがNULLのレコードも検索結果に上がる
SELECT * FROM tester 
WHERE COALESCE(test_val, '') NOT IN ('1','2')
```

```sql:こう書くとtest_valがNULLのレコードは検索結果に上がってこない
SELECT * FROM tester 
WHERE test_val NOT IN ('1','2')
```

**test_valがNULLのレコードは値が『1』でも『2』でもないから検索結果に上がってくるだろう**
と思ってるとダメ。

# Access

MariaDBと同様。
NULL置換関数をかませるかどうかで結果が変わる。

```sql:test_valがNULLのレコードも検索結果に上がる
SELECT * FROM tester 
WHERE Nz(test_val, '') NOT IN ('1','2')
```

```sql:こう書くとtest_valがNULLのレコードは検索結果に上がってこない
SELECT * FROM tester
WHERE test_val NOT IN ('1','2')
```

# バージョン

Windows 10 Pro 21H2 OSビルド 19044.1889
 Microsoft Access for Microsoft 365 MSO (バージョン 2207 ビルド 16.0.15427.20166) 32 ビット
10.5.4-MariaDB

TODO:Oracleの場合もMariaDBとか同じ挙動。だけどCOALESCE(カラム名,'')の戻り値がNULLになっちゃうので、そのへんを調べた上で結果まとめる。
Oracle日付の処理

## 月初日を取得するSQL
```sql
SELECT TRUNC(SYSDATE, 'MONTH') FROM DUAL;

-- 日付整形
SELECT TO_CHAR(TRUNC(SYSDATE, 'MONTH'), 'YYYY/MM/DD') FROM DUAL;
```
## 月末を取得する
```sql
SELECT LAST_DAY(SYSDATE) FROM DUAL;

-- 日付整形
SELECT TO_CHAR(LAST_DAY(SYSDATE), 'YYYY/MM/DD') FROM DUAL;
```

## SYSDATEの値を一時的に変更する方法
```sql
alter system set fixed_date = '20220701' scope=memory;
```

## SYSDATEの値を元に戻す方法
```sql
alter system set fixed_date = none scope=memory;
```
クロスサイトリクエストフォージェリ : CSRF について調べてみた

## クロスサイトリクエストフォージェリ : CSRF とは
Webアプリケーションの脆弱性のひとつであるCSRFは「Cross Site Request Forgery」の略で、 **Webシステムを悪用し、ユーザーが意図していないリクエストを行わせるサイバー攻撃** の一種です。
ちなみに読み方は、「シーサーフ」と読むらしい。

### CSRFの仕組み
0 : 攻撃者は罠となるWebサイトを作成。
1 : ユーザーは攻撃対象サービスにログイン(Cookieなどを用いてセッションIDを保持)
2 : 攻撃対象サービスにログイン済みのユーザーを巧みに罠サイトへと誘導。(メールやURLクリック等)
3 : ユーザーが保持しているセッションIDを用いて意図していないリクエストを送信
4 : 攻撃対象WebサービスはセッションIDにて正規ユーザーからのリクエストだと判断し実行。

![スクリーンショット 2022-08-16 14.33.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2644766/84c50d0a-92e0-a013-4136-b42bb3f432d6.png)

罠サイトにアクセスしてしまったユーザーが攻撃対象のWebサービス（SNS等）に **ログイン状態** になっていると、その **Webサービスに偽のリクエストが投げられ・実行させる** という仕組みになっています。

ログインが必要なWebサービスの多くはログイン処理を省くためにCookieを利用して自動ログイン機能を提供しているため、 **一度ログインを行えばしばらくの間は自動ログインが可能な状態** になり、それ故CSFR攻撃の条件が成立してしまうわけです。

[*セッションIDとは](https://e-words.jp/w/%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3ID.html)

[*Cookieとは](https://time-space.kddi.com/ict-keywords/20180726/2392)

## 実際に起ったCSRFによる被害例
実際に起きた事例としては **「はまちちゃん事件」** や **「横浜CSRF事件」** などが有名です。

#### 「はまちちゃん事件」
大手SNSの「mixi」にてある日突然 **「ぼくははまちちゃん！！」** といった内容の書き込みが同日に数多くのユーザーの日記に投稿されたみたいです。

 **この投稿にはURLが貼られておりそのURLをクリックすることでそのユーザーも同じ投稿がされる** ような仕組みになっており、連鎖的に数多くのユーザーが同じ投稿をした事で話題になったらしい。。

#### 「横浜CSRF事件」
犯人が用意した罠サイトにクリックした男性Aが横浜市の小学校のホームページの投稿コーナーに「横浜市内の小学校を襲撃し、自動を大量虐殺する」と投稿された事件。

この事件では **別のWebサイトの掲示板に書き込まれたURLをクリックすることで勝手に書き込まえれてしまう仕組み** で、真犯人ではなく書き込んだ男性Aが誤認逮捕されるなどの被害があったそうです。

## なぜCSRFが防ぎづらいのか
CSRFでは正規ユーザーが罠サイトを開くことで成立するサイバー攻撃であるという特徴がある。
攻撃対象のWebサービスからすると正規ユーザーが正規のセッションIDを用いて **正規の機能を実行するリクエスト** が投げられるので防ぐ事が難しく対処しずらいっぽい。

## CSRFを防ぐには
### ユーザー側
 **1.Webサービス後はログアウトする** 
CSRFは基本的にユーザーがWebサービスにログインしている状態が狙われています。
可能な限りログアウトすることで最低限防げそう。
 **2.怪しいサイトにアクセスしない**
信頼性の低いWebサイトにはなるべくアクセスしないのが基本です。
アダルトサイトは危なそうなので男性の方は気をつけてねw
### Webサービス側
 **1.重要な処理の前にパスワードを再入力させる** 
 **2.リクエストの発信元をチェックする** 
HTTPリクエストを受けたときにどこのWebサイトから発行されたものかを示す **「リファラー」** と呼ばれる情報を得る事ができる。
 **3.ワンタイムトークンを使用する**
1.フォーム送信用ページ毎にランダムな文字列を生成し、送信用のhtmlに生成したトークンを埋め込む。
2.リクエストを受信時、トークンがない場合や、トークンが一致しない場合はリクエストを受け付けないようにプログラムを書く。
 **4.パズルや英数字・画像について答えさせる**
よく見るやつですが、これもCSRF対策の一種だったんですね。
## さいごに
今回CSRFについて調べてみましたが、 **基本的に利用者側の立場で防ぐのはかなり難しい** と思いました。
Webサービスやサイトを運営する側がしっかりと対策をすることで大半は防げそう。

いつかWebに触れる機会があればもう少ししっかりと調べて適切な対処をしたいっ！！
予定はないですが。w

ではまたっ！！
【Ruby on Rails】link_toの中でhtmlタグを表示させずにタグの内容だけ適用させる方法

## やろうとしていたこと
``` 
p= link_to "#{use_tmp(gorira.name)}", user_path
```
こんな感じのコードをrailsのslimを使用して書いていた。
ちなみに↑の```use_tmp```はapplication_helper.rb内に記述したヘルパーメソッド。
このヘルパーメソッドでは、文字を青く表示する処理を聞いた。

そのため、ユーザーが実際にみる画面では文字が青く表示されれば良い。

が、うえの書き方だと
```
<span style="color:blue">ごりら</span>
```
このように、ユーザーが見る画面でもspanタグが表示されてしまう状態だった。

## 解決方法
```
- gorira_name = "#{use_tmp(gorira.name)}"
p= link_to "#{gorira_name}".html_safe, user_path
```
このようにすると、htmlタグは表示されず、ごりらという文字が青で表示されるようになった。
忙しいレビュアーにも読んでもらえるような優しいコミットコメントをつけよう

# 概要
レビュアーは得てして忙しいことが多いと思うので、読んでもらえるような優しいコミットコメントをつけようというお話

# 結論
## 1コミットで1つの対応「のみ」を行う
シンプルにこれだけ。 
Simple is best.

# 利点と欠点
## 利点
レビュアーの負荷軽減。
大量のコミット、大量の変更、かつコメントと修正内容の不一致を起こしていると、レビュアーが疲弊してしまう。
コミット単位の意味が単純かつ明確であると、背景を読む必要がなくなり負荷が減る。
また、コミットが複数ある場合でも、「このコミットまで確認した」という区切りがつけやすい。
複数の意図が混ざったコミットコメントだと、作業中断から再開したときに、スイッチングコストがかかってしまう。

## 欠点
レビュイーの手間が少し増える。
ただし、これを意識できると、忙しいレビュアーから後回しにされるようなことは減ると思う。

# 具体例
## NG
・コミットコメントで記載されている以外のことしている
「バグ修正のコミットコメントに対して、コード差分としてはリファクタリングをも実施している」場合などが該当。
意図が異なるものを混ぜてコミットしている。
先に触れたとおり。見る側が大変。

・曖昧なコミットコメント
「一時コミット」のようなもの。意図がわからず確認する手間が出てしまう。
一時利用には `git stash`　を使ったり、コミットメッセージを修正して明確にしよう。

## OK
・hoge機能の新規追加と、それに伴うテスト修正。
・バグ番号{num} の修正対応。それに伴うテスト修正。
・パフォーマンスチューニング。DBのconnection数を、{num}から{num}に変更。
・リファクタリング

# スペシャルサンクス
監修　@yk-azarashi
組み込み基礎　I2C

# I2C（Inter-Integrated Circuit）とは
I2C（Inter-Integrated Circuit）とは、フィリップス社が提唱するシリアルインターフェースで、組み込みではセンサー類や、外付けEEPROMとの通信に使用されたりします。
I2CではSCL（クロック）とSDA（データ入出力）を使用して同期通信を行います。
通信では主体的に通信を行うマスタと、受動的に通信を行うスレーブに分かれ、マスタが出力するクロックに合わせて信号を変化させてデータのやり取りを行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811365/b5760ae4-c732-63f7-79c2-ff0491f855ba.png)

スレーブには機器ごとにI2Cアドレスが割り振られているため、1つのマスタに複数のスレーブを接続することも可能になります。

# マイコンからのデータ読み出し方法
マスタとスレーブ間の通信は書き込みの場合と読み出しの場合で以下のように行われます。

## 書き込みの場合
1. [マスタ]スタートコンディションを送信
1. [マスタ]I2Cアドレスの送信
1. [マスタ]書き込みを送信
1. [スレーブ]ACKを送信
1. [マスタ]データを送信
1. [スレーブ]ACKを送信
1. 5～6をデータサイズ分繰り返す
1. [マスタ]ストップコンディションを送信

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811365/d962f44b-6953-c40c-42a5-9f6377e86cff.png)


## 読み出しの場合
実際は先にコマンドを書き込んでから、読み出しを実行することで読み出すデータを選択することができます。

1. [マスタ]スタートコンディションを送信
1. [マスタ]I2Cアドレスの送信
1. [マスタ]読み出しを送信
1. [スレーブ]ACKを送信
1. [スレーブ]データを送信
1. [マスタ]ACKを送信
1. 5～6をデータサイズ分繰り返す
1. [スレーブ]ストップコンディションを送信

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1811365/8d2e8d4d-f201-9e19-caf8-f57685f6a4c1.png)

# Arduinoの使ったセンサ(SHT3x-DIS)の読み出し例
今後更新予定


# 参考文献
* [I2Cバス仕様およびユーザーマニュアル](https://www.nxp.com/docs/ja/user-guide/UM10204.pdf)
* [データシート：SHT3x-DIS](https://strawberry-linux.com/pub/Sensirion_Humidity_SHT3x_DIS_Datasheet_V3_J.pdf)
ファビコン ( タブの上にある画像 ) を svg で

サイトを作ってるとき、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2747899/89d27a21-c78b-0741-c2ee-137b48030f68.png)
タブの上にある画像(緑色のやつ)が画質荒いと思ったことありませんか?

まずはこの画像の変え方を教えます。

# ファビコンの変え方

```<head>```の後に```<link rel="icon" href="画像の場所">```を追加するだけ

# 本題 ファビコンをsvgにする

簡単です。
```html
<link rel="icon" href="画像の場所">
```
　　を
```html
<link rel="icon" href="画像の場所" type="image/svg+xml">
```
にするだけです。

qiitaﾉﾛｺﾞｶﾜﾙｶﾅ?

<link rel="icon" href="https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg" type="image/svg+xml">

ｻｽｶﾞﾆﾑﾘﾀﾞｯﾀ...
SQL ServerのFOR XMLでXMLを作る

# やりたいこと
DBからSELECTしてきたデータでXMLデータを作成したい。
FOR JSON AUTOのようにやればいける？
作りたい形↓
```
<AAA>
  <BBB>
    <CCC>
      <DDD>20220804</DDD>
      <EEE>朝</EEE>
      <FFF>
        <GGG>
          <HHH>コメ</HHH>
          <III>味噌汁</III>
          <JJJ>焼き魚</JJJ>
        </GGG>
      </FFF>
    </CCC>
    <CCC>
      <DDD>20220804</DDD>
      <EEE>夜</EEE>
      <FFF>
        <GGG>
          <HHH>うどん</HHH>
          <III>かつ丼</III>
          <JJJ>漬物</JJJ>
        </GGG>
      </FFF>
    </CCC>
  </BBB>
</AAA>
```
# 結論
```
DECLARE @Date	nvarchar(8) = '20220804'
DECLARE @MealTbl TABLE (
	mealTime	nvarchar(1),				
	dish1		nvarchar(10),
	dish2		nvarchar(10),
	dish3		nvarchar(10)
)

-- データ挿入
INSERT INTO @MealTbl
VALUES('朝','コメ','味噌汁','焼き魚')
INSERT INTO @MealTbl
VALUES('夜','うどん','かつ丼','漬物')

SELECT
	(
	SELECT 
		@Date as DDD,
		CCC.mealTime as EEE,
		(
		SELECT
			GGG.dish1 as HHH,
			GGG.dish2 as III,
			GGG.dish3 as JJJ
		FROM @MealTbl GGG
		WHERE GGG.mealTime = CCC.mealTime
		FOR XML AUTO, ELEMENTS, TYPE	-- ELEMENTSで要素と認識する、TYPEでXML型にする
		) FFF
	FROM @MealTbl CCC
	GROUP BY mealTime
	FOR XML AUTO, ELEMENTS, TYPE
) 
FOR XML PATH('BBB'), ROOT('AAA') --rootはトップレベル要素
```
実現できました。


# リファレンス
https://docs.microsoft.com/ja-jp/sql/relational-databases/xml/for-xml-sql-server?view=sql-server-ver16
WslRegisterDistribution failed with error: 0x800701bc　の解決方法

PC買い替えたしNext.jsで開発していくぞー！っていうところでいきなりド躓いたので共有しておきます。こちらの環境はWindows11でOSビルドは22000.856です。※管理者権限で実行していきましょう。

# WslRegisterDistribution failed with error: 0x800701bc 

エラーコードはこれ。詳細は全部？？？？の文字化けで読めないならあなたも同じ現象のはずです。

```
wsl --install -d Ubuntu
```

おそらく上記のコマンドを試したときに発生していると思うので、

```
wsl --update
```

で解決するはずです。

# Voltaがインストールできない

次にVoltaをインストールしようとして躓いているんじゃないかと予想します。

```
$ curl https://get.volta.sh | bash
```

これをいくらやっても無理じゃん！！っていう人は
https://docs.volta.sh/guide/getting-started
こちらからインストーラーをダウンロードしてインストールしましょう。

あとはコマンドプロンプトから
```
$ volta install node
```
LibSassからDartSassに乗り換えよう！

# はじめに
昨年の夏ごろからですが、以下のSass公式サイトに記載があるように、node-sass(LibSass)は公式には2020年10月に非推奨になりました。
今後はDartSassを使用していく形になるのでしょう。
DartSassに乗り換える上で、重要となる記述方法の違いについて解説します。

# 結論
ざっと変更点をまとめました。

```:変更点
- @useと@forwardの違いを理解して使い分ける
- @importから@useに書き変えるだけでは使えない
- @useはファイルごとに読み込む必要がある
- @useを使うと名前空間が発生する
```

# 詳細
DartSassに乗り換える上で、
重要となる記述方法の違いについて解説します。

## 1. @importが廃止、今後は@useを使用
パーシャルファイルを読み込むときに使っていた@importが廃止され、代わりに@useを使うことになります。

@importルールは2022年10月にサポートが終了する予定です。

例えば、「parts」フォルダにある「_vars.scss」を読み込みたいとき、@use "parts/vars";と指定します。読み込んだ_vars.scssの中にある変数を読み込み先のstyle.scssで使用するには以下のように記述します。

ファイル名は名前空間(namespace)になるので、指定する場所で「名前空間.変数名」と指定します。

```globals/_vars.scss
$color-red: #f00;
```

```style.scss
@use "parts/vars";

p {
  color: vars.$color-red;
}
```

名前空間を指定する方法、
「as hoge」で任意の名前に設定できます。

```style.scss
@use "globals/_vars" as v;

p {
  color: v.$color-red;
}
```

## 2. @forwardの基本的な使い方

他のファイルの内容を別のファイルにも渡したいというときがあります。
そうしたときに使うのが@forwardです。

中継点ようなものとイメージするとわかりやすいと思います。

@forwardが記載してあるファイルを読み込むと、
その中で@forwardで読み込んでいるファイルの内容を引き継ぐことができます。
(主に変数・mixinを呼び出す場合で使用する)

```globals/_index.scss
@forward "vars";
@forward "mixin";
```

```globals/_vars.scss
$colorBlack: #333;
```

```globals/_mixin.scss
@mixin fontset {
  font-size: 16px;
  font-weight: normal;
  font-style: normal;
}
```

```style.scss
@use 'globals';

p {
  @include globals.fontset;
  color: globals.$colorBlack;
}
```

@forwardを使っているファイル内で変数などを呼び出したいときは、
@forwardと@useを併用する必要があります。

```globals/_index.scss
@forward "vars";
@forward "mixin";

@use "vars";

a {
  color: vars.$colorBlack;
}
```

毎回呼び出し時に名前空間を指定するのは面倒な場合は*(アスタリスク)を付ける。

```style.scss
@use "globals/vars" as *;

p {
  color: $color-red;
}
```

組み込み関数からビルトインモジュールの使用については参考・引用から確認してください。

# 参考・引用
- [Sassを使うならDart Sassに乗り換えよう！](https://tiplib-web.com/tips/211204_dart_sass/)
- [LibSassからDartSassに変更](https://suzunon.com/web-develop/css/from-import-to-use-in-sass/)
CSSのdisplay: contentsでdivの仕切りを取り払い、同じHTMLでいろんなレイアウト

画面幅によりコンテンツの配置や順序が大きく変わるデザインに対して、HTMLに記述する階層構造は変えずにCSSだけで対応したい。

この記事では下図のレイアウトを題材にします。１つのセクションの中に、見出し１個、画像２個、テキストの段落４個を配置したページです。レイアウトはデスクトップ向け、タブレット向け、およびスマホ向けの３種類です。
![fig01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/03cdb09e-7b6c-c282-bb9f-3522b095bd9a.png)
※画像引用: Photo by [Johnny Africa](https://unsplash.com/photos/CgwzPOgimrg) on [Unsplash](https://unsplash.com/), Photo by [Katja Rooke](https://unsplash.com/photos/77JACslA8G0) on [Unsplash](https://unsplash.com/)

これを実現するため、最初にデスクトップ向けレイアウトのコーディングだけを考えてみます（下図の左側）。そこで、画像を囲むdiv.b、本文のp要素を囲むテキストブロックをdiv.cとし、div.bとdiv.cをコンテナdiv.aで包み、さらにテキストを回り込ませるためdiv.bをfloatで配置しました。
![fig02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469745/c6f00588-874d-5d76-5874-90f131a67078.png)
では、同じマークアップを使ってタブレット向けレイアウトにCSSで対応させるには？ div.bをflexboxにしてimg要素を横並びにし、section（一番外側の赤い枠）をflexboxにして、アイテムを縦並び、アイテムの順番をorderで変えて見出しh2を２番目に...ダメです。デスクトップ用に入れたコンテナdiv.aが"壁"になってしまい、h2をdiv.bとdiv.cと同じ階層に持っていくことができません。

スマホ向けレイアウトの場合はどうでしょう。こちらは２つ目のimg要素がp要素の並びに挿入された形をしています。今度はデスクトップ用に入れたdiv.bとdiv.cの壁が邪魔です。これらのdivを"解体"して子要素に分解しないといけませんね。

HTMLに記述した階層構造は変えずにdivの"壁"だけ撤去したい...こんな時に役立つのが、CSSの`display`プロパティの[contents](https://caniuse.com/?search=contents)キーワードです。

https://twitter.com/kazhashimoto1/status/1557645918312472576

ソースコードはこちら: https://codepen.io/kaz_hashimoto/pen/oNqMPor

このCodePenは、HTMLの同じマークアップから11種類のレイアウトを生成します。レイアウトの切り替えは、JavaScriptを使って`section`要素にclassを設定することにより行います。レイアウトの種類を表すclass名は "layout1"〜"layout11"です。レイアウトの種類に応じて、div.group1, div.group2, div.group3の表示種別（CSSの`display`プロパティの値）が変化します： `block`, `grid`, `flex`, `contents`。

```html:html
  <section class="section layout1">
    <h2>Section 1</h2>
    <div class="group1">
      <div class="group2">
        <div class="photo">
          <img src="photo1.jpg">
        </div>
        <div class="photo">
          <img src="photo2.jpg">
        </div>
      </div>
      <div class="group3">
        <p class="text">1. ....</p>
        <p class="text">2. ....</p>
        <p class="text">3. ....</p>
        <p class="text">4. ....</p>
      </div>
    </div>
  </section>
```

このテクニックを用いて、冒頭に示したレスポンシブ対応のレイアウトを実装したのがこちらのDEMOです。classの代わりにメディアクエリーでスタイルを上書きしてレイアウトを切り替えています。
※上記CodePenのlayout3, layout5, およびlayout7に相当します。

DEMO: https://codepen.io/kaz_hashimoto/pen/RwMeeXp

<p class="codepen" data-height="487.7935791015625" data-default-tab="result" data-slug-hash="RwMeExd" data-user="kaz_hashimoto" style="height: 487.7935791015625px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kaz_hashimoto/pen/RwMeExd">
  [video] Responsive layout with css display: contents</a> by Kazuhiro Hashimoto (<a href="https://codepen.io/kaz_hashimoto">@kaz_hashimoto</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
[C言語]scanf関数の欠陥とscanf_s関数

〇時系列
・scanf関数が使われる
・scanf関数に欠陥ありハッキングによりPCが乗っ取られる事件が発生
・対処法としてマイクロソフト社の独自拡張によりscanf_s関数が作られる
・マイクロソフト社製のコンパイラではscanf関数を使うと警告が発生する使用になる

〇問題点
・あくまでもscanf_s関数は標準関数ではなくマイクロソフト社の独自拡張のため他社コンパイラではscanf_s関数は弾かれる。


〇scanf_s関数の約束
char型配列に文字列を入力する場合は、第三引数に受け取れる最大文字数を指定する
Reactでモーダル実装のベストプラクティスを考えてみた

FE開発においてモーダル実装はあらゆるところで使う場面があり、要件やモーダルの数が増えるに従って実装も複雑になり設計に悩まされてる方も多いと思います。
そこでモーダル実装に関するベストプラクティスを考えてみました
## [設計方針](設計方針)
状態管理にRecoil、モーダルに関するロジックをカスタムhook化することにしました
Recoilを使う理由は、Recoilに用意されているステート管理の`atomFamily`がモーダル実装と非常に相性がいいからです

## [モーダル実装のアンチパターン](モーダル実装のアンチパターン)
```js:MainPage.tsx
const MainPage = () => {
  const [isFaqVisible, setIsFaqVisible] = useState(false)

  return (
    <div>
      {isFaqVisible && <FaqModal />}
      <button onClick={() => setIsFaqVisible(true)}>
        クリックするとFAQモーダルが開くよ
      </button>
    </div>
  )
}

export default MainPage
```

あるあるな書き方ですが、このように同じコンポーネント内でモーダルの開閉状態をもつと以下のデメリットが出てしまいます
- 開閉処理と表示の状態が完全にコンポーネントに依存しているため、別のコンポーネントからの開閉処理がやりずらい。特にFAQモーダルなど多くのページからコールされる事が予想されるため、予期せぬバグの温床になりやすい
- 表示させたいモーダルの数が増えるごとにstateが増えてコードの見通しが悪くなり保守性が悪くなる

## 解決策
- 開閉に関する状態と処理はカスタムhook化してコンポーネントと疎結合にする
- モーダルの状態を```atomFamily```で抽象化する事で、stateの冗長な記述を解消する

モーダルのステート管理
```js:src/states/modal.ts
import { atomFamily } from 'recoil'

export type ModalType =
  | 'contact'
  | 'faq'
  | 'confirm'
export const ModalVisibilityState = atomFamily({
  key: 'ModalVisibilityState',
  default: false,
})

```
ここでは、モーダルの種類に応じた```ModalType```と```atomFamily```でモーダルのステートを抽象化しています

FAQモーダル
```tsx:Faq.tsx
import Modal from 'components/Common/Modal'
import useModal from 'hooks/useModal'

const FaqModal = () => {
  const [isVisible, setIsVisible] = useModal('faq')

  return (
    isVisible && (
      // propsにモーダルを閉じるcomponent
      <Modal closeModal={() => setIsVisible(false)}>{/*Modalの中身*/}</Modal>
    )
  )
}

export default FaqModal
```
ポイントはコンポーネントの内部で表示/非表示の関心だけを持たせる事で、呼び出しもとで開閉状態を意識せず実装できる点です



**モーダルのカスタムフック**
```ts:src/hooks/useModal.ts
import { useRecoilState, SetterOrUpdater } from 'recoil'
import { ModalVisibilityState, ModalType } from 'states/modal'

type Response = [
  boolean,
  SetterOrUpdater<boolean>
]

const useModal = (modalType: ModalType): Response => {
  const [isVisible, setIsVisible] = useRecoilState(
    ModalVisibilityState(modalType)
  )

  return [isVisible, setIsVisible]
}

export default useModal
```

```atomFamily```で作った```ModalVisibilityState```を```useRecoilState```でラップして一意なステートを作成して開閉処理の管理をしています
こうすることで、モーダル毎に応じたstateを一々記述する必要がなくなりスッキリかけます
また、引数に```ModalType```を渡すことで、どのコンポーネントからも柔軟に開けるようになります

***モーダルを表示させたいコンポーネント***
```tsx:DisplayModalComponent.tsx
import React from 'react'
import FaqModal from 'components/Modal/FaqModal'

const DisplayModalComponent = () => {
  return (
   <FaqModal />
  )
}

export default DisplayModalComponent
```

***モーダルを呼び出したいコンポーネント***
```tsx:CallModalComponent.tsx
import useModal from 'hooks/useModal'

const CallModalComponent = () => {
  const [, setIsVisible] = useModal("faq")

  return (
    <button onClick={() => setIsVisible(true)}>
      クリックするとFAQモーダルが開くよ
    </button>
  )
}



export default CallModalComponent
```
```useModal```を呼び出して、ボタンをクリックするとFAQモーダルが開くようになります

## 考察
他にもcontextやRecoilRootを使ってグローバルに状態を管理する方法もあると思いますが、この書き方の方が遥かにスッキリ描けるので今のところ個人的なベストプラクティスかなと思います！
[C言語] scanf関数使用時「C6031 戻り値が無視されました」警告の原因と対策

〇原因
セキュリティやIDEのバージョンに起因するものと考えられる

〇対策
「scanf()」を「scanf_s()」に置き換える
又はセキュリティ開発サイクル（SDL）チェックをオフ
whenever gem mac cron log どこ ? - wheneverでcronを正常作動させるまでの備忘録 -

# - wheneverでcronを正常作動させるまでの備忘録 -

## 執筆経緯
> [whenever(github)](https://github.com/javan/whenever)

上記のgemを導入してmacbookローカル上で定期実行を試みたが、全くうまくいかず

・ログどこにあるの？？？
・何のエラー起きてるの？？？

となり、想定した動作をするまでにかなり時間を費やしたので
同じ症状の方が短時間で解決できるよう、解決方法と原因を周知するために執筆する。

## 私の環境
PC：MacBook Air (M1, 2020)
rails(アプリ側): 6.1.6.1
rails(ターミナル標準):5.2.8.1

## テーマと扱わない事項
:::note
本記事のテーマは、macでwheneverを使用した際にcronを正常動作させるために
・”schedule.rb”にどのように記載すべきか
・記載内容の意味
をテーマに解説していきます。
:::
:::note alert
wheneverの具体的な使い方については解説していません
:::

## 結論
```ruby:schedule.rb
set :output, "#{Rails.root}/log/cron.log"
#railsアプリフォルダ内の./log/cron.logにログが出力されるようにする記述

require File.expand_path(File.dirname(__FILE__) + '/environment')
set :path_env, ENV['PATH']
rails_env = ENV['RAILS_ENV'] || :development
set :environment, rails_env
#railsアプリ内の実行環境を変数に代入している

job_type :runner, "cd :path && PATH=':path_env' bin/rails runner -e :environment ':task' :output"
#railsアプリ上の実行環境と同条件になるよう規定している
#:outputで事前にsetしたパスにログの出力先を設定

```
とりあえず、schedule.rb内に上記の記述を追記すればOK

### 補足
上記を追記してもうまくいかない方は
少なからず、ログは取れるようになったはずなのでログのエラー内容を見れば対処できるようになってます！

## 原因
### macのcronログどこ？
最近のmac_bookのcronはログ出力先を指定しないとログを出力しない設定になっているようです。。。

そして、
```ruby:schedule.rb
every '*/1 * * * *' do
  runner "Movie.publish_check"
end
```
のみしか記述せずにwhenever ==> cronに上げてしまうと
ログ出力先を指定してないことになり、どこにもログが吐き出されなくなります。。。

### ターミナル(cron)とアプリ上で実行環境が違くなる
```:エラーログ
From: motoya@murakamimotoyas-MacBook-Air.local (Cron Daemon)
To: motoya@murakamimotoyas-MacBook-Air.local
Subject: Cron <motoya@murakamimotoyas-MacBook-Air> /bin/zsh -l -c 'cd /Users/motoya/study/whenevertest && bundle exec bin/rails runner -e development '\''Movie.publish_check'\'''
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=motoya>
X-Cron-Env: <USER=motoya>
Message-Id: <20220806024702.83064923436@murakamimotoyas-MacBook-Air.local>
Date: Sat,  6 Aug 2022 11:47:01 +0900 (JST)

/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems.rb:283:in `find_spec_for_exe': Could not find 'bundler' (2.2.33) required by your /Users/motoya/study/whenevertest/Gemfile.lock. (Gem::GemNotFoundException)
To update to the latest version installed on your system, run `bundle update --bundler`.
To install the missing version, run `gem install bundler:2.2.33`
	from /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/rubygems.rb:302:in `activate_bin_path'
	from /usr/bin/bundle:23:in `<main>'
```
私の場合、上記のようなログがcron.logに残っていたのですが
先に提示した通り私の環境では

railsの標準バージョン：5.2.8.1
wheneverを実行するアプリのrailsバージョン：6.1.6.1

と差異が発生しており
cron側で特に何も設定しないと
ターミナル標準バージョンのrailsを使用して実行してしまうため
エラーが発生しておりました。。。

## 参考
>https://qiita.com/uot/questions/a283becff015139ac760
上記の解答を参考に問題を解決させて頂きました！

## 最後に
これを機にcronのlog出力先は必ず指定することを忘れないようにしていきます！
間違ってる箇所等ありましたらお気軽に御指摘頂けますと幸いです！！！