OmniAICreator/Qiita-1.07M huggingface dataset:
RxSwift基礎-オペレーターその4

RxSwiftで使えるオペレーターを備忘録的に書き綴っていきたいと思います。
また、公式Exanpleを参考にしています。
その1は[こちら](https://qiita.com/masasumi0327/items/ef3d2cf4d014414f42d5)
その2は[こちら](https://qiita.com/masasumi0327/items/c5f2c57420235cb58a5e)
その3は[こちら](https://qiita.com/masasumi0327/items/9bf2ad48f2c6a7183dae)


https://github.com/ReactiveX/RxSwift

また、今回の内容はこちらの動画が非常に解りやすいです。

https://www.youtube.com/watch?v=7M3sQEcDS20&t=1559s


作業環境については、

https://qiita.com/masasumi0327/items/2ae144160987e571bce4

を参考に構築して頂ければと思います。
早速、やっていきましょう!!



## TransformingOperators
流れてくるNext eventを変換するオペレーターです。**map**や**flatMap**など、かなり使えるオペレーターがあります!!
### map
```swift
func map() {
    let disposeBag = DisposeBag()
    Observable.of(1, 2, 3)
        .map { "String型に変換された\($0)です" }
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
}
map() /*
String型に変換された1です
String型に変換された2です
String型に変換された3です
*/
```
流れてくるonNextの値を加工して流していますね。
今回はInt型の整数をString型に変換して出力しました。
### flatMap
```swift
func flatMap() {
    let disposeBag = DisposeBag()
    Observable.of("🐵", "🐶", "🦜")
        .flatMap{ Observable.of($0 + "🍡", $0 + "🥐") }
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
}
flatMap() /*
🐵🍡
🐵🥐
🐶🍡
🐶🥐
🦜🍡
🦜🥐
*/
```
flatMapはObservable.ofで生成されたObservableに対して、flatMap内で生成されたObservable.ofのObservableを合成しています。
それぞれの動物が🍡と🥐を食べる(合成)する事に成功しています。
### flatMapLatest
```swift
func flatMapLatest() {
    let disposeBag = DisposeBag()
    Observable.of("🐵", "🐶", "🦜")
        .flatMapLatest{ Observable.of($0 + "🍡", $0 + "🥐") }
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
}
flatMapLatest() /*
🐵🍡
🐶🍡
🦜🍡
🦜🥐
*/
```
先ほどのコードの記述を**flatMap→flatMapLatest**に変更しただけですが、出力が大きく変わっています。
これは、最初に作成したObservableの🐵→🐶に切り替わったタイミングで、🐵のObservableが流れなくなるため(常に最新のObservableの値を出力する)為です。なので、🦜が今回作成した最新のObservableになるので、🦜だけが🥐を食べる(合成)出来ています。名前は似ていますが、出力が全く違ってくるので、しっかり理解を深めていきたいです。
### scan
```swift
func scan() {
    let disposeBag = DisposeBag()
    
    Observable.of("🐵", "🐶", "🦜")
        .scan("👶🏻") { aggregateValue, newValue in
            aggregateValue + newValue
        }
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
}
scan() /*
👶🏻🐵
👶🏻🐵🐶
👶🏻🐵🐶🦜
*/
```
👶🏻と🐵→👶🏻と🐵と🐶→👶🏻🐵🐶🦜とobservableがscanの引数に指定した値を初期値として、一つずつ合成していっているのが出力を見て頂くと解りやすいかと思います。
matplotlibで複数系列の点をプロットして回帰式を描いた

# はじめに
エクセルでやってみると結構めんどくさかったので書いた。
以下のようなグラフを作成できる。
![TN.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1974522/492286e1-e7cc-d567-32fa-aa73a58ac949.png)

# グラフ作成
## 解説
pandasでcsvを読み込んでmatplotを使って読み込んだ全ての値を用いて回帰式を作成。
回帰式を表示した後に, csvのmarkの項目に従って点の形を変えてプロット。

:::note info
データセットは以下の形式のものを扱う(.csv)。
xValue, yValue, mark
0.341, 0.6546, winter
0.421, 0.5341, winter
0.113, 0.1536, summer
0.114, 0.1342, summer
 .
 .
 .
:::

## ソースコード
```python
from turtle import color
import matplotlib.pyplot as plt
import numpy.polynomial.polynomial as P
import pandas as pd
import sklearn.metrics as metrics

def func(_x, _a, _b):
    return _a*_x + _b

#回帰式計算
def regression(_x, _y):
    coef = P.polyfit(_x, _y,1)
    #傾き
    a = coef[1]
    #切片
    b = coef[0]
    #近似直線の決定係数
    r2 = metrics.r2_score(_y, func(_x, a, b))
    return a, b, r2

#式情報をグラフに表示
def putEquationText(_a, _b, _r2, _start, _end, _ax):
    #回帰式をグラフ上に表示(表示場所も決定)
    text_x = _start*0.4 + _end*0.6
    if   _a > 0 and _b > 0:
        _ax.text(text_x, func(text_x, _a, _b)*0.8, f'y = {round(_a, 2)}x + {round(_b, 2)}', fontsize = 12)
    elif _a > 0 and _b < 0:
        _ax.text(text_x, func(text_x, _a, _b)*0.8, f'y = {round(_a, 2)}x - {-1*round(_b, 2)}', fontsize = 12)
    elif _a < 0 and _b > 0:
        _ax.text(text_x, func(text_x, _a, _b)*0.8, f'y = -{-1*round(_a, 2)}x + {round(_b, 2)}', fontsize = 12)
    elif _a < 0 and _b < 0:
        _ax.text(text_x, func(text_x, _a, _b)*0.8, f'y = -{-1*round(_a, 2)}x - {-1*round(_b, 2)}', fontsize = 12)
    else:
        _ax.text(text_x, func(text_x, _a, _b)*0.8, f'y = -{-1*round(_a, 2)}x', fontsize = 12)
    #決定係数の表示
    _ax.text(text_x, func(text_x, _a, _b)*0.65, r'$r^2 = {}$'.format(round(_r2, 2)), fontsize = 12)

#点をグラフ上に表示
def putSeveralMark(_df, _x, _y, _mark ,_plt):
    #要素ごとにプロット
    markers = ["x","+",",", "v", "^", "<", ">", "1", "2", "3"]
    marks = _df[_mark].unique()
    for mark, i in zip(marks, range(len(marks))):
        df_each = _df[_df[_mark] == mark]
        _plt.scatter(df_each[_x], df_each[_y], s = 100, marker=markers[i], color = "black")

#csvをpandasで読み込み
path = "input.csv"
df = pd.read_csv(path)
#列名取得
df_column = df.columns.values
x_column = df_column[0]
y_column = df_column[1]
mark_column = df_column[2]

#x座標の最大値, 最小値から直線の表示域を決定
start = df[x_column].min()*0.9
end = df[x_column].max()*1.1

#グラフ定義
plt.rcParams['figure.subplot.bottom'] = 0.15
plt.rcParams['lines.linewidth'] = 3
fig, ax = plt.subplots()

#回帰式を計算
a, b, r2 = regression(df[x_column], df[y_column])

#回帰式を表示
plt.plot([start, end], [a*start+b, a*end+b], color = "blue")

#軸ラベルを表示
ax.set_xlabel(r'$flow(m^3/s)$', fontsize = 12)
ax.set_ylabel(r'$TN(mg/L)$', fontsize = 12)

#直線の式, 決定係数を表示
putEquationText(a, b, r2, start, end, ax)

#点をプロット
putSeveralMark(df, x_column, y_column, mark_column ,plt)

#画像を保存
plt.savefig("output.png", dpi=200, bbox_inches="tight", pad_inches=0.1)
plt.show()
```

# おわりに
適宜改善して使ってくれると喜びます。
【Ruby 初心者向け 演習問題】配列・範囲とは

## 対象の読者
独学で5年ほどpython/VBAを学習・開発した筆者の経験から初心者向けに

・配列の抑えるポイント
・配列を使えるくらいに理解してるか

という点について解説していきます！

# 配列とはなんぞや

:::note
【ここだけ抑えれば配列は完璧です！】
数字の振ってある箱のイメージ

--> 
そして、<配列の入っている変数名[箱の番号]>とすると
箱の中に入っている要素が取り出せる

:::

![Screen Shot 2022-07-26 at 16.56.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2646082/e89e24c8-9d9b-4f32-e89d-1a96800773ee.png)


```ruby:Q1-usagiを出力させてみよう！
arr = ['niwatori','neko','usagi']
```

<details><summary>Q1解答</summary>
arr[2]
</details>

## どういう時に使うの？

:::note alert
プログラム実装する場合で配列(又はハッシュ)を使わないことは、まずない
というくらい使います
:::

## ブロックとは

:::note
配列をまとめて処理する方法
==> メソッドの引数として渡す事のできる処理の塊
:::

```ruby:例
arr = ['niwatori','neko','usagi']

arr.each do |box|
  puts box
end

#==> niwatori
#==> neko
#==> usagi

```
eachメソッドは、配列を左から順にブロックに渡す

## 演習問題

```ruby:Q2-出力値は?-
arr = ['niwatori','neko','usagi']

arr.map! do |box|
  box + '_chan'
end

puts arr
```
<details><summary>Q2解答</summary>
["niwatori_chan", "neko_chan", "usagi_chan"]
</details>

```ruby:Q3-出力値は?-
arr = ['niwatori','neko','usagi']
puts arr.join('-')
```
<details><summary>Q3解答</summary>
niwatori-neko-usagi
</details>

```ruby:Q4-出力値は?-
arr = ['niwatori','neko','usagi']
arr.each {|n| puts n.length }
```
<details><summary>Q4解答</summary>
8<br>
4<br>
5
</details>

# 範囲とは
1..10 ==> 1から10までの範囲を示すオブジェクト
1...10 ==> 1から10未満までの範囲を示すオブジェクト
※a..eという使用も可能

ここら辺は習うより慣れよだと思うので、問題解いて覚えましょう！

## 演習問題

```ruby:Q5-範囲を使ってxxxにあたる部分を埋めよ-
arr = ['niwatori','neko','usagi']

puts xxx

#==> ['neko','usagi']
```

<details><summary>Q5解答</summary>
arr[1..2]
</details>

```ruby:Q6-範囲を使って1~100までの配列を出力せよ-
```

<details><summary>Q6解答</summary>
(1..100).to_a
</details>

# 終わりに
初学者の方へ：
配列が使えるようになると作れるものが増えて楽しくなるので積極的に使っていきましょう♪

VBA出身者の方へ：
ハッシュ(辞書型)アレルギー起きるかもですが、配列ではなく積極的にハッシュ使っていきましょうwww
【GitHub】 簡単にcommit(コミット)の履歴を1つにまとめる方法

# 背景
アプリ開発中に気づいたらコミットが10件あり履歴が多くてみにくことがあったので
簡単に履歴を一つにまとめる方法があるので紹介します。
今回使うものは、Squash(スカッシュ)です。
## Squashとは
Squashは複数のコミット履歴を1つのコミット履歴でまとめる時使います。
# 使い方
それでは実際にやってみよう！

前提条件として、gitのエディタとしてvimを使用します。

もしvimを使っていないなら設定を変更する必要があります。

## 1. 履歴を探す
まず初めに、下記のコマンドを実行します。
```
$ git merge-base [pushしたいブランチ] HEAD 

//例えば,リモートのmainにpushしたければ下記のように書きます
$ git merge-base origin/main HEAD
```
実行すると下記のように英数字が表示されます。
```
$ git merge-base origin/main HEAD                    
73c9372c8801d9ba05b791d57e67f95de1aa06da //この英数字をコピー
```
`73c9372c8801d9ba05b791d57e67f95de1aa06da` をコピーしてください。
皆さんは、自分のところに出た英数字をコピーしてください。
## 2. 貼り付ける
git rebase -i の後にコピーした、英数字を貼り付けます。
```
$ git rebase -i 73c9372c8801d9ba05b791d57e67f95de1aa06da //貼り付ける
```
## 3. 履歴をまとめる
* `git rebase -i 73c9372c8801d9ba05b791d57e67f95de1aa06da`を実行すると

* 下記のような画面になりましたら、キーボードで英数字の`a`を押してください。

* すると`-INSERT-`と下に出ます。
`-INSERT-`と出れば書き換えが可能になります。
```
pick 950dd6f　コミットのコメント1
pick 565fd5g　コミットのコメント2
pick 5555j6f　コミットのコメント3
pick 484b548　コミットのコメント4
pick gb665gb　コミットのコメント5
pick bg4bg4b　コミットのコメント6
pick 545454g　コミットのコメント7
pick 454gbb5　コミットのコメント8

# Rebase 7911981..950dd6f onto 7911981 (1 command)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
//以下省略
-INSERT-
```
* 下記のように一番上の`pick`以外の`pick`を`s`に書き換えてください。
```
pick 950dd6f コミットのコメント1
s 565fd5g　コミットのコメント2
s 5555j6f　コミットのコメント3
s 484b548　コミットのコメント4
s gb665gb　コミットのコメント5
s bg4bg4b　コミットのコメント6
s 545454g　コミットのコメント7
s 454gbb5　コミットのコメント8

# Rebase 7911981..950dd6f onto 7911981 (1 command)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
//以下省略
```
* できましたら、保存をします。
キーボードの`esc`キーを押して、`:wq`を入力しEnterで実行します。

**※印必ず、`esc`キーを押してから`:wq`を入力してください。**

* もし、保存しないで抜けたい場合は`:q!`としてください。
```
:wq
```
その後はいつも通りpushします。
```
 ! [rejected]        feature/symptom_revision -> feature/symptom_revision (non-fast-forward)
error: failed to push some refs to 'github.com:jurabiinc/oarfish.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```
push時に、上記のエラーが出るときは、強制pushしてください。
```
$ git push -f origin <ブランチ名>
```
これで終了です。
お疲れ様でした。
# 最後に
プルリク時、履歴はできるだけまとめるように心がけましょう！
Training API：lightGBMのラベルエラー　LightGBMError: Label must be in [0, 4), but found 4 in label

# 参加コンペ

https://signate.jp/competitions/724

# エラー内容
Training APIによるLightgbmの多クラス分類を実行する際に次のエラーが発生
*Scikit-learn APIの場合は実行可能

```
LightGBMError: Label must be in [0, 4), but found 4 in label
```

# 原因
元データに付与されているラベルが[1,2,3,4]と0から始まっていないことが原因

# 解決法
ラベルを0から始まるように修正
[1,2,3,4]->[0,1,2,3]
画像選別を行うUI

# 目的
画像認識の機械学習の教師データ（Webからのスクレイピングで集めたデータ）のうち教師データとして不適切なものを削除するために用いる。
基本手作業で行うのでデータが多いほど効率は悪いからこれ以外の解決法がない場合にのみ使うことを推奨する。

集め方についてはここから↓

https://qiita.com/taxinumber1729/items/9d61a65da7962225e765

# 環境
- python=3.6.13
- opencv=3.4.2
- pyautogui=0.9.53


# コード

```python
import cv2
import os
from tkinter import messagebox
import pyautogui as pag

#自分が使っているモニターの高さを取得
monitor_height = pag.size().height

def img_select(car_path):    
    car_img_list = os.listdir(car_path)
    for car_img in car_img_list:
        img = cv2.imread(car_path+'/'+car_img)
        img_height = img.shape[0]
        #画像の高さがモニターの高さの半分よりも大きかったらモニターの半分の大きさにリサイズ
        if img_height>monitor_height*0.5:
            img = cv2.resize(img, dsize=None, fx=float(monitor_height*0.5/img_height), fy=float(monitor_height*0.5/img_height))

        cv2.imshow("image", img)
        k = cv2.waitKey(0)

        if k==ord('s'):
            os.remove(car_path+'/'+car_img)
            print(car_path+'/'+car_img+"を削除しました")
        elif k == ord("q"):
            ret = messagebox.askyesno('確認', 'このフォルダの処理をスキップしますか？')
            if ret==True:
                print("処理をスキップしました")
                return    

        cv2.destroyWindow("img")
        cv2.waitKey(1)


if __name__=='__main__':
    print("Sキーで削除、Qキーで処理を終わる、それ以外のキーは次の画像に移る")
    folder_path = input("フォルダのパスを入力してください")
    cars_list = os.listdir(folder_path)
    for car in cars_list:
        car_path = folder_path+'/'+car
        img_select(car_path)
        ret = messagebox.askyesno('確認', '処理を終わりますか？')
        if ret==True:
            break
    print('処理を終了しました')
```


# 入力フォルダ構造
入力フォルダの構造はこんな感じ

```
root/
├img1_folder/
│ ├img1.png
│ ├img2.png
│ └img3.png
├img2_folder/
│ ├img1.png
│ ├img2.png
│ └img3.png
:
:
├imgn_folder/
│ ├img1.png
│ ├img2.png
│ └img3.png
```



# 操作方法
- 実行したら`フォルダのパスを入力してください`と指示されるので上記のディレクトリ構造の`root`のパスを入力する。
    - Google-images-downloderを使っていたら実行したときに作成される`downloads`のフォルダのパスを入力
- `root`ディレクトリ内のフォルダが上から順にそのディレクトリ内の画像が新しいウィンドウに表示される。
- `S`を押すと表示されている画像が削除される。
- `Q`を押すと今いるディレクトリの処理をスキップする。
    - 次の画像ディレクトリに移動する。
- それ以外のキーを押すと画像が切り替わる
- 画像がまとまっているディレクトリ（imgn_folder）の中の画像すべて見終わったらプログラムを終了するかを確認するウィンドウが表示される。
    - `はい`を押したらプログラムが終了する。`いいえ`を押したら次の画像フォルダに移動する。
積が平方数になる部分集合の数を媒介変数の数から求める


**【例題１】 連続した正の整数の集合 {5,6,7,8,9,10,11}の部分集合でその要素の積が平方数になるものの数を求めよ**

まずこれらの数を素因数分解して現れた素数との関係を表にします。

|  | 5| 6 | 7 |8|9|10|11|
| :---: | :---: | :---: | :---: |:---: |:---: |:---: |:---: |
| 2| 0| 1|0 |3 |0 |1 | 0
| 3| 0| 1| 0| 0| 2|0|0|
| 5|1|0|0|0|0|1|0|
| 7|0|0|1|0|0|0|0|
| 11|0|0|0|0|0|0|1|

各々の数が部分集合に含まれるかどうかを2値変数$n_5, n_6, n_7, n_8, n_9, n_{10},n_{11}$で表します。計算を$\pmod 2$で考えると、平方数になるということは部分集合に含まれるすべての素因数が偶数乗すなわち$0 \pmod 2$になるような$n_x$の組み合わせを求めるという問題になります（式（１））。
$\pmod 2$で考えるので行列の要素は$(0,1)$に変更してあります。

```math 
\begin{pmatrix} 
0&1&0&1&0&1&0 \\ 
0&1&0&0&0&0&0 \\ 
1&0&0&0&0&1&0 \\ 
0&0&1&0&0&0&0 \\ 
0&0&0&0&0&0&1 \\ 
\end{pmatrix}
\begin{pmatrix} 
n_5 \\ n_6 \\ n_7 \\ n_8 \\ n_9 \\ n_{10} \\ n_{11} \\ 
\end{pmatrix}
= 
\begin{pmatrix} 
0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 0 \\ 
\end{pmatrix}
\ \ \ \ \large \dots 式(１)
```

これを手計算で解くと、

```math 

n_6 = n_7 = n_{11} = 0 \\
n_5 + n_{10} = n_8 + n_{10} = 0
となり、\\
 n_9 = s_1 , n_{10} = s_2　と置くと\\
n_5 = n_8 = s_2 となり 
```

2つの媒介変数 $s_1, s_2$を使ってすべての変数が表されます。
$s_1, s_2$が$(0,1)$をとる組み合わせは以下の4通りなので空集合を除くと答えは**3個**となります。

|  $s_1$|$s_2$ |  積が平方数になる部分集合   |
| :---: | :---: | :---: |
| 0| 0| ー|
| 0| 1| $\lbrace  5,8,10 \rbrace$|
| 1| 0| $\lbrace  9 \rbrace$|
| 1| 1|  $\lbrace  5,8,9,10 \rbrace$|

今回は手計算で解きましたが式（１）を見ると行列が$5 \times 7$なので媒介変数の数=$7-5=2$が分かれば$2^2-1=3$という答えを出すことが出来ますね。この考え方を利用して一般化を行います。

**【例題２】 連続した正の整の集合  $\lbrace  k,k+1, \dots, k+n \rbrace$の部分集合でそのその要素の積が平方数になるものの数を求めよ**

この場合、列=$n+1$で、行の数は $\lbrace  k,k+1, \dots, k+n \rbrace$の素因数分解に1回でも現れる素数の数ということになります。pythonで書くと以下のようになります。

```python 
from sympy import primerange

def nprmrange(k1,k2):
  return sum([1 if (k1//p+1)*p <= k2 else 0 for p in primerange(2,k2+1)])
```
素数の数$pn$分かれば積が平方数になる部分集合の数はは$2^{(n+1-pn)}$となるので答えは以下のように簡単に求まります。

```python 
for k1, k2 in [(5,11),(20,30),(50,75)]:
  pn = nprmrange(k1, k2)
  print(f"(k1,k2)=({k1}, {k2}), prime#={pn}, para#={k2-k1+1-pn}, answer={pow(2,k2-k1+1-pn)-1}")
# (k1,k2)=(5, 11), prime#=5, para#=2, answer=3
# (k1,k2)=(20, 30), prime#=8, para#=3, answer=7
# (k1,k2)=(50, 75), prime#=18, para#=8, answer=255
```

この考え方はProject Euler: Problem 619 Square subsetsを解くのに役に立ちます

（開発環境：Google Colab）
RAIDはハードディスクの合体技

# RAID（レイド）とは？
ハードディスクを論理的に一つにまとめた仮想的なハードディスクの運用する技術を```ディスクアレイ```と呼ぶ。
RAIDはその代表的な実装手段のこと。
RAIDはRAID0~RAID6の種類に分けられている。求める速度と信頼性に応じて各種類を組み合わせて使えるようにもなっている。
その中でもRAID0、RAID1、RAID5が多く使われている。

# RAIDの代表的な種類とその特徴
## RAID0（ストライピング）
一つのデータを2台以上のディスクに分散させて書き込みます。
### メリット
応答性能が速くなる
### デメリット
いづれかの一段が壊れると全ファイルが失われることになる。
## RAID１（ミラーリング）
常に2台以上のディスクに対して同じデータを書き込む。
### メリット
常時バックアップが取れる。
### デメリット
使えるディスクが半分になる。
## RAID5
3台以上のディスクを使って、データと同時にパリティと呼ばれる誤り修正符号も分散させて書き込みます。
### メリット
どれか一台のディスクが故障してもパリティ情報を使ってデータを復元できる。
## 気づき
なんで誤り修正符号でデータを復元できるのか理解できない。
あぁ難しそうだ。
調べよう。

### 疑問　誤り訂正符号とは?
データを記録・伝送する際に発生する誤りを受け手の側で検出し、```訂正することができるように付加される符号```。元のデータから一定の手順に基いて算出し、データと共に記録・伝送する。

パリティ情報にはDATA1とDATA2の誤り修正符号が入っているから例え1台がダメになっても残ったディスクから```誤り修正符号とその片方のデータで復元できる```のか。（多分）

## 気づき
まだ終わらない。
はやく先に行こう。

# 関連記事
https://qiita.com/masatom86650860/items/b4a08514e0df254d0f43

# 出典 
https://gihyo.jp/book/2020/978-4-297-11781-8
SES（AWS）のアカウントレベルのサプレッションリストを有効化する

## 概要
AWSの[SES](https://aws.amazon.com/jp/ses/)を使用する際にメールの送信が失敗することがある。
メールの送信が失敗した際に、アカウントレベルのサプレッションリストへと格納されるように設定を変更した。
サプレッションリストに関して調べた内容とその設定方法を記載する。

## 用語
### サプレッションリストとは
サプレッションは抑制・抑圧などの意味がある。
商用電子メールの送信に関するアメリカの国家規格である[CAN-SPAM法](https://en.wikipedia.org/wiki/CAN-SPAM_Act_of_2003)に準拠するため、メールの送信を実施しないリストである。

### Amazon SESにおけるグローバルサプレッションリスト
メールを送信してバウンスとなった場合に、グローバルサプレッションリストに追加される。
グローバルサプレッションリストでは、全てのAWS利用者に適応されるため、別の利用者によってグローバルサプレッションリストに追加されたメールアドレスにも送信することができない。
また、リストに格納される期間は最大14日間である。

### AWSにおけるアカウントレベルのサプレッションリスト
利用者が独自のサプレッションリストを作成して管理することができる。
メールを送信してバウンスとなった場合に、自動的に独自のサプレッションリストに入るようになる。
また、手動でもリストにメールアドレスを追加することもできる。
リストからアカウントの削除も可能であるため柔軟にリストを使用することができる。
グローバルサプレッションリストの様に、バウンスすると全てのAWS利用者に適応されるようなことはなく、アカウントレベルで管理することができる。

## アカウントレベルのサプレッションリストを有効化する
コマンドラインで切り替えることも可能であるが、今回はAWSコンソールを使用する。

SESのサービス画面の左サイドバーの「Suppression list」をクリックする。
![SnapCrab_AWS Simple Email Service - Google Chrome_2022-7-21_16-7-10_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1229062/786eddac-6143-02c5-130e-c1ac6c907639.png)

「Account-level settings」の「Edit」ボタンをクリックし、「Enabled」にチェックを入れて、どのような場合にリストに格納するのかを選択して「Save changes」をクリックする。

![SnapCrab_NoName_2022-7-21_16-10-34_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1229062/6b4edd16-d20f-f6f0-ec82-117bf6b65af6.png)

上記設定でアカウントレベルのサプレッションリストを有効化することができる。
有効化すると「AWSにおけるアカウントレベルのサプレッションリスト」で記載した内容を実現することができる。

## 参考文献
[CAN-SPAM法](https://en.wikipedia.org/wiki/CAN-SPAM_Act_of_2003)
[Amazon SES サプレッションリストに関して](https://docs.aws.amazon.com/ja_jp/ses/latest/dg/sending-email-global-suppression-list.html)
Prism コードサンプル学習：29-InvokeCommandAction

# Prism コードサンプル学習：29-InvokeCommandAction

## はじめに

以下の記事の続きです。
<https://qiita.com/mngreen/items/0e0e41705b4f53d45360>

## 29-InvokeCommandAction

本サンプルは、Itemの一覧を表示するビューが表示されるサンプルになっており、その一覧の要素を選択するとウインドウ下部のテキストブロックが書き換わります。
この書き換える処理の実装にPrismのInvokeCommandActionが利用されています。

```xml
<Window ... >
    <Grid>
        ...
        <ListBox Grid.Row="1" Margin="5" ItemsSource="{Binding Items}" SelectionMode="Single">
            <i:Interaction.Triggers>
                <!-- This event trigger will execute the action when the corresponding event is raised by the ListBox. -->
                <i:EventTrigger EventName="SelectionChanged">
                    <!-- This action will invoke the selected command in the view model and pass the parameters of the event to it. -->
                    <prism:InvokeCommandAction Command="{Binding SelectedCommand}" TriggerParameterPath="AddedItems" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ListBox>
        ...
    </Grid>
</Window>
```

上記でバインディングされているコマンドはVMで定義されています。
また、TriggerParameterPathで指定されている"AddedItems"はSelectionChangedイベントが発行したときのSelectionChangedEventArgs引数の中のAddedItemsプロパティを利用するという宣言になります。
VMは以下の処理となっています。

```cs
...

namespace UsingInvokeCommandAction.ViewModels
{
    public class MainWindowViewModel : BindableBase
    {
        ...
        private string _selectedItemText;
        public string SelectedItemText
        {
            get { return _selectedItemText; }
            private set { SetProperty(ref _selectedItemText, value); }
        }
        public IList<string> Items { get; private set; }
        public DelegateCommand<object[]> SelectedCommand { get; private set; }
        public MainWindowViewModel()
        {
            Items = new List<string>();
            Items.Add("Item1");
            Items.Add("Item2");
            Items.Add("Item3");
            Items.Add("Item4");
            Items.Add("Item5");
            // This command will be executed when the selection of the ListBox in the view changes.
            SelectedCommand = new DelegateCommand<object[]>(OnItemSelected);
        }
        private void OnItemSelected(object[] selectedItems)
        {
            if (selectedItems != null && selectedItems.Count() > 0)
            {
                SelectedItemText = selectedItems.FirstOrDefault().ToString();
            }
        }
    }
}
```

上記の中で、MainWindowViewModel.OnItemSelectedメソッドがSelectedCommandの実処理となりますが、このときの引数であるselectedItemsパラメーターにさきほど示したAddedItemsプロパティが入るという関係性になっています。
ここでは[InvokeCommandAction](https://github.com/PrismLibrary/Prism/blob/master/src/Wpf/Prism.Wpf/Interactivity/InvokeCommandAction.cs)の実装を読み進め、どのようにプロパティを取得しているか見ていきます。
読み進めると、[Invoke](https://github.com/PrismLibrary/Prism/blob/master/src/Wpf/Prism.Wpf/Interactivity/InvokeCommandAction.cs#L118)メソッド内の処理でリフレクションを利用してプロパティを取得していました。
"."で分割してループしているため、イベント引数が入れ子になっていた場合があったとしても問題ない実装になっています。
もし値が取得できればコマンド実行時にパラメーターとして渡され、上記の振る舞いが実現されているようです。

## おわりに

今回は29-InvokeCommandActionクラスを読み進め、どのようにイベント引数とコマンドのパラメーターをつなげているのかを読み進めました。
リフレクションをうまく活用する、という点で勉強になりました。
WPFのサンプルは本サンプルですべて読み終わったため、他のリポジトリを読んだり、気になるところがあればまた取り上げて見ていこうと思います。
Octave で「peaks」を描画

# Octave で「peaks」を描画

3 次元空間の曲面 `peaks` を描く。

    z = 3*(1-x)^2*exp(-x^2 - (y+1)^2) ...
             - 10*(x/5 - x^3 - y^5)*exp(-x^2-y^2) ...
             - 1/3*exp(-(x+1)^2 - y^2)

$z = \displaystyle 3(1-x)^2 \times \exp(-x^2 - (y+1)^2) - 10(x/5 - x^3 - y^5) \times \exp(-x^2-y^2)- \frac{\exp(-(x+1)^2 - y^2)}{3}$

    peaks()
    peaks(n)
    peaks(x, y)
    z = peaks(…)
    [x, y, z] = peaks(…)

引数無しで呼べば `surf()` で曲面を描く。

`n` がスカラーならば `n x n` のグリッド，[-3, 3] の範囲で曲面を描く（`n=49` がデフォルト）。

`n` がベクトルの場合はグリッドとして，指定された座標に基づいて `z` 座標値を返す。

`x`，`y` が指定された場合は，指定された座標に基づいて `z` 座標値を返す。

戻り値を 1 個指定した場合は `z` 座標値を返す。

戻り値を 3 個指定した場合は `x`, `y`, `z` 座標値を返し，引き続いて `surf(x, y, z)` で曲面, `mesh(x, y, z)` でワイヤーフレームを描くことができる。



```matlab
peaks()
```


    
![output_1_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/e3a12a88-bd42-6ebc-3a3d-652daa0dcdeb.png)

    



```matlab
colormap("pink")
peaks(100)
```


    
![output_2_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/5f2e9fcb-bcc2-98c4-3e81-07353502a1be.png)

    



```matlab
[x, y, z] = peaks(21);
colormap("autumn")
surf(x, y, z)
```


    
![output_3_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/c8f58bda-2184-7ba3-10fa-b749e2f40f85.png)

    



```matlab
colormap("spring")
mesh(x, y, z)
```


    
![output_4_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/5fccc5b3-f189-e60f-6cde-3a47cf07dc3b.png)

    


`peaks()` の結果を使わずに `meshgrid()` を計算し，`z` 座標を計算して，さらに `mesh()` でワイヤーフレームを描くのは以下のようになる。


```matlab
tx = ty = linspace(-3, 3, 21)';
[x, y] = meshgrid(tx, ty);
z = 3*(1-x).^2 .* exp(-x.^2 - (y+1).^2) ...
         - 10 * (x/5 - x.^3 - y.^5) .* exp(-x.^2-y.^2) ...
         - 1/3 * exp(-(x+1).^2 - y.^2);
```


```matlab
colormap("autumn")
surf(x, y, z)
```


    
![output_7_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/08de56c6-525e-6315-58c4-bb7f29392cf1.png)

    



```matlab
colormap("spring")
mesh(x, y, z)
```


    
![output_8_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/4f75e1da-0b4d-a3c0-9170-0641f160d15a.png)
PowerShell V5で2GBを超えるzipファイル作成

PowerShell V5(powershell.exe)でCompress-Archiveコマンドレットでフォルダからzipを作成しようとして以下のようなエラーになった
```
Compress-Archive : Exception calling "Write" with "3" argument(s): "Stream was too long."
At C:\XXX\XXX.ps1:98 char:3
+   Compress-Archive -Path $dir -DestinationPath $zipFile -Force
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Compress-Archive], MethodInvocationException
    + FullyQualifiedErrorId : IOException,Compress-Archive
```

上記は以下の2GB制限があるため
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.archive/compress-archive?view=powershell-7#description
>The Compress-Archive cmdlet uses the Microsoft .NET API System.IO.Compression.ZipArchive to compress files. The maximum file size is 2 GB because there's a limitation of the underlying API.

PowerShell V7(pwsh.exe)だと以下が使える
```
[IO.Compression.ZipFile]::CreateFromDirectory($dir, $zipFile)
```

しかしV5だと上記は以下のエラーになる
```
Unable to find type [IO.Compression.ZipFile].
At C:\XXX\XXX.ps1:98 char:1
+ [IO.Compression.ZipFile]::CreateFromDirectory($dir, $zipFile ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (IO.Compression.ZipFile:TypeName) [], RuntimeException
    + FullyQualifiedErrorId : TypeNotFound
```

V5の場合には事前に以下を実行しておく
```
Add-Type -AssemblyName System.IO.Compression.FileSystem
```

さらに、上書きエラー回避も入れて以下が完成版
```
if (Test-Path $zipFile) {
  Remove-Item $zipFile -Force
}
Add-Type -AssemblyName System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::CreateFromDirectory($dir, $zipFile)
```
ECCube関連コマンド一覧

sudo systemctl stop mysqld
sudo yum -y remove mariadb-libs
sudo yum -y remove mysql-community-*
sudo rm -rf /var/lib/mysql/
sudo yum localinstall http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
sudo yum repolist all | grep mysql
sudo yum-config-manager --disable mysql80-community
sudo yum-config-manager --enable mysql57-community
sudo yum repolist all | grep mysql
sudo yum list | grep mysql-community-server
sudo yum -y install mysql-community-server
sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022
sudo yum -y install mysql-community-server
sudo mysqld --version　
sudo  systemctl enable mysqld
grep "temporary password" `find /var/log/ -name "mysql*log"`
sudo systemctl stop mysqld
sudo systemctl set-environment MYSQLD_OPTS="--skip-grant-tables"
sudo systemctl start mysqld &
mysql -u root
use mysql;
UPDATE mysql.user SET authentication_string=null WHERE User='root';
FLUSH PRIVILEGES;
quit;
sudo systemctl stop mysqld
sudo systemctl unset-environment MYSQLD_OPTS
systemctl start mysqld
mysql -u root
SET PASSWORD = PASSWORD('@Hatti7900');
quit;
sudo mysql -u root -p
yum info httpd　
sudo yum install httpd
httpd -version　
systemctl start httpd.service
sudo systemctl status httpd.service
sudo yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
sudo yum -y install --enablerepo=remi,remi-php74 php php-mbstring php-xml php-xmlrpc php-gd php-pdo php-pecl-mcrypt php-
mysqlnd php-pecl-mysql
php -v  　
sudo vi /var/www/html/index.php　　→ php　phpinfo();
sudo systemctl restart httpd　
mv /home/hachiya/eccube /var/www/html/
user@USERnoMacBook-Pro Downloads % sftp -P 2222 hachiya@localhost 
sftp> put -r /Users/user/Downloads/eccube 
sudo yum list installed | grep php
sudo yum install --enablerepo=remi-safe php74-php-zip
sudo yum list installed | grep php
sudo find / -name "*zip.so"　
sudo ln -s  /opt/remi/php74/root/usr/lib64/php/modules/zip.so /usr/lib64/php/modules/zip.so
ls /usr/lib64/php/modules/
sudo vi /etc/php.ini　→ extension=zip.so
sudo systemctl restart httpd
sudo yum install --enablerepo=remi-safe php74-php-intl
sudo yum list installed | grep php
sudo find / -name "*zip.so"　
sudo ln -s  /opt/remi/php74/root/usr/lib64/php/modules/intl.so /usr/lib64/php/modules/intl.so
ls /usr/lib64/php/modules/　
sudo vi /etc/php.ini　→ extension=intl.so
sudo systemctl restart httpd
sudo chmod -R 777 /var/www/html/eccube/app/
sudo chmod -R 777 /var/www/html/eccube/html/
sudo chmod -R 777 /var/www/html/eccube/vendor/
フラグメンテーション

ハードディスクに書き込みと削除を繰り返していくと空きのプラッタが分散してしまう。
このような分散した状態を```フラグメンテーション(断片化)```と言う。
これによりアクセス速度は遅くなり、アクセス時間が長くなる。

# デフラグで再整理
フラグメンテーションが生じてアクセス時間が長くなるがその中のシーク（位置決め）に時間がかかる。
（一つのファイルの内容を断片化した空きの容量にそえぞれ振り分けられているから）
断片化したファイルのデータを連続した領域に並べ直してフラグメンテーションを解消する。
この作業を```デフラグメンテーション```と言う。

# 問題を解いた時の気づき
## 疑問 データベース応答性能とは？
数千万・何億件ものデータを格納するデータベースに対して検索を行う時、こういう台詞を「言う・聞く」事があります。数千件や数万件の規模であれば瞬きする程度で```結果が表示```されますが、数千万や「億」といった単位に差し掛かると、```データベース性能は「僕らの期待値」から徐々にずれ始めていきます。```
...
このような経験を日々積み重ねていくと「あ、なんか引っかかるなぁ」とか「このアプリ遅いなぁ」と感じる事が増えてきます。
...
単純に言えば「CPU性能」を向上させるのが有効と言えるケースがあると思います。

ですが、「数千万、数億件」というデータを取り扱い始めると、重要となるのは「CPU性能」よりも```「記憶装置」```と言えます。
数億件ものデータを格納する「記憶装置」の動きが遅ければ、どれだけ「CPU性能」を向上させたとしても大きな改善はない可能性が高い。
...
ハードディスクは円盤状の磁気ディスクを高速に回転させ、磁気ヘッドを物理的に移動させながら情報の記録・参照を行います。このような物理的な動作がある以上、どこまで処理速度は上限に到達し、お客様の期待値からずれ始めていきます。
...
「半導体チップを利用したストレージ装置」です。パソコン業界に詳しい方であれば「SSD」(Solid State Drive) と言えばご理解いただけると思います。
...
ハードディスク装置と比較して驚く程の高速性能が発揮されます。2倍? 3倍くらい? いえいえ「数十倍以上」という表現が適しています。物理的に部品が動くわけではないので、故障率もぐっと低くなります。

出典　https://www.synergy-marketing.co.jp/blog/database-response-time
### 疑問　カットオーバーとは？
新しく開発されたシステムが稼動すること

### 気づき
データベース応答性能とは検索して結果が表示される時間のことを言うのか。
それには記憶装置の性能が大きく作用しているのか。
またハードディスクよりもSSDの方が早いのか。
これからSSDについては勉強していくのかな。
lxdで立ち上げた仮想マシンのCPUとメモリの設定をする

起動している仮想マシン

```bash
$ lxc list
+--------------------------+---------+-----------------------+-------------------------------------------------+-----------------+-----------+
|           NAME           |  STATE  |         IPV4          |                      IPV6                       |      TYPE       | SNAPSHOTS |
+--------------------------+---------+-----------------------+-------------------------------------------------+-----------------+-----------+
| ubuntu2204-desktop-vm-00 | RUNNING | 10.86.163.88 (enp5s0) | fd42:f181:9c81:dde3:216:3eff:fe03:b48b (enp5s0) | VIRTUAL-MACHINE | 0         |
+--------------------------+---------+-----------------------+-------------------------------------------------+-----------------+-----------+
```

CPU情報を表示させるとCPUコアは1個認識していました。

```bash
$ lxc exec ubuntu2204-desktop-vm-00 -- cat /proc/cpuinfo | grep ^process
processor	: 0
```

メモリは約1GBでした。

```bash
$ lxc exec ubuntu2204-desktop-vm-00 -- free -h
               total        used        free      shared  buff/cache   available
Mem:           967Mi       590Mi        99Mi        50Mi       277Mi       188Mi
Swap:             0B          0B          0B
```

一旦仮想マシンを停止します。

```bash
$ lxc stop ubuntu2204-desktop-vm-00
$ lxc list
+--------------------------+---------+------+------+-----------------+-----------+
|           NAME           |  STATE  | IPV4 | IPV6 |      TYPE       | SNAPSHOTS |
+--------------------------+---------+------+------+-----------------+-----------+
| ubuntu2204-desktop-vm-00 | STOPPED |      |      | VIRTUAL-MACHINE | 0         |
+--------------------------+---------+------+------+-----------------+-----------+
```

CPUコアを4個、メモリ容量を8GBに設定します。

```bash
$ lxc config set ubuntu2204-desktop-vm-00 limits.cpu 4
$ lxc config set ubuntu2204-desktop-vm-00 limits.memory 8GB
```

仮想マシンを起動します。

```bash
$ lxc start ubuntu2204-desktop-vm-00
```

CPU情報を表示させるとCPUコアは4個認識していました。

```bash
$ lxc exec ubuntu2204-desktop-vm-00 -- cat /proc/cpuinfo | grep ^process
processor	: 0
processor	: 1
processor	: 2
processor	: 3
```

メモリは約8GBでした。

```bash
$ lxc exec ubuntu2204-desktop-vm-00 -- free -h
               total        used        free      shared  buff/cache   available
Mem:           7.2Gi       700Mi       6.0Gi        54Mi       528Mi       6.3Gi
Swap:             0B          0B          0B
```
Octave で「ソンブレロ」を描画

# Octave で「ソンブレロ」を描画

3 次元空間の曲面，いわゆる「ソンブレロ」を描く。

`z = sin(sqrt(x^2 + y^2)) / (sqrt(x^2 + y^2))`

$z = \displaystyle \frac{\sin \big(\sqrt{x^2 + y^2}\big)}{\sqrt{x^2 + y^2}}$

    sombrero()
    sombrero(n)
    z = sombrero(…)
    [x, y, z] = sombrero(…)

Plot the familiar 3-D sombrero function. 
The function plotted is 

引数無しで呼べば [-8, 8] での曲面を描く。

`n` がスカラーならば `n` 本のグリッドで曲面を描く（`n=41` がデフォルト）。

戻り値を 1 個指定した場合は `z` 座標値を返す。

戻り値を 3 個指定した場合は `x`, `y`, `z` 座標値を返し，引き続いて `surf(x, y, z)` で曲面, `mesh(x, y, z)` でワイヤーフレームを描くことができる。



```matlab
sombrero()
```


    
![output_1_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/c3b52185-6721-63ec-a6d1-104e60c73e10.png)

    



```matlab
colormap("pink")
sombrero(100)
```


    

![output_2_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/22dd1a6e-50cd-6d0e-7fda-b8a8afc2ede9.png)

    



```matlab
[x, y, z] = sombrero(21);
colormap("autumn")
surf(x, y, z)
```


    
![output_3_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/04f88d3c-b2ad-2003-1582-476f641ac9ed.png)





```matlab
colormap("spring")
mesh(x, y, z)
```


    
![output_4_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/0114c420-b14e-1d02-4325-d7777d21b152.png)

    


`sombrero()` の結果を使わずに `meshgrid()` を計算し，`z` 座標を計算して，さらに `mesh()` でワイヤーフレームを描くのは以下のようになる。


```matlab
colormap("summer")
tx = ty = linspace(-8, 8, 21)';
[x, y] = meshgrid(tx, ty);
r = sqrt(x .^ 2 + y .^ 2) + eps;
z = sin(r) ./ r;
mesh(x, y, z);
xlabel("x");
ylabel("y");
zlabel("z");
title("3-D Sombrero plot");
```


    
![output_6_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2611739/173caf42-d7fb-2bb7-137d-d95eb554ddda.png)
競技プログラミングってお作法あるよね（標準入力・出力など）

こんにちは。
C#の基本的な記述を学んでいきます、と前回の記事に書きました。

https://paiza.jp/works/

こちらで地道に勉強しています。

ところで、paiza、**スキルチェック**というものがあるじゃないですか。

スキルチェック問題を解いていくとランクが上がっていきます。
paizaが運営している転職サイトなどからランクに応じて**スカウトが来たり、応募できるようになったり**するんですね。

https://paiza.jp/guide/career#rank

ちなみに私は今Cランク。
![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2737718/fc7224cc-0e58-ca95-39fb-a8c1026bb6b6.png)

スキルチェック問題解いて思ったのですが、これ、競技プログラミングで使われる **「標準入力」とか「標準出力」とかの知識** が必要になってくるっぽいのですね。あとは **「制約」** とか。
私はこれらを **「お作法」** って勝手に呼んでいます。

今日は競技プログラミングやpaizaのお作法ついて書いていきたいと思います。

# 標準入力と標準出力
むかしむかし、競技プログラミングについて勉強していた時期がありました。
AtCoderもやってましたよ、ビギナーだけど。

https://atcoder.jp/?lang=ja

そこで躓いたんです、**「標準入力」と「標準出力」** に。

### そもそも「標準入力」と「標準出力」とは？

以下の **「コードの評価方法」** を読んでください。

https://paiza.jp/guide/samplecode

>各問題とも「提出いただいたコードの実行(標準入力による値の取得、計算処理)→標準出力→正誤の判定」という流れになります。(中略)  **標準入力の値取得および、標準出力による計算結果の出力を必ず実装してください。** 

とあります。「標準入力」と「標準出力」は**必須**ということですね。

#### **標準入力とは**
入力される値を入れるもの。値（「あいうえお」とか123,456とか）には「型」があって、Stringだったり、intだったりします。それを、問題文の通りに入力するようにするコードが「標準入力」です。たとえば、「**前後の余分な空白を消して、** 文字列だけを入力してください」って問題文にあったら、
```trim.cs
public static void Main(string[] args)
{
    var text = System.Console.ReadLine().Trim();
}
```
って、書くと、文字列の前後の余分なスペースが削除されます。

ちなみに**Trim()** は以下のような関数。
>現在の文字列から、指定した文字セットを先頭および末尾の出現箇所からすべて削除した新しい文字列を返します。

https://docs.microsoft.com/ja-jp/dotnet/api/system.string.trim?view=net-6.0

C#では、``Console.ReadLine();``が標準入力の基本的な値の受け取り方です。

#### **標準出力とは**
入力とは反対に、画面に出力します。ハローワールドを出すように、基本的には問題文の中にある、出力例のように出力されていればOKです。

C#では、``Console.WriteLine();``が標準出力の基本的な記述です。

#### 参考サイト

https://konichallengelog.com/inputoutput-cs/

# 「制約」という値
スキルチェック問題や競技プログラミングの問題を解いたことがある人なら見たことあると思います。
**1 ≦ N ≦ 100** という感じの**制約**（条件）を・・・。

**とつぜん数学始まった～！！** と瞬時に諦めるにはまだ早いです。

これどういう意味かっていうと、

**「Nには1以上100以下の値しか入力されないよ」。**

という意味です。

制約では、**入力される可能性のある値の範囲**を示しています。
だから、実行時間の指定がシビアだったりする場合以外はとりあえず気にしなくて良いかなと思います。（もちろん言語と問題文によります）

# 個人的に思う「あの時欲しかった予備知識」
以下サイトの、

https://yukicoder.me/wiki/knowledge

>出力ベースに考える
>ACが正義

このあたりから問題を考え始めると良いんじゃないかと思います。

こうやって冷静に振り返っていると、意外とさっぱりしたもんだなって思います。
あとは問題文のとおりに制限時間内に出力できればいいんです。

(2022.07.27追記)

paizaなら以下のサイトに本番に近い問題集があるので実際にやって慣れていくと良いと思います。

https://paiza.jp/works/mondai

---------

なんか色々間違っていたらどうしよう・・・。
これ致命的にやばいぞって記載ミス等あったらコメントくださいまし。

おわり。
Dockerで何もしていないのにRubyのバージョンが変わった時の対処法

## エラー内容

突然、Dockerで環境構築していたアプリで、
```terminal:terminal
Your Ruby version is 2.7.4, but your Gemfile specified 3.1.2
```
となり、何もできなくなった。。。


## 解決方法
vscodeの拡張機能「Remote - Containers」を使っていたので、そこの「Rebuild Container」をクリック！
[![Image from Gyazo](https://i.gyazo.com/1110a3c08a1bff63884324bfcc1c49ef.png)](https://gyazo.com/1110a3c08a1bff63884324bfcc1c49ef)
ビルドされるのを待って、再度試すとエラー解決していました👏

正常にビルドされていなかったことが原因っぽいです。
windowsエクスプローラーがtsをビデオと判断してしまう

windowsエクスプローラーがtsをビデオと判断してしまうので、エクスプローラーで開くのにモタモタする。。の対処

・レジストリエディタを開く。windowsキー→regeditとか
・コンピューター\HKEY_CLASSES_ROOT\.tsを編集
![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2726391/96f9ff38-802f-fafa-5576-252a2e0c9248.jpeg)
Windows Server 2022評価版を日本語化する

# What's？

VagrantのBoxで公開されている、Windows Server 2022の評価版を日本語化したいなということで。

手順を少しメモ。

# 対象

こちらのBoxを使用しています。

https://app.vagrantup.com/gusztavvargadr/boxes/windows-server

利用時のバージョン。

```shell
gusztavvargadr/windows-server (virtualbox, 2102.0.2207)
```

起動した時のWindows Serverのバージョンキャプチャ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/ca40a098-5501-7739-84f1-05c798b64b0e.png)

# Let's 日本語化

「Settings」から

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/2ce19902-7124-8be6-d548-2e1587b5ccbc.png)

「Time & Language」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/e4a484b6-dc63-1211-55c2-d48eb9a46e02.png)

「Language」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/d99c60ca-d4d2-79ae-adc7-b1f2877546ab.png)

「Add a language」を選んで、「日本語」を選択して「Next」。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/30cfe685-ad1b-ef11-312a-3dcd0d4f4b84.png)

そのまま「Install」。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/18290a87-f8ff-3516-00b8-8bd66156a204.png)

ダウンロードが行われるので、しばらく待機。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/de287708-0023-b1a7-e4e8-478fe3d185a9.png)

ダウンロードが完了したら、言語が選択できるようになっているので「日本語」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/870e62dc-ebd7-1c65-b18a-2fc15c2f354e.png)

ここで1度サインアウトまたは再起動。

「日本語」を選択して、「オプション」を選ぶ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/f56509a1-b04e-62ca-0182-d08d4e5d734a.png)

「ハードウェア キーボード レイアウト」の「レイアウトを変更する」から、「日本語キーボード」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/dd481220-025a-9f4c-902d-f1f55f1717ef.png)

「日付と時刻」から、タイムゾーンを日本時間に設定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/f67ac076-61af-07a3-ee4a-d39637565ffe.png)

