OmniAICreator/Qiita-1.07M huggingface dataset:
【C#】2021/05/22最新のMagick.NETは.toBitmap()が使えない！！の解決策

##初めに

【注意】2021/05/22現在における最新の<b>NuGetからインストールするMagick.NET-Q8-AnyCPU</b>についてになります。

C#のwindowsアプリケーションを作っていまして、
Magick.NETでsvgファイルを扱う時に困って調べて疲れたので備忘録です。

##Magick.NETでsvgを扱う方法を調べた

色々なサイトを見ると、NuGetからMagick.NET-Q8-AnyCPUをインストールすると扱えると書いていますが、うまくいきませんでした。
情報はどれも古く、最新版の情報は少ないです。

以下は<font color =red>エラーが出た</font>サンプルコードです。

```C#
    //ピクチャーボックス表示用
    System.Drawing.Bitmap myBitmap;
    //svgファイル読み込み
    var Magick = new ImageMagick.MagickImage("Sample.svg");
    //ピクチャーボックスへ表示する為、Bitmapへ変換
    myBitmap = Magick.ToBitmap();
    //リソース解放
    myMagick.Dispose();
    //pictureBox1に表示
    pictureBox1.Image = myBitmap;
    pictureBox.Refresh();
```
`var Magick = new ImageMagick.MagickImage("Sample.svg");`
svgファイルを読み込みます。
`myBitmap = Magick.ToBitmap();`
bitmapに変換します。

一見何も問題なさそうですが、エラーが出てしまいます。
<b>最新版のMagick.NET-Q8-AnyCPUでは　.toBitmap()機能　が削除されています。</b>
>情報元:https://github.com/dlemstra/Magick.NET/discussions/652

これでは、pictureBoxに入れられません。(ほかの方法もあるかもしれませんが)

##対策
拡張機能の<b>NuGetでMagick.NET.SYystemDrawingをインストールしてください。</b>
これをインストールすれば、.toBitmap()が使えるようになります。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/485495/0111faa7-d24b-7433-0b99-64c4a60ad744.png)

この３つをインストールすれば少なくとも私の環境では大丈夫でした。

##まとめ
そんな感じでした。

>参考:
C# Magick.NETを使ってみる。その１
http://1studying.blogspot.com/2017/05/c-magicknet.html
Magick.NETドキュメント
https://github.com/dlemstra/Magick.NET/tree/main/docs
tobitmap extension gone from release 1.18
https://github.com/dlemstra/Magick.NET/discussions/652
package.json のアップデート

#概要
色々なライブラリを管理はされているが、そういえばいつからかアップデされていない！！
って事で、アップデしました。

package.json内のライブラリ達を一括アップでしてくださります。

ローカル環境：windows10

参考サイト様 -> https://omachizura.com/2016/02/npm-package-new.html

# npm を使ってアップデ
https://www.npmjs.com/package/npm-check-updates
こちらを利用して、アップデートしていきます。

`npm install -g npm-check-updates`

実行
`npm-check-updates -u`

実行後、アップデートされたファイルが列挙されますよー


# エラーが出た
```code:Error.ps1
npm-check-updates : このシステムではスクリプトの実行が無効になっているため、ファイル C:\Users\user\AppData\Roaming\npm\npm-check-updates.ps1 を読み込むことができません。詳細については、「about_Execution_Policies」(https://go.m 
icrosoft.com/fwlink/?LinkID=135170) を参照してください。
発生場所 行:1 文字:1
+ npm-check-updates -u
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : セキュリティ エラー: (: ) []、PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess
```

`PSSecurityException` ってところでググったところ、ファイルの権限が原因でした。

つまりは、カレントディレクトリから` C:\Users\user\AppData\Roaming\npm\npm-check-updates.ps1`を呼び出しているらしいです。

権限変更していきましょうか。私の環境では以下だったので・・
参考サイト様：https://qiita.com/Targityen/items/3d2e0b5b0b7b04963750

```code:chagePermition.ps1
# PowerShell -ExecutionPolicy RemoteSigned C:\Users\user\AppData\Roaming\npm\npm-check-updates.ps1
```

`-ExecutionPolicy` がPSの権限の変更。
エラーになったファイルをしてしてます。
`Get-ExecutionPolicy ファイル名` にすると、ファイルの現在の権限がわかります。

#最後に
ハマってはないけど、一応メモっておくー！

PSは、昔触ってたからねー！ > ADの方だけど・・
最近、windows触っていて、やっぱりマウスとキーボは使いやすい!!
だが、しかし、windowsの内部構造をあまり知らないので、色々ハマりやすくて＞＜辛い！！

最近、お仕事の面談とか色々受けているのですが、やっぱり凄腕エンジニアさんがいらっしゃると「あーここでお仕事させて頂きたいです!!!」と思ってしまう。自分がソレになるようぢゃなきゃダメやね。
はい、頑張りましょー。
Elastic IP をEC2インスタンスに関連付けるとhttpリクエストができなくなった話

Elastic IP をEC2インスタンスに関連付けるとEC2のパブリック IPv4 アドレスが変わってしまいますので、httpリクエストのパラメータのURLにパブリック IPv4 アドレスが含まれている場合は注意が必要です。きちんとドメインを取得していればそもそも関係のない話ではありますが、そのままEC2を試すだけといった時には起こりうるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630191/cd7e91cd-aee9-aabe-4130-30b53f9b8e95.png)
Macのターミナルに(base)と表示された時の対処法

Macのターミナルに base と表示されていました。
baseがなんなのか、又消すにはどうすればよいか調べたことをまとめます。

<h1>baseとはなんぞや</h1>
実はこれは、Pythonの仮想環境ソフトAnacondaがインストールされたことが原因で起こる現象です。
Anacondaをインストールすると以下のようにMacのターミナルの先頭に(base)と表示されるようになります。

```html:terminal
（base） test@myMacBook ~ %
```

anaconda3のPythonが使われていることがわかります

これはAnacondaの仮想環境baseがアクティベートされていることを意味しています。
Anacondaをインストールすると、Macのターミナルを起動した時に自動的にbaseをアクティベートするように設定されるようです。

どのPythonが使われているか調べてみると。

```html:terminal
（base） test@myMacBook ~ % which python
/Users/test/opt/anaconda3/bin/python
```

<h1>この仮想環境から抜けるにはどうすればよいか？</h1>
この仮想環境から抜けるには、ディアクティベートすれば良いのです。

```html:terminal
（base） test@myMacBook ~ % conda deactivate
test@myMacBook ~ %
```

baseの表記がなくなりました。
Pythonの場所を調べてみると

```html:terminal
test@myMacBook ~ % which python
/usr/bin/python
```

Anacondaの仮想環境から抜けて、MacのデフォルトのPythonが使えるようになっていることが確認できました。
ただ、毎回 deactivate するのは面倒なので、Terminal起動時にbaseが activate しないように以下のコマンドを打っておきます。

```html:terminal
conda config --set auto_activate_base False
```

以上、まとめです。
migrationできない理由

```terminal:terminal
Caused by:
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'tagtweet_development.tweets' doesn't exist
/Users/maedatakuo/projects/tagtweet/db/migrate/20210522115800_create_tweet_tag_relations.rb:3:in `change'
/Users/maedatakuo/projects/tagtweet/bin/rails:9:in `<top (required)>'
/Users/maedatakuo/projects/tagtweet/bin/spring:15:in `<top (required)>'
bin/rails:3:in `load'
bin/rails:3:in `<main>'
```



原因：
-
ActiveRecord :: StatementInvalid：Mysql2 :: Error：テーブル 'tagtweet_development.tweets'は存在しません
・・・・・

どうやらテーブルを探しに行っているようです。

結論
-
外部キーばかりで作られたテービルを先に作ってしまっていました。
外部キーを含んだテーブルは後に作らないと連携の関係があるのでどうやら外部キー先のテーブルを参照するように作成されるようです。


マイグレーションの最初の番号を入れ替えると
以下のようにうまく作成できました。

```terminal:terminal
== 20210522115800 CreateTags: migrating =======================================
-- create_table(:tags)
   -> 0.0824s
== 20210522115800 CreateTags: migrated (0.0827s) ==============================

== 20210522115853 CreateTweets: migrating =====================================
-- create_table(:tweets)
   -> 0.0908s
== 20210522115853 CreateTweets: migrated (0.0914s) ============================

== 20210522120027 CreateTweetTagRelations: migrating ==========================
-- create_table(:tweet_tag_relations)
   -> 0.0808s
== 20210522120027 CreateTweetTagRelations: migrated (0.0814s) =================
```
シークレットロックトランザクションを利用した比較的安全な自動送金

# はじめに

なんかアプリとかゲームとかで、ユーザーがなんかミッションをクリアしたら、システムから自動的にXYMかモザイクを送りたい、といった場面があるかもしれません。

そういった場合、ユーザーが保有しているアドレスを入力してもらうことが必要になると思います。

けど、ユーザーが入力した受取アドレスが間違っている可能性があります。

アドレスフォーマットのチェックはできますが、ユーザーが保有しているアドレスかどうかを確認するのは難しいです。

そこで、この記事は、ユーザーがそのアドレスの所有者である確度を少しでも上げるために、シークレットロックトランザクションと、シークレットプルーフトランザクションを利用するアイディアについて書きつづります。

# シークレットロックトランザクション

シークレットロックトランザクションとシークレットプルーフトランザクションについて少し説明します。

シークレットロックトランザクションは、トランスファートランザクションと同様に、XYMなどのモザイク（資金）を特定のアドレスに対して送ることができます。しかし、資金は手元を離れますが、この段階ではまだ相手には届きません。

上記のトランザクションによって指定されたアドレスの持ち主は、シークレットプルーフトランザクションを送信することで、資金を受け取ることができます。

このとき、シークレットロックトランザクションに設定されたシークレットというバイト値が、プルーフから計算される値と一致している必要があります。（プルーフはシークレットプルーフトランザクションにて指定します。）

もしこれが一致していない場合、シークレットプルーフトランザクションは送信に失敗します。

一定の期間、シークレットプルーフトランザクションが送信されない場合、資金は送り主に戻ってきます。

公式ドキュメント
https://docs.symbolplatform.com/ja/serialization/lock_secret.html#secret-lock-transaction

## 応用シーン

このことを利用して、資金を受け取って欲しい人に対して、安全に送金することができる可能性があります。

例えば、とある開発者がゲームを作ったとします。このゲームのユーザーは、ミッションをクリアすると、XYMを受け取ることができます。

初めに、ユーザーはゲーム内で自分の所有しているアドレスを入力します。

次に、何かしらのミッションをクリアしたり、報酬受け取りボタンを押したりして、XYMを受け取る段階になったとします。

このとき、ゲームのサーバーはユーザーの入力したアドレスに対して、シークレットロックトランザクションを送信します。（資金の拠出は開発者が行うとします）

そしてつぎに、アプリやメールなどでプルーフを開示します。

最後に、ユーザーは自らシークレットプルーフトランザクションを送信し、資金を受け取ります。

このとき、ユーザーが入力したアドレスが、実はユーザーが所有しているものでなかった場合、シークレットプルーフトランザクションは失敗します。

そして、誰も受け取らないまま一定期間が過ぎると、資金は開発者に返却されます。

これにより開発者は、ユーザーが入力したアドレスが間違っていた場合に資金を失うというリスクを避けることができます。ユーザーもまた、入力したアドレスが間違っていたことを通知してもらい、再度正しいアドレスを入力することにより、確実にXYMを受け取ることができるようになります。

# アグリゲートトランザクションでいいじゃん

アグリゲートトランザクションでも似たようなことができると思われます。

ゲームのサーバーは以下のようなアグリゲートボンデッドトランザクションを送信します。

* サーバーからユーザーにXYMを送金する。
* ユーザーからサーバーに0XYM送金する。

こうすることで、サーバーとユーザーの両方の署名が揃わないと、トランザクションが成立しなくなります。

ユーザーが入力したアドレスが間違っていた場合、ユーザーは署名を作成することができないため、安全に送金することができるようになります。

## アグリゲートの欠点

ユーザーから資金を送信するトランザクションが含まれるため、ユーザーは内部トランザクションをしっかり確認しないと、資金を抜かれる恐れがあります。

アグリゲートボンデッドトランザクションを送信するためには、ロックハッシュトランザクションによって10XYMを供託しなければなりません。これは場合によってはかなりのコストになり得ます。

# 注意点

シークレットロック／プルーフトランザクションは、シークレットとプルーフに加え、受取人アドレスを指定します。

このとき、シークレットプルーフトランザクションに署名するアカウントは、受取人アドレスのものでなくても問題ありません。

ですので、以下のようなことが起こってしまう可能性があります。

ユーザーがアプリ／ゲームに入力したアドレスが間違っていたとして、XYMを受け取ろうとしてシークレットプルーフトランザクションを送信する際、受取人アドレスをその間違ったアドレスを指定してしまうと、その間違ったアドレスに資金が送られてしまいます。（＝ユーザーは資金を受け取れない）

なので、ユーザーがシークレットプルーフトランザクションを送信するときには、受取人アドレスには、必ずトランザクションに署名したアカウントのアドレスを指定するようにしなければなりません。

でないと、間違ったアドレスに送金してしまうことを防ぐことができません。
【初心者でもわかる】背景画像を固定して、スクロールしても動かないようにする方法

#どうも7noteです。固定背景画像の作り方

スクロールしても、動かない固定の背景画像の設定方法を解説していきます。


## 固定背景の書き方

```index.html
<div class="box">
  <p>サンプルテ 〜省略〜 サンプルテキスト</p>
  <img src="photo01.jpg" alt="">
  <p>サンプルテ 〜省略〜 サンプルテキスト</p>
  <img src="photo01.jpg" alt="">
</div>
```

```style.css
.box {
  background: url(sample.jpg) no-repeat; /* 背景画像を指定、繰り返し禁止 */
  background-attachment: fixed; /* 背景画像をスクロールしても固定させる */
  background-size: cover; /* 背景画像を要素全体を覆うように拡大縮小させる */
}
	
p {
  background: rgba(255,255,255,0.5); /* 半透明の白い背景を設定 */
  padding: 20px;  /* 適当な余白を指定 */
}

img {
  width: 100%; /* 画像幅を100%に指定 */
}
```

![スクリーンショット 2021-05-16 18.39.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/b9c3a0f5-432e-4b3a-2455-15a81d4acec6.png)

![スクリーンショット 2021-05-16 18.39.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/38863d2f-8d54-dd94-0e5f-16b4381f7070.png)



##まとめ

「1行で簡単指定」＆「自由に他の装飾と組み合わせが可能」なところがポイントですね。
難しくなく簡単に設定することができます。

一時期よく見かけましたが最近ではこれを使ってるサイトは減ってきたように感じます。
逆に動画なんかが増えてるような印象がありますね。計測したわけではないので実際のところはあまりわからないですが。

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
ファイル分類()

ファイルを分類するために作ったものですが、
すごく個人的な目的のため,特に参考になりません。

以下、スクリプトです。

```python：フォルダ分類
import shutil
import os
import pathlib
import string

##実際は何らかの形で引数として割り当てる
#voicefile ='namefileの絶対パス'

#実行ファイルを分類したいフォルダ内に移動して実行
voicefile = './'

#カレントディパレクトリを音声データがまとまって入っているフォルダにする
os.chdir(voicefile) 

ki='01-25'
gu='26-50'

#まとめる用のフォルダを作成
for i in range(9):
     #chi(97)=a
     
      makefilename =chr(i+97)+ki
      os.makedirs(makefilename, exist_ok=True)
      makefilename =chr(i+97)+gu
      os.makedirs(makefilename, exist_ok=True)
        
i=9
makefilename =chr(i+97)+ki
os.makedirs(makefilename, exist_ok=True)
makefilename =chr(i+97)+'26-53'
os.makedirs(makefilename, exist_ok=True)


# WAVファイルがあるフォルダの名前と同じ名前のフォルダを
# 作業ディレクトリから見つけ、コピー
def process(file_path):
   
        #WAVファイルが入っているフォルダ名(ディレクトリ)を取得
        dirname = os.path.dirname(file_path)

        #下6桁(a01-25etc.)を抽出
        folder_name =  dirname[-6:]
        #voicefile+'/フォルダ名'のディレクトリにコピー
        shutil.copy(file_path, voicefile+folder_name)


def recursive_file_check(path):
    if os.path.isdir(path):
        # directoryだったら中のファイルに対して再帰的にこの関数を実行
        files = os.listdir(path)
        for file in files:
            recursive_file_check(path + "/" + file)
    else:
        if path[-4:] == '.wav':
        # WAVfileだったら処理
         process(path)

recursive_file_check(voicefile)

```
ESP-WROOM-02搭載移動ロボットをMQTTで制御する - MQTT編

本記事の内容はQiitaの[コミュニティガイドライン](https://blog.qiita.com/notice-community-guideline-update/)に沿わないと判断したため、Zennへ移行しました。

https://zenn.dev/yakiimo121/articles/a2ff58f723461a
Python 機械学習 #1

# 機械学習のジャンル
機械学習を一から始めてます。勉強で自分なりに解釈をしております。間違っているところがありましたらお伝えしてくださると幸いです。
##教師あり学習
入力と出力のペア群から学習するアルゴリズムである。なぜ教師となるかというと学習のために与えられる入出力ペア群がある意味先生となるからである。アルゴリズムは入力から望ましい出力を生成する方法を発見する。
封筒に書かれた手書きから郵便番号を読み取るのも入力から望ましい出力を生成する方法を見つけて照合する事によって可能になる。

##教師なし学習
入力データだけが与えられていて出力データはアルゴリズムに与えられない。だからこれと言った答えが導かれないようなものである。
例えば顧客をグループに分けるときもジャンルはある程度決まっているものもあるが新しいユーザが来るたびにジャンルは更新していくというように正確な答えというものはあまりない。

##まとめ
教師あり・なしに関わらず入力データを計算きが理解できる形で表現することが重要である。
データ（＝テーブル）と考え、それぞれのデータポイント（個々のメール、個々の顧客）が行となり、データポイントを記述する個々の特性は列（顧客の年齢、トランザクションが行われた場所とか）となる。この時この行に当たる部分をサンプル（＝データポイント）と呼び、列を特徴量という風に呼ぶ。


扱っているデータと解決しようとしている問題とデータとの関係を理解することだ。適当にアルゴリズムを選んでデータを投げ込むというようなことをしては望んでいるような結果が適当にやっているわけであるから良い値が返ってこない。



#必要なライブラリとツールについて
##Jupyter Notebookについて
使い方について説明する。
（１）Anacondaのアプリを開く
（２）Jupyter NotebookのLaunchをタップする
（３）右上にある新規をタップしてPython3をタップする
それで完了となる
##操作方法
###入力
入力の横にある細長い空欄をタップして自分の実行するしたいコードを入力できる
###再生ボタン
入力としたものを実行したいときはこのボタンを押すと可能になる。

##Numpyについて
Numpyは大学とか高校で使うようなレベルの高い数学を使うことができる。よくNumpyをインポートするときにはいちいちNumpyと打ち込むのは面倒なのでnpとしてやっていく。一つの例として三角関数について説明していく。他にもいっぱいあるのでぜひNumpyと調べてみてください！

```py
import numpy as np
list_1 = np.array([[1, 2, 3], [4, 5, 6]])
print(list_1)
#実行結果
[[1 2 3] [4 5 6]]
```
###三角関数

```py
import numpy as np
np.sin(0)
#実行結果
1
np.sin(45)
#実行結果
0.8509035245341184
```
##Scipy

線形代数ルーチンや数が奇関数の最適化、統計分布などを行う。こちらでは例として積分をやってみたいと思う。

```py
結果, 誤差 = integrate.quad(積分したい関数, x, y(x~yが積分区間))
```

```python
from scipy import integrate