「地域」から「国または地域」を「日本」に設定。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/bfd1e22e-cce9-430f-bbe7-84df74cbacd5.png)

「地域」の「日付、時刻、地域の追加設定」を選び、「地域」の「日付、時刻、数値形式の変更」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/9f233649-9368-c0dd-0005-e5a71b6f343a.png)

「管理」を選んで

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/46189c4f-a66a-8c85-cfd2-ba0c9323f727.png)

「設定のコピー」から「ようこそ画面とシステムアカウント」および「新しいユーザーアカウント」にチェックを入れて「OK」。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/a353cefd-2cbf-8887-98fc-a289e7774d87.png)

「システム ロケールの変更」から、「現在のシステム ロケール」を「日本語(日本)」にして「OK」。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309669/33762c08-8dc1-710e-2e58-eba7911a4bd7.png)

再起動して完了。

# 参考

https://www.dell.com/support/kbdoc/ja-jp/000111205/windows-server-2019-%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%A9%E3%82%A4%E3%82%BA-%E6%89%8B%E9%A0%86
22新卒が1か月勉強してJava SE Bronzeを受けてみた

## はじめに
今回、入社後の課題としてJava SE Bronzeを受験しました。
なんとかギリギリで合格したので記録と反省として記事を残します。
参考になるかはわかりませんが、暇つぶしに読んでいただけると幸いです。