def math_func1(x):
    return x**3 + x + 3

result, missing = integrate.quad(math_func1, 0, 1)

print("結果は", result, "誤差は", missing)
#実行結果
結果は 3.75 誤差は 4.163336342344337e-14
```

##matplotlib
このライブラリはグラフを書くことができる。要はデータを可視化することができるのだ。%matplotlib inlineを用いることによって図をブラウザに直接図示することが可能になる。今回は先ほどしました関数を図示する感じで使ってみる

```python
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-1000, 1000, 100000)

def math_func1(x):
    return x**3 + x + 3

y = math_func1(x)
plt.plot(x, y, marker="x")
```
実行結果はこのようになるであろう。このようにして図示することができるため非常に便利なツールである。

![スクリーンショット 2021-05-22 20.52.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406024/2a5c52a4-db79-cae9-1cc6-0b4903d2c85d.png)


##pandas
データを変換したり解析したりするためのツールである。この中で代表的なライブラリとしてDateFrameというものが存在する。これは表のようなものであり、テーブルを変更する関数などの手法が掲載してある。pandasの長所としては列ごとに異なる型でも良い。小数と整数というペアも可能になる。また、エクセルのファイルやSQLのデータベース、CSVファイルからデータを取り込むことが可能であるところも長所の一つである。

```python
import pandas as pd
from IPython.display import display
soccer_information = {'Name':['Liverpool', 'Barcelona', 'Dortmund', 'Monaco'],
'Country':['England', 'Spain', 'Germany', 'France'],
'Superstar':['Sarah', 'Messi', 'Sancho', 'Cesc']}
soccer = pd.DataFrame(soccer_information)
display(soccer)
```
![スクリーンショット 2021-05-22 21.12.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/406024/32b80489-727f-3853-16f1-ba1074f350ad.png)

##mglearn
こちらに関してはグラフの絵やデータのロードを読みにくくならないようにするものである。
詳細については調べてくださると幸いです

この記事は「Pythonで始める機械学習」から一部引用しております。
こちらの本は参考になるのでもし宜しかったらご購入を検討してみてください！

また順番においてもこちらの書籍を参考にしております。
【OBS】生放送に表示する時計を透過したいのでCSSを書いた【コピペすればOK】

# 生放送の配信画面の時刻を透過します
「Y●u Tubeで生放送してみたいなぁ」
「ちょっと時計出すか」
「右下の時計を透過したいのになぁ。。。」→__できます__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198686/2c1fc4ad-0828-e79f-e1b0-c6d5cd8d8b96.png)

# 手順

1. [ソース]の[+]ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198686/33df7371-4342-f58d-580a-c40d3e75ad99.png)

1. [ブラウザ]をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198686/b13434e0-8f06-e03b-a3c4-0b755648108c.png)

1. [新規作成]欄に適当な名前を入力して、[OK]をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198686/34b7ee47-d7e4-0017-04aa-b08e022cba29.png)

1. 次のような画面が表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198686/ee2eab08-1e82-0102-1c30-4902565cbfd5.png)

1. [URL]欄に[Time.is][link4]（東京）のURLを入力
`https://time.is/ja/Tokyo`

1. [カスタムCSS]欄に次のCSSを入力し、 [OK]をクリック

```css
/* 背景を透過する */
body, #mainwrapper {
    background-color: rgba(0,0,0,0);
}

/* 時計の文字色を黒色にする */
#clock {
    color: #000000;
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198686/2aacb897-6178-ced1-be2d-cfab03d63d38.png)

# 完成
※この画像だけ、OBS画面の背景色を灰色に変更しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198686/246e9a2e-6678-ae5a-1af9-eab49aab7c2d.png)

# おまけ（時計の文字色を変更）
文字色を変える場合は、`#clock`の`color`を変更します。

```css
/* 背景を透過する */
body, #mainwrapper {
    background-color: rgba(0,0,0,0);
}

/* 時計の文字色を赤にする */
#clock {
    color: #ff0000;    /* ここのカラーコードを好きな色に変更 */
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/198686/f493919c-708f-8597-7374-3dcb15ca66df.png)


# 参考
- [Time.is][link4]
- [OBSなどの配信画面に現在時刻を載せる簡単な方法][link1]
- [Time.is用カスタムCSSジェネレーター][link2]
- [OBS向けにTime.isの時刻表示の色を変更する【生配信向け】][link3]



[link1]:https://twitch-memo.net/stream/streaming-time/
[link2]:http://css4obs.starfree.jp/clock.html
[link3]:https://note.com/riyadazo/n/nf980530e2d4e
[link4]:https://time.is/ja/Tokyo
【AWS】EC2インスタンスのユーザーデータの設定方法

#プログラミング勉強日記
2021年5月22日
[昨日の記事](https://qiita.com/mzmz__02/items/766f7240bc9ca67054a7)でユーザーデータについて扱ったが、スクリプトの書き方を備忘録として残す。

#設定するスクリプト
　ユーザーデータはEC2インスタンス作成の`ステップ3: インスタンスの詳細設定`の下の方にある`高度な詳細`をクリックすると出てくる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/741cc240-95b6-b5b0-aa8e-24b8ce51d091.png)

```:httpsをインストールしてEC2起動後にWebサーバーを起動する
yum install -y httpd
/etc/init.d/httpd start
```

```:ホスト名を変更する
sed -i 's/^HOSTNAME=[a-zA-Z0-9\.\-]*$/HOSTNAME=ホスト名/g' 
```

```:ネットワークホスト名を変更する
/etc/sysconfig/network hostname 'ホスト名'
```

```:日本の時間帯をコピーする
cp /usr/share/zoneinfo/Japan /etc/localtime
```

```:サーバーの時間帯を日本の時間帯に設定しなおす
sed -i 's|^ZONE=[a-zA-Z0-9\.\-\"]*$|ZONE="Asia/Tokyo"|g' /etc/sysconfig/clock
```

```:言語設定をUTF_8に設定する
echo "LANG=ja_JP.UTF-8" > /etc/sysconfig/i18n
```

```:ソフトウェアの更新状況を確認する
sudo yum update -y
```

```:サーバーにApacheをインストールする
sudo yum install httpd -y 
```
ノートPCファンの取り替え

こんにちは！
先日3年半ほど使っているノートパソコンのファンの交換を行いました。
そのレポートをしていきたいと思います。

少しでも参考になればと思います。

<h1>注意</h1>
自分でPCを分解することで，より悪化させてしまう場合もありますので，
注意して作業を行ってください。また，分解行為での破損などはメーカーなどの
保証から対象外となりますのでご注意ください。

この記事を参考にしたことによる故障や破損は一切の責任を負いません。

<h1>今回分解したPCについて</h1>
メーカー：Fujitsu
品名：LIFEBOOK WU2/B1
型名：FMVWB1U257
購入日：2017年9月

<h1>今回の問題</h1>
さて，今回このPCに起きた問題は，cpuの冷却機能である
ファンの不具合です。

<h3>①異常なファンの音</h3>
3年経ったあたりから，「ウィーーーン！！！」「ブウ〜〜ん！！」と言った異様な音がしました。

<h3>②ずっとファンが作動している</h3>
パソコンを起動して，使っている間は，ずっと最強の状態でファンが作動していました。
スリープ状態でも，仕様していない間に作動していました。

<h1>分解</h1>

分解の前に必ずパソコンはシャットダウンしましょう。電源から抜くようにしましょう。

<strong>①始めに，パソコンを裏返してネジを外す</strong>
![00B84DFD-CD88-4473-8756-3293C1BC5493_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372857/3746b038-38aa-743d-22dc-019b119a74d8.jpeg)

ネジを外す際は，きちんと合ったものを使用しましょう。
できれば精密ドライバーがおすすめです。2000〜5000円程度で購入できます。
![DF4E93C0-A60D-49E0-9E44-A3B795690778_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372857/4ba50dd5-e21d-c5db-5ce5-878e0e19501a.jpeg)

<strong>③開封</strong>
中身はこんな感じです。

既製品を開けて無闇に公開していいものではないので，ざっくり隠してますww
![733192A3-A740-44B0-8794-D1900AA345D4_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372857/7463996f-689b-360c-ce85-ccde5fc57719.jpeg)

<strong>④ファンについた埃の除去</strong>
ファンに埃が溜まっているのが確認できます。
この埃を丁寧に慎重に取り除いてあげましょう。

こんなにも埃が溜まってるなんて驚きました！！
![5B9487AF-6776-4856-AD84-199C2DEED419_1_201_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372857/c0c82e73-2477-fde1-7898-324796d6e65c.jpeg)

![AD8181CD-125B-4485-BB69-73A61C30A50F_1_105_c.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/372857/09aae1fa-7918-af50-e058-015fd6068dfe.jpeg)

埃が排気を邪魔していて，ファンが回り続けていたんですね！

しかし，音は変わらないままでした。

<strong>⑤ファンの交換</strong>
ファンを長く使っていると，軸が曲がったりなどで，スムーズな回転でないために，
異様な音が出てしまいます。

先程の写真に合った同じ型番のファンを取り寄せました。（約２週間）

あとは，ファンを交換するだけです！

<strong>そのPCに合ったファンを使用しましょう。そうでないと動かなかったり，サイズが合わなかったりしてしまいます。</strong>

<strong>⑥元に戻す</strong>
再び，外カバーを取り付けて完了です！

<h1>交換後</h1>
音は静かになりました！！

連続してファンが回ることも無くなりました！！

しかし，新規購入時よりかは作動時間が長いように感じます。
それは，CPU自体の問題かもしれませんね。

<h1>最後に</h1>
冒頭でも書きましたが，
分解作業は細心の注意をはらって行ってください。
静電気によるCPUの故障や電源を入れたままでの作業などで感電やデータの抹消などが起こり得ます。

保証が効く場合には，既製品であれば修理に出した方が安く済むこともあります。
自分で行うと保証対象外になってしまうこともあることを留意してください。

それでも，自分のPCを自分で直すと言うことはとてもいい経験になりますので，
ぜひ，やってみてください。

それでは，最後まで読んでいただきありがとうございました。
AWS AmplifyのReact向けWorkshopをTypeScript化しながら体験してみた

## はじめに

今回はAWS AmplifyのReact向けワークショップ「AMPLIFY SNS WORKSHOP」をTypeScript+Redux Toolkit化しながら体験してみました。

https://amplify-sns.workshop.aws/ja/

## いざWorkshop

TwitterライクなSNSアプリケーションを作成するというテーマの中で、Amplifyの使い方を徐々に機能アップしながら学んでいけるワークショップになっています。Cognitoを使った認証の実装から始まり、AppSyncを用いたCRUD機能の実装、Lambda、Elasticsearchまでと盛りだくさん。しかも間々ではAmplifyCLIの使い方やAmplify Mocking、GitHubとの連携、さらにCypressを使ったE2Eテストとこれでもか！というくらいいたれりつくせりの内容なのでAmplifyをまず触ってみようという方には確実にオススメです！

まずWorkshopの通りJavaScriptで1周回、2周目をTypeScript + Redux Toolkitに書き換えながら進めてみました。
`.js`を`.tsx`に書き換えて、エラーの出ている箇所をエディターと自分の推論？を効かせながら少しづつ書き換えていきます。以前[Amplifyチュートリアルの書き換え](https://qiita.com/himorishige/items/d69839efd97ec523631a)も行っているので書き換えるソース量は多いですが徐々にエラーを消していくことができました。

なんとなく書き換え前から嫌な予感はしていたのですが今回のラスボスは`subscription`部分。
いろいろと調べながらトライし続けましたがなかなかうまくいかず。。
subscription部分については一度諦めかけたところ、調べ尽くしかけたところにDEVの記事を見つけてやっと解決することができました。あやうく全部`// @ts-ignore`で逃げるところでした。。。