## Java SE Bronze試験について
### 試験概要 
- 試験名： Java SE Bronze 
- 試験番号：1Z0-818-JPN
- 試験時間：65分
- 問題数：60問
- 合格ライン：60%
- 試験方法：CBTによる選択式
- 試験料：16,500円(税込)

Java資格の入門レベルです。
試験料が高めなので、落とすと再受験となり割と痛いです。
また、弊社では不合格の場合、試験料が経費精算できないため新卒からすると大赤字になります。

## わたしのスペック
- 22新卒でIT企業に入社
- 大学時代の専攻は情報系(笑)
- 入社して2年ぶりにコードを書いた
- Javaへの理解ほぼ皆無
- 集中力も皆無

## 学習期間と時間
- 6月28日から学習開始、7月23日に受験
- 学習時間は1か月×1~1.5時間程度(30時間くらい)
(平日1時間程度、休日はやったりやらなかったり)

## 使用した教材
### 徹底攻略Java SE Bronze問題集[1Z0-818]対応
- 黒本と呼ばれている問題集で、実際の試験に同じような問題が出ます。

https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5Java-SE-Bronze%E5%95%8F%E9%A1%8C%E9%9B%86-1Z0-818-%E5%AF%BE%E5%BF%9C/dp/4295008958


## 学習方法
- **黒本を周回した(計4周)**
最初に1週間ほどで1周して、後半は時間がなかったので2日で1周していました。

- **わからないことは質問・ググる**
よく同期に質問して、説明してもらっていました。
話したことや調べたことは頭に残りやすかったです。
自分なりに調べたことをまとめるのもいいかもしれません。

## 学習する中で躓いたこと
- そもそも用語の知識が浅く、理解に時間を要した
- オーバーロードとオーバーライドなど似ている言葉を混同しがち
- コンパイルエラーになるのか例外スローされるのかの判断ができない
- コンストラクタチェーンの流れがわからない
- というかほぼ全部

ここらへんはまた別で記事を書けたらいいなと思っています。。。

## もっとこうしておけば、、、
- **基礎的な用語の復習から始めておけばよかった**
用語がわかっていないと、解説読んでも理解が難しかったです。

- **ほかの問題集も解けばよかった**
問題集一冊だけだと、答えを覚えてしまって解いてる意味があるのかわからなくなりました。
解き方を理解しながら問題を解くのがおすすめです。

- **時間を計って勉強しておけばよかった**
60問を65分で解かないといけないため、時間が結構シビアです。
時間感覚を身に付けておくと本番も落ち着いて対応できると思います。
私は本番でものすごく焦りました。

- **実際にコード動かしてみればよかった**
実際にコードを書いて動かした方が挙動を理解しやすかったのかなと思いました。
また、記憶にも残りやすいと思います。