https://dev.to/mwarger/series/1515

この記事で他怪しげだった部分もだいぶ参考にさせていただきました。

```typescript:src/containers/Timeline.tsxの抜粋
useEffect(() => {
  console.log(currentUsername);
  if (!currentUsername) return;
  console.log('make subscription');

  let unsubscribe;
  const subscription = API.graphql(
    graphqlOperation(onCreateTimeline, { userId: currentUsername }),
  );
  if (subscription instanceof Observable) {
    const client = subscription.subscribe({
      next: (msg: PostSubscriptionEvent) => {
        console.log('timeline subscription fired');
        console.log(msg);
        const post = msg?.value?.data?.onCreateTimeline?.post;
        if (post) {
          appDispatch(subscriptionPosts(post));
        }
      },
    });
    unsubscribe = () => {
      client.unsubscribe();
    };
  }

  return unsubscribe;
}, [appDispatch, currentUsername])
```

firebaseのfirestoreやmongoDBのmongooseのようにもうちょっとシンプルな方法を用意してくれるとうれしいなと思った次第。

ひととおりTypeScript化ができたところで、Reduxの学習をかねてWorkshopのソース内でreducerを利用している部分、useStateを利用している部分をRedux Toolkitで管理する形に書き換えていきます。
今回はPost部分とUserの認証情報の2つのスライスを作成して管理するように実装しました。

## さいごに

AmplifyのTODOアプリ作成のチュートリアル、SNSアプリ作成のworkshopをそれぞれTypeScript化しながら体験してみることで、Amplifyでのアプリケーション作成のイメージを少し理解することができたかなと思います。
これからAmplifyを使ってみようと思ってい方はぜひこの2つのチュートリアルとWorkshop試してみてください！

https://amplify-sns.workshop.aws/ja/

https://docs.amplify.aws/start/q/integration/react

## 成果物

参考になるかは微妙ですが書き換えソースも下記に置いておきます。（amplifyリソースは入っていませんのでこのままでは動作はしません）

https://github.com/himorishige/amplify_workshop_ts_rtk

## 関連記事

https://qiita.com/himorishige/items/d69839efd97ec523631a

## 参考サイト

https://zenn.dev/ynakamura/articles/210460b470f7b973e5cc

https://dev.to/mwarger/series/1515
【AWS】1か月の勉強でクラウドプラクティショナー900点取った合格体験記

<h2>はじめに</h2>
この4月から2年目エンジニアになりましたshionです。
本日、AWSクラウドプラクティショナーを受験・合格したので
その勢いでこれまでに行った勉強を書いていきます。


<h2>試験結果</h2>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771526/f6e4ae9a-5e08-2fc0-ca2f-81b0d2563e79.png)
まさか9割行くと思っていなかったので大満足。

<h2>受験前の状態</h2>
・昨年7月から実務についた未経験文系バックエンドエンジニア
　└一年間どういうことをしていたかは[こちら](https://qiita.com/shion01/items/04ee0825251026f87ee7)
・インフラは苦手
　└新卒研修で一番点が低かった分野...もちろん実務で関わったこともない
・AWSは軽く触ったことがあるが、体系的な知識は0
　└先輩に言われるがまま、何もわからずパイプラインを実行していただけ
　　自分で何かを考えて構築する..といったことは一切したことがない

<h2>なぜ受験しようと思ったか</h2>
上述のように業務でAWSに触れていたのだが、自分で操作をしておきながら自分が何をしているのかさっぱりわからなかった。
さらに、先輩方の話（Fargateが～、Lambdaが～、SESが～）にも全くついていけず...
そのため、最低限AWSの各サービスの名前と概要くらいはわかるようになりたいと感じた。

<h2>勉強期間</h2>
4月中旬～5月中旬のほぼ1か月。業務前の時間や休日を利用して勉強。
~~GWはずっとNieRしてたのでノーカン~~


<h2>勉強方法</h2>
・1週目　__AWS Cloud Practitioner Essentials__を受講
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771526/fc09371b-31aa-3f88-5f04-7e62b6bba2b7.png)
試験申込用にAWS認定アカウントを作成すると、ログイン後に上記講座が無料で受講できる。
日本語字幕のおかげで分かりやすく、さらに講義自体も飽きさせないように工夫されており、
一通り観ればAWSの各サービスの基本が学べるようになっている。
これを観ているといると観ていないでは、この先の知識の頭への入り方が全く変わってくるため、
適宜メモを取りつつ理解していくのがおすすめ。

（ちなみに、公式テキストである__AWS認定資格試験テキスト AWS認定クラウドプラクティショナー__もここで読んだが、情報が古かったりわかりづらかったりで自分には合わなかった。
正直、上述の講義で代替できると思う。）


・2週目～4週目　__Udemy この問題だけで合格可能！AWS 認定クラウドプラクティショナー 模擬試験問題集（7回分455問）__ で演習
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771526/77fde655-ee54-93ea-8f68-205c6ae51da6.png)

みんなおすすめ、公式より公式らしい問題が解ける問題集。
本当に実際のテストにレベル・形式が近しい問題が解けるので、ぜひ検討してほしい。

私は基本レベル①～応用レベル③までを1周したのち、基本①～応用①のみもう1周解いた。
1周目の結果はこんな感じ。~~応用③で心折れた。~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771526/120335ca-072b-c17f-24ba-336d05a8bfd4.png)
演習後の見直しでわからない用語があれば、都度調べて手元のノートにまとめる..というのを繰り返した。