- **理解できていないところを明確にしておけばよかった**
わからない部分を明確にすることで、ピンポイントに理解を深めることができたと思います。
私はこれに気付くのが試験直前になってしまい、中途半端な理解のまま受験してしまいました。

## 受けてみた感想
- **問題がちょっと意地悪**
問題が少し意地悪なので、ちゃんと問題文を読まないと間違えます。
集中力がない人や読み飛ばしが多い人は注意した方がいいです。

- **勉強すれば取れるはず**
集中力皆無の私でもぎりぎり合格(正答率61%)できたので、それなりに勉強すれば取れるはずです。

## 最後に
今回は私がJava SE Bronzeを受験した際の学習方法や後悔をまとめてみました。
私の後悔と反省が誰かの役に立てばいいなと思います。
地道に問題を解くだけでは、知識は身につかないと実感しました。
今回の反省を踏まえながら、今後もさらなる資格取得に取り組んでいきたいと思います。
ここまで読んでいただきありがとうございました。
QR分解による対角化の可視化

https://qiita.com/antiplastics/items/17d3885fe1fc033e0e09

https://qiita.com/antiplastics/items/fc7b7b0066cbd823b6a6

の続き。

ハウスホルダー変換によって三重対角化された後、最後にQR分解で得られた行列Qで再び相似変換することで対角化するところを可視化した。

```r
plotA2 <- function(A, step){
  image.plot(log10(A[, ncol(A):1]+1),
    main=paste0("k = ", step),
    xaxt="n", yaxt = "n")
}

QR <- function(A, viz=FALSE, viz.dir="", num.step=100){
  if(viz){
    if(viz.dir==""){
      plotA2(A, 0)
      Sys.sleep(0.2)
    }else{
      png(file=paste0(viz.dir, "/Step0000.png"))
      plotA2(A, 0)
      dev.off()
    }
  }
  step <- 1
  while(step <= num.step){
    Q <- qr.Q(qr(A))
    A <- t(Q) %*% A %*% Q
    if(viz){
      if(viz.dir==""){
        plotA2(A, step)
        Sys.sleep(0.2)
      }else{
        png(file=paste0(viz.dir, "/Step",
          str_sub(paste0("000", step), start = -4),
          ".png"))
        plotA2(A, step)
        dev.off()
      }
    }
    step <- step + 1
  }
  list(U=U, Sigma=A)
}

# 30×30行列で実験
dir.create("QR", showWarnings=FALSE)
out2 <- QR(out$Sigma, viz=TRUE, viz.dir="QR")
```

![merged.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17038/82588159-f12a-30d7-0a94-277d2786604f.gif)

確かに、Qが左右にかかることで、少しずつ三重対角行列が、対角行列になっていることがわかる。