・直前3日間　__AWS Cloud Practitioner Essentials__を再び視聴
章末問題やまとめ動画の演習・視聴や、苦手分野の動画を見直しをした。
直前で新しい問題に手を出すと焦るだけだと思ったので、復習を重点的に行った。

<h2>試験直前のレベル</h2>
Udemyの問題を2周目した時の結果。参考までに。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/771526/a9827f1e-88c2-a021-2202-1708349aad9b.png)

<h2>試験当日</h2>
自分はピアソンVUEのテストセンター受験を選んだため、会場へ。
__身分証明書は[ルール](https://www.pearsonvue.co.jp/Test-takers/Tutorial/Identification-2.aspx)に則って複数持って行かないといけない__ので注意。
私は運転免許書＆パスポートを持って行った。
あと、当日現地で顔写真取られるので注意。

テストセンターにはかなり早く着いたが、予定時間より早く入室・テスト実施できた。
自分は30分~40分で解き終わって退室。
ただ知らないサービスや横文字が複数出たため、解いていて自信はなかった。

合否は退室前に画面に出る。
詳細なスコアレポートは後日AWS認定アカウントから確認できるようになる。

<h2>勉強・受験の感想</h2>
当初の目標だった「最低限AWSの各サービスの名前と概要くらいはわかるように」というのは達成できたように思う。
実際に試験対策として学んだ知識のおかげで先輩方の会話内容がざっくりわかるようになり、
嬉しかったし面白かった。
自分はインフラ系のエンジニアを目指すわけではないが、
AWSにお世話になるいちエンジニアならば、教養として学んでおいて損はないと思う。
Node-RED でディスコードイベントの検知 (ボイスチャンネルに人が入ったら通知してGoogleHomeに喋らせる)

## 必要なもの

* Node.js
* Node-RED
* ディスコードのBOTを自分で作る
* 出力先(今回はGoogleHome)

## BOT作ってない人はこちらから

https://note.com/exteoi/n/nf1c37cb26c41

## 注意

これ多分 Node-RED のバグなんですが、Objectをデバッグコンソールに出そうとすると `RangeError: Maximum call stack size exceeded` を吐いて死ぬ時があります。すなおに出てくる場合もあるから多分循環参照とかを最初に解決して文字列にしようとしてるんじゃないかなーと。これで結構ハマりました。デバグ機能を使う時には注意しましょう。

## 手順

### Node-Red

今回は適当にローカルで。

https://nodered.jp/docs/getting-started/local

インストールして、 `http://<対象サーバ>:1880/` にアクセスすれば編集画面が開けます。

### 必要ライブラリ

右上のハンバーガーメニューから「パレットの管理」>「ノードの追加」とすればライブラリをインストールする事ができます。今回入れたのは

* node-red-contrib-cast (GoogleHome用)
* node-red-new-discord (discord用)

### フローの作成

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6817/1ce034a8-1e5e-7527-146a-ce47ca19f138.png)

全体構造として

* 起動時のキック
* クライアントオブジェクトの呼び出し
* イベントの設定
* GoogleHomeにキャスト

といった単純な構造です。

### クライアントトークンの登録

ベタベタと置いたところで、`discodeClient` に赤い三角がついていると思います。
![キャプチャ_.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6817/ad02c03d-3129-6196-015f-2d1f14fe2684.png)
これをダブルクリックすると `token` という変数と登録しろと出ている筈なので、画面に従ってBOTのTOKENを入れてあげましょう。

### 初動のキック - クライアントオブジェクトの呼び出し