試しに適当に作った対称行列で、ハウスホルダー変換を経ずにいきなりQR分解による対角化を適用してみた。

```r
# 30×30行列で実験
dir.create("QR2", showWarnings=FALSE)
A <- matrix(runif(30*30), nrow=30, ncol=30)
A <- t(A) %*% A # 対称行列にする
out3 <- QR(A, viz=TRUE, viz.dir="QR2")
```

![merged.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17038/68108344-1f5d-7eb1-c87e-bab1f719d6b5.gif)


これでも対角化はできる模様。
互いに直交する基底を取り出すだけのQR分解がなぜ固有値分解（対角化）にもなるのかはよく知らない。
Apache＋php-fpmの構築

# 環境
・CentOS7.3
・Apache2.4
・php5.4


# Apahceのインストール

```

# yum install httpd

```

# phpのインストール

```

# yum install php

```

# php-fpmのインストール

```

# yum install php-fpm

```

# php-fpmの設定

/etc/php-fpm.d/www.confの下記を変更
```
# vi /etc/php-fpm.d/www.conf

listen = /var/run/php-fpm/php-fpm.sock ← 好み

listen.owner = apache
listen.group = apache
listen.mode = 0660

```

#phpの設定

下記コマンドでphp.iniの場所を確認

```
# php --ini

（出力例）
Loaded Configure File: /etc/php.ini

```