最初の二つですが、単純にdiscordClientを引っぱってくるためだけのものです。
`node-red-new-discord` にはテキストメッセージをフックにするノードしか用意されておらずその他のイベントに対応したい場合は自分でイベントを登録しなければいけません。
[readme](https://github.com/gdomod/node-red-new-discord) を読めばわかりますが、この `discordClient` は単純に [Discode.js の Client](https://discord.js.org/#/docs/main/stable/class/Client) を次のノードに渡してくれるノードです。

右のノード一覧の一番上に「inject」というノードがありますので、そこからキックしてあげましょう。ノードをダブルクリックすると一番下に「Node-RED起動の ** 秒後、以下を行う」というチェックボックスがありますので、それをチェックすれば開始時にキックしてくれます。
どうやら0.1秒のままだとDiscord.jsの初期化が間に合わないみたいなので、2秒ぐらいにするといいかんじです。

### イベントの登録

渡ってきたメッセージは `msg` という変数で参照でき、 `msg.discord` にClientオブジェクトがまるっと入っています。
なのでそこにフックを入れてあげましょう。この方式でどんなイベントフックにも対応できます。というか本来のDiscode.jsの使いかたですね。

```javascript
const bot = msg.discord;
// ボイスチャンネルに何かあった場合は voiceStateUpdate がトリガーされる。
bot.on('voiceStateUpdate', (oldState, newState) => {
    // 今どこかのボイスチャンネルにいる、かつさっきとチャンネルが違う時
    if(newState.channelID && oldState.channelID != newState.channelID){
        let member = newState.member.displayName
        let channel = newState.channel.name
        msg.payload = '';
        // GoogleHomeの場合はこのプロパティが読み上げられる
        msg.message = member + 'が' + channel + 'に入りました';
        // 非同期でメッセージの送信を行う場合は node.send を呼んであげる
        node.send(msg);
    }
});

// 最初にキックされた時の後続処理
// なにか喋ってくれた方がいいので入れてるだけ。
delete msg.discord
msg.payload = '';
msg.message = 'ボイスステータスアップデート登録';
return msg;
```

### GoogleHomeに喋らせる

Castのノードをクリックすると、一番上にIPを入れるところがありますので、そこにGoogleHomeのIPを入れましょう。
上でも触れましたが、メッセージの `message` というプロパティが読み上げられます。
nginxにてアプリが表示されない

デプロイ準備も終わり、後はIPアドレスを入力して表示させて完了！という段階で、IPアドレスを入力したのですがウェルカムページが表示されました。
状況としてはrailsで作成アプリをnginxを使ってAWSにデプロイしようとしていました。

![スクリーンショット 2021-05-21 18.11.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1340120/fe6b9f0e-4a30-6a0e-963e-a0ef49475dbb.png)

nginxの設定など見返してみたのですが、特に問題なく…。
途方に暮れていた中で、スーパーリロード(command + shift + r)で解決するということを聞き、試してみると無事表示されました！

かなり初歩的な内容となりますが、同じ現象で困っている方がいらっしゃれば一度試してみてはいかがでしょうか。
【Rails】LEFT OUTER JOIN先のテーブルの条件でCOUNTする

# やりたいこと
ある日付に発送する商品名一覧と、それぞれの発送数 ＝ 注文が決済された数を取得したい。

# 結論（完成形）
```rb
Product.where(delivery_date: delivery_date).
  left_joins(:orders).
  group(:id).
  select('products.name, COUNT(orders.status = 1 or null) AS quantity')
```

# 今回の設定
## テーブル
- 商品（products）
- 注文（orders）

## 主な登場人物
- ある日付： delivery_date<br>
（productsの関連テーブル「delivery_date」のインスタンス。<br>
　今回ここは重要じゃないので、絞り込むための日付と捉えればOK）
- 商品名： products.name
- 各商品が売れた数： orders.status = 1 （決済済）の件数

# さて、どうやって実現しよう
 
## まずはやりたい事を日本語で書く
日付で絞り込んだproductsテーブルとordersテーブルをLEFT OUTER JOIN（左外部結合）した上で
各productに紐づくordersのうち orders.status = 1 になってる数の合計を出す
（商品ごとの決済数合計を出す＝商品ごとにgroup化してcount）

## やり方を考える

まずはLEFT OUTER JOIN（左外部結合）から。

- [Rails における内部結合、外部結合まとめ - 2. actressesとmoviesの左外部結合](https://qiita.com/yuyasat/items/c2ad37b5a24a58ee3d30#2-actresses%E3%81%A8movies%E3%81%AE%E5%B7%A6%E5%A4%96%E9%83%A8%E7%B5%90%E5%90%88)

みんな大好き`eager_load`を使ってしまいそうになるが、
今回のように「結合先のテーブルでcountする」場合は使えないもよう。

> 結論としては、結合先のテーブルで COUNT をしたい場合は joins が有効です。
> eager_load では、結合先テーブルの全カラムを select に入れてしまい、集計関数が使えなくなってしまうためです。

- [Ruby on Rails の ActiveRecord で結合先のテーブルを COUNT する場合は joins/left_joins が良い](https://qiita.com/phayacell/items/2db6280e68640eef7f59)

なので今回は`left_joins`を使うッ！
日付の絞り込みはもちろん`where`で。

```rb
Product.where(delivery_date: delivery_date).left_joins(:orders)
```


で、「商品ごとに`group`化してから`count`」する必要があるので
product.idでグループ化させる。

```rb
Product.where(delivery_date: delivery_date).left_joins(:orders).group(:id)
```


そして、取得したいのは「商品名」と「決済された数量」。

```rb
Product.where(delivery_date: delivery_date).
  left_joins(:orders).
  group(:id).
  select('products.name, COUNT(orders.status = 1) AS quantity')
```

これでできた！！沖田さん大勝利〜！！😍


・・・って思いきや、これだと意図した集計結果にならない。

理由：
COUNTは非NULL値の数を返すので、statusが1以外（0とか2とか）の場合も計上されてしまうため

> COUNT(expr)

> SELECT ステートメントで取得された行に含まれる expr の非 NULL 値の数を返します。結果は BIGINT 値になります。
> MySQL :: MySQL 5.6 リファレンスマニュアル :: 12.19.1 GROUP BY (集約) 関数


## 解決法
or nullをつけてあげる。

```
COUNT(orders.status = 1 or null)
```

これなら、orders.status = 1がtrueの場合は
true or null（trueとnullの和集合）= true　すなわちカウント対象になり

falseの場合（orders.statusが0とか2の場合）は
false or null（falseとnullの和集合）= nullとされる＝非NULL値のためカウント対象にならない。

- [【SQL】COUNT関数で条件に合致する件数を取得する](https://qiita.com/zb185423/items/f20b21ca041989410b5f)

- [MySQLの『COUNT(条件式 OR NULL)』の『 OR NULL』 を置く理由](https://qiita.com/shinkuFencer/items/eef08353b43f3512da7d)


# もっかい完成形（と出力例）
```rb
Product.where(delivery_date: delivery_date).
  left_joins(:orders).
  group(:id).
  select('products.name, COUNT(orders.status = 1 or null) AS quantity')
```

こうすることで、

```rb
products.each do |product|
  puts "商品名：#{product.name} ／ #{product.quantity}件"  
end

# "商品名：うんまぁァァ〜いッ！！ただの水 ／ 204件"
# "商品名：アヴドゥルさんの養鶏所の卵 ／ 126件"
# "商品名：花京院がレロレロしたいさくらんぼ ／ 0件"
```

無事目的を達成できましたね！！😊



僥倖っ……！なんという僥倖……！
Gulpを起動すると "no template named 'remove_cv_t' ..." エラーが出たときの対処

Macを新調したのを機に、Node関係をいちから設定しなおしました。
旧環境から持ち込んだpackage.jsonをインストールしようとしたところ、以下のようなエラーが表示されました。

```
error: no template named 'remove_cv_t' in namespace 'std'; did you mean 'remove_cv'?
```

## 原因

node-sassが最新のNodeに対応していないことが原因のようです。

https://github.com/sass/node-sass/issues/3077

ここのissueによるともう修正されているようなのですが…nodebrew経由だと最新バージョンがインストールされないのでしょうか？

## 対応

node-sassを再インストールする手も考えられましたが、私はNodeのバージョンを旧環境と同じ15に下げる対応をしました。その方が旧環境から他のプロジェクトを移行したときに、後々問題が少なそうだからです。

nodebrewを使用している場合、useコマンドで使用バージョンを変更することができます。

https://qiita.com/k3ntar0/items/322e668468716641aa5c

### インストールできるバージョンをリストアップする

```
$ nodebrew ls-remote
```

### 15系の最終版をインストールする

この記事を書いた時点では v15.14.0 が最新です。

```
$ nodebrew install-binary v15.14.0
```

### nodebrewで使用するバージョンを変更する

```
$ nodebrew use v15.14.0
```

### 確認（インストールされているバージョン一覧を表示）

```
$ nodebrew ls
```

currentに変更したバージョンが入っていればOKです。

```
current: v15.14.0
```

----

よりにもよってSassなので、あまりNodeの扱いに慣れていないマークアップ関係の人ほど、はまりそうな気がします。
node-sassをバージョンアップすると解決するのかご存じの方がいたら、コメント欄に書いてくださるとありがたいです。

エラーの詳細は、stackoverflowに記載されています。C++のスクリプトと干渉しているようです。

https://stackoverflow.com/questions/67241196/error-no-template-named-remove-cv-t-in-namespace-std-did-you-mean-remove
homebrewを使ってvscodeをインストールしたい




<details><summary> 背景（余談)</summary>
新しいアプリインストールするのに<div>

  - アプリのサイトにとんで、
  - dmgダウンロードして
  - 実行する

</div>
って手順多すぎ、
<div>

 - `brew install`

</div>
なら一発で終わるのにね、という話を友人にされた。
そのときに初めてbrewなる存在を知ったので使ってみたかった。
あと、qiitaに記事書いてみたかった。
</details>


## 環境
 - OS : maxOS 11.3.1
 - PC : MacBook Pro(13-inch, 2019)
 
## コマンド
これだけ

``` shell
❯ brew install --cask visual-studio-code
```

## 失敗談
最初は以下コマンド実行して失敗してた。。。

``` zsh
❯ brew cask update      
Error: Unknown command: cask

~
❯ 
```

いつからかわからないけど、`cask`はオプション扱いになっているんですね。。
FlaskアプリのDBをFlask-SQLAlchemyで構築する（前編）

どうも、Flask学習中の民です。
今回はFlask-SQLAlchemyを使ってデータベースへの接続とテーブルの作成、クエリの作成から送信を行ってみます。
この記事はテーブルの作成までです。クエリの送信に関しては下記をご確認ください。

<a href="">FlaskアプリのDBをFlask-SQLAlchemyで構築する（後編）</a>
※近日公開します

# 前提
この記事は下記を教材として学習する過程で書いたものです。
<a href="https://www.oreilly.com/library/view/flask-web-development/9781491991725/">『Flask Web Development Developing Web Applications with Python』 Miguel Grinberg</a>


FlaskでWebアプリを作る際に必要となるDB構築の初歩について書きます。
前提は

・PostgreSQLを利用（MySQL、SQLiteでも対して変わりません）
・PostgreSQLとロールとデータベースは作成済み

です。

# Flask-SQLAlchemyの導入と環境設定
DBの構築に対してはFlask-SQLAlchemyというFlask向けORMsを利用します。
ORMsとは簡単に言ってしまうとデータベースを操作する際に、SQLを用いて低水準で操作する代わりにオブジェクト指向の言語を用いて高水準での操作を行うための技法です。
技法というとすごくテクニカルなものを想像してしまいますが、まぁPython(Flask)でデータベースを操作できるようにする方法、くらいの認識でまずは良いと思います。
※少なくとも僕はこれ以上の説明はできません。

まずはpipなどでモジュールをインストールし、configの設定を行います。

```console
pip install flask-sqlalchemy
```

```Python
from flask_sqlalchemy import SQLAlchemy

# 中略

app.config['SQLALCHEMY_DATABASE_URI'] = postgresql://flasker@localhost/flaskdb
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
```

SQLALCHEMY_DATABASE_URIはその名の通り、利用するDBを一意に特定するための情報です。
PostgreSQLの場合は

```python
postgresql://[ユーザー名]:[パスワード]@[ホスト名]/[データベース名]
```

となります。ちなみにMySQLやSQLiteの場合は

```python
mysql://[ユーザー名]:[パスワード]@[ホスト名]/[データベース名]
sqlite:////absolute/path/to/database # Linux, maxOS
sqlite:///c:/absolute/path/to/database # Windows
```

となります。
コード例は特にパスワードを設定していないロールなので省略しています。

また'SQLALCHEMY_TRACK_MODIFICATIONS'はデバック時やテスト時に利用するもので、公式ドキュメントでは普段はメモリ削減のためにFalseにすることが奨励されています。

configの設定を終えたらSQLAlchemyクラスの引数にappを加えてdbオブジェクトを作成します。


# テーブルの定義
次にテーブルの定義を行います。Flask-SQLAlchemyではモデルと呼ばれるテーブルの名前を含むテーブル構成に関連する情報のことです。
Flask-SQLAlchemyではテーブル構成をクラスで定義し、それをモデルと呼び、そのモデルのインスタンスを作成することでレコードの値を作成します。

実際のモデルは

```python
class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key = True)
    name = db.Column(db.String(64), unique = True)
    users = db.relationship('User', backref = 'role', lazy = 'dynamic')

    def __repr__(self):
        return '<Role %r>' % self.name

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key = True)
    username = db.Column(db.String(64), unique = True, index = True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return '<User %r>' % self.username
```
のように定義します。
モデルは```db.Model```を継承する形で作成し、各クラス変数はテーブルの各カラムと対応、```__tablename__```はテーブル名と対応しています。

また```def __repr__(self)```はそのクラスやレコードの簡単な要約を文字列で返してくれるメソッドです。

rolesテーブルの変数```users```はusersテーブルとリレーションを張るために定義しています。
なお細かい話ですが```lazy = 'dynamic'```の必要性に関しては後編で出てきます。

ここで```Role```に含まれている```users = db.relationship()```の部分で```User```に対してリレーションを張っています。
これがあることでテーブル```User```のレコードを作成する際に、テーブル```Role```の任意のレコードを指定し、2つのテーブルのレコード同士を紐づけることができます。
またその紐付けがされた際に```User```側のレコードに含まれている```role_id```部分に```Role```側で紐づいたレコードのIDが格納されます。これをForeignKeyと呼び、```role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))```で定義しています。
```User```側ではForeignKeyを見れば対応する```Role```側のレコードが、```Role```側では```.users```を見れば対応する```User```側のレコードがわかります。

これでテーブルの定義が完了したので、次回はテーブルの作成からクエリの送信を見ていきます。
javascriptの共通処理を作成（共通処理用のオブジェクトから各オブジェクトにmethodをコピーして利用する）

javascriptで共通処理を作成する際に少しクラスっぽく作成。
※「$(function () {})」はjqueryになります。

## ■ html
sample.js → test.js の順に読み込む必要があります。

```index.html
<script src="sample.js"></script>
<script src="test.js"></script>
```

## ■ sample.js

共通処理を記載します

```sample.js
// Sampleオブジェクトを上書きしないように作成します。
Sample = function () { return typeof Sample === 'undefined' ? {} : Sample; };

$(function () {
  /**
   * SampleにCommonとして設定する
   *
   * @constructor
   */
  Sample.Common = function () {
    const self = this;
    self.setup();
  };
  /**
   * 設定メソッド
   */
  Sample.Common.prototype.setup = function () {
    const self = this;

    self.xxx = {};
    self.xxx.yyy = 80;
  };
  /**
   * ベースのメソッド1
   *
   * @param {int} value 対象データ
   * @returns {int} 
   */
  Sample.Common.prototype.method1 = function (value) {
    return value;
  };
  /**
   * ベースのメソッド2
   *
   * @param {int} value 対象データ
   * @returns {int} 
   */
  Sample.Common.prototype.method2 = function (value) {
    return value;
  };
});
```

## ■ test.js

共通処理を使用する側のjsになります

```test.js
// Sampleオブジェクトを上書きしないように作成します。
Sample = function () { return typeof Sample === 'undefined' ? {} : Sample; };

$(function () {
  /**
   * SampleにTestとして設定する
   *
   * @constructor
   */
  Sample.Test = function () {
    const self = this;
    // Sample.Commonの初期設定を呼び出します
    self.setup();
  };
  // Sample.Commonの処理をSample.Testに反映します
  Sample.Test.prototype = Object.create(Sample.Common.prototype);

  // オブジェクトを生成します
  const obj = new Sample.Test();
  // Sample.Commonで定義している処理が利用できます
  const result= obj.method1(111);
});
```
【Unity】スクリプトテンプレートについて

## 0．前提 
この記事ではUnityの`ScriptTemplates`について書いていきたいと思います。
間違いなどありましたら、コメント頂けるとありがたいです。
##1.この記事を読んで出来るようになること
###スクリプトを作成する時のテンプレートを自由に作成出来るように！（複数可）
##2.具体的に何するの
皆さん一度は見たことあるこれ

```C#:NewBehaviourScript
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
```
そう、Unityで新しいスクリプトを作成するとこれが出来ますよね。
このテンプレートを（自分の好きなように）変更しよう！ということです。

##3.やり方
やり方はすごく簡単です。

`Assets`フォルダ直下に、`ScriptTemplates`というフォルダを作成します。

`ScriptTemplates`フォルダの中にテキスト ドキュメントを作成し、名前を「81-Script__Monobehaviour Script-DefaultMonobehaviourScript.cs.txt」に変更します。
※ファイル名については後で説明します

次に、ドキュメントの中を変更します。

```
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// ---------------------------------------------------------
// #SCRIPTNAME#.cs
// 作成日:  2021/1/1
// 作成者:  
// ---------------------------------------------------------

/// <summary>
/// 
/// </summary>
public class #SCRIPTNAME# : MonoBehaviour
{
	#region 変数

	#endregion

	#region プロパティ

	#endregion

	#region メソッド

	private void Awake()
	{

	}

	private void Start() 
	{

	}
	
	private void Update() 
	{

	}

	#endregion
}
```
※ここで書いたものが、テンプレートになります。

__これで、設定は完了です！__

##4.実際に確認してみる

Unityを開き、いつも通りスクリプトを作成しようとします。

![スクリーンショット (14).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666040/69e5cf16-f70c-379d-f6b1-bd312e08083f.png)

さきほど付けた名前のメニューが出来ています。

![スクリーンショット (18).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666040/d5d1c040-4196-f42f-cb82-cdc889870a76.png)

ちゃんとテンプレート通りに作成されました。

##5.ファイル名について
「番号-カテゴリ名__メニュー名-デフォルトの名前.text」という意味があります
番号はウィンドウに表示される順番です。(昇順)
カテゴリ名は省略可能です。
また、カテゴリ名＿カテゴリ名＿メニュー名などもできます。
※「＿」は半角アンダーバーを2個

##6.最後に
自分はMonoBehaviour継承クラス、MonoBehaviourなしクラス、Editor拡張用クラスなどいくつか用意し、使い分けています。
__皆さんも自分の用途に合ったテンプレートを作成してみてください！__
/dev/sda2: clean, .../...files, .../...blocks 表記以降画面変化がない場合の解決法

### 状況
色々ありRTX3070とPCを入手した！
&rarr;RTX3070を導入したPCでWindows 10とUbuntu 18.04デュアルブートしたい
&rarr;LinuxをインストールするためにISOイメージファイルを書き込んだUSBメモリを作成する
&rarr;Ubuntuをインストールし、設定、再起動する
&rarr;`/dev/sda2: clean, .../...files, .../...blocks`のみ表記され、そのまま…

###解決法
CUDAとNVIDIAドライバのバージョン違いによりGUIが表示されなかった模様。
まず一度古いドライバを削除する。

```
$ sudo apt-get purge nvidia*
$ sudo apt-get autoremove
$ sudo apt-get autoclean
$ sudo rm -rf /usr/local/cuda*
```
次にCUDAとNVIDIAの依存性を考慮してドライバをインストールする（下記サイトからCUDAをインストールすることでそのバージョンのCUDAに対応したNVIDIAドライバがインストールされる）。


https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=18.04&target_type=deb_network

CUDA11.3の場合、

```
$ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
$ sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
$ sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
$ sudo add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /"
$ sudo apt-get update
$ sudo apt-get -y install cuda
```

でインストール。
終わり次第再起動

```
$ sudo shutdown -r now
```

することで解決。無事GUIが表示された。
[JavaScript] テンプレート文字列がうまく働かない？！（超初歩的）

初歩的な勘違いを紹介します。恥ずかしいですが、もしかしたら同じ落とし穴にはまる方がいるかもしれないので。
## 初歩的な間違い
JavaScriptのサンプルプログラムを見本にシンプルがプログラムを書いて実行したところ、

```
const name ='world';
console.log('Hello ${name}!');
```

### 実行結果

```
Hello ${name}!
```

あれ？

サンプルプログラムをよくみると、クォーテーションマークが違う。バッククォートというやつだった。

## 正解

```
const name ='world';
console.log(`Hello ${name}!`);
```
```
Hello World!
```
## 感想
- バッククォート「___`___」が、日本語キーボードのPの右隣にあることに初めて気が付きました。

- バッククォート「___`___」ですが、実は引用符（クォーテーションマーク）ではなく、本来はアクセント記号（フランス語でいえば、アクサングラーブ）らしい。ウン十年前に受けたフランス語授業を思い出しました。
- バッククォート「___`___」は一般には無名な存在かも。似たような特殊な文字である___＠___は最初何に使うのだろうかとおもったけれど、インターネットが始まってからURLに使われるようになり、一気にメジャーな存在になったのとは好対照です。
RowやCellをイテレータで処理する場合は未定義の行やセルに気を付ける

# 発生した問題

Apache POIを利用するシステム開発プロジェクトでは「指定したシートを読み込み、2次元配列に変換する」というようなAPIを作成することがあります。自分がかかわっているプロジェクトでもそのようなAPIが提供されており、おおよそ以下のように実装されていました (読み込ませるシートはすべて文字列になっている想定)

```java
try (Workbook book = WorkbookFactory.create(Paths.get("target-book.xlsx").toFile())) {
    Sheet sheet = book.getSheet("target-sheet");
    
    List<List<String>> lists = new ArrayList<>();
    for (Row row : sheet) {
        List<String> list = new ArrayList<>();
        for (Cell cell : row) {
            list.add(cell.getStringCellValue());
        }
        lists.add(list);
    }
    
    doSomeThing(lists);
}
```

さてこの実装は少なくともこのAPIを提供したチームが公表していた仕様を満たしていませんでした。たとえばこのAPIを使って以下のようなExcelを読み込ませたとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/105859/b3dc2644-bbf6-e55d-9f34-77264b6ba53c.png)

このシートは以下のような二次元配列に変換されます。

```
[A1, B1, C1, D1, E1], 
[B2, D2],  
[A4, B4, C4, D4, E4]
```

しかしAPI提供チームがうたっていた仕様では、このExcelシートは以下のように変換されるはずでした。

```
[A1, B1, C1, D1, E1], 
[  , B2, ,   D2], 
[], 
[A4, B4, C4, D4, E4]
```

つまり、空の行や空のセルについても適切に処理するというのがAPI仕様でしたが、実装はそのようになっていませんでした。

# 原因と対策

**原因は`Row`や`Cell`の読み込みにイテレータを利用していることです。**`Sheet`は`Iteratable<Row>`を、 `Row`は`Iterable<Cell>`をそれぞれ実装していますが、これらを利用すると、未定義の行や未定義のセルについては、存在しないものとしてスキップします。上述の例でいうと、3行目やA2セルやA3セルは、Apache POI上、未定義として扱われてしまい、イテレータ読み込みではないものとしてスキップされてしまいます。

こういう空の行や空のセルをうまくハンドリングするには、`Sheet.getRow`や`Row.getCell`を使う必要があります。今回の場合は以下のように実装を修正しました。

```java
try (Workbook book = WorkbookFactory.create(Paths.get("target-book.xlsx").toFile())) {
    Sheet sheet = book.getSheet("target-sheet");
    
    List<List<String>> lists = new ArrayList<>();
    for (int i = 0; i <= sheet.getLastRowNum(); i++) {
        Row row = sheet.getRow(i);
        List<String> list = new ArrayList<>();
        
        int len = (row == null) ? 0 : row.getLastCellNum();
        for (int j = 0; j < len; j++) {
            Cell cell = row.getCell(j);
            list.add((cell == null) ? "" : cell.getStringCellValue());
        }
        lists.add(list);
    }
    
    doSomeThing(lists);
}
```

# 環境情報 (pom.xml抜粋) 

```xml
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.0.0</version>
</dependency>
```
DockerでSpringBootを動かす

作りたいものがあるので動かします。

**環境**

```bash
$ sw_vers
ProductVersion:	11.3.1
$ java -version
openjdk version "11.0.11" 2021-04-20
$ gradle --version
Gradle 7.0.2
```

# 事前準備
インストール済み！
・VisualStudioCode(以下「VSC」)
・Gradle

# 作業開始
Spring Boot with Docker
https://spring.io/guides/gs/spring-boot-docker/

**Dockerの導入**
https://docs.docker.com/get-docker/
「Mac with Apple chip」をインストール

**Starting with Spring Initializr**
VSC上でSpringinitializrを動かしてプロジェクト作成

**ビルド**

```bash
$ ./gradlew build
BUILD SUCCESSFUL in 17s
$ ls -l build/libs 
build/libs/grapy-0.0.1-SNAPSHOT.jar
$ java -jar build/libs/grapy-0.0.1-SNAPSHOT.jar
```
**ブラウザで確認**
http://localhost:8080/
画面上に「Hello Docker World」が表示できた。

**dockerfile作成**

```dockerfile
FROM adoptopenjdk/openjdk11	
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
```


**実行**

```bash
$ docker build --build-arg JAR_FILE=build/libs/\*.jar -t springio/gs-spring-boot-docker .
$ docker run -p 8080:8080 -t springio/gs-spring-boot-docker
```

以下で確認できました！
http://localhost:8080/

今回動かしたプログラム
https://github.com/jamcookjapan/grapy
Yarn のpackage.jsonのscriptsの指定で環境変数がうまく渡せない（Windows10） 'NODE_ENV' is not recognized as an internal or external command,

ある書籍のサンプルプログラムを写経して勉強していたときのちょっとした困りごとを紹介します。
# 困ったこと
書籍のサンプルプログラムを参考に、yarnのpackage.jsonのspriptsに次のように記述して、yarnからスクリプトを実行したらエラーとなりました。

```package.json
   "scripts": {
      "build:prod": "NODE_ENV=production webpack --config webpack.prod.js",
    },
```
コマンドプロンプトから次を実行。

```
C:\Users\abc\MyProject>yarn run build:prod
```
## エラーメッセージ

```
'NODE_ENV' is not recognized as an internal or external command,
```

## 環境
- yarn 1.22.10
- Windows 10 Home 20H2

# 対策
環境変数NODE_ENVをセットするために__SET__コマンドをつけて、webpackを連続実行させるために__&__を追加しました。

```
  "scripts": {
    "build:prod": "SET NODE_ENV=production& webpack --config webpack.prod.js",
  },
````
## 結果
期待通り（書籍の説明通り）動作した。

# 注意点
```
"build:prod": "SET NODE_ENV=production & webpack --config webpack.prod.js",
```
のように__＆__の前に__半角スペース__があると、環境変数の値の後ろに__半角スペース__が付加されます。つまり"production "（最後に__半角スペース__がついている）という文字列になり、環境変数を用いるプログラムがうまく動かないことがあるので注意しましょう。

# 調査したサイト（英語）
https://stackoverflow.com/a/37131308

# 読んでいた書籍
ネコミミでもわかるフロントエンド開発環境構築 (技術の泉シリーズ（NextPublishing）) Kindle版
汐瀬 なぎ (著)  形式: Kindle版

https://www.amazon.co.jp/%E3%83%8D%E3%82%B3%E3%83%9F%E3%83%9F%E3%81%A7%E3%82%82%E3%82%8F%E3%81%8B%E3%82%8B%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89-%E6%8A%80%E8%A1%93%E6%9B%B8%E5%85%B8%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA%EF%BC%88NextPublishing%EF%BC%89-%E6%B1%90%E7%80%AC-%E3%81%AA%E3%81%8E-ebook/dp/B07J1144ZR


# 感想
 - 書籍の中のサンプルプログラムの実行環境をよく確認すべし。OSによって記述が変わるのはムズい。
 - MS-DOSの頃から変わっていない。SETで環境変数を設定、&でコマンド連続実行。

# 補足
yarnがScriptをどんな環境で実行しているかを気になる方は、次のようにするといいかもしれません。

```
"build:prod": "SET& WHERE webpack& SET NODE_ENV=production & webpack --config webpack.prod.js",
```

スクリプトの前に`SET& WHERE webpack& `を付けただけです。__SET__コマンドで環境変数が全部表示されます。__WHERE webpack__でwebpackコマンドのパスが表示されます。
Mysql2::Error: Tablespace is missing for tableの対処法

Laravelでコマンド開発中に、**何もしてないのに**突如下記のエラーがでました。
「Mysql2::Error: Tablespace is missing for table」

 **何もしてないのに！！** 
あまり日本語記事がなかったので、自分用に残しておこうと思います😃

## 環境
```bash:ターミナル
$ php artisan --version
Laravel Framework 5.5.50

$ php -v    
PHP 7.1.33 (cli) (built: Oct 31 2019 17:37:57) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies

$ composer -v
Composer version 2.0.12 2021-04-01 10:14:59

$ mysql --version
mysql Ver 8.0.22 osx10.15 x86_64 (Homebrew)
```

## 原因
エラーメッセージを翻訳してみると、下記の通り。
>Mysql2 :: Error：テーブルのテーブルスペースがありません

うん、そのまんまですね。
テーブルスペースとやらがないらしいけど、テーブルスペースってなんだろう？？
調べてみた。

>InnoDB テーブルおよび関連するインデックスのデータを保持できるデータファイル。
システムテーブルスペースには InnoDB データディクショナリが含まれており、MySQL 5.6 より前は、デフォルトで他のすべての InnoDB テーブルが保持されます。

mysqlのデータファイルのようですね。
そして、拡張子「.ibd」ファイルとしてmysqlのディレクトリの保存される様子。

>.ibd ファイル
file-per-table テーブルスペースおよび一般テーブルスペースのデータファイル。 File-per-table テーブルスペースの .ibd ファイルには、単一のテーブルおよび関連するインデックスデータが含まれます。 一般テーブルスペース .ibd ファイルには、複数のテーブルのテーブルおよびインデックスデータを含めることができます。

参照：https://dev.mysql.com/doc/refman/8.0/ja/glossary.html#glos_tablespace

あ、、、そういえばMacBookのストレージ容量が少なくなってきて大容量のファイルを消している時に、
「これいらなそうだな～」と思って消した気がする。。。
dumpだと思ってたけど、あれが.ibdファイルだったのか。。。(すいません何かしてました)

単純にディレクトリ消したりHDDが死んでたりしても、出ることもありそうですね。

## 試してみたこと
という訳で、.ibdファイルを復活させれば良さそうなので色々試してみます。

### マイグレーションしてみる
私の場合はLaravelなので、マイグレーションをもっかいすれば復活してくれそうなので試してみます。

```php
bash-4.2# php artisan migrate
Nothing to migrate.
```
あれ？特にマイグレーションできるファイルがないみたい。
DBを見てみると、しっかりテーブルが存在してました😮
どうやら、**idbファイルが消えてもテーブルごと消える訳ではなさそうです。**

そして、テーブルを開こうとしてもエラーになって開けない。。。
今回はテーブルのデータも必要ないので、テーブルごと消してしまいましょう。

##テーブルを削除する

```sql
drop table hogehoge
```
すると、下記エラーで怒られました🙃
>cannot delete or update a parent row: a foreign key constraint fails

外部キー制約が貼られてた。
参照している別テーブルのレコードを削除すれば消せると思いますが、今回は消したくないので一時的に外部キー制約を無効にします。

### 外部キー制約を一時的に無効にする
```sql
SET FOREIGN_KEY_CHECKS = 0;

drop table hogehoge
```

無事削除できました、忘れないように外部キーを戻しておきます。

```sql
SET FOREIGN_KEY_CHECKS = 1;
```
本来はよろしくない対応ですが、今回は他のテーブルに影響を与えずに問題が出ているテーブルだけ作り直したいので、この対応としました。
マイグレーションをやり直してみます。

## 再度マイグレーションする
```php
bash-4.2# php artisan migrate
Migrating: 2021_05_20_164657_create_hoge_table
Migrated:  2021_05_20_164657_create_hoge_table
```
いけました！🤗
テーブルが無事に開けるようになり、SQLの発行やモデル参照も問題ないようです！！
第３部完！！

## docker環境でDBごと作り直しても良いなら
dockerのDBコンテナイメージを削除してビルドし直せば、何も考えず解決できそう。
何も考えなくて良いのでラクっちゃラクですね。

## 終わりに
「何もしてないと思ってる時は、だいたい何かやらかしているのが人間」だと改めて認識しましたｗ
mysqlのidbファイルは絶対触らないようにしましょう。（教訓）