php.iniの下記を変更

```
# vi /etc/php.ini

default_charset = UTF-8            ← 使用したいもの
date.timezone = Asia/Tokyo         ← 実態に合わせて
mbstring.language = Japanese       ← 実態に合わせて
mbstring.internal_encoding = UTF-8 ← 使用したいもの
mbstring.http_outpu = UTF-8        ← 使用したいもの

```

# Apacheの設定

/etc/httpd/conf/httpd.confに下記を追加

```

# vi /etc/httpd/conf/httpd.conf

<Directory "/var/www/php-fpm/">                                            ← php-fpmで動かしたいプログラムの格納場所
  <FileMatch (.+\.php)$>                                                   ← 拡張子に合わせて
    SetHandler "proxy:unix:/var/run/php-fpm/php-fpm.sock|fcgi://localhost" ← /etc/php-fpm.d/www.confに設定したもの
  </FileMatch>
</Directory>

```

# php-fpmの起動
```
systemctl start php-fpm

```

# apacheの起動
```
systemctl start httpd

```

# 困った時には
php-fpmのログを確認する
私は下記のような設定にしている

```
/etc/php-fpm.d/www.conf
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_value[log_errors] = on

/etc/php-fpm.conf
log_level = error

```
【機械学習】MLOpsとModelOps、それぞれ「何のために」「誰のために」使われるのか【AI】

# 1.はじめに
・機械学習に触れている過程で**MLOps**とか**ModelOps**という単語が同じ意味で使われていたり、違いが分からなかったりしたので簡単にまとめてみます。

# 2.背景
・現在では多くのAIや機械学習のモデルが開発され、企業など様々なところに取り入れられ始めているが、<font color="red"><B>その内の約半分は生産や運用がされていない(企業のビジネスに活かされていない)</B></font>そうです。

・じゃあどうしたらいいのか、そもそもなんで約半分のモデルがダメになってるのか、それらを解決するために<B>MLOps</B>や<B>ModelOps</B>の**意味**や**違い**を正しく理解する必要があるんですね。

# 3.MLOpsとModelOpsの違い

## 3.1.MLOps(機械学習基盤)

#### <font color="red">AIモデルの開発を円滑に行えるようにすること</font>

・例として、

<B>Amazon Sagemaker</B>

https://aws.amazon.com/jp/sagemaker/


**Domino Data Lab**


https://www.dominodatalab.com/product/domino-enterprise-mlops-platform


**DataRobot**


https://www.datarobot.com/jp/platform/

などのプラットフォームがあります。



## 3.2.ModelOps
#### <font color="red">開発されたモデルが、適切に効率的に企業のビジネスに活かせるようにすること</font>

・例として、

<B>ModelOp Center</B>

https://www.modelop.com/product/

のプラットフォームがあります。



# 4.それぞれ「何のために」「誰のために」使われるのか

## 4.1.MLOps(機械学習基盤)

### <font color="red">機械学習モデルの開発のために使われる</font>

#### 機械学習モデルの開発の過程

- ①：コーディング
- ②：コードのテスト
- ③：トレーニング
- ④：検証
- ⑤：再トレーニング

・これらの開発過程を円滑に行えるようにし、良い機械学習モデルができるようにします。

### <font color="red">データサイエンティストのために使われる</font>

#### データサイエンティストのやること
- 機械学習のモデル開発(上記のような過程)
- 機械学習モデルに対して、適切なデータセットの特定

・これらデータサイエンティストのやることを効率化するために使われます。


## 4.2.ModelOps

### <font color="red">本番環境にある機械学習モデルに対して、最適な結果を出すために使われる</font>

#### 最適な結果を出すために行われる管理

- 本番環境にあるモデルのインベントリ作成
- 使われている機械学習モデルが企業のビジネスに対して信頼できる結果を出しているかの確認
- **コンプライアンスの管理**
- **リスクの要件と管理**

・このように本番環境のモデルのすべての側面の管理します。

### <font color="red">CIO(情報統括役員)、ITオペレーターのために使われる</font>

#### CIO(情報統括役員)、ITオペレーターのやること
- 本番環境にある機械学習モデルの保守、運用
- 企業のニーズを満たすModelOpsプラットフォーム(機械学習モデルを実際にビジネスに使う環境)の確立、実装

・これらCIO、ITオペレーターのやることを効率化するために使われます。


# 5.それぞれの価値
#### **MLOps**も**ModelOps**も、どちらが欠けても企業にとっては損失となる
・ModelOpsだけでは機械学習モデルを開発できません。
・MLOpsだけでは企業の行なっているビジネスの中で、機械学習モデルを運用、保守することはできません。

#### 両方揃って、企業全体のAI導入を加速させる

# 参考サイト

https://www.kdnuggets.com/2021/09/mlops-modelops-difference.html
Reactでカスタムhooks使うときのディレクトリ構成リンク集（独自hooks アーキテクチャ）

カスタムhooksを使うときのディレクトリ構成でググると、

- トップレベルにhooksディレクトリを作る
- カスタムフックスの命名は「use」をつける

くらいしか引っかからずに、凝集性を意識した上でのhooksはどこに置けばいいかについて、ナレッジが見つかりにくかったので、ここにショートカットを置く

[そのファイル、本当に hooks/・utils/ に入れるんですか？React プロジェクトを蝕む「見かけ駆動パッケージング」](https://qiita.com/honey32/items/dbf3c5a5a71636374567?utm_source%3DQiita%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9%26utm_campaign%3D187f9ebba1-Qiita_newsletter_525_07_27_2022%26utm_medium%3Demail%26utm_term%3D0_e44feaa081-187f9ebba1-34577097)
[SPA Componentの推しディレクトリ構成について語る](https://zenn.dev/yoshiko/articles/99f8047555f700)
[Reactベストプラクティスの宝庫！「bulletproof-react」が勉強になりすぎる件](https://zenn.dev/meijin/articles/bulletproof-react-is-best-architecture)
【RSpec】createアクションに関するテスト(リクエストスペックでUserモデルとリレーションのあるデータが追加されるかをテストする)

# 前提
表を作成するアプリをRailsを使って作成しています。
作成した表は、作成者のみが閲覧・編集・削除できるようにしたいと思っています。

# やりたいこと
createアクションに関するリクエストスペックを書く。

# 書いたコード
```ruby:spec/requests/tables_controller_spec.rb
describe"#create"do
  context "as an authorized user" do
    before do
      @user = FactoryBot.create(:user)
    end

    it "adds a table" do
      table_params = FactoryBot.attributes_for(:table)
      sign_in @user
      expect {
        post tables_path, params: { table: table_params }
      }.to change(@user.tables, :count).by(1)
    end
  end
end
```

```ruby:spec/factories/users.rb
FactoryBot.define do
  factory :user do
    id {"1"}
    email { "itirou@example.com" }
    password { "itirou" }
  end
end
```

```ruby:spec/factories/tables.rb
FactoryBot.define do
  factory :table do
    id {"1"}
    title { "表1" }
  end
end
```

```ruby:app/controllers/tables_controller.rb
class TablesController < ApplicationController
  def create
    @table = Table.new(table_params)
    if @table.save
      flash[:notice] = "表を新規登録しました"
      redirect_to :tables
    else
      render "new"
    end
  end

  def table_params
    params.require(:table).permit(:title, :user_id)
  end
end
```

<br>

# テスト失敗
この状態で bundle exec rspec を行ってもテストは失敗します。

```shell
Failures:

  1) Tables #create as an authorized user adds a table
     Failure/Error:
       expect {
         post tables_path, params: { table: table_params }
       }.to change(@user.tables, :count).by(1)
     
       expected `Table::ActiveRecord_Associations_CollectionProxy#count` to have changed by 1, but was changed by 0

```

<br>

# 原因
user_idを登録できていないからです。
私が作成中のアプリでは、ビューに <%= f.hidden_field :user_id, value: current_user.id %> を書き込むことで、作成した表に作成者のuser_idを登録していました。
この方法では、上記のコードでテストできません。

<br>

# 解決
以下のように、コントローラのコードを書き換えることでテストが通ります。

```ruby:app/controllers/tables_controller.rb
  def create
    @table = current_user.tables.new(table_params) #この行を変更
    if @table.save
      flash[:notice] = "表を新規登録しました"
      redirect_to :tables
    else
      render "new"
    end
  end

  def table_params
    params.require(:table).permit(:title) #この行も変更
  end
```
ビューに書いた <%= f.hidden_field :user_id, value: current_user.id %> も削除します。

# 所感
機能の実装のために書いたコードとテストは連動してないと意味がないと痛感しました。